Browse code

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>

Vivek Goyal authored on 2015/10/05 22:02:31
Showing 1 changed files
... ...
@@ -1469,40 +1469,67 @@ func (devices *DeviceSet) AddDevice(hash, baseHash string) error {
1469 1469
 	return nil
1470 1470
 }
1471 1471
 
1472
-// Should be called with devices.Lock() held.
1473
-func (devices *DeviceSet) deleteDevice(info *devInfo) error {
1474
-	if devices.doBlkDiscard {
1475
-		// This is a workaround for the kernel not discarding block so
1476
-		// on the thin pool when we remove a thinp device, so we do it
1477
-		// manually
1478
-		if err := devices.activateDeviceIfNeeded(info); err == nil {
1479
-			if err := devicemapper.BlockDeviceDiscard(info.DevName()); err != nil {
1480
-				logrus.Debugf("Error discarding block on device: %s (ignoring)", err)
1481
-			}
1482
-		}
1472
+// Should be caled with devices.Lock() held.
1473
+func (devices *DeviceSet) deleteTransaction(info *devInfo) error {
1474
+	if err := devices.openTransaction(info.Hash, info.DeviceID); err != nil {
1475
+		logrus.Debugf("Error opening transaction hash = %s deviceId = %d", "", info.DeviceID)
1476
+		return err
1483 1477
 	}
1484 1478
 
1485
-	// Try to deactivate deivce in case it is active.
1486
-	if err := devices.deactivateDevice(info); err != nil {
1487
-		logrus.Debugf("Error deactivating device: %s", err)
1479
+	defer devices.closeTransaction()
1480
+
1481
+	if err := devicemapper.DeleteDevice(devices.getPoolDevName(), info.DeviceID); err != nil {
1482
+		logrus.Debugf("Error deleting device: %s", err)
1488 1483
 		return err
1489 1484
 	}
1490 1485
 
1491
-	if err := devices.openTransaction(info.Hash, info.DeviceID); err != nil {
1492
-		logrus.Debugf("Error opening transaction hash = %s deviceID = %d", "", info.DeviceID)
1486
+	if err := devices.unregisterDevice(info.DeviceID, info.Hash); err != nil {
1493 1487
 		return err
1494 1488
 	}
1495 1489
 
1496
-	if err := devicemapper.DeleteDevice(devices.getPoolDevName(), info.DeviceID); err != nil {
1497
-		logrus.Debugf("Error deleting device: %s", err)
1490
+	return nil
1491
+}
1492
+
1493
+// Issue discard only if device open count is zero.
1494
+func (devices *DeviceSet) issueDiscard(info *devInfo) error {
1495
+	logrus.Debugf("devmapper: issueDiscard(device: %s). START", info.Hash)
1496
+	defer logrus.Debugf("devmapper: issueDiscard(device: %s). END", info.Hash)
1497
+	// This is a workaround for the kernel not discarding block so
1498
+	// on the thin pool when we remove a thinp device, so we do it
1499
+	// manually
1500
+	if err := devices.activateDeviceIfNeeded(info); err != nil {
1498 1501
 		return err
1499 1502
 	}
1500 1503
 
1501
-	if err := devices.unregisterDevice(info.DeviceID, info.Hash); err != nil {
1504
+	devinfo, err := devicemapper.GetInfo(info.Name())
1505
+	if err != nil {
1502 1506
 		return err
1503 1507
 	}
1504 1508
 
1505
-	if err := devices.closeTransaction(); err != nil {
1509
+	if devinfo.OpenCount != 0 {
1510
+		logrus.Debugf("devmapper: Device: %s is in use. OpenCount=%d. Not issuing discards.", info.Hash, devinfo.OpenCount)
1511
+		return nil
1512
+	}
1513
+
1514
+	if err := devicemapper.BlockDeviceDiscard(info.DevName()); err != nil {
1515
+		logrus.Debugf("Error discarding block on device: %s (ignoring)", err)
1516
+	}
1517
+	return nil
1518
+}
1519
+
1520
+// Should be called with devices.Lock() held.
1521
+func (devices *DeviceSet) deleteDevice(info *devInfo) error {
1522
+	if devices.doBlkDiscard {
1523
+		devices.issueDiscard(info)
1524
+	}
1525
+
1526
+	// Try to deactivate device in case it is active.
1527
+	if err := devices.deactivateDevice(info); err != nil {
1528
+		logrus.Debugf("Error deactivating device: %s", err)
1529
+		return err
1530
+	}
1531
+
1532
+	if err := devices.deleteTransaction(info); err != nil {
1506 1533
 		return err
1507 1534
 	}
1508 1535
 
... ...
@@ -1657,6 +1684,14 @@ func (devices *DeviceSet) Shutdown() error {
1657 1657
 	var devs []*devInfo
1658 1658
 
1659 1659
 	devices.Lock()
1660
+	// Save DeviceSet Metadata first. Docker kills all threads if they
1661
+	// don't finish in certain time. It is possible that Shutdown()
1662
+	// routine does not finish in time as we loop trying to deactivate
1663
+	// some devices while these are busy. In that case shutdown() routine
1664
+	// will be killed and we will not get a chance to save deviceset
1665
+	// metadata. Hence save this early before trying to deactivate devices.
1666
+	devices.saveDeviceSetMetaData()
1667
+
1660 1668
 	for _, info := range devices.Devices {
1661 1669
 		devs = append(devs, info)
1662 1670
 	}
... ...
@@ -1698,8 +1733,6 @@ func (devices *DeviceSet) Shutdown() error {
1698 1698
 			logrus.Debugf("Shutdown deactivate pool , error: %s", err)
1699 1699
 		}
1700 1700
 	}
1701
-
1702
-	devices.saveDeviceSetMetaData()
1703 1701
 	devices.Unlock()
1704 1702
 
1705 1703
 	return nil