This reverts commit 0a376291b2213699f986a7bca1cc8c4f4ed00f8d.
Signed-off-by: David Calavera <david.calavera@gmail.com>
| ... | ... |
@@ -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 |
// We retry device removal so many a times that even error messages |
| ... | ... |
@@ -89,22 +90,23 @@ type DeviceSet struct {
|
| 89 | 89 |
deviceIdMap []byte |
| 90 | 90 |
|
| 91 | 91 |
// Options |
| 92 |
- dataLoopbackSize int64 |
|
| 93 |
- metaDataLoopbackSize int64 |
|
| 94 |
- baseFsSize uint64 |
|
| 95 |
- filesystem string |
|
| 96 |
- mountOptions string |
|
| 97 |
- mkfsArgs []string |
|
| 98 |
- dataDevice string // block or loop dev |
|
| 99 |
- dataLoopFile string // loopback file, if used |
|
| 100 |
- metadataDevice string // block or loop dev |
|
| 101 |
- metadataLoopFile string // loopback file, if used |
|
| 102 |
- doBlkDiscard bool |
|
| 103 |
- thinpBlockSize uint32 |
|
| 104 |
- thinPoolDevice string |
|
| 105 |
- Transaction `json:"-"` |
|
| 106 |
- deferredRemove bool // use deferred removal |
|
| 107 |
- BaseDeviceUUID string //save UUID of base device |
|
| 92 |
+ dataLoopbackSize int64 |
|
| 93 |
+ metaDataLoopbackSize int64 |
|
| 94 |
+ baseFsSize uint64 |
|
| 95 |
+ filesystem string |
|
| 96 |
+ mountOptions string |
|
| 97 |
+ mkfsArgs []string |
|
| 98 |
+ dataDevice string // block or loop dev |
|
| 99 |
+ dataLoopFile string // loopback file, if used |
|
| 100 |
+ metadataDevice string // block or loop dev |
|
| 101 |
+ metadataLoopFile string // loopback file, if used |
|
| 102 |
+ doBlkDiscard bool |
|
| 103 |
+ thinpBlockSize uint32 |
|
| 104 |
+ thinPoolDevice string |
|
| 105 |
+ Transaction `json:"-"` |
|
| 106 |
+ overrideUdevSyncCheck bool |
|
| 107 |
+ deferredRemove bool // use deferred removal |
|
| 108 |
+ BaseDeviceUUID string //save UUID of base device |
|
| 108 | 109 |
} |
| 109 | 110 |
|
| 110 | 111 |
type DiskUsage struct {
|
| ... | ... |
@@ -1104,7 +1106,10 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
|
| 1104 | 1104 |
|
| 1105 | 1105 |
// https://github.com/docker/docker/issues/4036 |
| 1106 | 1106 |
if supported := devicemapper.UdevSetSyncSupport(true); !supported {
|
| 1107 |
- 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")
|
|
| 1107 |
+ 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")
|
|
| 1108 |
+ if !devices.overrideUdevSyncCheck {
|
|
| 1109 |
+ return graphdriver.ErrNotSupported |
|
| 1110 |
+ } |
|
| 1108 | 1111 |
} |
| 1109 | 1112 |
|
| 1110 | 1113 |
if err := os.MkdirAll(devices.metadataDir(), 0700); err != nil && !os.IsExist(err) {
|
| ... | ... |
@@ -1786,15 +1791,16 @@ func NewDeviceSet(root string, doInit bool, options []string) (*DeviceSet, error |
| 1786 | 1786 |
devicemapper.SetDevDir("/dev")
|
| 1787 | 1787 |
|
| 1788 | 1788 |
devices := &DeviceSet{
|
| 1789 |
- root: root, |
|
| 1790 |
- MetaData: MetaData{Devices: make(map[string]*DevInfo)},
|
|
| 1791 |
- dataLoopbackSize: DefaultDataLoopbackSize, |
|
| 1792 |
- metaDataLoopbackSize: DefaultMetaDataLoopbackSize, |
|
| 1793 |
- baseFsSize: DefaultBaseFsSize, |
|
| 1794 |
- filesystem: "ext4", |
|
| 1795 |
- doBlkDiscard: true, |
|
| 1796 |
- thinpBlockSize: DefaultThinpBlockSize, |
|
| 1797 |
- deviceIdMap: make([]byte, DeviceIdMapSz), |
|
| 1789 |
+ root: root, |
|
| 1790 |
+ MetaData: MetaData{Devices: make(map[string]*DevInfo)},
|
|
| 1791 |
+ dataLoopbackSize: DefaultDataLoopbackSize, |
|
| 1792 |
+ metaDataLoopbackSize: DefaultMetaDataLoopbackSize, |
|
| 1793 |
+ baseFsSize: DefaultBaseFsSize, |
|
| 1794 |
+ overrideUdevSyncCheck: DefaultUdevSyncOverride, |
|
| 1795 |
+ filesystem: "ext4", |
|
| 1796 |
+ doBlkDiscard: true, |
|
| 1797 |
+ thinpBlockSize: DefaultThinpBlockSize, |
|
| 1798 |
+ deviceIdMap: make([]byte, DeviceIdMapSz), |
|
| 1798 | 1799 |
} |
| 1799 | 1800 |
|
| 1800 | 1801 |
foundBlkDiscard := false |
| ... | ... |
@@ -1851,6 +1857,12 @@ func NewDeviceSet(root string, doInit bool, options []string) (*DeviceSet, error |
| 1851 | 1851 |
} |
| 1852 | 1852 |
// convert to 512b sectors |
| 1853 | 1853 |
devices.thinpBlockSize = uint32(size) >> 9 |
| 1854 |
+ case "dm.override_udev_sync_check": |
|
| 1855 |
+ devices.overrideUdevSyncCheck, err = strconv.ParseBool(val) |
|
| 1856 |
+ if err != nil {
|
|
| 1857 |
+ return nil, err |
|
| 1858 |
+ } |
|
| 1859 |
+ |
|
| 1854 | 1860 |
case "dm.use_deferred_removal": |
| 1855 | 1861 |
EnableDeferredRemoval, err = strconv.ParseBool(val) |
| 1856 | 1862 |
if err != nil {
|
| ... | ... |
@@ -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 |
} |
| ... | ... |
@@ -8,7 +8,6 @@ import ( |
| 8 | 8 |
"strings" |
| 9 | 9 |
|
| 10 | 10 |
"github.com/Sirupsen/logrus" |
| 11 |
- "github.com/docker/docker/autogen/dockerversion" |
|
| 12 | 11 |
"github.com/docker/docker/pkg/archive" |
| 13 | 12 |
) |
| 14 | 13 |
|
| ... | ... |
@@ -23,10 +22,9 @@ var ( |
| 23 | 23 |
// All registred drivers |
| 24 | 24 |
drivers map[string]InitFunc |
| 25 | 25 |
|
| 26 |
- ErrNotSupported = errors.New("driver not supported")
|
|
| 27 |
- ErrPrerequisites = errors.New("prerequisites for driver not satisfied (wrong filesystem?)")
|
|
| 28 |
- ErrIncompatibleFS = fmt.Errorf("backing file system is unsupported for this graph driver")
|
|
| 29 |
- 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")
|
|
| 26 |
+ ErrNotSupported = errors.New("driver not supported")
|
|
| 27 |
+ ErrPrerequisites = errors.New("prerequisites for driver not satisfied (wrong filesystem?)")
|
|
| 28 |
+ ErrIncompatibleFS = fmt.Errorf("backing file system is unsupported for this graph driver")
|
|
| 30 | 29 |
) |
| 31 | 30 |
|
| 32 | 31 |
type InitFunc func(root string, options []string) (Driver, error) |
| ... | ... |
@@ -115,35 +113,36 @@ func New(root string, options []string) (driver Driver, err error) {
|
| 115 | 115 |
} |
| 116 | 116 |
|
| 117 | 117 |
// Guess for prior driver |
| 118 |
- priorDriver, err := scanPriorDrivers(root) |
|
| 119 |
- if err != nil {
|
|
| 120 |
- return nil, err |
|
| 121 |
- } |
|
| 122 |
- |
|
| 123 |
- if len(priorDriver) != 0 {
|
|
| 124 |
- // Do not allow devicemapper when it's not explicit and the Docker binary was built statically. |
|
| 125 |
- if staticWithDeviceMapper(priorDriver) {
|
|
| 126 |
- return nil, ErrDeviceMapperWithStaticDocker |
|
| 118 |
+ priorDrivers := scanPriorDrivers(root) |
|
| 119 |
+ for _, name := range priority {
|
|
| 120 |
+ if name == "vfs" {
|
|
| 121 |
+ // don't use vfs even if there is state present. |
|
| 122 |
+ continue |
|
| 127 | 123 |
} |
| 128 |
- |
|
| 129 |
- driver, err = GetDriver(priorDriver, root, options) |
|
| 130 |
- if err != nil {
|
|
| 131 |
- // unlike below, we will return error here, because there is prior |
|
| 132 |
- // state, and now it is no longer supported/prereq/compatible, so |
|
| 133 |
- // something changed and needs attention. Otherwise the daemon's |
|
| 134 |
- // images would just "disappear". |
|
| 135 |
- logrus.Errorf("[graphdriver] prior storage driver %q failed: %s", priorDriver, err)
|
|
| 136 |
- return nil, err |
|
| 124 |
+ for _, prior := range priorDrivers {
|
|
| 125 |
+ // of the state found from prior drivers, check in order of our priority |
|
| 126 |
+ // which we would prefer |
|
| 127 |
+ if prior == name {
|
|
| 128 |
+ driver, err = GetDriver(name, root, options) |
|
| 129 |
+ if err != nil {
|
|
| 130 |
+ // unlike below, we will return error here, because there is prior |
|
| 131 |
+ // state, and now it is no longer supported/prereq/compatible, so |
|
| 132 |
+ // something changed and needs attention. Otherwise the daemon's |
|
| 133 |
+ // images would just "disappear". |
|
| 134 |
+ logrus.Errorf("[graphdriver] prior storage driver %q failed: %s", name, err)
|
|
| 135 |
+ return nil, err |
|
| 136 |
+ } |
|
| 137 |
+ if err := checkPriorDriver(name, root); err != nil {
|
|
| 138 |
+ return nil, err |
|
| 139 |
+ } |
|
| 140 |
+ logrus.Infof("[graphdriver] using prior storage driver %q", name)
|
|
| 141 |
+ return driver, nil |
|
| 142 |
+ } |
|
| 137 | 143 |
} |
| 138 |
- logrus.Infof("[graphdriver] using prior storage driver %q", priorDriver)
|
|
| 139 |
- return driver, nil |
|
| 140 | 144 |
} |
| 141 | 145 |
|
| 142 | 146 |
// Check for priority drivers first |
| 143 | 147 |
for _, name := range priority {
|
| 144 |
- if staticWithDeviceMapper(name) {
|
|
| 145 |
- continue |
|
| 146 |
- } |
|
| 147 | 148 |
driver, err = GetDriver(name, root, options) |
| 148 | 149 |
if err != nil {
|
| 149 | 150 |
if err == ErrNotSupported || err == ErrPrerequisites || err == ErrIncompatibleFS {
|
| ... | ... |
@@ -155,10 +154,7 @@ func New(root string, options []string) (driver Driver, err error) {
|
| 155 | 155 |
} |
| 156 | 156 |
|
| 157 | 157 |
// Check all registered drivers if no priority driver is found |
| 158 |
- for name, initFunc := range drivers {
|
|
| 159 |
- if staticWithDeviceMapper(name) {
|
|
| 160 |
- continue |
|
| 161 |
- } |
|
| 158 |
+ for _, initFunc := range drivers {
|
|
| 162 | 159 |
if driver, err = initFunc(root, options); err != nil {
|
| 163 | 160 |
if err == ErrNotSupported || err == ErrPrerequisites || err == ErrIncompatibleFS {
|
| 164 | 161 |
continue |
| ... | ... |
@@ -170,31 +166,31 @@ func New(root string, options []string) (driver Driver, err error) {
|
| 170 | 170 |
return nil, fmt.Errorf("No supported storage backend found")
|
| 171 | 171 |
} |
| 172 | 172 |
|
| 173 |
-// scanPriorDrivers returns a previosly used driver. |
|
| 174 |
-// it returns an error when there are several drivers scanned. |
|
| 175 |
-func scanPriorDrivers(root string) (string, error) {
|
|
| 176 |
- var priorDrivers []string |
|
| 173 |
+// scanPriorDrivers returns an un-ordered scan of directories of prior storage drivers |
|
| 174 |
+func scanPriorDrivers(root string) []string {
|
|
| 175 |
+ priorDrivers := []string{}
|
|
| 177 | 176 |
for driver := range drivers {
|
| 178 | 177 |
p := filepath.Join(root, driver) |
| 179 |
- if _, err := os.Stat(p); err == nil && driver != "vfs" {
|
|
| 178 |
+ if _, err := os.Stat(p); err == nil {
|
|
| 180 | 179 |
priorDrivers = append(priorDrivers, driver) |
| 181 | 180 |
} |
| 182 | 181 |
} |
| 182 |
+ return priorDrivers |
|
| 183 |
+} |
|
| 183 | 184 |
|
| 184 |
- if len(priorDrivers) > 1 {
|
|
| 185 |
- return "", multipleDriversError(root, priorDrivers) |
|
| 186 |
- } |
|
| 187 |
- |
|
| 188 |
- if len(priorDrivers) == 0 {
|
|
| 189 |
- return "", nil |
|
| 185 |
+func checkPriorDriver(name, root string) error {
|
|
| 186 |
+ priorDrivers := []string{}
|
|
| 187 |
+ for _, prior := range scanPriorDrivers(root) {
|
|
| 188 |
+ if prior != name && prior != "vfs" {
|
|
| 189 |
+ if _, err := os.Stat(filepath.Join(root, prior)); err == nil {
|
|
| 190 |
+ priorDrivers = append(priorDrivers, prior) |
|
| 191 |
+ } |
|
| 192 |
+ } |
|
| 190 | 193 |
} |
| 191 |
- return priorDrivers[0], nil |
|
| 192 |
-} |
|
| 193 | 194 |
|
| 194 |
-func multipleDriversError(root string, drivers []string) error {
|
|
| 195 |
- return fmt.Errorf("%q contains several graphdrivers: %s; Please cleanup or explicitly choose storage driver (--storage-driver <DRIVER>)", root, strings.Join(drivers, ", "))
|
|
| 196 |
-} |
|
| 195 |
+ if len(priorDrivers) > 0 {
|
|
| 197 | 196 |
|
| 198 |
-func staticWithDeviceMapper(name string) bool {
|
|
| 199 |
- return name == "devicemapper" && dockerversion.IAMSTATIC == "true" |
|
| 197 |
+ return errors.New(fmt.Sprintf("%q contains other graphdrivers: %s; Please cleanup or explicitly choose storage driver (-s <DRIVER>)", root, strings.Join(priorDrivers, ",")))
|
|
| 198 |
+ } |
|
| 199 |
+ return nil |
|
| 200 | 200 |
} |
| ... | ... |
@@ -323,6 +323,45 @@ options for `zfs` start with `zfs`. |
| 323 | 323 |
|
| 324 | 324 |
$ docker -d --storage-opt dm.blkdiscard=false |
| 325 | 325 |
|
| 326 |
+ * `dm.override_udev_sync_check` |
|
| 327 |
+ |
|
| 328 |
+ Overrides the `udev` synchronization checks between `devicemapper` and `udev`. |
|
| 329 |
+ `udev` is the device manager for the Linux kernel. |
|
| 330 |
+ |
|
| 331 |
+ To view the `udev` sync support of a Docker daemon that is using the |
|
| 332 |
+ `devicemapper` driver, run: |
|
| 333 |
+ |
|
| 334 |
+ $ docker info |
|
| 335 |
+ [...] |
|
| 336 |
+ Udev Sync Supported: true |
|
| 337 |
+ [...] |
|
| 338 |
+ |
|
| 339 |
+ When `udev` sync support is `true`, then `devicemapper` and udev can |
|
| 340 |
+ coordinate the activation and deactivation of devices for containers. |
|
| 341 |
+ |
|
| 342 |
+ When `udev` sync support is `false`, a race condition occurs between |
|
| 343 |
+ the`devicemapper` and `udev` during create and cleanup. The race condition |
|
| 344 |
+ results in errors and failures. (For information on these failures, see |
|
| 345 |
+ [docker#4036](https://github.com/docker/docker/issues/4036)) |
|
| 346 |
+ |
|
| 347 |
+ To allow the `docker` daemon to start, regardless of `udev` sync not being |
|
| 348 |
+ supported, set `dm.override_udev_sync_check` to true: |
|
| 349 |
+ |
|
| 350 |
+ $ docker -d --storage-opt dm.override_udev_sync_check=true |
|
| 351 |
+ |
|
| 352 |
+ When this value is `true`, the `devicemapper` continues and simply warns |
|
| 353 |
+ you the errors are happening. |
|
| 354 |
+ |
|
| 355 |
+ > **Note:** |
|
| 356 |
+ > The ideal is to pursue a `docker` daemon and environment that does |
|
| 357 |
+ > support synchronizing with `udev`. For further discussion on this |
|
| 358 |
+ > topic, see [docker#4036](https://github.com/docker/docker/issues/4036). |
|
| 359 |
+ > Otherwise, set this flag for migrating existing Docker daemons to |
|
| 360 |
+ > a daemon with a supported environment. |
|
| 361 |
+ |
|
| 362 |
+ |
|
| 363 |
+## Docker execdriver option |
|
| 364 |
+ |
|
| 326 | 365 |
Currently supported options of `zfs`: |
| 327 | 366 |
|
| 328 | 367 |
* `zfs.fsname` |
| ... | ... |
@@ -451,6 +451,45 @@ removed. |
| 451 | 451 |
|
| 452 | 452 |
Example use: `docker -d --storage-opt dm.blkdiscard=false` |
| 453 | 453 |
|
| 454 |
+#### dm.override_udev_sync_check |
|
| 455 |
+ |
|
| 456 |
+By default, the devicemapper backend attempts to synchronize with the |
|
| 457 |
+`udev` device manager for the Linux kernel. This option allows |
|
| 458 |
+disabling that synchronization, to continue even though the |
|
| 459 |
+configuration may be buggy. |
|
| 460 |
+ |
|
| 461 |
+To view the `udev` sync support of a Docker daemon that is using the |
|
| 462 |
+`devicemapper` driver, run: |
|
| 463 |
+ |
|
| 464 |
+ $ docker info |
|
| 465 |
+ [...] |
|
| 466 |
+ Udev Sync Supported: true |
|
| 467 |
+ [...] |
|
| 468 |
+ |
|
| 469 |
+When `udev` sync support is `true`, then `devicemapper` and `udev` can |
|
| 470 |
+coordinate the activation and deactivation of devices for containers. |
|
| 471 |
+ |
|
| 472 |
+When `udev` sync support is `false`, a race condition occurs between |
|
| 473 |
+the`devicemapper` and `udev` during create and cleanup. The race |
|
| 474 |
+condition results in errors and failures. (For information on these |
|
| 475 |
+failures, see |
|
| 476 |
+[docker#4036](https://github.com/docker/docker/issues/4036)) |
|
| 477 |
+ |
|
| 478 |
+To allow the `docker` daemon to start, regardless of whether `udev` sync is |
|
| 479 |
+`false`, set `dm.override_udev_sync_check` to true: |
|
| 480 |
+ |
|
| 481 |
+ $ docker -d --storage-opt dm.override_udev_sync_check=true |
|
| 482 |
+ |
|
| 483 |
+When this value is `true`, the driver continues and simply warns you |
|
| 484 |
+the errors are happening. |
|
| 485 |
+ |
|
| 486 |
+**Note**: The ideal is to pursue a `docker` daemon and environment |
|
| 487 |
+that does support synchronizing with `udev`. For further discussion on |
|
| 488 |
+this topic, see |
|
| 489 |
+[docker#4036](https://github.com/docker/docker/issues/4036). |
|
| 490 |
+Otherwise, set this flag for migrating existing Docker daemons to a |
|
| 491 |
+daemon with a supported environment. |
|
| 492 |
+ |
|
| 454 | 493 |
# EXEC DRIVER OPTIONS |
| 455 | 494 |
|
| 456 | 495 |
Use the **--exec-opt** flags to specify options to the exec-driver. The only |