From 9c3380039e15f11fc07741edd4cbc0c7e5c490aa Mon Sep 17 00:00:00 2001 From: Vincent Batts Date: Mon, 19 Jan 2015 15:10:37 -0500 Subject: [PATCH 1/3] devicemapper: dm_udev_get_sync_support expose an api to call dm_udev_get_sync_support/dm_udev_set_sync_support Signed-off-by: Vincent Batts --- pkg/devicemapper/devmapper.go | 20 ++++++++++++++++++++ pkg/devicemapper/devmapper_wrapper.go | 10 ++++++++++ 2 files changed, 30 insertions(+) diff --git a/pkg/devicemapper/devmapper.go b/pkg/devicemapper/devmapper.go index c23a3624db..486ec15db7 100644 --- a/pkg/devicemapper/devmapper.go +++ b/pkg/devicemapper/devmapper.go @@ -319,6 +319,26 @@ func GetLibraryVersion() (string, error) { return version, nil } +// UdevSyncSupported returns whether device-mapper is able to sync with udev +// +// This is essential otherwise race conditions can arise where both udev and +// device-mapper attempt to create and destroy devices. +func UdevSyncSupported() bool { + return DmUdevGetSyncSupport() != 0 +} + +// UdevSetSyncSupport allows setting whether the udev sync should be enabled. +// The return bool indicates the state of whether the sync is enabled. +func UdevSetSyncSupport(enable bool) bool { + if enable { + DmUdevSetSyncSupport(1) + } else { + DmUdevSetSyncSupport(0) + } + + return UdevSyncSupported() +} + // Useful helper for cleanup func RemoveDevice(name string) error { log.Debugf("[devmapper] RemoveDevice START") diff --git a/pkg/devicemapper/devmapper_wrapper.go b/pkg/devicemapper/devmapper_wrapper.go index 499405a10d..aff8446528 100644 --- a/pkg/devicemapper/devmapper_wrapper.go +++ b/pkg/devicemapper/devmapper_wrapper.go @@ -107,6 +107,8 @@ var ( DmTaskSetRo = dmTaskSetRoFct DmTaskSetSector = dmTaskSetSectorFct DmUdevWait = dmUdevWaitFct + DmUdevSetSyncSupport = dmUdevSetSyncSupportFct + DmUdevGetSyncSupport = dmUdevGetSyncSupportFct LogWithErrnoInit = logWithErrnoInitFct ) @@ -231,6 +233,14 @@ func dmGetNextTargetFct(task *CDmTask, next uintptr, start, length *uint64, targ return uintptr(nextp) } +func dmUdevSetSyncSupportFct(syncWithUdev int) { + (C.dm_udev_set_sync_support(C.int(syncWithUdev))) +} + +func dmUdevGetSyncSupportFct() int { + return int(C.dm_udev_get_sync_support()) +} + func dmUdevWaitFct(cookie uint) int { return int(C.dm_udev_wait(C.uint32_t(cookie))) } From 022e1232f84966c4b70a612bc35463ebb58e3137 Mon Sep 17 00:00:00 2001 From: Vincent Batts Date: Mon, 19 Jan 2015 15:11:40 -0500 Subject: [PATCH 2/3] devmapper: udev sync on init when initializing the devmapper driver, attempt to sync udev and device mapper. If udev sync is not supported, print a warning. Eventually we'll likely bail here to avoid unpredictable behavior for users. Signed-off-by: Vincent Batts --- daemon/graphdriver/devmapper/deviceset.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/daemon/graphdriver/devmapper/deviceset.go b/daemon/graphdriver/devmapper/deviceset.go index 1e0a6d3f83..e53686343b 100644 --- a/daemon/graphdriver/devmapper/deviceset.go +++ b/daemon/graphdriver/devmapper/deviceset.go @@ -947,6 +947,12 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error { return graphdriver.ErrNotSupported } + // https://github.com/docker/docker/issues/4036 + if supported := devicemapper.UdevSetSyncSupport(true); !supported { + log.Warnf("WARNING: Udev sync is not supported. This will lead to unexpected behavior, data loss and errors") + } + log.Debugf("devicemapper: udev sync support: %v", devicemapper.UdevSyncSupported()) + if err := os.MkdirAll(devices.metadataDir(), 0700); err != nil && !os.IsExist(err) { return err } From d2593546f9a234699cd0034cc6b97c748c10c93e Mon Sep 17 00:00:00 2001 From: Vincent Batts Date: Mon, 19 Jan 2015 16:28:02 -0500 Subject: [PATCH 3/3] devmapper: udev sync in `docker info` now: ``` [...] Storage Driver: devicemapper Pool Name: docker-253:2-5767172-pool [...] Udev Sync Supported: true [...] ``` Signed-off-by: Vincent Batts --- daemon/graphdriver/devmapper/deviceset.go | 18 ++++++++++-------- daemon/graphdriver/devmapper/driver.go | 1 + 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/daemon/graphdriver/devmapper/deviceset.go b/daemon/graphdriver/devmapper/deviceset.go index e53686343b..de1f720d46 100644 --- a/daemon/graphdriver/devmapper/deviceset.go +++ b/daemon/graphdriver/devmapper/deviceset.go @@ -105,14 +105,15 @@ type DiskUsage struct { } type Status struct { - PoolName string - DataFile string // actual block device for data - DataLoopback string // loopback file, if used - MetadataFile string // actual block device for metadata - MetadataLoopback string // loopback file, if used - Data DiskUsage - Metadata DiskUsage - SectorSize uint64 + PoolName string + DataFile string // actual block device for data + DataLoopback string // loopback file, if used + MetadataFile string // actual block device for metadata + MetadataLoopback string // loopback file, if used + Data DiskUsage + Metadata DiskUsage + SectorSize uint64 + UdevSyncSupported bool } type DevStatus struct { @@ -1578,6 +1579,7 @@ func (devices *DeviceSet) Status() *Status { status.DataLoopback = devices.dataLoopFile status.MetadataFile = devices.MetadataDevicePath() status.MetadataLoopback = devices.metadataLoopFile + status.UdevSyncSupported = devicemapper.UdevSyncSupported() totalSizeInSectors, _, dataUsed, dataTotal, metadataUsed, metadataTotal, err := devices.poolStatus() if err == nil { diff --git a/daemon/graphdriver/devmapper/driver.go b/daemon/graphdriver/devmapper/driver.go index a7dafc657a..2feed5720f 100644 --- a/daemon/graphdriver/devmapper/driver.go +++ b/daemon/graphdriver/devmapper/driver.go @@ -74,6 +74,7 @@ func (d *Driver) Status() [][2]string { {"Data Space Total", fmt.Sprintf("%s", units.HumanSize(float64(s.Data.Total)))}, {"Metadata Space Used", fmt.Sprintf("%s", units.HumanSize(float64(s.Metadata.Used)))}, {"Metadata Space Total", fmt.Sprintf("%s", units.HumanSize(float64(s.Metadata.Total)))}, + {"Udev Sync Supported", fmt.Sprintf("%v", s.UdevSyncSupported)}, } if len(s.DataLoopback) > 0 { status = append(status, [2]string{"Data loop file", s.DataLoopback})