From c77697a45ca615f66351a7363e93c3903e92553f Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Mon, 7 Oct 2013 14:06:24 +0200 Subject: [PATCH] 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 --- deviceset.go | 2 +- devmapper/deviceset_devmapper.go | 359 +++++++------------------------ devmapper/devmapper.go | 263 +++++++++++++++++++++- image.go | 23 +- utils_test.go | 4 +- 5 files changed, 345 insertions(+), 306 deletions(-) diff --git a/deviceset.go b/deviceset.go index b2a968738c..21d5fd4d2f 100644 --- a/deviceset.go +++ b/deviceset.go @@ -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 diff --git a/devmapper/deviceset_devmapper.go b/devmapper/deviceset_devmapper.go index b789f94aa3..d0d4fbf85c 100644 --- a/devmapper/deviceset_devmapper.go +++ b/devmapper/deviceset_devmapper.go @@ -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 diff --git a/devmapper/devmapper.go b/devmapper/devmapper.go index 02922e836b..e4db906637 100644 --- a/devmapper/devmapper.go +++ b/devmapper/devmapper.go @@ -14,6 +14,10 @@ package devmapper #include #include +#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 +} diff --git a/image.go b/image.go index a937c74086..6a1191ef1b 100644 --- a/image.go +++ b/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 } diff --git a/utils_test.go b/utils_test.go index 78968432e1..9c7ab2f26c 100644 --- a/utils_test.go +++ b/utils_test.go @@ -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 {