devmapper: Few code cleanups

This patch does three things. Following are the descriptions.

===
Create a separate function for delete transactions so that parent function
is little smaller.

Also close transaction if an error happens.
===
When docker is being shutdown, save deviceset metadata first before
trying to remove the devices. Generally caller gives only 10 seconds
for shutdown to complete and then kills it after that. So if some device
is busy, we will wait 20 seconds for it removal and never be able to save
metadata. So first save metadata and then deal with device removal.
===
Move issue discard operation in a separate function. This makes reading code
little easier.

Also don't issue discards if device is still open. That means devices is
still probably being used and issuing discards is not a good idea.

This is especially true in case of deferred deletion. We want to issue
discards when device is not open. At that time device can be deleted too.
Otherwise we will issue discards and deletion will actually fail. Later
we will try deletion again and issue discards again and deletion will
fail again as device is open and busy.

So this will ensure that discards are issued once when device is not open
and it can actually be deleted.

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
This commit is contained in:
Vivek Goyal 2015-10-05 09:02:31 -04:00
parent 072ac5e7f0
commit 482eca3099
1 changed files with 56 additions and 23 deletions

View File

@ -1469,30 +1469,15 @@ func (devices *DeviceSet) AddDevice(hash, baseHash string) error {
return nil
}
// Should be called with devices.Lock() held.
func (devices *DeviceSet) deleteDevice(info *devInfo) error {
if devices.doBlkDiscard {
// 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(info); err == nil {
if err := devicemapper.BlockDeviceDiscard(info.DevName()); err != nil {
logrus.Debugf("Error discarding block on device: %s (ignoring)", err)
}
}
}
// Try to deactivate deivce in case it is active.
if err := devices.deactivateDevice(info); err != nil {
logrus.Debugf("Error deactivating device: %s", err)
return err
}
// Should be caled with devices.Lock() held.
func (devices *DeviceSet) deleteTransaction(info *devInfo) error {
if err := devices.openTransaction(info.Hash, info.DeviceID); err != nil {
logrus.Debugf("Error opening transaction hash = %s deviceID = %d", "", info.DeviceID)
logrus.Debugf("Error opening transaction hash = %s deviceId = %d", "", info.DeviceID)
return err
}
defer devices.closeTransaction()
if err := devicemapper.DeleteDevice(devices.getPoolDevName(), info.DeviceID); err != nil {
logrus.Debugf("Error deleting device: %s", err)
return err
@ -1502,7 +1487,49 @@ func (devices *DeviceSet) deleteDevice(info *devInfo) error {
return err
}
if err := devices.closeTransaction(); err != nil {
return nil
}
// Issue discard only if device open count is zero.
func (devices *DeviceSet) issueDiscard(info *devInfo) error {
logrus.Debugf("devmapper: issueDiscard(device: %s). START", info.Hash)
defer logrus.Debugf("devmapper: issueDiscard(device: %s). END", info.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(info); err != nil {
return err
}
devinfo, err := devicemapper.GetInfo(info.Name())
if err != nil {
return err
}
if devinfo.OpenCount != 0 {
logrus.Debugf("devmapper: Device: %s is in use. OpenCount=%d. Not issuing discards.", info.Hash, devinfo.OpenCount)
return nil
}
if err := devicemapper.BlockDeviceDiscard(info.DevName()); err != nil {
logrus.Debugf("Error discarding block on device: %s (ignoring)", err)
}
return nil
}
// Should be called with devices.Lock() held.
func (devices *DeviceSet) deleteDevice(info *devInfo) error {
if devices.doBlkDiscard {
devices.issueDiscard(info)
}
// Try to deactivate device in case it is active.
if err := devices.deactivateDevice(info); err != nil {
logrus.Debugf("Error deactivating device: %s", err)
return err
}
if err := devices.deleteTransaction(info); err != nil {
return err
}
@ -1657,6 +1684,14 @@ func (devices *DeviceSet) Shutdown() error {
var devs []*devInfo
devices.Lock()
// Save DeviceSet Metadata first. Docker kills all threads if they
// don't finish in certain time. It is possible that Shutdown()
// routine does not finish in time as we loop trying to deactivate
// some devices while these are busy. In that case shutdown() routine
// will be killed and we will not get a chance to save deviceset
// metadata. Hence save this early before trying to deactivate devices.
devices.saveDeviceSetMetaData()
for _, info := range devices.Devices {
devs = append(devs, info)
}
@ -1698,8 +1733,6 @@ func (devices *DeviceSet) Shutdown() error {
logrus.Debugf("Shutdown deactivate pool , error: %s", err)
}
}
devices.saveDeviceSetMetaData()
devices.Unlock()
return nil