github.com/damirazo/docker@v1.9.0/pkg/devicemapper/devmapper.go (about)

     1  // +build linux
     2  
     3  package devicemapper
     4  
     5  import (
     6  	"errors"
     7  	"fmt"
     8  	"os"
     9  	"runtime"
    10  	"syscall"
    11  	"unsafe"
    12  
    13  	"github.com/Sirupsen/logrus"
    14  )
    15  
    16  // DevmapperLogger defines methods for logging with devicemapper.
    17  type DevmapperLogger interface {
    18  	DMLog(level int, file string, line int, dmError int, message string)
    19  }
    20  
    21  const (
    22  	deviceCreate TaskType = iota
    23  	deviceReload
    24  	deviceRemove
    25  	deviceRemoveAll
    26  	deviceSuspend
    27  	deviceResume
    28  	deviceInfo
    29  	deviceDeps
    30  	deviceRename
    31  	deviceVersion
    32  	deviceStatus
    33  	deviceTable
    34  	deviceWaitevent
    35  	deviceList
    36  	deviceClear
    37  	deviceMknodes
    38  	deviceListVersions
    39  	deviceTargetMsg
    40  	deviceSetGeometry
    41  )
    42  
    43  const (
    44  	addNodeOnResume AddNodeType = iota
    45  	addNodeOnCreate
    46  )
    47  
    48  // List of errors returned when using devicemapper.
    49  var (
    50  	ErrTaskRun                = errors.New("dm_task_run failed")
    51  	ErrTaskSetName            = errors.New("dm_task_set_name failed")
    52  	ErrTaskSetMessage         = errors.New("dm_task_set_message failed")
    53  	ErrTaskSetAddNode         = errors.New("dm_task_set_add_node failed")
    54  	ErrTaskSetRo              = errors.New("dm_task_set_ro failed")
    55  	ErrTaskAddTarget          = errors.New("dm_task_add_target failed")
    56  	ErrTaskSetSector          = errors.New("dm_task_set_sector failed")
    57  	ErrTaskGetDeps            = errors.New("dm_task_get_deps failed")
    58  	ErrTaskGetInfo            = errors.New("dm_task_get_info failed")
    59  	ErrTaskGetDriverVersion   = errors.New("dm_task_get_driver_version failed")
    60  	ErrTaskDeferredRemove     = errors.New("dm_task_deferred_remove failed")
    61  	ErrTaskSetCookie          = errors.New("dm_task_set_cookie failed")
    62  	ErrNilCookie              = errors.New("cookie ptr can't be nil")
    63  	ErrAttachLoopbackDevice   = errors.New("loopback mounting failed")
    64  	ErrGetBlockSize           = errors.New("Can't get block size")
    65  	ErrUdevWait               = errors.New("wait on udev cookie failed")
    66  	ErrSetDevDir              = errors.New("dm_set_dev_dir failed")
    67  	ErrGetLibraryVersion      = errors.New("dm_get_library_version failed")
    68  	ErrCreateRemoveTask       = errors.New("Can't create task of type deviceRemove")
    69  	ErrRunRemoveDevice        = errors.New("running RemoveDevice failed")
    70  	ErrInvalidAddNode         = errors.New("Invalid AddNode type")
    71  	ErrGetLoopbackBackingFile = errors.New("Unable to get loopback backing file")
    72  	ErrLoopbackSetCapacity    = errors.New("Unable set loopback capacity")
    73  	ErrBusy                   = errors.New("Device is Busy")
    74  	ErrDeviceIDExists         = errors.New("Device Id Exists")
    75  	ErrEnxio                  = errors.New("No such device or address")
    76  )
    77  
    78  var (
    79  	dmSawBusy  bool
    80  	dmSawExist bool
    81  	dmSawEnxio bool // No Such Device or Address
    82  )
    83  
    84  type (
    85  	// Task represents a devicemapper task (like lvcreate, etc.) ; a task is needed for each ioctl
    86  	// command to execute.
    87  	Task struct {
    88  		unmanaged *cdmTask
    89  	}
    90  	// Deps represents dependents (layer) of a device.
    91  	Deps struct {
    92  		Count  uint32
    93  		Filler uint32
    94  		Device []uint64
    95  	}
    96  	// Info represents information about a device.
    97  	Info struct {
    98  		Exists         int
    99  		Suspended      int
   100  		LiveTable      int
   101  		InactiveTable  int
   102  		OpenCount      int32
   103  		EventNr        uint32
   104  		Major          uint32
   105  		Minor          uint32
   106  		ReadOnly       int
   107  		TargetCount    int32
   108  		DeferredRemove int
   109  	}
   110  	// TaskType represents a type of task
   111  	TaskType int
   112  	// AddNodeType represents a type of node to be added
   113  	AddNodeType int
   114  )
   115  
   116  // DeviceIDExists returns whether error conveys the information about device Id already
   117  // exist or not. This will be true if device creation or snap creation
   118  // operation fails if device or snap device already exists in pool.
   119  // Current implementation is little crude as it scans the error string
   120  // for exact pattern match. Replacing it with more robust implementation
   121  // is desirable.
   122  func DeviceIDExists(err error) bool {
   123  	return fmt.Sprint(err) == fmt.Sprint(ErrDeviceIDExists)
   124  }
   125  
   126  func (t *Task) destroy() {
   127  	if t != nil {
   128  		DmTaskDestroy(t.unmanaged)
   129  		runtime.SetFinalizer(t, nil)
   130  	}
   131  }
   132  
   133  // TaskCreateNamed is a convenience function for TaskCreate when a name
   134  // will be set on the task as well
   135  func TaskCreateNamed(t TaskType, name string) (*Task, error) {
   136  	task := TaskCreate(t)
   137  	if task == nil {
   138  		return nil, fmt.Errorf("Can't create task of type %d", int(t))
   139  	}
   140  	if err := task.setName(name); err != nil {
   141  		return nil, fmt.Errorf("Can't set task name %s", name)
   142  	}
   143  	return task, nil
   144  }
   145  
   146  // TaskCreate initializes a devicemapper task of tasktype
   147  func TaskCreate(tasktype TaskType) *Task {
   148  	Ctask := DmTaskCreate(int(tasktype))
   149  	if Ctask == nil {
   150  		return nil
   151  	}
   152  	task := &Task{unmanaged: Ctask}
   153  	runtime.SetFinalizer(task, (*Task).destroy)
   154  	return task
   155  }
   156  
   157  func (t *Task) run() error {
   158  	if res := DmTaskRun(t.unmanaged); res != 1 {
   159  		return ErrTaskRun
   160  	}
   161  	return nil
   162  }
   163  
   164  func (t *Task) setName(name string) error {
   165  	if res := DmTaskSetName(t.unmanaged, name); res != 1 {
   166  		return ErrTaskSetName
   167  	}
   168  	return nil
   169  }
   170  
   171  func (t *Task) setMessage(message string) error {
   172  	if res := DmTaskSetMessage(t.unmanaged, message); res != 1 {
   173  		return ErrTaskSetMessage
   174  	}
   175  	return nil
   176  }
   177  
   178  func (t *Task) setSector(sector uint64) error {
   179  	if res := DmTaskSetSector(t.unmanaged, sector); res != 1 {
   180  		return ErrTaskSetSector
   181  	}
   182  	return nil
   183  }
   184  
   185  func (t *Task) setCookie(cookie *uint, flags uint16) error {
   186  	if cookie == nil {
   187  		return ErrNilCookie
   188  	}
   189  	if res := DmTaskSetCookie(t.unmanaged, cookie, flags); res != 1 {
   190  		return ErrTaskSetCookie
   191  	}
   192  	return nil
   193  }
   194  
   195  func (t *Task) setAddNode(addNode AddNodeType) error {
   196  	if addNode != addNodeOnResume && addNode != addNodeOnCreate {
   197  		return ErrInvalidAddNode
   198  	}
   199  	if res := DmTaskSetAddNode(t.unmanaged, addNode); res != 1 {
   200  		return ErrTaskSetAddNode
   201  	}
   202  	return nil
   203  }
   204  
   205  func (t *Task) setRo() error {
   206  	if res := DmTaskSetRo(t.unmanaged); res != 1 {
   207  		return ErrTaskSetRo
   208  	}
   209  	return nil
   210  }
   211  
   212  func (t *Task) addTarget(start, size uint64, ttype, params string) error {
   213  	if res := DmTaskAddTarget(t.unmanaged, start, size,
   214  		ttype, params); res != 1 {
   215  		return ErrTaskAddTarget
   216  	}
   217  	return nil
   218  }
   219  
   220  func (t *Task) getDeps() (*Deps, error) {
   221  	var deps *Deps
   222  	if deps = DmTaskGetDeps(t.unmanaged); deps == nil {
   223  		return nil, ErrTaskGetDeps
   224  	}
   225  	return deps, nil
   226  }
   227  
   228  func (t *Task) getInfo() (*Info, error) {
   229  	info := &Info{}
   230  	if res := DmTaskGetInfo(t.unmanaged, info); res != 1 {
   231  		return nil, ErrTaskGetInfo
   232  	}
   233  	return info, nil
   234  }
   235  
   236  func (t *Task) getInfoWithDeferred() (*Info, error) {
   237  	info := &Info{}
   238  	if res := DmTaskGetInfoWithDeferred(t.unmanaged, info); res != 1 {
   239  		return nil, ErrTaskGetInfo
   240  	}
   241  	return info, nil
   242  }
   243  
   244  func (t *Task) getDriverVersion() (string, error) {
   245  	res := DmTaskGetDriverVersion(t.unmanaged)
   246  	if res == "" {
   247  		return "", ErrTaskGetDriverVersion
   248  	}
   249  	return res, nil
   250  }
   251  
   252  func (t *Task) getNextTarget(next unsafe.Pointer) (nextPtr unsafe.Pointer, start uint64,
   253  	length uint64, targetType string, params string) {
   254  
   255  	return DmGetNextTarget(t.unmanaged, next, &start, &length,
   256  			&targetType, &params),
   257  		start, length, targetType, params
   258  }
   259  
   260  func getLoopbackBackingFile(file *os.File) (uint64, uint64, error) {
   261  	loopInfo, err := ioctlLoopGetStatus64(file.Fd())
   262  	if err != nil {
   263  		logrus.Errorf("Error get loopback backing file: %s", err)
   264  		return 0, 0, ErrGetLoopbackBackingFile
   265  	}
   266  	return loopInfo.loDevice, loopInfo.loInode, nil
   267  }
   268  
   269  // LoopbackSetCapacity reloads the size for the loopback device.
   270  func LoopbackSetCapacity(file *os.File) error {
   271  	if err := ioctlLoopSetCapacity(file.Fd(), 0); err != nil {
   272  		logrus.Errorf("Error loopbackSetCapacity: %s", err)
   273  		return ErrLoopbackSetCapacity
   274  	}
   275  	return nil
   276  }
   277  
   278  // FindLoopDeviceFor returns a loopback device file for the specified file which
   279  // is backing file of a loop back device.
   280  func FindLoopDeviceFor(file *os.File) *os.File {
   281  	stat, err := file.Stat()
   282  	if err != nil {
   283  		return nil
   284  	}
   285  	targetInode := stat.Sys().(*syscall.Stat_t).Ino
   286  	targetDevice := stat.Sys().(*syscall.Stat_t).Dev
   287  
   288  	for i := 0; true; i++ {
   289  		path := fmt.Sprintf("/dev/loop%d", i)
   290  
   291  		file, err := os.OpenFile(path, os.O_RDWR, 0)
   292  		if err != nil {
   293  			if os.IsNotExist(err) {
   294  				return nil
   295  			}
   296  
   297  			// Ignore all errors until the first not-exist
   298  			// we want to continue looking for the file
   299  			continue
   300  		}
   301  
   302  		dev, inode, err := getLoopbackBackingFile(file)
   303  		if err == nil && dev == targetDevice && inode == targetInode {
   304  			return file
   305  		}
   306  		file.Close()
   307  	}
   308  
   309  	return nil
   310  }
   311  
   312  // UdevWait waits for any processes that are waiting for udev to complete the specified cookie.
   313  func UdevWait(cookie *uint) error {
   314  	if res := DmUdevWait(*cookie); res != 1 {
   315  		logrus.Debugf("Failed to wait on udev cookie %d", *cookie)
   316  		return ErrUdevWait
   317  	}
   318  	return nil
   319  }
   320  
   321  // LogInitVerbose is an interface to initialize the verbose logger for the device mapper library.
   322  func LogInitVerbose(level int) {
   323  	DmLogInitVerbose(level)
   324  }
   325  
   326  var dmLogger DevmapperLogger
   327  
   328  // LogInit initializes the logger for the device mapper library.
   329  func LogInit(logger DevmapperLogger) {
   330  	dmLogger = logger
   331  	LogWithErrnoInit()
   332  }
   333  
   334  // SetDevDir sets the dev folder for the device mapper library (usually /dev).
   335  func SetDevDir(dir string) error {
   336  	if res := DmSetDevDir(dir); res != 1 {
   337  		logrus.Debugf("Error dm_set_dev_dir")
   338  		return ErrSetDevDir
   339  	}
   340  	return nil
   341  }
   342  
   343  // GetLibraryVersion returns the device mapper library version.
   344  func GetLibraryVersion() (string, error) {
   345  	var version string
   346  	if res := DmGetLibraryVersion(&version); res != 1 {
   347  		return "", ErrGetLibraryVersion
   348  	}
   349  	return version, nil
   350  }
   351  
   352  // UdevSyncSupported returns whether device-mapper is able to sync with udev
   353  //
   354  // This is essential otherwise race conditions can arise where both udev and
   355  // device-mapper attempt to create and destroy devices.
   356  func UdevSyncSupported() bool {
   357  	return DmUdevGetSyncSupport() != 0
   358  }
   359  
   360  // UdevSetSyncSupport allows setting whether the udev sync should be enabled.
   361  // The return bool indicates the state of whether the sync is enabled.
   362  func UdevSetSyncSupport(enable bool) bool {
   363  	if enable {
   364  		DmUdevSetSyncSupport(1)
   365  	} else {
   366  		DmUdevSetSyncSupport(0)
   367  	}
   368  
   369  	return UdevSyncSupported()
   370  }
   371  
   372  // CookieSupported returns whether the version of device-mapper supports the
   373  // use of cookie's in the tasks.
   374  // This is largely a lower level call that other functions use.
   375  func CookieSupported() bool {
   376  	return DmCookieSupported() != 0
   377  }
   378  
   379  // RemoveDevice is a useful helper for cleaning up a device.
   380  func RemoveDevice(name string) error {
   381  	task, err := TaskCreateNamed(deviceRemove, name)
   382  	if task == nil {
   383  		return err
   384  	}
   385  
   386  	var cookie uint
   387  	if err := task.setCookie(&cookie, 0); err != nil {
   388  		return fmt.Errorf("Can not set cookie: %s", err)
   389  	}
   390  	defer UdevWait(&cookie)
   391  
   392  	dmSawBusy = false // reset before the task is run
   393  	if err = task.run(); err != nil {
   394  		if dmSawBusy {
   395  			return ErrBusy
   396  		}
   397  		return fmt.Errorf("Error running RemoveDevice %s", err)
   398  	}
   399  
   400  	return nil
   401  }
   402  
   403  // RemoveDeviceDeferred is a useful helper for cleaning up a device, but deferred.
   404  func RemoveDeviceDeferred(name string) error {
   405  	logrus.Debugf("[devmapper] RemoveDeviceDeferred START(%s)", name)
   406  	defer logrus.Debugf("[devmapper] RemoveDeviceDeferred END(%s)", name)
   407  	task, err := TaskCreateNamed(deviceRemove, name)
   408  	if task == nil {
   409  		return err
   410  	}
   411  
   412  	if err := DmTaskDeferredRemove(task.unmanaged); err != 1 {
   413  		return ErrTaskDeferredRemove
   414  	}
   415  
   416  	if err = task.run(); err != nil {
   417  		return fmt.Errorf("Error running RemoveDeviceDeferred %s", err)
   418  	}
   419  
   420  	return nil
   421  }
   422  
   423  // CancelDeferredRemove cancels a deferred remove for a device.
   424  func CancelDeferredRemove(deviceName string) error {
   425  	task, err := TaskCreateNamed(deviceTargetMsg, deviceName)
   426  	if task == nil {
   427  		return err
   428  	}
   429  
   430  	if err := task.setSector(0); err != nil {
   431  		return fmt.Errorf("Can't set sector %s", err)
   432  	}
   433  
   434  	if err := task.setMessage(fmt.Sprintf("@cancel_deferred_remove")); err != nil {
   435  		return fmt.Errorf("Can't set message %s", err)
   436  	}
   437  
   438  	dmSawBusy = false
   439  	dmSawEnxio = false
   440  	if err := task.run(); err != nil {
   441  		// A device might be being deleted already
   442  		if dmSawBusy {
   443  			return ErrBusy
   444  		} else if dmSawEnxio {
   445  			return ErrEnxio
   446  		}
   447  		return fmt.Errorf("Error running CancelDeferredRemove %s", err)
   448  
   449  	}
   450  	return nil
   451  }
   452  
   453  // GetBlockDeviceSize returns the size of a block device identified by the specified file.
   454  func GetBlockDeviceSize(file *os.File) (uint64, error) {
   455  	size, err := ioctlBlkGetSize64(file.Fd())
   456  	if err != nil {
   457  		logrus.Errorf("Error getblockdevicesize: %s", err)
   458  		return 0, ErrGetBlockSize
   459  	}
   460  	return uint64(size), nil
   461  }
   462  
   463  // BlockDeviceDiscard runs discard for the given path.
   464  // This is used as a workaround for the kernel not discarding block so
   465  // on the thin pool when we remove a thinp device, so we do it
   466  // manually
   467  func BlockDeviceDiscard(path string) error {
   468  	file, err := os.OpenFile(path, os.O_RDWR, 0)
   469  	if err != nil {
   470  		return err
   471  	}
   472  	defer file.Close()
   473  
   474  	size, err := GetBlockDeviceSize(file)
   475  	if err != nil {
   476  		return err
   477  	}
   478  
   479  	if err := ioctlBlkDiscard(file.Fd(), 0, size); err != nil {
   480  		return err
   481  	}
   482  
   483  	// Without this sometimes the remove of the device that happens after
   484  	// discard fails with EBUSY.
   485  	syscall.Sync()
   486  
   487  	return nil
   488  }
   489  
   490  // CreatePool is the programmatic example of "dmsetup create".
   491  // It creates a device with the specified poolName, data and metadata file and block size.
   492  func CreatePool(poolName string, dataFile, metadataFile *os.File, poolBlockSize uint32) error {
   493  	task, err := TaskCreateNamed(deviceCreate, poolName)
   494  	if task == nil {
   495  		return err
   496  	}
   497  
   498  	size, err := GetBlockDeviceSize(dataFile)
   499  	if err != nil {
   500  		return fmt.Errorf("Can't get data size %s", err)
   501  	}
   502  
   503  	params := fmt.Sprintf("%s %s %d 32768 1 skip_block_zeroing", metadataFile.Name(), dataFile.Name(), poolBlockSize)
   504  	if err := task.addTarget(0, size/512, "thin-pool", params); err != nil {
   505  		return fmt.Errorf("Can't add target %s", err)
   506  	}
   507  
   508  	var cookie uint
   509  	var flags uint16
   510  	flags = DmUdevDisableSubsystemRulesFlag | DmUdevDisableDiskRulesFlag | DmUdevDisableOtherRulesFlag
   511  	if err := task.setCookie(&cookie, flags); err != nil {
   512  		return fmt.Errorf("Can't set cookie %s", err)
   513  	}
   514  	defer UdevWait(&cookie)
   515  
   516  	if err := task.run(); err != nil {
   517  		return fmt.Errorf("Error running deviceCreate (CreatePool) %s", err)
   518  	}
   519  
   520  	return nil
   521  }
   522  
   523  // ReloadPool is the programmatic example of "dmsetup reload".
   524  // It reloads the table with the specified poolName, data and metadata file and block size.
   525  func ReloadPool(poolName string, dataFile, metadataFile *os.File, poolBlockSize uint32) error {
   526  	task, err := TaskCreateNamed(deviceReload, poolName)
   527  	if task == nil {
   528  		return err
   529  	}
   530  
   531  	size, err := GetBlockDeviceSize(dataFile)
   532  	if err != nil {
   533  		return fmt.Errorf("Can't get data size %s", err)
   534  	}
   535  
   536  	params := fmt.Sprintf("%s %s %d 32768 1 skip_block_zeroing", metadataFile.Name(), dataFile.Name(), poolBlockSize)
   537  	if err := task.addTarget(0, size/512, "thin-pool", params); err != nil {
   538  		return fmt.Errorf("Can't add target %s", err)
   539  	}
   540  
   541  	if err := task.run(); err != nil {
   542  		return fmt.Errorf("Error running deviceCreate %s", err)
   543  	}
   544  
   545  	return nil
   546  }
   547  
   548  // GetDeps is the programmatic example of "dmsetup deps".
   549  // It outputs a list of devices referenced by the live table for the specified device.
   550  func GetDeps(name string) (*Deps, error) {
   551  	task, err := TaskCreateNamed(deviceDeps, name)
   552  	if task == nil {
   553  		return nil, err
   554  	}
   555  	if err := task.run(); err != nil {
   556  		return nil, err
   557  	}
   558  	return task.getDeps()
   559  }
   560  
   561  // GetInfo is the programmatic example of "dmsetup info".
   562  // It outputs some brief information about the device.
   563  func GetInfo(name string) (*Info, error) {
   564  	task, err := TaskCreateNamed(deviceInfo, name)
   565  	if task == nil {
   566  		return nil, err
   567  	}
   568  	if err := task.run(); err != nil {
   569  		return nil, err
   570  	}
   571  	return task.getInfo()
   572  }
   573  
   574  // GetInfoWithDeferred is the programmatic example of "dmsetup info", but deferred.
   575  // It outputs some brief information about the device.
   576  func GetInfoWithDeferred(name string) (*Info, error) {
   577  	task, err := TaskCreateNamed(deviceInfo, name)
   578  	if task == nil {
   579  		return nil, err
   580  	}
   581  	if err := task.run(); err != nil {
   582  		return nil, err
   583  	}
   584  	return task.getInfoWithDeferred()
   585  }
   586  
   587  // GetDriverVersion is the programmatic example of "dmsetup version".
   588  // It outputs version information of the driver.
   589  func GetDriverVersion() (string, error) {
   590  	task := TaskCreate(deviceVersion)
   591  	if task == nil {
   592  		return "", fmt.Errorf("Can't create deviceVersion task")
   593  	}
   594  	if err := task.run(); err != nil {
   595  		return "", err
   596  	}
   597  	return task.getDriverVersion()
   598  }
   599  
   600  // GetStatus is the programmatic example of "dmsetup status".
   601  // It outputs status information for the specified device name.
   602  func GetStatus(name string) (uint64, uint64, string, string, error) {
   603  	task, err := TaskCreateNamed(deviceStatus, name)
   604  	if task == nil {
   605  		logrus.Debugf("GetStatus: Error TaskCreateNamed: %s", err)
   606  		return 0, 0, "", "", err
   607  	}
   608  	if err := task.run(); err != nil {
   609  		logrus.Debugf("GetStatus: Error Run: %s", err)
   610  		return 0, 0, "", "", err
   611  	}
   612  
   613  	devinfo, err := task.getInfo()
   614  	if err != nil {
   615  		logrus.Debugf("GetStatus: Error GetInfo: %s", err)
   616  		return 0, 0, "", "", err
   617  	}
   618  	if devinfo.Exists == 0 {
   619  		logrus.Debugf("GetStatus: Non existing device %s", name)
   620  		return 0, 0, "", "", fmt.Errorf("Non existing device %s", name)
   621  	}
   622  
   623  	_, start, length, targetType, params := task.getNextTarget(unsafe.Pointer(nil))
   624  	return start, length, targetType, params, nil
   625  }
   626  
   627  // GetTable is the programmatic example for "dmsetup table".
   628  // It outputs the current table for the specified device name.
   629  func GetTable(name string) (uint64, uint64, string, string, error) {
   630  	task, err := TaskCreateNamed(deviceTable, name)
   631  	if task == nil {
   632  		logrus.Debugf("GetTable: Error TaskCreateNamed: %s", err)
   633  		return 0, 0, "", "", err
   634  	}
   635  	if err := task.run(); err != nil {
   636  		logrus.Debugf("GetTable: Error Run: %s", err)
   637  		return 0, 0, "", "", err
   638  	}
   639  
   640  	devinfo, err := task.getInfo()
   641  	if err != nil {
   642  		logrus.Debugf("GetTable: Error GetInfo: %s", err)
   643  		return 0, 0, "", "", err
   644  	}
   645  	if devinfo.Exists == 0 {
   646  		logrus.Debugf("GetTable: Non existing device %s", name)
   647  		return 0, 0, "", "", fmt.Errorf("Non existing device %s", name)
   648  	}
   649  
   650  	_, start, length, targetType, params := task.getNextTarget(unsafe.Pointer(nil))
   651  	return start, length, targetType, params, nil
   652  }
   653  
   654  // SetTransactionID sets a transaction id for the specified device name.
   655  func SetTransactionID(poolName string, oldID uint64, newID uint64) error {
   656  	task, err := TaskCreateNamed(deviceTargetMsg, poolName)
   657  	if task == nil {
   658  		return err
   659  	}
   660  
   661  	if err := task.setSector(0); err != nil {
   662  		return fmt.Errorf("Can't set sector %s", err)
   663  	}
   664  
   665  	if err := task.setMessage(fmt.Sprintf("set_transaction_id %d %d", oldID, newID)); err != nil {
   666  		return fmt.Errorf("Can't set message %s", err)
   667  	}
   668  
   669  	if err := task.run(); err != nil {
   670  		return fmt.Errorf("Error running SetTransactionID %s", err)
   671  	}
   672  	return nil
   673  }
   674  
   675  // SuspendDevice is the programmatic example of "dmsetup suspend".
   676  // It suspends the specified device.
   677  func SuspendDevice(name string) error {
   678  	task, err := TaskCreateNamed(deviceSuspend, name)
   679  	if task == nil {
   680  		return err
   681  	}
   682  	if err := task.run(); err != nil {
   683  		return fmt.Errorf("Error running deviceSuspend %s", err)
   684  	}
   685  	return nil
   686  }
   687  
   688  // ResumeDevice is the programmatic example of "dmsetup resume".
   689  // It un-suspends the specified device.
   690  func ResumeDevice(name string) error {
   691  	task, err := TaskCreateNamed(deviceResume, name)
   692  	if task == nil {
   693  		return err
   694  	}
   695  
   696  	var cookie uint
   697  	if err := task.setCookie(&cookie, 0); err != nil {
   698  		return fmt.Errorf("Can't set cookie %s", err)
   699  	}
   700  	defer UdevWait(&cookie)
   701  
   702  	if err := task.run(); err != nil {
   703  		return fmt.Errorf("Error running deviceResume %s", err)
   704  	}
   705  
   706  	return nil
   707  }
   708  
   709  // CreateDevice creates a device with the specified poolName with the specified device id.
   710  func CreateDevice(poolName string, deviceID int) error {
   711  	logrus.Debugf("[devmapper] CreateDevice(poolName=%v, deviceID=%v)", poolName, deviceID)
   712  	task, err := TaskCreateNamed(deviceTargetMsg, poolName)
   713  	if task == nil {
   714  		return err
   715  	}
   716  
   717  	if err := task.setSector(0); err != nil {
   718  		return fmt.Errorf("Can't set sector %s", err)
   719  	}
   720  
   721  	if err := task.setMessage(fmt.Sprintf("create_thin %d", deviceID)); err != nil {
   722  		return fmt.Errorf("Can't set message %s", err)
   723  	}
   724  
   725  	dmSawExist = false // reset before the task is run
   726  	if err := task.run(); err != nil {
   727  		// Caller wants to know about ErrDeviceIDExists so that it can try with a different device id.
   728  		if dmSawExist {
   729  			return ErrDeviceIDExists
   730  		}
   731  
   732  		return fmt.Errorf("Error running CreateDevice %s", err)
   733  
   734  	}
   735  	return nil
   736  }
   737  
   738  // DeleteDevice deletes a device with the specified poolName with the specified device id.
   739  func DeleteDevice(poolName string, deviceID int) error {
   740  	task, err := TaskCreateNamed(deviceTargetMsg, poolName)
   741  	if task == nil {
   742  		return err
   743  	}
   744  
   745  	if err := task.setSector(0); err != nil {
   746  		return fmt.Errorf("Can't set sector %s", err)
   747  	}
   748  
   749  	if err := task.setMessage(fmt.Sprintf("delete %d", deviceID)); err != nil {
   750  		return fmt.Errorf("Can't set message %s", err)
   751  	}
   752  
   753  	dmSawBusy = false
   754  	if err := task.run(); err != nil {
   755  		if dmSawBusy {
   756  			return ErrBusy
   757  		}
   758  		return fmt.Errorf("Error running DeleteDevice %s", err)
   759  	}
   760  	return nil
   761  }
   762  
   763  // ActivateDevice activates the device identified by the specified
   764  // poolName, name and deviceID with the specified size.
   765  func ActivateDevice(poolName string, name string, deviceID int, size uint64) error {
   766  	return activateDevice(poolName, name, deviceID, size, "")
   767  }
   768  
   769  // ActivateDeviceWithExternal activates the device identified by the specified
   770  // poolName, name and deviceID with the specified size.
   771  func ActivateDeviceWithExternal(poolName string, name string, deviceID int, size uint64, external string) error {
   772  	return activateDevice(poolName, name, deviceID, size, external)
   773  }
   774  
   775  func activateDevice(poolName string, name string, deviceID int, size uint64, external string) error {
   776  	task, err := TaskCreateNamed(deviceCreate, name)
   777  	if task == nil {
   778  		return err
   779  	}
   780  
   781  	var params string
   782  	if len(external) > 0 {
   783  		params = fmt.Sprintf("%s %d %s", poolName, deviceID, external)
   784  	} else {
   785  		params = fmt.Sprintf("%s %d", poolName, deviceID)
   786  	}
   787  	if err := task.addTarget(0, size/512, "thin", params); err != nil {
   788  		return fmt.Errorf("Can't add target %s", err)
   789  	}
   790  	if err := task.setAddNode(addNodeOnCreate); err != nil {
   791  		return fmt.Errorf("Can't add node %s", err)
   792  	}
   793  
   794  	var cookie uint
   795  	if err := task.setCookie(&cookie, 0); err != nil {
   796  		return fmt.Errorf("Can't set cookie %s", err)
   797  	}
   798  
   799  	defer UdevWait(&cookie)
   800  
   801  	if err := task.run(); err != nil {
   802  		return fmt.Errorf("Error running deviceCreate (ActivateDevice) %s", err)
   803  	}
   804  
   805  	return nil
   806  }
   807  
   808  // CreateSnapDevice creates a snapshot based on the device identified by the baseName and baseDeviceId,
   809  func CreateSnapDevice(poolName string, deviceID int, baseName string, baseDeviceID int) error {
   810  	devinfo, _ := GetInfo(baseName)
   811  	doSuspend := devinfo != nil && devinfo.Exists != 0
   812  
   813  	if doSuspend {
   814  		if err := SuspendDevice(baseName); err != nil {
   815  			return err
   816  		}
   817  	}
   818  
   819  	task, err := TaskCreateNamed(deviceTargetMsg, poolName)
   820  	if task == nil {
   821  		if doSuspend {
   822  			ResumeDevice(baseName)
   823  		}
   824  		return err
   825  	}
   826  
   827  	if err := task.setSector(0); err != nil {
   828  		if doSuspend {
   829  			ResumeDevice(baseName)
   830  		}
   831  		return fmt.Errorf("Can't set sector %s", err)
   832  	}
   833  
   834  	if err := task.setMessage(fmt.Sprintf("create_snap %d %d", deviceID, baseDeviceID)); err != nil {
   835  		if doSuspend {
   836  			ResumeDevice(baseName)
   837  		}
   838  		return fmt.Errorf("Can't set message %s", err)
   839  	}
   840  
   841  	dmSawExist = false // reset before the task is run
   842  	if err := task.run(); err != nil {
   843  		if doSuspend {
   844  			ResumeDevice(baseName)
   845  		}
   846  		// Caller wants to know about ErrDeviceIDExists so that it can try with a different device id.
   847  		if dmSawExist {
   848  			return ErrDeviceIDExists
   849  		}
   850  
   851  		return fmt.Errorf("Error running deviceCreate (createSnapDevice) %s", err)
   852  
   853  	}
   854  
   855  	if doSuspend {
   856  		if err := ResumeDevice(baseName); err != nil {
   857  			return err
   858  		}
   859  	}
   860  
   861  	return nil
   862  }