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:
Alexander Larsson 2013-10-07 14:06:24 +02:00 committed by Solomon Hykes
parent 1804fcba93
commit c77697a45c
5 changed files with 345 additions and 306 deletions

View File

@ -6,7 +6,7 @@ type DeviceSet interface {
DeactivateDevice(hash string) error DeactivateDevice(hash string) error
RemoveDevice(hash string) error RemoveDevice(hash string) error
MountDevice(hash, path string) error MountDevice(hash, path string) error
UnmountDevice(hash, path string) error UnmountDevice(hash, path string, deactivate bool) error
HasDevice(hash string) bool HasDevice(hash string) bool
HasInitializedDevice(hash string) bool HasInitializedDevice(hash string) bool
HasActivatedDevice(hash string) bool HasActivatedDevice(hash string) bool

View File

@ -13,6 +13,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"syscall" "syscall"
"sync"
) )
const ( const (
@ -36,6 +37,7 @@ type MetaData struct {
type DeviceSetDM struct { type DeviceSetDM struct {
MetaData MetaData
sync.Mutex
initialized bool initialized bool
root string root string
devicePrefix string devicePrefix string
@ -77,74 +79,6 @@ func (devices *DeviceSetDM) getPoolDevName() string {
return getDevName(devices.getPoolName()) 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 { func (devices *DeviceSetDM) hasImage(name string) bool {
dirname := devices.loopbackDir() dirname := devices.loopbackDir()
filename := path.Join(dirname, name) filename := path.Join(dirname, name)
@ -178,194 +112,6 @@ func (devices *DeviceSetDM) ensureImage(name string, size int64) (string, error)
return filename, nil 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 { func (devices *DeviceSetDM) allocateDeviceId() int {
// TODO: Add smarter reuse of deleted devices // TODO: Add smarter reuse of deleted devices
id := devices.nextFreeDevice id := devices.nextFreeDevice
@ -412,7 +158,7 @@ func (devices *DeviceSetDM) saveMetadata() error {
} }
if devices.NewTransactionId != devices.TransactionId { 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) utils.Debugf("\n--->Err: %s\n", err)
return err return err
} }
@ -448,11 +194,11 @@ func (devices *DeviceSetDM) activateDeviceIfNeeded(hash string) error {
return fmt.Errorf("Unknown device %s", hash) 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 nil
} }
return devices.activateDevice(info) return activateDevice(devices.getPoolDevName(), info.Name(), info.DeviceId, info.Size)
} }
func (devices *DeviceSetDM) createFilesystem(info *DevInfo) error { func (devices *DeviceSetDM) createFilesystem(info *DevInfo) error {
@ -470,7 +216,7 @@ func (devices *DeviceSetDM) createFilesystem(info *DevInfo) error {
} }
func (devices *DeviceSetDM) loadMetaData() error { func (devices *DeviceSetDM) loadMetaData() error {
_, _, _, params, err := devices.getStatus(devices.getPoolName()) _, _, _, params, err := getStatus(devices.getPoolName())
if err != nil { if err != nil {
utils.Debugf("\n--->Err: %s\n", err) utils.Debugf("\n--->Err: %s\n", err)
return err return err
@ -521,7 +267,7 @@ func (devices *DeviceSetDM) setupBaseImage() error {
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.RemoveDevice(""); err != nil { if err := devices.removeDevice(""); err != nil {
utils.Debugf("\n--->Err: %s\n", err) utils.Debugf("\n--->Err: %s\n", err)
return err return err
} }
@ -532,14 +278,14 @@ func (devices *DeviceSetDM) setupBaseImage() error {
id := devices.allocateDeviceId() id := devices.allocateDeviceId()
// Create initial device // 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) utils.Debugf("\n--->Err: %s\n", err)
return err return err
} }
info, err := devices.registerDevice(id, "", defaultBaseFsSize) info, err := devices.registerDevice(id, "", defaultBaseFsSize)
if err != nil { if err != nil {
_ = devices.deleteDevice(id) _ = deleteDevice(devices.getPoolDevName(), id)
utils.Debugf("\n--->Err: %s\n", err) utils.Debugf("\n--->Err: %s\n", err)
return err return err
} }
@ -582,7 +328,7 @@ func setCloseOnExec(name string) {
} }
func (devices *DeviceSetDM) initDevmapper() error { func (devices *DeviceSetDM) initDevmapper() error {
info, err := devices.getInfo(devices.getPoolName()) info, err := getInfo(devices.getPoolName())
if info == nil { if info == nil {
utils.Debugf("Error device getInfo: %s", err) utils.Debugf("Error device getInfo: %s", err)
return err return err
@ -636,7 +382,7 @@ func (devices *DeviceSetDM) initDevmapper() error {
} }
defer metadataFile.Close() 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) utils.Debugf("\n--->Err: %s\n", err)
return err return err
} }
@ -657,6 +403,9 @@ func (devices *DeviceSetDM) initDevmapper() error {
} }
func (devices *DeviceSetDM) AddDevice(hash, baseHash string) error { func (devices *DeviceSetDM) AddDevice(hash, baseHash string) error {
devices.Lock()
defer devices.Unlock()
if err := devices.ensureInit(); err != nil { if err := devices.ensureInit(); err != nil {
utils.Debugf("Error init: %s\n", err) utils.Debugf("Error init: %s\n", err)
return err return err
@ -674,33 +423,28 @@ func (devices *DeviceSetDM) AddDevice(hash, baseHash string) error {
deviceId := devices.allocateDeviceId() 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) utils.Debugf("Error creating snap device: %s\n", err)
return err return err
} }
if _, err := devices.registerDevice(deviceId, hash, baseInfo.Size); err != nil { 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) utils.Debugf("Error registering device: %s\n", err)
return err return err
} }
return nil return nil
} }
func (devices *DeviceSetDM) RemoveDevice(hash string) error { func (devices *DeviceSetDM) removeDevice(hash string) error {
if err := devices.ensureInit(); err != nil {
utils.Debugf("\n--->Err: %s\n", err)
return err
}
info := devices.Devices[hash] info := devices.Devices[hash]
if info == nil { if info == nil {
return fmt.Errorf("hash %s doesn't exists", hash) 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 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) utils.Debugf("Error removing device: %s\n", err)
return 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) utils.Debugf("Error deleting device: %s\n", err)
return err return err
} }
@ -731,24 +475,32 @@ func (devices *DeviceSetDM) RemoveDevice(hash string) error {
return nil 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 { if err := devices.ensureInit(); err != nil {
utils.Debugf("\n--->Err: %s\n", err) utils.Debugf("\n--->Err: %s\n", err)
return err return err
} }
return devices.removeDevice(hash)
}
func (devices *DeviceSetDM) deactivateDevice(hash string) error {
info := devices.Devices[hash] info := devices.Devices[hash]
if info == nil { if info == nil {
return fmt.Errorf("hash %s doesn't exists", hash) return fmt.Errorf("hash %s doesn't exists", hash)
} }
devinfo, err := devices.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)
return err return err
} }
if devinfo.Exists != 0 { 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) utils.Debugf("\n--->Err: %s\n", err)
return err return err
} }
@ -757,7 +509,24 @@ func (devices *DeviceSetDM) DeactivateDevice(hash string) error {
return nil 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 { func (devices *DeviceSetDM) Shutdown() error {
devices.Lock()
defer devices.Unlock()
if !devices.initialized { if !devices.initialized {
return nil return nil
} }
@ -772,14 +541,14 @@ func (devices *DeviceSetDM) Shutdown() error {
} }
for _, d := range devices.Devices { 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) utils.Debugf("Shutdown deactivate %s , error: %s\n", d.Hash, err)
} }
} }
pool := devices.getPoolDevName() pool := devices.getPoolDevName()
if devinfo, err := devices.getInfo(pool); err == nil && devinfo.Exists != 0 { if devinfo, err := getInfo(pool); err == nil && devinfo.Exists != 0 {
if err := devices.removeDevice(pool); err != nil { if err := removeDevice(pool); err != nil {
utils.Debugf("Shutdown deactivate %s , error: %s\n", pool, err) 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 { func (devices *DeviceSetDM) MountDevice(hash, path string) error {
devices.Lock()
defer devices.Unlock()
if err := devices.ensureInit(); err != nil { if err := devices.ensureInit(); err != nil {
utils.Debugf("\n--->Err: %s\n", err) utils.Debugf("\n--->Err: %s\n", err)
return err return err
@ -815,7 +587,10 @@ func (devices *DeviceSetDM) MountDevice(hash, path string) error {
return nil 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 { if err := syscall.Unmount(path, 0); err != nil {
utils.Debugf("\n--->Err: %s\n", err) utils.Debugf("\n--->Err: %s\n", err)
return err return err
@ -827,10 +602,17 @@ func (devices *DeviceSetDM) UnmountDevice(hash, path string) error {
delete(devices.activeMounts, path) delete(devices.activeMounts, path)
} }
if deactivate {
devices.deactivateDevice(hash)
}
return nil return nil
} }
func (devices *DeviceSetDM) HasDevice(hash string) bool { func (devices *DeviceSetDM) HasDevice(hash string) bool {
devices.Lock()
defer devices.Unlock()
if err := devices.ensureInit(); err != nil { if err := devices.ensureInit(); err != nil {
return false return false
} }
@ -838,6 +620,9 @@ func (devices *DeviceSetDM) HasDevice(hash string) bool {
} }
func (devices *DeviceSetDM) HasInitializedDevice(hash string) bool { func (devices *DeviceSetDM) HasInitializedDevice(hash string) bool {
devices.Lock()
defer devices.Unlock()
if err := devices.ensureInit(); err != nil { if err := devices.ensureInit(); err != nil {
return false return false
} }
@ -847,6 +632,9 @@ func (devices *DeviceSetDM) HasInitializedDevice(hash string) bool {
} }
func (devices *DeviceSetDM) HasActivatedDevice(hash string) bool { func (devices *DeviceSetDM) HasActivatedDevice(hash string) bool {
devices.Lock()
defer devices.Unlock()
if err := devices.ensureInit(); err != nil { if err := devices.ensureInit(); err != nil {
return false return false
} }
@ -855,11 +643,14 @@ func (devices *DeviceSetDM) HasActivatedDevice(hash string) bool {
if info == nil { if info == nil {
return false return false
} }
devinfo, _ := devices.getInfo(info.Name()) devinfo, _ := getInfo(info.Name())
return devinfo != nil && devinfo.Exists != 0 return devinfo != nil && devinfo.Exists != 0
} }
func (devices *DeviceSetDM) SetInitialized(hash string) error { func (devices *DeviceSetDM) SetInitialized(hash string) error {
devices.Lock()
defer devices.Unlock()
if err := devices.ensureInit(); err != nil { if err := devices.ensureInit(); err != nil {
utils.Debugf("\n--->Err: %s\n", err) utils.Debugf("\n--->Err: %s\n", err)
return err return err

View File

@ -14,6 +14,10 @@ package devmapper
#include <linux/fs.h> #include <linux/fs.h>
#include <errno.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) char* attach_loop_device(const char *filename, int *loop_fd_out)
{ {
struct loop_info64 loopinfo = {0}; 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); loop_fd = open(buf, O_RDWR);
if (loop_fd < 0 && errno == ENOENT) { if (loop_fd < 0 && errno == ENOENT) {
close(fd); close(fd);
perror("open");
fprintf (stderr, "no available loopback device!"); fprintf (stderr, "no available loopback device!");
return NULL; return NULL;
} else if (loop_fd < 0) } else if (loop_fd < 0)
continue; continue;
if (ioctl (loop_fd, LOOP_SET_FD, (void *)(size_t)fd) < 0) { if (ioctl (loop_fd, LOOP_SET_FD, (void *)(size_t)fd) < 0) {
perror("ioctl"); int errsv = errno;
close(loop_fd); close(loop_fd);
loop_fd = -1; loop_fd = -1;
if (errno != EBUSY) { if (errsv != EBUSY) {
close (fd); 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; return NULL;
} }
continue; continue;
@ -388,3 +391,255 @@ func RemoveDevice(name string) error {
func free(p *C.char) { func free(p *C.char) {
C.free(unsafe.Pointer(p)) 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
}

View File

@ -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 { if err := ioutil.WriteFile(path.Join(mountDir, ".docker-id"), []byte(image.ID), 0600); err != nil {
utils.Debugf("Error writing file: %s", err) utils.Debugf("Error writing file: %s", err)
devices.UnmountDevice(image.ID, mountDir) devices.UnmountDevice(image.ID, mountDir, true)
devices.RemoveDevice(image.ID) devices.RemoveDevice(image.ID)
return err return err
} }
if err = image.applyLayer(layerPath(root), mountDir); err != nil { if err = image.applyLayer(layerPath(root), mountDir); err != nil {
utils.Debugf("Error applying layer: %s", err) utils.Debugf("Error applying layer: %s", err)
devices.UnmountDevice(image.ID, mountDir) devices.UnmountDevice(image.ID, mountDir, true)
devices.RemoveDevice(image.ID) devices.RemoveDevice(image.ID)
return err return err
} }
@ -411,28 +411,24 @@ func (image *Image) ensureImageDevice(devices DeviceSet) error {
// part of the container changes // part of the container changes
dockerinitLayer, err := image.getDockerInitLayer() dockerinitLayer, err := image.getDockerInitLayer()
if err != nil { if err != nil {
devices.UnmountDevice(image.ID, mountDir) devices.UnmountDevice(image.ID, mountDir, true)
devices.RemoveDevice(image.ID) devices.RemoveDevice(image.ID)
return err return err
} }
if err := image.applyLayer(dockerinitLayer, mountDir); err != nil { if err := image.applyLayer(dockerinitLayer, mountDir); err != nil {
devices.UnmountDevice(image.ID, mountDir) devices.UnmountDevice(image.ID, mountDir, true)
devices.RemoveDevice(image.ID) devices.RemoveDevice(image.ID)
return err 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) devices.RemoveDevice(image.ID)
return err return err
} }
devices.SetInitialized(image.ID) 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 return nil
} }
@ -491,11 +487,11 @@ func (image *Image) Unmount(runtime *Runtime, root string, id string) error {
return err return err
} }
if err = devices.UnmountDevice(id, root); err != nil { if err = devices.UnmountDevice(id, root, true); err != nil {
return err return err
} }
return devices.DeactivateDevice(id) return nil
} }
func (image *Image) Changes(runtime *Runtime, root, rw, id string) ([]Change, error) { 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) changes, err := ChangesDirs(root, rw)
devices.UnmountDevice(image.ID, rw) devices.UnmountDevice(image.ID, rw, !wasActivated)
if !wasActivated {
devices.DeactivateDevice(image.ID)
}
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -356,8 +356,8 @@ func (wrapper *DeviceSetWrapper) MountDevice(hash, path string) error {
return wrapper.wrapped.MountDevice(wrapper.wrap(hash), path) return wrapper.wrapped.MountDevice(wrapper.wrap(hash), path)
} }
func (wrapper *DeviceSetWrapper) UnmountDevice(hash, path string) error { func (wrapper *DeviceSetWrapper) UnmountDevice(hash, path string, deactivate bool) error {
return wrapper.wrapped.UnmountDevice(wrapper.wrap(hash), path) return wrapper.wrapped.UnmountDevice(wrapper.wrap(hash), path, deactivate)
} }
func (wrapper *DeviceSetWrapper) HasDevice(hash string) bool { func (wrapper *DeviceSetWrapper) HasDevice(hash string) bool {