зеркало из https://github.com/microsoft/docker.git
devicemapper: Better/faster shutdown
Right now shutdown is looping over *all* devicemapper devices and actively deactivating them, this is pretty slow if you have a lot of non-active containers. We instead only deactivate the devices that are mounted. We also do the shutdown unmount using MNT_DETACH which forces the unmount in the global namespace, even if it is busy because of some container having it mounted. This means the device will be freed when that container exits. Also, we move the call to waitClose to deactivateDevice because all callers of any of them call both anyway. Docker-DCO-1.1-Signed-off-by: Alexander Larsson <alexl@redhat.com> (github: alexlarsson)
This commit is contained in:
Родитель
56c156190a
Коммит
a9fa1a13c3
|
@ -14,6 +14,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -677,6 +678,12 @@ func (devices *DeviceSet) deactivateDevice(hash string) error {
|
|||
utils.Debugf("[devmapper] deactivateDevice(%s)", hash)
|
||||
defer utils.Debugf("[devmapper] deactivateDevice END")
|
||||
|
||||
// Wait for the unmount to be effective,
|
||||
// by watching the value of Info.OpenCount for the device
|
||||
if err := devices.waitClose(hash); err != nil {
|
||||
utils.Errorf("Warning: error waiting for device %s to close: %s\n", hash, err)
|
||||
}
|
||||
|
||||
info := devices.Devices[hash]
|
||||
if info == nil {
|
||||
return fmt.Errorf("Unknown device %s", hash)
|
||||
|
@ -799,26 +806,20 @@ func (devices *DeviceSet) Shutdown() error {
|
|||
for _, info := range devices.Devices {
|
||||
info.lock.Lock()
|
||||
if info.mountCount > 0 {
|
||||
if err := sysUnmount(info.mountPath, 0); err != nil {
|
||||
// We use MNT_DETACH here in case it is still busy in some running
|
||||
// container. This means it'll go away from the global scope directly,
|
||||
// and the device will be released when that container dies.
|
||||
if err := sysUnmount(info.mountPath, syscall.MNT_DETACH); err != nil {
|
||||
utils.Debugf("Shutdown unmounting %s, error: %s\n", info.mountPath, err)
|
||||
}
|
||||
|
||||
if err := devices.deactivateDevice(info.Hash); err != nil {
|
||||
utils.Debugf("Shutdown deactivate %s , error: %s\n", info.Hash, err)
|
||||
}
|
||||
}
|
||||
info.lock.Unlock()
|
||||
}
|
||||
|
||||
for _, d := range devices.Devices {
|
||||
d.lock.Lock()
|
||||
|
||||
if err := devices.waitClose(d.Hash); err != nil {
|
||||
utils.Errorf("Warning: error waiting for device %s to unmount: %s\n", d.Hash, err)
|
||||
}
|
||||
if err := devices.deactivateDevice(d.Hash); err != nil {
|
||||
utils.Debugf("Shutdown deactivate %s , error: %s\n", d.Hash, err)
|
||||
}
|
||||
|
||||
d.lock.Unlock()
|
||||
}
|
||||
|
||||
if err := devices.deactivatePool(); err != nil {
|
||||
utils.Debugf("Shutdown deactivate pool , error: %s\n", err)
|
||||
}
|
||||
|
@ -920,14 +921,11 @@ func (devices *DeviceSet) UnmountDevice(hash string, mode UnmountMode) error {
|
|||
return err
|
||||
}
|
||||
utils.Debugf("[devmapper] Unmount done")
|
||||
// Wait for the unmount to be effective,
|
||||
// by watching the value of Info.OpenCount for the device
|
||||
if err := devices.waitClose(hash); err != nil {
|
||||
|
||||
if err := devices.deactivateDevice(hash); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
devices.deactivateDevice(hash)
|
||||
|
||||
info.mountPath = ""
|
||||
|
||||
return nil
|
||||
|
|
Загрузка…
Ссылка в новой задаче