mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
devmapper: Move all "raw" libdevmapper wrappers to devmapper.go
This separates out the DeviceSet logic a bit better from the raw device mapper operations. devicemapper: Serialize addess to the devicemapper deviceset This code is not safe to run in multiple threads at the same time, and neither is libdevmapper. DeviceMapper: Move deactivate into UnmountDevice This way the deactivate is atomic wrt othe device mapper operations and will not fail with EBUSY if someone else starts a devicemapper operation inbetween unmount and deactivate. devmapper: Fix loopback mounting regression Some changes were added to attach_loop_device which added a perror() in a place that caused it to override errno so that a later errno != EBUSY failed. This fixes that and cleans up the error reporting a bit. devmapper: Build on old kernels without LOOP_CTL_GET_FREE define
This commit is contained in:
parent
1804fcba93
commit
c77697a45c
5 changed files with 345 additions and 306 deletions
|
@ -6,7 +6,7 @@ type DeviceSet interface {
|
|||
DeactivateDevice(hash string) error
|
||||
RemoveDevice(hash string) error
|
||||
MountDevice(hash, path string) error
|
||||
UnmountDevice(hash, path string) error
|
||||
UnmountDevice(hash, path string, deactivate bool) error
|
||||
HasDevice(hash string) bool
|
||||
HasInitializedDevice(hash string) bool
|
||||
HasActivatedDevice(hash string) bool
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -36,6 +37,7 @@ type MetaData struct {
|
|||
|
||||
type DeviceSetDM struct {
|
||||
MetaData
|
||||
sync.Mutex
|
||||
initialized bool
|
||||
root string
|
||||
devicePrefix string
|
||||
|
@ -77,74 +79,6 @@ func (devices *DeviceSetDM) getPoolDevName() string {
|
|||
return getDevName(devices.getPoolName())
|
||||
}
|
||||
|
||||
func (devices *DeviceSetDM) createTask(t TaskType, name string) (*Task, error) {
|
||||
task := TaskCreate(t)
|
||||
if task == nil {
|
||||
return nil, fmt.Errorf("Can't create task of type %d", int(t))
|
||||
}
|
||||
if err := task.SetName(name); err != nil {
|
||||
return nil, fmt.Errorf("Can't set task name %s", name)
|
||||
}
|
||||
return task, nil
|
||||
}
|
||||
|
||||
func (devices *DeviceSetDM) getInfo(name string) (*Info, error) {
|
||||
task, err := devices.createTask(DeviceInfo, name)
|
||||
if task == nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := task.Run(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return task.GetInfo()
|
||||
}
|
||||
|
||||
func (devices *DeviceSetDM) getStatus(name string) (uint64, uint64, string, string, error) {
|
||||
task, err := devices.createTask(DeviceStatus, name)
|
||||
if task == nil {
|
||||
utils.Debugf("getStatus: Error createTask: %s", err)
|
||||
return 0, 0, "", "", err
|
||||
}
|
||||
if err := task.Run(); err != nil {
|
||||
utils.Debugf("getStatus: Error Run: %s", err)
|
||||
return 0, 0, "", "", err
|
||||
}
|
||||
|
||||
devinfo, err := task.GetInfo()
|
||||
if err != nil {
|
||||
utils.Debugf("getStatus: Error GetInfo: %s", err)
|
||||
return 0, 0, "", "", err
|
||||
}
|
||||
if devinfo.Exists == 0 {
|
||||
utils.Debugf("getStatus: Non existing device %s", name)
|
||||
return 0, 0, "", "", fmt.Errorf("Non existing device %s", name)
|
||||
}
|
||||
|
||||
_, start, length, target_type, params := task.GetNextTarget(0)
|
||||
return start, length, target_type, params, nil
|
||||
}
|
||||
|
||||
func (devices *DeviceSetDM) setTransactionId(oldId uint64, newId uint64) error {
|
||||
task, err := devices.createTask(DeviceTargetMsg, devices.getPoolDevName())
|
||||
if task == nil {
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := task.SetSector(0); err != nil {
|
||||
return fmt.Errorf("Can't set sector")
|
||||
}
|
||||
|
||||
if err := task.SetMessage(fmt.Sprintf("set_transaction_id %d %d", oldId, newId)); err != nil {
|
||||
return fmt.Errorf("Can't set message")
|
||||
}
|
||||
|
||||
if err := task.Run(); err != nil {
|
||||
return fmt.Errorf("Error running setTransactionId")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (devices *DeviceSetDM) hasImage(name string) bool {
|
||||
dirname := devices.loopbackDir()
|
||||
filename := path.Join(dirname, name)
|
||||
|
@ -178,194 +112,6 @@ func (devices *DeviceSetDM) ensureImage(name string, size int64) (string, error)
|
|||
return filename, nil
|
||||
}
|
||||
|
||||
func (devices *DeviceSetDM) createPool(dataFile *os.File, metadataFile *os.File) error {
|
||||
utils.Debugf("Activating device-mapper pool %s", devices.getPoolName())
|
||||
task, err := devices.createTask(DeviceCreate, devices.getPoolName())
|
||||
if task == nil {
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
size, err := GetBlockDeviceSize(dataFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Can't get data size")
|
||||
}
|
||||
|
||||
params := metadataFile.Name() + " " + dataFile.Name() + " 512 8192"
|
||||
if err := task.AddTarget(0, size/512, "thin-pool", params); err != nil {
|
||||
return fmt.Errorf("Can't add target")
|
||||
}
|
||||
|
||||
var cookie uint32 = 0
|
||||
if err := task.SetCookie(&cookie, 0); err != nil {
|
||||
return fmt.Errorf("Can't set cookie")
|
||||
}
|
||||
|
||||
if err := task.Run(); err != nil {
|
||||
return fmt.Errorf("Error running DeviceCreate")
|
||||
}
|
||||
|
||||
UdevWait(cookie)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (devices *DeviceSetDM) suspendDevice(info *DevInfo) error {
|
||||
task, err := devices.createTask(DeviceSuspend, info.Name())
|
||||
if task == nil {
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
}
|
||||
if err := task.Run(); err != nil {
|
||||
return fmt.Errorf("Error running DeviceSuspend")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (devices *DeviceSetDM) resumeDevice(info *DevInfo) error {
|
||||
task, err := devices.createTask(DeviceResume, info.Name())
|
||||
if task == nil {
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
var cookie uint32 = 0
|
||||
if err := task.SetCookie(&cookie, 0); err != nil {
|
||||
return fmt.Errorf("Can't set cookie")
|
||||
}
|
||||
|
||||
if err := task.Run(); err != nil {
|
||||
return fmt.Errorf("Error running DeviceSuspend")
|
||||
}
|
||||
|
||||
UdevWait(cookie)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (devices *DeviceSetDM) createDevice(deviceId int) error {
|
||||
task, err := devices.createTask(DeviceTargetMsg, devices.getPoolDevName())
|
||||
if task == nil {
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := task.SetSector(0); err != nil {
|
||||
return fmt.Errorf("Can't set sector")
|
||||
}
|
||||
|
||||
if err := task.SetMessage(fmt.Sprintf("create_thin %d", deviceId)); err != nil {
|
||||
return fmt.Errorf("Can't set message")
|
||||
}
|
||||
|
||||
if err := task.Run(); err != nil {
|
||||
return fmt.Errorf("Error running createDevice")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (devices *DeviceSetDM) createSnapDevice(deviceId int, baseInfo *DevInfo) error {
|
||||
devinfo, _ := devices.getInfo(baseInfo.Name())
|
||||
doSuspend := devinfo != nil && devinfo.Exists != 0
|
||||
|
||||
if doSuspend {
|
||||
if err := devices.suspendDevice(baseInfo); err != nil {
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
task, err := devices.createTask(DeviceTargetMsg, devices.getPoolDevName())
|
||||
if task == nil {
|
||||
devices.resumeDevice(baseInfo)
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := task.SetSector(0); err != nil {
|
||||
devices.resumeDevice(baseInfo)
|
||||
return fmt.Errorf("Can't set sector")
|
||||
}
|
||||
|
||||
if err := task.SetMessage(fmt.Sprintf("create_snap %d %d", deviceId, baseInfo.DeviceId)); err != nil {
|
||||
devices.resumeDevice(baseInfo)
|
||||
return fmt.Errorf("Can't set message")
|
||||
}
|
||||
|
||||
if err := task.Run(); err != nil {
|
||||
devices.resumeDevice(baseInfo)
|
||||
return fmt.Errorf("Error running DeviceCreate")
|
||||
}
|
||||
|
||||
if doSuspend {
|
||||
if err := devices.resumeDevice(baseInfo); err != nil {
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (devices *DeviceSetDM) deleteDevice(deviceId int) error {
|
||||
task, err := devices.createTask(DeviceTargetMsg, devices.getPoolDevName())
|
||||
if task == nil {
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := task.SetSector(0); err != nil {
|
||||
return fmt.Errorf("Can't set sector")
|
||||
}
|
||||
|
||||
if err := task.SetMessage(fmt.Sprintf("delete %d", deviceId)); err != nil {
|
||||
return fmt.Errorf("Can't set message")
|
||||
}
|
||||
|
||||
if err := task.Run(); err != nil {
|
||||
return fmt.Errorf("Error running deleteDevice")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (devices *DeviceSetDM) removeDevice(name string) error {
|
||||
task, err := devices.createTask(DeviceRemove, name)
|
||||
if task == nil {
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
}
|
||||
if err = task.Run(); err != nil {
|
||||
return fmt.Errorf("Error running removeDevice")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (devices *DeviceSetDM) activateDevice(info *DevInfo) error {
|
||||
task, err := devices.createTask(DeviceCreate, info.Name())
|
||||
if task == nil {
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
params := fmt.Sprintf("%s %d", devices.getPoolDevName(), info.DeviceId)
|
||||
if err := task.AddTarget(0, info.Size/512, "thin", params); err != nil {
|
||||
return fmt.Errorf("Can't add target")
|
||||
}
|
||||
|
||||
var cookie uint32 = 0
|
||||
if err := task.SetCookie(&cookie, 0); err != nil {
|
||||
return fmt.Errorf("Can't set cookie")
|
||||
}
|
||||
|
||||
if err := task.Run(); err != nil {
|
||||
return fmt.Errorf("Error running DeviceCreate")
|
||||
}
|
||||
|
||||
UdevWait(cookie)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (devices *DeviceSetDM) allocateDeviceId() int {
|
||||
// TODO: Add smarter reuse of deleted devices
|
||||
id := devices.nextFreeDevice
|
||||
|
@ -412,7 +158,7 @@ func (devices *DeviceSetDM) saveMetadata() error {
|
|||
}
|
||||
|
||||
if devices.NewTransactionId != devices.TransactionId {
|
||||
if err = devices.setTransactionId(devices.TransactionId, devices.NewTransactionId); err != nil {
|
||||
if err = setTransactionId(devices.getPoolDevName(), devices.TransactionId, devices.NewTransactionId); err != nil {
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
}
|
||||
|
@ -448,11 +194,11 @@ func (devices *DeviceSetDM) activateDeviceIfNeeded(hash string) error {
|
|||
return fmt.Errorf("Unknown device %s", hash)
|
||||
}
|
||||
|
||||
if devinfo, _ := devices.getInfo(info.Name()); devinfo != nil && devinfo.Exists != 0 {
|
||||
if devinfo, _ := getInfo(info.Name()); devinfo != nil && devinfo.Exists != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return devices.activateDevice(info)
|
||||
return activateDevice(devices.getPoolDevName(), info.Name(), info.DeviceId, info.Size)
|
||||
}
|
||||
|
||||
func (devices *DeviceSetDM) createFilesystem(info *DevInfo) error {
|
||||
|
@ -470,7 +216,7 @@ func (devices *DeviceSetDM) createFilesystem(info *DevInfo) error {
|
|||
}
|
||||
|
||||
func (devices *DeviceSetDM) loadMetaData() error {
|
||||
_, _, _, params, err := devices.getStatus(devices.getPoolName())
|
||||
_, _, _, params, err := getStatus(devices.getPoolName())
|
||||
if err != nil {
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
|
@ -521,7 +267,7 @@ func (devices *DeviceSetDM) setupBaseImage() error {
|
|||
|
||||
if oldInfo != nil && !oldInfo.Initialized {
|
||||
utils.Debugf("Removing uninitialized base image")
|
||||
if err := devices.RemoveDevice(""); err != nil {
|
||||
if err := devices.removeDevice(""); err != nil {
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
}
|
||||
|
@ -532,14 +278,14 @@ func (devices *DeviceSetDM) setupBaseImage() error {
|
|||
id := devices.allocateDeviceId()
|
||||
|
||||
// Create initial device
|
||||
if err := devices.createDevice(id); err != nil {
|
||||
if err := createDevice(devices.getPoolDevName(), id); err != nil {
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
info, err := devices.registerDevice(id, "", defaultBaseFsSize)
|
||||
if err != nil {
|
||||
_ = devices.deleteDevice(id)
|
||||
_ = deleteDevice(devices.getPoolDevName(), id)
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
}
|
||||
|
@ -582,7 +328,7 @@ func setCloseOnExec(name string) {
|
|||
}
|
||||
|
||||
func (devices *DeviceSetDM) initDevmapper() error {
|
||||
info, err := devices.getInfo(devices.getPoolName())
|
||||
info, err := getInfo(devices.getPoolName())
|
||||
if info == nil {
|
||||
utils.Debugf("Error device getInfo: %s", err)
|
||||
return err
|
||||
|
@ -636,7 +382,7 @@ func (devices *DeviceSetDM) initDevmapper() error {
|
|||
}
|
||||
defer metadataFile.Close()
|
||||
|
||||
if err := devices.createPool(dataFile, metadataFile); err != nil {
|
||||
if err := createPool(devices.getPoolName(), dataFile, metadataFile); err != nil {
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
}
|
||||
|
@ -657,6 +403,9 @@ func (devices *DeviceSetDM) initDevmapper() error {
|
|||
}
|
||||
|
||||
func (devices *DeviceSetDM) AddDevice(hash, baseHash string) error {
|
||||
devices.Lock()
|
||||
defer devices.Unlock()
|
||||
|
||||
if err := devices.ensureInit(); err != nil {
|
||||
utils.Debugf("Error init: %s\n", err)
|
||||
return err
|
||||
|
@ -674,33 +423,28 @@ func (devices *DeviceSetDM) AddDevice(hash, baseHash string) error {
|
|||
|
||||
deviceId := devices.allocateDeviceId()
|
||||
|
||||
if err := devices.createSnapDevice(deviceId, baseInfo); err != nil {
|
||||
if err := devices.createSnapDevice(devices.getPoolDevName(), deviceId, baseInfo.Name(), baseInfo.DeviceId); err != nil {
|
||||
utils.Debugf("Error creating snap device: %s\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := devices.registerDevice(deviceId, hash, baseInfo.Size); err != nil {
|
||||
devices.deleteDevice(deviceId)
|
||||
deleteDevice(devices.getPoolDevName(), deviceId)
|
||||
utils.Debugf("Error registering device: %s\n", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (devices *DeviceSetDM) RemoveDevice(hash string) error {
|
||||
if err := devices.ensureInit(); err != nil {
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
func (devices *DeviceSetDM) removeDevice(hash string) error {
|
||||
info := devices.Devices[hash]
|
||||
if info == nil {
|
||||
return fmt.Errorf("hash %s doesn't exists", hash)
|
||||
}
|
||||
|
||||
devinfo, _ := devices.getInfo(info.Name())
|
||||
devinfo, _ := getInfo(info.Name())
|
||||
if devinfo != nil && devinfo.Exists != 0 {
|
||||
if err := devices.removeDevice(info.Name()); err != nil {
|
||||
if err := removeDevice(info.Name()); err != nil {
|
||||
utils.Debugf("Error removing device: %s\n", err)
|
||||
return err
|
||||
}
|
||||
|
@ -714,7 +458,7 @@ func (devices *DeviceSetDM) RemoveDevice(hash string) error {
|
|||
}
|
||||
}
|
||||
|
||||
if err := devices.deleteDevice(info.DeviceId); err != nil {
|
||||
if err := deleteDevice(devices.getPoolDevName(), info.DeviceId); err != nil {
|
||||
utils.Debugf("Error deleting device: %s\n", err)
|
||||
return err
|
||||
}
|
||||
|
@ -731,24 +475,32 @@ func (devices *DeviceSetDM) RemoveDevice(hash string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (devices *DeviceSetDM) DeactivateDevice(hash string) error {
|
||||
func (devices *DeviceSetDM) RemoveDevice(hash string) error {
|
||||
devices.Lock()
|
||||
defer devices.Unlock()
|
||||
|
||||
if err := devices.ensureInit(); err != nil {
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
return devices.removeDevice(hash)
|
||||
}
|
||||
|
||||
func (devices *DeviceSetDM) deactivateDevice(hash string) error {
|
||||
info := devices.Devices[hash]
|
||||
if info == nil {
|
||||
return fmt.Errorf("hash %s doesn't exists", hash)
|
||||
}
|
||||
|
||||
devinfo, err := devices.getInfo(info.Name())
|
||||
devinfo, err := getInfo(info.Name())
|
||||
if err != nil {
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
}
|
||||
if devinfo.Exists != 0 {
|
||||
if err := devices.removeDevice(info.Name()); err != nil {
|
||||
if err := removeDevice(info.Name()); err != nil {
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
}
|
||||
|
@ -757,7 +509,24 @@ func (devices *DeviceSetDM) DeactivateDevice(hash string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (devices *DeviceSetDM) DeactivateDevice(hash string) error {
|
||||
devices.Lock()
|
||||
defer devices.Unlock()
|
||||
|
||||
if err := devices.ensureInit(); err != nil {
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
utils.Debugf("DeactivateDevice %s", hash)
|
||||
return devices.deactivateDevice(hash);
|
||||
}
|
||||
|
||||
|
||||
func (devices *DeviceSetDM) Shutdown() error {
|
||||
devices.Lock()
|
||||
defer devices.Unlock()
|
||||
|
||||
if !devices.initialized {
|
||||
return nil
|
||||
}
|
||||
|
@ -772,14 +541,14 @@ func (devices *DeviceSetDM) Shutdown() error {
|
|||
}
|
||||
|
||||
for _, d := range devices.Devices {
|
||||
if err := devices.DeactivateDevice(d.Hash); err != nil {
|
||||
if err := devices.deactivateDevice(d.Hash); err != nil {
|
||||
utils.Debugf("Shutdown deactivate %s , error: %s\n", d.Hash, err)
|
||||
}
|
||||
}
|
||||
|
||||
pool := devices.getPoolDevName()
|
||||
if devinfo, err := devices.getInfo(pool); err == nil && devinfo.Exists != 0 {
|
||||
if err := devices.removeDevice(pool); err != nil {
|
||||
if devinfo, err := getInfo(pool); err == nil && devinfo.Exists != 0 {
|
||||
if err := removeDevice(pool); err != nil {
|
||||
utils.Debugf("Shutdown deactivate %s , error: %s\n", pool, err)
|
||||
}
|
||||
}
|
||||
|
@ -788,6 +557,9 @@ func (devices *DeviceSetDM) Shutdown() error {
|
|||
}
|
||||
|
||||
func (devices *DeviceSetDM) MountDevice(hash, path string) error {
|
||||
devices.Lock()
|
||||
defer devices.Unlock()
|
||||
|
||||
if err := devices.ensureInit(); err != nil {
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
|
@ -815,7 +587,10 @@ func (devices *DeviceSetDM) MountDevice(hash, path string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (devices *DeviceSetDM) UnmountDevice(hash, path string) error {
|
||||
func (devices *DeviceSetDM) UnmountDevice(hash, path string, deactivate bool) error {
|
||||
devices.Lock()
|
||||
defer devices.Unlock()
|
||||
|
||||
if err := syscall.Unmount(path, 0); err != nil {
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
|
@ -827,10 +602,17 @@ func (devices *DeviceSetDM) UnmountDevice(hash, path string) error {
|
|||
delete(devices.activeMounts, path)
|
||||
}
|
||||
|
||||
if deactivate {
|
||||
devices.deactivateDevice(hash)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (devices *DeviceSetDM) HasDevice(hash string) bool {
|
||||
devices.Lock()
|
||||
defer devices.Unlock()
|
||||
|
||||
if err := devices.ensureInit(); err != nil {
|
||||
return false
|
||||
}
|
||||
|
@ -838,6 +620,9 @@ func (devices *DeviceSetDM) HasDevice(hash string) bool {
|
|||
}
|
||||
|
||||
func (devices *DeviceSetDM) HasInitializedDevice(hash string) bool {
|
||||
devices.Lock()
|
||||
defer devices.Unlock()
|
||||
|
||||
if err := devices.ensureInit(); err != nil {
|
||||
return false
|
||||
}
|
||||
|
@ -847,6 +632,9 @@ func (devices *DeviceSetDM) HasInitializedDevice(hash string) bool {
|
|||
}
|
||||
|
||||
func (devices *DeviceSetDM) HasActivatedDevice(hash string) bool {
|
||||
devices.Lock()
|
||||
defer devices.Unlock()
|
||||
|
||||
if err := devices.ensureInit(); err != nil {
|
||||
return false
|
||||
}
|
||||
|
@ -855,11 +643,14 @@ func (devices *DeviceSetDM) HasActivatedDevice(hash string) bool {
|
|||
if info == nil {
|
||||
return false
|
||||
}
|
||||
devinfo, _ := devices.getInfo(info.Name())
|
||||
devinfo, _ := getInfo(info.Name())
|
||||
return devinfo != nil && devinfo.Exists != 0
|
||||
}
|
||||
|
||||
func (devices *DeviceSetDM) SetInitialized(hash string) error {
|
||||
devices.Lock()
|
||||
defer devices.Unlock()
|
||||
|
||||
if err := devices.ensureInit(); err != nil {
|
||||
utils.Debugf("\n--->Err: %s\n", err)
|
||||
return err
|
||||
|
|
|
@ -14,6 +14,10 @@ package devmapper
|
|||
#include <linux/fs.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifndef LOOP_CTL_GET_FREE
|
||||
#define LOOP_CTL_GET_FREE 0x4C82
|
||||
#endif
|
||||
|
||||
char* attach_loop_device(const char *filename, int *loop_fd_out)
|
||||
{
|
||||
struct loop_info64 loopinfo = {0};
|
||||
|
@ -56,19 +60,18 @@ char* attach_loop_device(const char *filename, int *loop_fd_out)
|
|||
loop_fd = open(buf, O_RDWR);
|
||||
if (loop_fd < 0 && errno == ENOENT) {
|
||||
close(fd);
|
||||
perror("open");
|
||||
fprintf (stderr, "no available loopback device!");
|
||||
return NULL;
|
||||
} else if (loop_fd < 0)
|
||||
continue;
|
||||
|
||||
if (ioctl (loop_fd, LOOP_SET_FD, (void *)(size_t)fd) < 0) {
|
||||
perror("ioctl");
|
||||
int errsv = errno;
|
||||
close(loop_fd);
|
||||
loop_fd = -1;
|
||||
if (errno != EBUSY) {
|
||||
if (errsv != EBUSY) {
|
||||
close (fd);
|
||||
fprintf (stderr, "cannot set up loopback device %s", buf);
|
||||
fprintf (stderr, "cannot set up loopback device %s: %s", buf, strerror(errsv));
|
||||
return NULL;
|
||||
}
|
||||
continue;
|
||||
|
@ -388,3 +391,255 @@ func RemoveDevice(name string) error {
|
|||
func free(p *C.char) {
|
||||
C.free(unsafe.Pointer(p))
|
||||
}
|
||||
|
||||
func createPool(poolName string, dataFile *os.File, metadataFile *os.File) error {
|
||||
task, err := createTask(DeviceCreate, poolName)
|
||||
if task == nil {
|
||||
return err
|
||||
}
|
||||
|
||||
size, err := GetBlockDeviceSize(dataFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Can't get data size")
|
||||
}
|
||||
|
||||
params := metadataFile.Name() + " " + dataFile.Name() + " 512 8192"
|
||||
if err := task.AddTarget(0, size/512, "thin-pool", params); err != nil {
|
||||
return fmt.Errorf("Can't add target")
|
||||
}
|
||||
|
||||
var cookie uint32 = 0
|
||||
if err := task.SetCookie(&cookie, 0); err != nil {
|
||||
return fmt.Errorf("Can't set cookie")
|
||||
}
|
||||
|
||||
if err := task.Run(); err != nil {
|
||||
return fmt.Errorf("Error running DeviceCreate")
|
||||
}
|
||||
|
||||
UdevWait(cookie)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createTask(t TaskType, name string) (*Task, error) {
|
||||
task := TaskCreate(t)
|
||||
if task == nil {
|
||||
return nil, fmt.Errorf("Can't create task of type %d", int(t))
|
||||
}
|
||||
if err := task.SetName(name); err != nil {
|
||||
return nil, fmt.Errorf("Can't set task name %s", name)
|
||||
}
|
||||
return task, nil
|
||||
}
|
||||
|
||||
func getInfo(name string) (*Info, error) {
|
||||
task, err := createTask(DeviceInfo, name)
|
||||
if task == nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := task.Run(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return task.GetInfo()
|
||||
}
|
||||
|
||||
func getStatus(name string) (uint64, uint64, string, string, error) {
|
||||
task, err := createTask(DeviceStatus, name)
|
||||
if task == nil {
|
||||
utils.Debugf("getStatus: Error createTask: %s", err)
|
||||
return 0, 0, "", "", err
|
||||
}
|
||||
if err := task.Run(); err != nil {
|
||||
utils.Debugf("getStatus: Error Run: %s", err)
|
||||
return 0, 0, "", "", err
|
||||
}
|
||||
|
||||
devinfo, err := task.GetInfo()
|
||||
if err != nil {
|
||||
utils.Debugf("getStatus: Error GetInfo: %s", err)
|
||||
return 0, 0, "", "", err
|
||||
}
|
||||
if devinfo.Exists == 0 {
|
||||
utils.Debugf("getStatus: Non existing device %s", name)
|
||||
return 0, 0, "", "", fmt.Errorf("Non existing device %s", name)
|
||||
}
|
||||
|
||||
_, start, length, target_type, params := task.GetNextTarget(0)
|
||||
return start, length, target_type, params, nil
|
||||
}
|
||||
|
||||
func setTransactionId(poolName string, oldId uint64, newId uint64) error {
|
||||
task, err := createTask(DeviceTargetMsg, poolName)
|
||||
if task == nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := task.SetSector(0); err != nil {
|
||||
return fmt.Errorf("Can't set sector")
|
||||
}
|
||||
|
||||
if err := task.SetMessage(fmt.Sprintf("set_transaction_id %d %d", oldId, newId)); err != nil {
|
||||
return fmt.Errorf("Can't set message")
|
||||
}
|
||||
|
||||
if err := task.Run(); err != nil {
|
||||
return fmt.Errorf("Error running setTransactionId")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func suspendDevice(name string) error {
|
||||
task, err := createTask(DeviceSuspend, name)
|
||||
if task == nil {
|
||||
return err
|
||||
}
|
||||
if err := task.Run(); err != nil {
|
||||
return fmt.Errorf("Error running DeviceSuspend")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func resumeDevice(name string) error {
|
||||
task, err := createTask(DeviceResume, name)
|
||||
if task == nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var cookie uint32 = 0
|
||||
if err := task.SetCookie(&cookie, 0); err != nil {
|
||||
return fmt.Errorf("Can't set cookie")
|
||||
}
|
||||
|
||||
if err := task.Run(); err != nil {
|
||||
return fmt.Errorf("Error running DeviceSuspend")
|
||||
}
|
||||
|
||||
UdevWait(cookie)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createDevice(poolName string, deviceId int) error {
|
||||
task, err := createTask(DeviceTargetMsg, poolName)
|
||||
if task == nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := task.SetSector(0); err != nil {
|
||||
return fmt.Errorf("Can't set sector")
|
||||
}
|
||||
|
||||
if err := task.SetMessage(fmt.Sprintf("create_thin %d", deviceId)); err != nil {
|
||||
return fmt.Errorf("Can't set message")
|
||||
}
|
||||
|
||||
if err := task.Run(); err != nil {
|
||||
return fmt.Errorf("Error running createDevice")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteDevice(poolName string, deviceId int) error {
|
||||
task, err := createTask(DeviceTargetMsg, poolName)
|
||||
if task == nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := task.SetSector(0); err != nil {
|
||||
return fmt.Errorf("Can't set sector")
|
||||
}
|
||||
|
||||
if err := task.SetMessage(fmt.Sprintf("delete %d", deviceId)); err != nil {
|
||||
return fmt.Errorf("Can't set message")
|
||||
}
|
||||
|
||||
if err := task.Run(); err != nil {
|
||||
return fmt.Errorf("Error running deleteDevice")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeDevice(name string) error {
|
||||
task, err := createTask(DeviceRemove, name)
|
||||
if task == nil {
|
||||
return err
|
||||
}
|
||||
if err = task.Run(); err != nil {
|
||||
return fmt.Errorf("Error running removeDevice")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func activateDevice(poolName string, name string, deviceId int, size uint64) error {
|
||||
task, err := createTask(DeviceCreate, name)
|
||||
if task == nil {
|
||||
return err
|
||||
}
|
||||
|
||||
params := fmt.Sprintf("%s %d", poolName, deviceId)
|
||||
if err := task.AddTarget(0, size/512, "thin", params); err != nil {
|
||||
return fmt.Errorf("Can't add target")
|
||||
}
|
||||
|
||||
var cookie uint32 = 0
|
||||
if err := task.SetCookie(&cookie, 0); err != nil {
|
||||
return fmt.Errorf("Can't set cookie")
|
||||
}
|
||||
|
||||
if err := task.Run(); err != nil {
|
||||
return fmt.Errorf("Error running DeviceCreate")
|
||||
}
|
||||
|
||||
UdevWait(cookie)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (devices *DeviceSetDM) createSnapDevice(poolName string, deviceId int, baseName string, baseDeviceId int) error {
|
||||
devinfo, _ := getInfo(baseName)
|
||||
doSuspend := devinfo != nil && devinfo.Exists != 0
|
||||
|
||||
if doSuspend {
|
||||
if err := suspendDevice(baseName); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
task, err := createTask(DeviceTargetMsg, poolName)
|
||||
if task == nil {
|
||||
if doSuspend {
|
||||
resumeDevice(baseName)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if err := task.SetSector(0); err != nil {
|
||||
if doSuspend {
|
||||
resumeDevice(baseName)
|
||||
}
|
||||
return fmt.Errorf("Can't set sector")
|
||||
}
|
||||
|
||||
if err := task.SetMessage(fmt.Sprintf("create_snap %d %d", deviceId, baseDeviceId)); err != nil {
|
||||
if doSuspend {
|
||||
resumeDevice(baseName)
|
||||
}
|
||||
return fmt.Errorf("Can't set message")
|
||||
}
|
||||
|
||||
if err := task.Run(); err != nil {
|
||||
if doSuspend {
|
||||
resumeDevice(baseName)
|
||||
}
|
||||
return fmt.Errorf("Error running DeviceCreate")
|
||||
}
|
||||
|
||||
if doSuspend {
|
||||
if err := resumeDevice(baseName); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
23
image.go
23
image.go
|
@ -391,14 +391,14 @@ func (image *Image) ensureImageDevice(devices DeviceSet) error {
|
|||
|
||||
if err := ioutil.WriteFile(path.Join(mountDir, ".docker-id"), []byte(image.ID), 0600); err != nil {
|
||||
utils.Debugf("Error writing file: %s", err)
|
||||
devices.UnmountDevice(image.ID, mountDir)
|
||||
devices.UnmountDevice(image.ID, mountDir, true)
|
||||
devices.RemoveDevice(image.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
if err = image.applyLayer(layerPath(root), mountDir); err != nil {
|
||||
utils.Debugf("Error applying layer: %s", err)
|
||||
devices.UnmountDevice(image.ID, mountDir)
|
||||
devices.UnmountDevice(image.ID, mountDir, true)
|
||||
devices.RemoveDevice(image.ID)
|
||||
return err
|
||||
}
|
||||
|
@ -411,28 +411,24 @@ func (image *Image) ensureImageDevice(devices DeviceSet) error {
|
|||
// part of the container changes
|
||||
dockerinitLayer, err := image.getDockerInitLayer()
|
||||
if err != nil {
|
||||
devices.UnmountDevice(image.ID, mountDir)
|
||||
devices.UnmountDevice(image.ID, mountDir, true)
|
||||
devices.RemoveDevice(image.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := image.applyLayer(dockerinitLayer, mountDir); err != nil {
|
||||
devices.UnmountDevice(image.ID, mountDir)
|
||||
devices.UnmountDevice(image.ID, mountDir, true)
|
||||
devices.RemoveDevice(image.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := devices.UnmountDevice(image.ID, mountDir); err != nil {
|
||||
if err := devices.UnmountDevice(image.ID, mountDir, true); err != nil {
|
||||
devices.RemoveDevice(image.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
devices.SetInitialized(image.ID)
|
||||
|
||||
// No need to the device-mapper device to hang around once we've written
|
||||
// the image, it can be enabled on-demand when needed
|
||||
devices.DeactivateDevice(image.ID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -491,11 +487,11 @@ func (image *Image) Unmount(runtime *Runtime, root string, id string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if err = devices.UnmountDevice(id, root); err != nil {
|
||||
if err = devices.UnmountDevice(id, root, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return devices.DeactivateDevice(id)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (image *Image) Changes(runtime *Runtime, root, rw, id string) ([]Change, error) {
|
||||
|
@ -518,10 +514,7 @@ func (image *Image) Changes(runtime *Runtime, root, rw, id string) ([]Change, er
|
|||
}
|
||||
|
||||
changes, err := ChangesDirs(root, rw)
|
||||
devices.UnmountDevice(image.ID, rw)
|
||||
if !wasActivated {
|
||||
devices.DeactivateDevice(image.ID)
|
||||
}
|
||||
devices.UnmountDevice(image.ID, rw, !wasActivated)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -356,8 +356,8 @@ func (wrapper *DeviceSetWrapper) MountDevice(hash, path string) error {
|
|||
return wrapper.wrapped.MountDevice(wrapper.wrap(hash), path)
|
||||
}
|
||||
|
||||
func (wrapper *DeviceSetWrapper) UnmountDevice(hash, path string) error {
|
||||
return wrapper.wrapped.UnmountDevice(wrapper.wrap(hash), path)
|
||||
func (wrapper *DeviceSetWrapper) UnmountDevice(hash, path string, deactivate bool) error {
|
||||
return wrapper.wrapped.UnmountDevice(wrapper.wrap(hash), path, deactivate)
|
||||
}
|
||||
|
||||
func (wrapper *DeviceSetWrapper) HasDevice(hash string) bool {
|
||||
|
|
Loading…
Add table
Reference in a new issue