mirror of https://github.com/docker/docs.git
Merge pull request #4951 from alexlarsson/dm-fix-deadlock
Fix AB-BA deadlock in devicemapper backend
This commit is contained in:
commit
3e68d36485
|
@ -47,11 +47,17 @@ type DevInfo struct {
|
||||||
// sometimes release that lock while sleeping. In that case
|
// sometimes release that lock while sleeping. In that case
|
||||||
// this per-device lock is still held, protecting against
|
// this per-device lock is still held, protecting against
|
||||||
// other accesses to the device that we're doing the wait on.
|
// other accesses to the device that we're doing the wait on.
|
||||||
|
//
|
||||||
|
// WARNING: In order to avoid AB-BA deadlocks when releasing
|
||||||
|
// the global lock while holding the per-device locks all
|
||||||
|
// device locks must be aquired *before* the device lock, and
|
||||||
|
// multiple device locks should be aquired parent before child.
|
||||||
lock sync.Mutex `json:"-"`
|
lock sync.Mutex `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MetaData struct {
|
type MetaData struct {
|
||||||
Devices map[string]*DevInfo `json:devices`
|
Devices map[string]*DevInfo `json:devices`
|
||||||
|
devicesLock sync.Mutex `json:"-"` // Protects all read/writes to Devices map
|
||||||
}
|
}
|
||||||
|
|
||||||
type DeviceSet struct {
|
type DeviceSet struct {
|
||||||
|
@ -179,7 +185,9 @@ func (devices *DeviceSet) allocateTransactionId() uint64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (devices *DeviceSet) saveMetadata() error {
|
func (devices *DeviceSet) saveMetadata() error {
|
||||||
|
devices.devicesLock.Lock()
|
||||||
jsonData, err := json.Marshal(devices.MetaData)
|
jsonData, err := json.Marshal(devices.MetaData)
|
||||||
|
devices.devicesLock.Unlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Error encoding metadata to json: %s", err)
|
return fmt.Errorf("Error encoding metadata to json: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -214,6 +222,16 @@ func (devices *DeviceSet) saveMetadata() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (devices *DeviceSet) lookupDevice(hash string) (*DevInfo, error) {
|
||||||
|
devices.devicesLock.Lock()
|
||||||
|
defer devices.devicesLock.Unlock()
|
||||||
|
info := devices.Devices[hash]
|
||||||
|
if info == nil {
|
||||||
|
return nil, fmt.Errorf("Unknown device %s", hash)
|
||||||
|
}
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (devices *DeviceSet) registerDevice(id int, hash string, size uint64) (*DevInfo, error) {
|
func (devices *DeviceSet) registerDevice(id int, hash string, size uint64) (*DevInfo, error) {
|
||||||
utils.Debugf("registerDevice(%v, %v)", id, hash)
|
utils.Debugf("registerDevice(%v, %v)", id, hash)
|
||||||
info := &DevInfo{
|
info := &DevInfo{
|
||||||
|
@ -225,22 +243,23 @@ func (devices *DeviceSet) registerDevice(id int, hash string, size uint64) (*Dev
|
||||||
devices: devices,
|
devices: devices,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
devices.devicesLock.Lock()
|
||||||
devices.Devices[hash] = info
|
devices.Devices[hash] = info
|
||||||
|
devices.devicesLock.Unlock()
|
||||||
|
|
||||||
if err := devices.saveMetadata(); err != nil {
|
if err := devices.saveMetadata(); err != nil {
|
||||||
// Try to remove unused device
|
// Try to remove unused device
|
||||||
|
devices.devicesLock.Lock()
|
||||||
delete(devices.Devices, hash)
|
delete(devices.Devices, hash)
|
||||||
|
devices.devicesLock.Unlock()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return info, nil
|
return info, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (devices *DeviceSet) activateDeviceIfNeeded(hash string) error {
|
func (devices *DeviceSet) activateDeviceIfNeeded(info *DevInfo) error {
|
||||||
utils.Debugf("activateDeviceIfNeeded(%v)", hash)
|
utils.Debugf("activateDeviceIfNeeded(%v)", info.Hash)
|
||||||
info := devices.Devices[hash]
|
|
||||||
if info == nil {
|
|
||||||
return fmt.Errorf("Unknown device %s", hash)
|
|
||||||
}
|
|
||||||
|
|
||||||
if devinfo, _ := getInfo(info.Name()); devinfo != nil && devinfo.Exists != 0 {
|
if devinfo, _ := getInfo(info.Name()); devinfo != nil && devinfo.Exists != 0 {
|
||||||
return nil
|
return nil
|
||||||
|
@ -310,14 +329,14 @@ func (devices *DeviceSet) loadMetaData() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (devices *DeviceSet) setupBaseImage() error {
|
func (devices *DeviceSet) setupBaseImage() error {
|
||||||
oldInfo := devices.Devices[""]
|
oldInfo, _ := devices.lookupDevice("")
|
||||||
if oldInfo != nil && oldInfo.Initialized {
|
if oldInfo != nil && oldInfo.Initialized {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if oldInfo != nil && !oldInfo.Initialized {
|
if oldInfo != nil && !oldInfo.Initialized {
|
||||||
utils.Debugf("Removing uninitialized base image")
|
utils.Debugf("Removing uninitialized base image")
|
||||||
if err := devices.deleteDevice(""); err != nil {
|
if err := devices.deleteDevice(oldInfo); err != nil {
|
||||||
utils.Debugf("\n--->Err: %s\n", err)
|
utils.Debugf("\n--->Err: %s\n", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -343,7 +362,7 @@ func (devices *DeviceSet) setupBaseImage() error {
|
||||||
|
|
||||||
utils.Debugf("Creating filesystem on base device-manager snapshot")
|
utils.Debugf("Creating filesystem on base device-manager snapshot")
|
||||||
|
|
||||||
if err = devices.activateDeviceIfNeeded(""); err != nil {
|
if err = devices.activateDeviceIfNeeded(info); err != nil {
|
||||||
utils.Debugf("\n--->Err: %s\n", err)
|
utils.Debugf("\n--->Err: %s\n", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -566,21 +585,21 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (devices *DeviceSet) AddDevice(hash, baseHash string) error {
|
func (devices *DeviceSet) AddDevice(hash, baseHash string) error {
|
||||||
devices.Lock()
|
baseInfo, err := devices.lookupDevice(baseHash)
|
||||||
defer devices.Unlock()
|
if err != nil {
|
||||||
|
return err
|
||||||
if devices.Devices[hash] != nil {
|
|
||||||
return fmt.Errorf("hash %s already exists", hash)
|
|
||||||
}
|
|
||||||
|
|
||||||
baseInfo := devices.Devices[baseHash]
|
|
||||||
if baseInfo == nil {
|
|
||||||
return fmt.Errorf("Error adding device for '%s': can't find device for parent '%s'", hash, baseHash)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
baseInfo.lock.Lock()
|
baseInfo.lock.Lock()
|
||||||
defer baseInfo.lock.Unlock()
|
defer baseInfo.lock.Unlock()
|
||||||
|
|
||||||
|
devices.Lock()
|
||||||
|
defer devices.Unlock()
|
||||||
|
|
||||||
|
if info, _ := devices.lookupDevice(hash); info != nil {
|
||||||
|
return fmt.Errorf("device %s already exists", hash)
|
||||||
|
}
|
||||||
|
|
||||||
deviceId := devices.allocateDeviceId()
|
deviceId := devices.allocateDeviceId()
|
||||||
|
|
||||||
if err := devices.createSnapDevice(devices.getPoolDevName(), deviceId, baseInfo.Name(), baseInfo.DeviceId); err != nil {
|
if err := devices.createSnapDevice(devices.getPoolDevName(), deviceId, baseInfo.Name(), baseInfo.DeviceId); err != nil {
|
||||||
|
@ -596,16 +615,11 @@ func (devices *DeviceSet) AddDevice(hash, baseHash string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (devices *DeviceSet) deleteDevice(hash string) error {
|
func (devices *DeviceSet) deleteDevice(info *DevInfo) error {
|
||||||
info := devices.Devices[hash]
|
|
||||||
if info == nil {
|
|
||||||
return fmt.Errorf("hash %s doesn't exists", hash)
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a workaround for the kernel not discarding block so
|
// 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
|
// on the thin pool when we remove a thinp device, so we do it
|
||||||
// manually
|
// manually
|
||||||
if err := devices.activateDeviceIfNeeded(hash); err == nil {
|
if err := devices.activateDeviceIfNeeded(info); err == nil {
|
||||||
if err := BlockDeviceDiscard(info.DevName()); err != nil {
|
if err := BlockDeviceDiscard(info.DevName()); err != nil {
|
||||||
utils.Debugf("Error discarding block on device: %s (ignoring)\n", err)
|
utils.Debugf("Error discarding block on device: %s (ignoring)\n", err)
|
||||||
}
|
}
|
||||||
|
@ -633,10 +647,14 @@ func (devices *DeviceSet) deleteDevice(hash string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
devices.allocateTransactionId()
|
devices.allocateTransactionId()
|
||||||
|
devices.devicesLock.Lock()
|
||||||
delete(devices.Devices, info.Hash)
|
delete(devices.Devices, info.Hash)
|
||||||
|
devices.devicesLock.Unlock()
|
||||||
|
|
||||||
if err := devices.saveMetadata(); err != nil {
|
if err := devices.saveMetadata(); err != nil {
|
||||||
|
devices.devicesLock.Lock()
|
||||||
devices.Devices[info.Hash] = info
|
devices.Devices[info.Hash] = info
|
||||||
|
devices.devicesLock.Unlock()
|
||||||
utils.Debugf("Error saving meta data: %s\n", err)
|
utils.Debugf("Error saving meta data: %s\n", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -645,18 +663,18 @@ func (devices *DeviceSet) deleteDevice(hash string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (devices *DeviceSet) DeleteDevice(hash string) error {
|
func (devices *DeviceSet) DeleteDevice(hash string) error {
|
||||||
devices.Lock()
|
info, err := devices.lookupDevice(hash)
|
||||||
defer devices.Unlock()
|
if err != nil {
|
||||||
|
return err
|
||||||
info := devices.Devices[hash]
|
|
||||||
if info == nil {
|
|
||||||
return fmt.Errorf("Unknown device %s", hash)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
info.lock.Lock()
|
info.lock.Lock()
|
||||||
defer info.lock.Unlock()
|
defer info.lock.Unlock()
|
||||||
|
|
||||||
return devices.deleteDevice(hash)
|
devices.Lock()
|
||||||
|
defer devices.Unlock()
|
||||||
|
|
||||||
|
return devices.deleteDevice(info)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (devices *DeviceSet) deactivatePool() error {
|
func (devices *DeviceSet) deactivatePool() error {
|
||||||
|
@ -675,20 +693,16 @@ func (devices *DeviceSet) deactivatePool() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (devices *DeviceSet) deactivateDevice(hash string) error {
|
func (devices *DeviceSet) deactivateDevice(info *DevInfo) error {
|
||||||
utils.Debugf("[devmapper] deactivateDevice(%s)", hash)
|
utils.Debugf("[devmapper] deactivateDevice(%s)", info.Hash)
|
||||||
defer utils.Debugf("[devmapper] deactivateDevice END")
|
defer utils.Debugf("[devmapper] deactivateDevice END")
|
||||||
|
|
||||||
// Wait for the unmount to be effective,
|
// Wait for the unmount to be effective,
|
||||||
// by watching the value of Info.OpenCount for the device
|
// by watching the value of Info.OpenCount for the device
|
||||||
if err := devices.waitClose(hash); err != nil {
|
if err := devices.waitClose(info); err != nil {
|
||||||
utils.Errorf("Warning: error waiting for device %s to close: %s\n", hash, err)
|
utils.Errorf("Warning: error waiting for device %s to close: %s\n", info.Hash, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
info := devices.Devices[hash]
|
|
||||||
if info == nil {
|
|
||||||
return fmt.Errorf("Unknown device %s", hash)
|
|
||||||
}
|
|
||||||
devinfo, err := getInfo(info.Name())
|
devinfo, err := getInfo(info.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Debugf("\n--->Err: %s\n", err)
|
utils.Debugf("\n--->Err: %s\n", err)
|
||||||
|
@ -769,11 +783,7 @@ func (devices *DeviceSet) waitRemove(devname string) error {
|
||||||
// waitClose blocks until either:
|
// waitClose blocks until either:
|
||||||
// a) the device registered at <device_set_prefix>-<hash> is closed,
|
// a) the device registered at <device_set_prefix>-<hash> is closed,
|
||||||
// or b) the 10 second timeout expires.
|
// or b) the 10 second timeout expires.
|
||||||
func (devices *DeviceSet) waitClose(hash string) error {
|
func (devices *DeviceSet) waitClose(info *DevInfo) error {
|
||||||
info := devices.Devices[hash]
|
|
||||||
if info == nil {
|
|
||||||
return fmt.Errorf("Unknown device %s", hash)
|
|
||||||
}
|
|
||||||
i := 0
|
i := 0
|
||||||
for ; i < 1000; i += 1 {
|
for ; i < 1000; i += 1 {
|
||||||
devinfo, err := getInfo(info.Name())
|
devinfo, err := getInfo(info.Name())
|
||||||
|
@ -781,7 +791,7 @@ func (devices *DeviceSet) waitClose(hash string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if i%100 == 0 {
|
if i%100 == 0 {
|
||||||
utils.Debugf("Waiting for unmount of %s: opencount=%d", hash, devinfo.OpenCount)
|
utils.Debugf("Waiting for unmount of %s: opencount=%d", info.Hash, devinfo.OpenCount)
|
||||||
}
|
}
|
||||||
if devinfo.OpenCount == 0 {
|
if devinfo.OpenCount == 0 {
|
||||||
break
|
break
|
||||||
|
@ -791,20 +801,26 @@ func (devices *DeviceSet) waitClose(hash string) error {
|
||||||
devices.Lock()
|
devices.Lock()
|
||||||
}
|
}
|
||||||
if i == 1000 {
|
if i == 1000 {
|
||||||
return fmt.Errorf("Timeout while waiting for device %s to close", hash)
|
return fmt.Errorf("Timeout while waiting for device %s to close", info.Hash)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (devices *DeviceSet) Shutdown() error {
|
func (devices *DeviceSet) Shutdown() error {
|
||||||
devices.Lock()
|
|
||||||
defer devices.Unlock()
|
|
||||||
|
|
||||||
utils.Debugf("[deviceset %s] shutdown()", devices.devicePrefix)
|
utils.Debugf("[deviceset %s] shutdown()", devices.devicePrefix)
|
||||||
utils.Debugf("[devmapper] Shutting down DeviceSet: %s", devices.root)
|
utils.Debugf("[devmapper] Shutting down DeviceSet: %s", devices.root)
|
||||||
defer utils.Debugf("[deviceset %s] shutdown END", devices.devicePrefix)
|
defer utils.Debugf("[deviceset %s] shutdown END", devices.devicePrefix)
|
||||||
|
|
||||||
|
var devs []*DevInfo
|
||||||
|
|
||||||
|
devices.devicesLock.Lock()
|
||||||
for _, info := range devices.Devices {
|
for _, info := range devices.Devices {
|
||||||
|
devs = append(devs, info)
|
||||||
|
}
|
||||||
|
devices.devicesLock.Unlock()
|
||||||
|
|
||||||
|
for _, info := range devs {
|
||||||
info.lock.Lock()
|
info.lock.Lock()
|
||||||
if info.mountCount > 0 {
|
if info.mountCount > 0 {
|
||||||
// We use MNT_DETACH here in case it is still busy in some running
|
// We use MNT_DETACH here in case it is still busy in some running
|
||||||
|
@ -814,36 +830,47 @@ func (devices *DeviceSet) Shutdown() error {
|
||||||
utils.Debugf("Shutdown unmounting %s, error: %s\n", info.mountPath, err)
|
utils.Debugf("Shutdown unmounting %s, error: %s\n", info.mountPath, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := devices.deactivateDevice(info.Hash); err != nil {
|
devices.Lock()
|
||||||
|
if err := devices.deactivateDevice(info); err != nil {
|
||||||
utils.Debugf("Shutdown deactivate %s , error: %s\n", info.Hash, err)
|
utils.Debugf("Shutdown deactivate %s , error: %s\n", info.Hash, err)
|
||||||
}
|
}
|
||||||
|
devices.Unlock()
|
||||||
}
|
}
|
||||||
info.lock.Unlock()
|
info.lock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := devices.deactivateDevice(""); err != nil {
|
info, _ := devices.lookupDevice("")
|
||||||
utils.Debugf("Shutdown deactivate base , error: %s\n", err)
|
if info != nil {
|
||||||
|
info.lock.Lock()
|
||||||
|
devices.Lock()
|
||||||
|
if err := devices.deactivateDevice(info); err != nil {
|
||||||
|
utils.Debugf("Shutdown deactivate base , error: %s\n", err)
|
||||||
|
}
|
||||||
|
devices.Unlock()
|
||||||
|
info.lock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
devices.Lock()
|
||||||
if err := devices.deactivatePool(); err != nil {
|
if err := devices.deactivatePool(); err != nil {
|
||||||
utils.Debugf("Shutdown deactivate pool , error: %s\n", err)
|
utils.Debugf("Shutdown deactivate pool , error: %s\n", err)
|
||||||
}
|
}
|
||||||
|
devices.Unlock()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (devices *DeviceSet) MountDevice(hash, path string, mountLabel string) error {
|
func (devices *DeviceSet) MountDevice(hash, path string, mountLabel string) error {
|
||||||
devices.Lock()
|
info, err := devices.lookupDevice(hash)
|
||||||
defer devices.Unlock()
|
if err != nil {
|
||||||
|
return err
|
||||||
info := devices.Devices[hash]
|
|
||||||
if info == nil {
|
|
||||||
return fmt.Errorf("Unknown device %s", hash)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
info.lock.Lock()
|
info.lock.Lock()
|
||||||
defer info.lock.Unlock()
|
defer info.lock.Unlock()
|
||||||
|
|
||||||
|
devices.Lock()
|
||||||
|
defer devices.Unlock()
|
||||||
|
|
||||||
if info.mountCount > 0 {
|
if info.mountCount > 0 {
|
||||||
if path != info.mountPath {
|
if path != info.mountPath {
|
||||||
return fmt.Errorf("Trying to mount devmapper device in multple places (%s, %s)", info.mountPath, path)
|
return fmt.Errorf("Trying to mount devmapper device in multple places (%s, %s)", info.mountPath, path)
|
||||||
|
@ -858,14 +885,14 @@ func (devices *DeviceSet) MountDevice(hash, path string, mountLabel string) erro
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := devices.activateDeviceIfNeeded(hash); err != nil {
|
if err := devices.activateDeviceIfNeeded(info); err != nil {
|
||||||
return fmt.Errorf("Error activating devmapper device for '%s': %s", hash, err)
|
return fmt.Errorf("Error activating devmapper device for '%s': %s", hash, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var flags uintptr = sysMsMgcVal
|
var flags uintptr = sysMsMgcVal
|
||||||
|
|
||||||
mountOptions := label.FormatMountLabel("discard", mountLabel)
|
mountOptions := label.FormatMountLabel("discard", mountLabel)
|
||||||
err := sysMount(info.DevName(), path, "ext4", flags, mountOptions)
|
err = sysMount(info.DevName(), path, "ext4", flags, mountOptions)
|
||||||
if err != nil && err == sysEInval {
|
if err != nil && err == sysEInval {
|
||||||
mountOptions = label.FormatMountLabel(mountLabel, "")
|
mountOptions = label.FormatMountLabel(mountLabel, "")
|
||||||
err = sysMount(info.DevName(), path, "ext4", flags, mountOptions)
|
err = sysMount(info.DevName(), path, "ext4", flags, mountOptions)
|
||||||
|
@ -878,23 +905,24 @@ func (devices *DeviceSet) MountDevice(hash, path string, mountLabel string) erro
|
||||||
info.mountPath = path
|
info.mountPath = path
|
||||||
info.floating = false
|
info.floating = false
|
||||||
|
|
||||||
return devices.setInitialized(hash)
|
return devices.setInitialized(info)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (devices *DeviceSet) UnmountDevice(hash string, mode UnmountMode) error {
|
func (devices *DeviceSet) UnmountDevice(hash string, mode UnmountMode) error {
|
||||||
utils.Debugf("[devmapper] UnmountDevice(hash=%s, mode=%d)", hash, mode)
|
utils.Debugf("[devmapper] UnmountDevice(hash=%s, mode=%d)", hash, mode)
|
||||||
defer utils.Debugf("[devmapper] UnmountDevice END")
|
defer utils.Debugf("[devmapper] UnmountDevice END")
|
||||||
devices.Lock()
|
|
||||||
defer devices.Unlock()
|
|
||||||
|
|
||||||
info := devices.Devices[hash]
|
info, err := devices.lookupDevice(hash)
|
||||||
if info == nil {
|
if err != nil {
|
||||||
return fmt.Errorf("UnmountDevice: no such device %s\n", hash)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
info.lock.Lock()
|
info.lock.Lock()
|
||||||
defer info.lock.Unlock()
|
defer info.lock.Unlock()
|
||||||
|
|
||||||
|
devices.Lock()
|
||||||
|
defer devices.Unlock()
|
||||||
|
|
||||||
if mode == UnmountFloat {
|
if mode == UnmountFloat {
|
||||||
if info.floating {
|
if info.floating {
|
||||||
return fmt.Errorf("UnmountDevice: can't float floating reference %s\n", hash)
|
return fmt.Errorf("UnmountDevice: can't float floating reference %s\n", hash)
|
||||||
|
@ -929,7 +957,7 @@ func (devices *DeviceSet) UnmountDevice(hash string, mode UnmountMode) error {
|
||||||
}
|
}
|
||||||
utils.Debugf("[devmapper] Unmount done")
|
utils.Debugf("[devmapper] Unmount done")
|
||||||
|
|
||||||
if err := devices.deactivateDevice(hash); err != nil {
|
if err := devices.deactivateDevice(info); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -942,22 +970,20 @@ func (devices *DeviceSet) HasDevice(hash string) bool {
|
||||||
devices.Lock()
|
devices.Lock()
|
||||||
defer devices.Unlock()
|
defer devices.Unlock()
|
||||||
|
|
||||||
return devices.Devices[hash] != nil
|
info, _ := devices.lookupDevice(hash)
|
||||||
|
return info != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (devices *DeviceSet) HasInitializedDevice(hash string) bool {
|
func (devices *DeviceSet) HasInitializedDevice(hash string) bool {
|
||||||
devices.Lock()
|
devices.Lock()
|
||||||
defer devices.Unlock()
|
defer devices.Unlock()
|
||||||
|
|
||||||
info := devices.Devices[hash]
|
info, _ := devices.lookupDevice(hash)
|
||||||
return info != nil && info.Initialized
|
return info != nil && info.Initialized
|
||||||
}
|
}
|
||||||
|
|
||||||
func (devices *DeviceSet) HasActivatedDevice(hash string) bool {
|
func (devices *DeviceSet) HasActivatedDevice(hash string) bool {
|
||||||
devices.Lock()
|
info, _ := devices.lookupDevice(hash)
|
||||||
defer devices.Unlock()
|
|
||||||
|
|
||||||
info := devices.Devices[hash]
|
|
||||||
if info == nil {
|
if info == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -965,16 +991,14 @@ func (devices *DeviceSet) HasActivatedDevice(hash string) bool {
|
||||||
info.lock.Lock()
|
info.lock.Lock()
|
||||||
defer info.lock.Unlock()
|
defer info.lock.Unlock()
|
||||||
|
|
||||||
|
devices.Lock()
|
||||||
|
defer devices.Unlock()
|
||||||
|
|
||||||
devinfo, _ := getInfo(info.Name())
|
devinfo, _ := getInfo(info.Name())
|
||||||
return devinfo != nil && devinfo.Exists != 0
|
return devinfo != nil && devinfo.Exists != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (devices *DeviceSet) setInitialized(hash string) error {
|
func (devices *DeviceSet) setInitialized(info *DevInfo) error {
|
||||||
info := devices.Devices[hash]
|
|
||||||
if info == nil {
|
|
||||||
return fmt.Errorf("Unknown device %s", hash)
|
|
||||||
}
|
|
||||||
|
|
||||||
info.Initialized = true
|
info.Initialized = true
|
||||||
if err := devices.saveMetadata(); err != nil {
|
if err := devices.saveMetadata(); err != nil {
|
||||||
info.Initialized = false
|
info.Initialized = false
|
||||||
|
@ -989,12 +1013,15 @@ func (devices *DeviceSet) List() []string {
|
||||||
devices.Lock()
|
devices.Lock()
|
||||||
defer devices.Unlock()
|
defer devices.Unlock()
|
||||||
|
|
||||||
|
devices.devicesLock.Lock()
|
||||||
ids := make([]string, len(devices.Devices))
|
ids := make([]string, len(devices.Devices))
|
||||||
i := 0
|
i := 0
|
||||||
for k := range devices.Devices {
|
for k := range devices.Devices {
|
||||||
ids[i] = k
|
ids[i] = k
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
devices.devicesLock.Unlock()
|
||||||
|
|
||||||
return ids
|
return ids
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1011,24 +1038,24 @@ func (devices *DeviceSet) deviceStatus(devName string) (sizeInSectors, mappedSec
|
||||||
}
|
}
|
||||||
|
|
||||||
func (devices *DeviceSet) GetDeviceStatus(hash string) (*DevStatus, error) {
|
func (devices *DeviceSet) GetDeviceStatus(hash string) (*DevStatus, error) {
|
||||||
devices.Lock()
|
info, err := devices.lookupDevice(hash)
|
||||||
defer devices.Unlock()
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
info := devices.Devices[hash]
|
|
||||||
if info == nil {
|
|
||||||
return nil, fmt.Errorf("No device %s", hash)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
info.lock.Lock()
|
info.lock.Lock()
|
||||||
defer info.lock.Unlock()
|
defer info.lock.Unlock()
|
||||||
|
|
||||||
|
devices.Lock()
|
||||||
|
defer devices.Unlock()
|
||||||
|
|
||||||
status := &DevStatus{
|
status := &DevStatus{
|
||||||
DeviceId: info.DeviceId,
|
DeviceId: info.DeviceId,
|
||||||
Size: info.Size,
|
Size: info.Size,
|
||||||
TransactionId: info.TransactionId,
|
TransactionId: info.TransactionId,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := devices.activateDeviceIfNeeded(hash); err != nil {
|
if err := devices.activateDeviceIfNeeded(info); err != nil {
|
||||||
return nil, fmt.Errorf("Error activating devmapper device for '%s': %s", hash, err)
|
return nil, fmt.Errorf("Error activating devmapper device for '%s': %s", hash, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue