diff --git a/graphdriver/devmapper/deviceset.go b/graphdriver/devmapper/deviceset.go index 7308c0e922..6e3caf657d 100644 --- a/graphdriver/devmapper/deviceset.go +++ b/graphdriver/devmapper/deviceset.go @@ -568,6 +568,15 @@ func (devices *DeviceSet) removeDevice(hash string) error { return fmt.Errorf("hash %s doesn't exists", hash) } + // This is a workaround for the kernel not discarding block so + // on the thin pool when we remove a thinp device, so we do it + // manually + if err := devices.activateDeviceIfNeeded(hash); err == nil { + if err := BlockDeviceDiscard(info.DevName()); err != nil { + utils.Debugf("Error discarding block on device: %s (ignoring)\n", err) + } + } + devinfo, _ := getInfo(info.Name()) if devinfo != nil && devinfo.Exists != 0 { if err := removeDevice(info.Name()); err != nil { diff --git a/graphdriver/devmapper/devmapper.go b/graphdriver/devmapper/devmapper.go index dfbdf385d7..d3eba78a27 100644 --- a/graphdriver/devmapper/devmapper.go +++ b/graphdriver/devmapper/devmapper.go @@ -7,6 +7,7 @@ import ( "fmt" "github.com/dotcloud/docker/utils" "runtime" + "syscall" ) type DevmapperLogger interface { @@ -288,6 +289,29 @@ func GetBlockDeviceSize(file *osFile) (uint64, error) { return uint64(size), nil } +func BlockDeviceDiscard(path string) error { + file, err := osOpenFile(path, osORdWr, 0) + if err != nil { + return err + } + defer file.Close() + + size, err := GetBlockDeviceSize(file) + if err != nil { + return err + } + + if err := ioctlBlkDiscard(file.Fd(), 0, size); err != nil { + return err + } + + // Without this sometimes the remove of the device that happens after + // discard fails with EBUSY. + syscall.Sync() + + return nil +} + // This is the programmatic example of "dmsetup create" func createPool(poolName string, dataFile, metadataFile *osFile) error { task, err := createTask(DeviceCreate, poolName) diff --git a/graphdriver/devmapper/devmapper_wrapper.go b/graphdriver/devmapper/devmapper_wrapper.go index 80d430e2bf..7e6dd5e0cb 100644 --- a/graphdriver/devmapper/devmapper_wrapper.go +++ b/graphdriver/devmapper/devmapper_wrapper.go @@ -66,6 +66,7 @@ type ( // IOCTL consts const ( BlkGetSize64 = C.BLKGETSIZE64 + BlkDiscard = C.BLKDISCARD LoopSetFd = C.LOOP_SET_FD LoopCtlGetFree = C.LOOP_CTL_GET_FREE diff --git a/graphdriver/devmapper/driver_test.go b/graphdriver/devmapper/driver_test.go index b6d997bc2f..9a2e409b63 100644 --- a/graphdriver/devmapper/driver_test.go +++ b/graphdriver/devmapper/driver_test.go @@ -641,6 +641,10 @@ func TestDriverRemove(t *testing.T) { "DmTaskSetMessage", "DmTaskCreate", "DmTaskGetInfo", + "DmTaskSetCookie", + "DmTaskSetTarget", + "DmTaskSetAddNode", + "DmUdevWait", "Mounted", "sysUnmount", ) diff --git a/graphdriver/devmapper/ioctl.go b/graphdriver/devmapper/ioctl.go index 448d2d5a50..f9bf34f353 100644 --- a/graphdriver/devmapper/ioctl.go +++ b/graphdriver/devmapper/ioctl.go @@ -58,3 +58,14 @@ func ioctlBlkGetSize64(fd uintptr) (int64, error) { } return size, nil } + +func ioctlBlkDiscard(fd uintptr, offset, length uint64) error { + var r [2]uint64 + r[0] = offset + r[1] = length + + if _, _, err := sysSyscall(sysSysIoctl, fd, BlkDiscard, uintptr(unsafe.Pointer(&r[0]))); err != 0 { + return err + } + return nil +}