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