github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/pkg/devicemapper/devmapper.go (about)

     1  // +build linux,cgo
     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  	runtime.KeepAlive(t)
   159  	return nil
   160  }
   161  
   162  func (t *Task) setName(name string) error {
   163  	if res := DmTaskSetName(t.unmanaged, name); res != 1 {
   164  		return ErrTaskSetName
   165  	}
   166  	return nil
   167  }
   168  
   169  func (t *Task) setMessage(message string) error {
   170  	if res := DmTaskSetMessage(t.unmanaged, message); res != 1 {
   171  		return ErrTaskSetMessage
   172  	}
   173  	return nil
   174  }
   175  
   176  func (t *Task) setSector(sector uint64) error {
   177  	if res := DmTaskSetSector(t.unmanaged, sector); res != 1 {
   178  		return ErrTaskSetSector
   179  	}
   180  	return nil
   181  }
   182  
   183  func (t *Task) setCookie(cookie *uint, flags uint16) error {
   184  	if cookie == nil {
   185  		return ErrNilCookie
   186  	}
   187  	if res := DmTaskSetCookie(t.unmanaged, cookie, flags); res != 1 {
   188  		return ErrTaskSetCookie
   189  	}
   190  	return nil
   191  }
   192  
   193  func (t *Task) setAddNode(addNode AddNodeType) error {
   194  	if addNode != addNodeOnResume && addNode != addNodeOnCreate {
   195  		return ErrInvalidAddNode
   196  	}
   197  	if res := DmTaskSetAddNode(t.unmanaged, addNode); res != 1 {
   198  		return ErrTaskSetAddNode
   199  	}
   200  	return nil
   201  }
   202  
   203  func (t *Task) setRo() error {
   204  	if res := DmTaskSetRo(t.unmanaged); res != 1 {
   205  		return ErrTaskSetRo
   206  	}
   207  	return nil
   208  }
   209  
   210  func (t *Task) addTarget(start, size uint64, ttype, params string) error {
   211  	if res := DmTaskAddTarget(t.unmanaged, start, size,
   212  		ttype, params); res != 1 {
   213  		return ErrTaskAddTarget
   214  	}
   215  	return nil
   216  }
   217  
   218  func (t *Task) getDeps() (*Deps, error) {
   219  	var deps *Deps
   220  	if deps = DmTaskGetDeps(t.unmanaged); deps == nil {
   221  		return nil, ErrTaskGetDeps
   222  	}
   223  	return deps, nil
   224  }
   225  
   226  func (t *Task) getInfo() (*Info, error) {
   227  	info := &Info{}
   228  	if res := DmTaskGetInfo(t.unmanaged, info); res != 1 {
   229  		return nil, ErrTaskGetInfo
   230  	}
   231  	return info, nil
   232  }
   233  
   234  func (t *Task) getInfoWithDeferred() (*Info, error) {
   235  	info := &Info{}
   236  	if res := DmTaskGetInfoWithDeferred(t.unmanaged, info); res != 1 {
   237  		return nil, ErrTaskGetInfo
   238  	}
   239  	return info, nil
   240  }
   241  
   242  func (t *Task) getDriverVersion() (string, error) {
   243  	res := DmTaskGetDriverVersion(t.unmanaged)
   244  	if res == "" {
   245  		return "", ErrTaskGetDriverVersion
   246  	}
   247  	return res, nil
   248  }
   249  
   250  func (t *Task) getNextTarget(next unsafe.Pointer) (nextPtr unsafe.Pointer, start uint64,
   251  	length uint64, targetType string, params string) {
   252  
   253  	return DmGetNextTarget(t.unmanaged, next, &start, &length,
   254  			&targetType, &params),
   255  		start, length, targetType, params
   256  }
   257  
   258  // UdevWait waits for any processes that are waiting for udev to complete the specified cookie.
   259  func UdevWait(cookie *uint) error {
   260  	if res := DmUdevWait(*cookie); res != 1 {
   261  		logrus.Debugf("devicemapper: Failed to wait on udev cookie %d, %d", *cookie, res)
   262  		return ErrUdevWait
   263  	}
   264  	return nil
   265  }
   266  
   267  // LogInitVerbose is an interface to initialize the verbose logger for the device mapper library.
   268  func LogInitVerbose(level int) {
   269  	DmLogInitVerbose(level)
   270  }
   271  
   272  var dmLogger DevmapperLogger
   273  
   274  // LogInit initializes the logger for the device mapper library.
   275  func LogInit(logger DevmapperLogger) {
   276  	dmLogger = logger
   277  	LogWithErrnoInit()
   278  }
   279  
   280  // SetDevDir sets the dev folder for the device mapper library (usually /dev).
   281  func SetDevDir(dir string) error {
   282  	if res := DmSetDevDir(dir); res != 1 {
   283  		logrus.Debug("devicemapper: Error dm_set_dev_dir")
   284  		return ErrSetDevDir
   285  	}
   286  	return nil
   287  }
   288  
   289  // GetLibraryVersion returns the device mapper library version.
   290  func GetLibraryVersion() (string, error) {
   291  	var version string
   292  	if res := DmGetLibraryVersion(&version); res != 1 {
   293  		return "", ErrGetLibraryVersion
   294  	}
   295  	return version, nil
   296  }
   297  
   298  // UdevSyncSupported returns whether device-mapper is able to sync with udev
   299  //
   300  // This is essential otherwise race conditions can arise where both udev and
   301  // device-mapper attempt to create and destroy devices.
   302  func UdevSyncSupported() bool {
   303  	return DmUdevGetSyncSupport() != 0
   304  }
   305  
   306  // UdevSetSyncSupport allows setting whether the udev sync should be enabled.
   307  // The return bool indicates the state of whether the sync is enabled.
   308  func UdevSetSyncSupport(enable bool) bool {
   309  	if enable {
   310  		DmUdevSetSyncSupport(1)
   311  	} else {
   312  		DmUdevSetSyncSupport(0)
   313  	}
   314  
   315  	return UdevSyncSupported()
   316  }
   317  
   318  // CookieSupported returns whether the version of device-mapper supports the
   319  // use of cookie's in the tasks.
   320  // This is largely a lower level call that other functions use.
   321  func CookieSupported() bool {
   322  	return DmCookieSupported() != 0
   323  }
   324  
   325  // RemoveDevice is a useful helper for cleaning up a device.
   326  func RemoveDevice(name string) error {
   327  	task, err := TaskCreateNamed(deviceRemove, name)
   328  	if task == nil {
   329  		return err
   330  	}
   331  
   332  	cookie := new(uint)
   333  	if err := task.setCookie(cookie, 0); err != nil {
   334  		return fmt.Errorf("devicemapper: Can not set cookie: %s", err)
   335  	}
   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 UdevWait(cookie)
   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  	// set a task cookie and disable library fallback, or else libdevmapper will
   362  	// disable udev dm rules and delete the symlink under /dev/mapper by itself,
   363  	// even if the removal is deferred by the kernel.
   364  	cookie := new(uint)
   365  	var flags uint16
   366  	flags = DmUdevDisableLibraryFallback
   367  	if err := task.setCookie(cookie, flags); err != nil {
   368  		return fmt.Errorf("devicemapper: Can not set cookie: %s", err)
   369  	}
   370  
   371  	if err = task.run(); err != nil {
   372  		return fmt.Errorf("devicemapper: Error running RemoveDeviceDeferred %s", err)
   373  	}
   374  
   375  	// libdevmapper and udev relies on System V semaphore for synchronization,
   376  	// semaphores created in `task.setCookie` will be cleaned up in `UdevWait`.
   377  	// So these two function call must come in pairs, otherwise semaphores will
   378  	// be leaked, and the  limit of number of semaphores defined in `/proc/sys/kernel/sem`
   379  	// will be reached, which will eventually make all follwing calls to 'task.SetCookie'
   380  	// fail.
   381  	// this call will not wait for the deferred removal's final executing, since no
   382  	// udev event will be generated, and the semaphore's value will not be incremented
   383  	// by udev, what UdevWait is just cleaning up the semaphore.
   384  
   385  	return UdevWait(cookie)
   386  }
   387  
   388  // CancelDeferredRemove cancels a deferred remove for a device.
   389  func CancelDeferredRemove(deviceName string) error {
   390  	task, err := TaskCreateNamed(deviceTargetMsg, deviceName)
   391  	if task == nil {
   392  		return err
   393  	}
   394  
   395  	if err := task.setSector(0); err != nil {
   396  		return fmt.Errorf("devicemapper: Can't set sector %s", err)
   397  	}
   398  
   399  	if err := task.setMessage(fmt.Sprintf("@cancel_deferred_remove")); err != nil {
   400  		return fmt.Errorf("devicemapper: Can't set message %s", err)
   401  	}
   402  
   403  	dmSawBusy = false
   404  	dmSawEnxio = false
   405  	if err := task.run(); err != nil {
   406  		// A device might be being deleted already
   407  		if dmSawBusy {
   408  			return ErrBusy
   409  		} else if dmSawEnxio {
   410  			return ErrEnxio
   411  		}
   412  		return fmt.Errorf("devicemapper: Error running CancelDeferredRemove %s", err)
   413  
   414  	}
   415  	return nil
   416  }
   417  
   418  // GetBlockDeviceSize returns the size of a block device identified by the specified file.
   419  func GetBlockDeviceSize(file *os.File) (uint64, error) {
   420  	size, err := ioctlBlkGetSize64(file.Fd())
   421  	if err != nil {
   422  		logrus.Errorf("devicemapper: Error getblockdevicesize: %s", err)
   423  		return 0, ErrGetBlockSize
   424  	}
   425  	return uint64(size), nil
   426  }
   427  
   428  // BlockDeviceDiscard runs discard for the given path.
   429  // This is used as a workaround for the kernel not discarding block so
   430  // on the thin pool when we remove a thinp device, so we do it
   431  // manually
   432  func BlockDeviceDiscard(path string) error {
   433  	file, err := os.OpenFile(path, os.O_RDWR, 0)
   434  	if err != nil {
   435  		return err
   436  	}
   437  	defer file.Close()
   438  
   439  	size, err := GetBlockDeviceSize(file)
   440  	if err != nil {
   441  		return err
   442  	}
   443  
   444  	if err := ioctlBlkDiscard(file.Fd(), 0, size); err != nil {
   445  		return err
   446  	}
   447  
   448  	// Without this sometimes the remove of the device that happens after
   449  	// discard fails with EBUSY.
   450  	syscall.Sync()
   451  
   452  	return nil
   453  }
   454  
   455  // CreatePool is the programmatic example of "dmsetup create".
   456  // It creates a device with the specified poolName, data and metadata file and block size.
   457  func CreatePool(poolName string, dataFile, metadataFile *os.File, poolBlockSize uint32) error {
   458  	task, err := TaskCreateNamed(deviceCreate, poolName)
   459  	if task == nil {
   460  		return err
   461  	}
   462  
   463  	size, err := GetBlockDeviceSize(dataFile)
   464  	if err != nil {
   465  		return fmt.Errorf("devicemapper: Can't get data size %s", err)
   466  	}
   467  
   468  	params := fmt.Sprintf("%s %s %d 32768 1 skip_block_zeroing", metadataFile.Name(), dataFile.Name(), poolBlockSize)
   469  	if err := task.addTarget(0, size/512, "thin-pool", params); err != nil {
   470  		return fmt.Errorf("devicemapper: Can't add target %s", err)
   471  	}
   472  
   473  	cookie := new(uint)
   474  	var flags uint16
   475  	flags = DmUdevDisableSubsystemRulesFlag | DmUdevDisableDiskRulesFlag | DmUdevDisableOtherRulesFlag
   476  	if err := task.setCookie(cookie, flags); err != nil {
   477  		return fmt.Errorf("devicemapper: Can't set cookie %s", err)
   478  	}
   479  
   480  	if err := task.run(); err != nil {
   481  		return fmt.Errorf("devicemapper: Error running deviceCreate (CreatePool) %s", err)
   482  	}
   483  
   484  	return UdevWait(cookie)
   485  }
   486  
   487  // ReloadPool is the programmatic example of "dmsetup reload".
   488  // It reloads the table with the specified poolName, data and metadata file and block size.
   489  func ReloadPool(poolName string, dataFile, metadataFile *os.File, poolBlockSize uint32) error {
   490  	task, err := TaskCreateNamed(deviceReload, poolName)
   491  	if task == nil {
   492  		return err
   493  	}
   494  
   495  	size, err := GetBlockDeviceSize(dataFile)
   496  	if err != nil {
   497  		return fmt.Errorf("devicemapper: Can't get data size %s", err)
   498  	}
   499  
   500  	params := fmt.Sprintf("%s %s %d 32768 1 skip_block_zeroing", metadataFile.Name(), dataFile.Name(), poolBlockSize)
   501  	if err := task.addTarget(0, size/512, "thin-pool", params); err != nil {
   502  		return fmt.Errorf("devicemapper: Can't add target %s", err)
   503  	}
   504  
   505  	if err := task.run(); err != nil {
   506  		return fmt.Errorf("devicemapper: Error running ReloadPool %s", err)
   507  	}
   508  
   509  	return nil
   510  }
   511  
   512  // GetDeps is the programmatic example of "dmsetup deps".
   513  // It outputs a list of devices referenced by the live table for the specified device.
   514  func GetDeps(name string) (*Deps, error) {
   515  	task, err := TaskCreateNamed(deviceDeps, name)
   516  	if task == nil {
   517  		return nil, err
   518  	}
   519  	if err := task.run(); err != nil {
   520  		return nil, err
   521  	}
   522  	return task.getDeps()
   523  }
   524  
   525  // GetInfo is the programmatic example of "dmsetup info".
   526  // It outputs some brief information about the device.
   527  func GetInfo(name string) (*Info, error) {
   528  	task, err := TaskCreateNamed(deviceInfo, name)
   529  	if task == nil {
   530  		return nil, err
   531  	}
   532  	if err := task.run(); err != nil {
   533  		return nil, err
   534  	}
   535  	return task.getInfo()
   536  }
   537  
   538  // GetInfoWithDeferred is the programmatic example of "dmsetup info", but deferred.
   539  // It outputs some brief information about the device.
   540  func GetInfoWithDeferred(name string) (*Info, error) {
   541  	task, err := TaskCreateNamed(deviceInfo, name)
   542  	if task == nil {
   543  		return nil, err
   544  	}
   545  	if err := task.run(); err != nil {
   546  		return nil, err
   547  	}
   548  	return task.getInfoWithDeferred()
   549  }
   550  
   551  // GetDriverVersion is the programmatic example of "dmsetup version".
   552  // It outputs version information of the driver.
   553  func GetDriverVersion() (string, error) {
   554  	task := TaskCreate(deviceVersion)
   555  	if task == nil {
   556  		return "", fmt.Errorf("devicemapper: Can't create deviceVersion task")
   557  	}
   558  	if err := task.run(); err != nil {
   559  		return "", err
   560  	}
   561  	return task.getDriverVersion()
   562  }
   563  
   564  // GetStatus is the programmatic example of "dmsetup status".
   565  // It outputs status information for the specified device name.
   566  func GetStatus(name string) (uint64, uint64, string, string, error) {
   567  	task, err := TaskCreateNamed(deviceStatus, name)
   568  	if task == nil {
   569  		logrus.Debugf("devicemapper: GetStatus() Error TaskCreateNamed: %s", err)
   570  		return 0, 0, "", "", err
   571  	}
   572  	if err := task.run(); err != nil {
   573  		logrus.Debugf("devicemapper: GetStatus() Error Run: %s", err)
   574  		return 0, 0, "", "", err
   575  	}
   576  
   577  	devinfo, err := task.getInfo()
   578  	if err != nil {
   579  		logrus.Debugf("devicemapper: GetStatus() Error GetInfo: %s", err)
   580  		return 0, 0, "", "", err
   581  	}
   582  	if devinfo.Exists == 0 {
   583  		logrus.Debugf("devicemapper: GetStatus() Non existing device %s", name)
   584  		return 0, 0, "", "", fmt.Errorf("devicemapper: Non existing device %s", name)
   585  	}
   586  
   587  	_, start, length, targetType, params := task.getNextTarget(unsafe.Pointer(nil))
   588  	return start, length, targetType, params, nil
   589  }
   590  
   591  // GetTable is the programmatic example for "dmsetup table".
   592  // It outputs the current table for the specified device name.
   593  func GetTable(name string) (uint64, uint64, string, string, error) {
   594  	task, err := TaskCreateNamed(deviceTable, name)
   595  	if task == nil {
   596  		logrus.Debugf("devicemapper: GetTable() Error TaskCreateNamed: %s", err)
   597  		return 0, 0, "", "", err
   598  	}
   599  	if err := task.run(); err != nil {
   600  		logrus.Debugf("devicemapper: GetTable() Error Run: %s", err)
   601  		return 0, 0, "", "", err
   602  	}
   603  
   604  	devinfo, err := task.getInfo()
   605  	if err != nil {
   606  		logrus.Debugf("devicemapper: GetTable() Error GetInfo: %s", err)
   607  		return 0, 0, "", "", err
   608  	}
   609  	if devinfo.Exists == 0 {
   610  		logrus.Debugf("devicemapper: GetTable() Non existing device %s", name)
   611  		return 0, 0, "", "", fmt.Errorf("devicemapper: Non existing device %s", name)
   612  	}
   613  
   614  	_, start, length, targetType, params := task.getNextTarget(unsafe.Pointer(nil))
   615  	return start, length, targetType, params, nil
   616  }
   617  
   618  // SetTransactionID sets a transaction id for the specified device name.
   619  func SetTransactionID(poolName string, oldID uint64, newID uint64) error {
   620  	task, err := TaskCreateNamed(deviceTargetMsg, poolName)
   621  	if task == nil {
   622  		return err
   623  	}
   624  
   625  	if err := task.setSector(0); err != nil {
   626  		return fmt.Errorf("devicemapper: Can't set sector %s", err)
   627  	}
   628  
   629  	if err := task.setMessage(fmt.Sprintf("set_transaction_id %d %d", oldID, newID)); err != nil {
   630  		return fmt.Errorf("devicemapper: Can't set message %s", err)
   631  	}
   632  
   633  	if err := task.run(); err != nil {
   634  		return fmt.Errorf("devicemapper: Error running SetTransactionID %s", err)
   635  	}
   636  	return nil
   637  }
   638  
   639  // SuspendDevice is the programmatic example of "dmsetup suspend".
   640  // It suspends the specified device.
   641  func SuspendDevice(name string) error {
   642  	task, err := TaskCreateNamed(deviceSuspend, name)
   643  	if task == nil {
   644  		return err
   645  	}
   646  	if err := task.run(); err != nil {
   647  		return fmt.Errorf("devicemapper: Error running deviceSuspend %s", err)
   648  	}
   649  	return nil
   650  }
   651  
   652  // ResumeDevice is the programmatic example of "dmsetup resume".
   653  // It un-suspends the specified device.
   654  func ResumeDevice(name string) error {
   655  	task, err := TaskCreateNamed(deviceResume, name)
   656  	if task == nil {
   657  		return err
   658  	}
   659  
   660  	cookie := new(uint)
   661  	if err := task.setCookie(cookie, 0); err != nil {
   662  		return fmt.Errorf("devicemapper: Can't set cookie %s", err)
   663  	}
   664  
   665  	if err := task.run(); err != nil {
   666  		return fmt.Errorf("devicemapper: Error running deviceResume %s", err)
   667  	}
   668  
   669  	return UdevWait(cookie)
   670  }
   671  
   672  // CreateDevice creates a device with the specified poolName with the specified device id.
   673  func CreateDevice(poolName string, deviceID int) error {
   674  	logrus.Debugf("devicemapper: CreateDevice(poolName=%v, deviceID=%v)", poolName, deviceID)
   675  	task, err := TaskCreateNamed(deviceTargetMsg, poolName)
   676  	if task == nil {
   677  		return err
   678  	}
   679  
   680  	if err := task.setSector(0); err != nil {
   681  		return fmt.Errorf("devicemapper: Can't set sector %s", err)
   682  	}
   683  
   684  	if err := task.setMessage(fmt.Sprintf("create_thin %d", deviceID)); err != nil {
   685  		return fmt.Errorf("devicemapper: Can't set message %s", err)
   686  	}
   687  
   688  	dmSawExist = false // reset before the task is run
   689  	if err := task.run(); err != nil {
   690  		// Caller wants to know about ErrDeviceIDExists so that it can try with a different device id.
   691  		if dmSawExist {
   692  			return ErrDeviceIDExists
   693  		}
   694  
   695  		return fmt.Errorf("devicemapper: Error running CreateDevice %s", err)
   696  
   697  	}
   698  	return nil
   699  }
   700  
   701  // DeleteDevice deletes a device with the specified poolName with the specified device id.
   702  func DeleteDevice(poolName string, deviceID int) error {
   703  	task, err := TaskCreateNamed(deviceTargetMsg, poolName)
   704  	if task == nil {
   705  		return err
   706  	}
   707  
   708  	if err := task.setSector(0); err != nil {
   709  		return fmt.Errorf("devicemapper: Can't set sector %s", err)
   710  	}
   711  
   712  	if err := task.setMessage(fmt.Sprintf("delete %d", deviceID)); err != nil {
   713  		return fmt.Errorf("devicemapper: Can't set message %s", err)
   714  	}
   715  
   716  	dmSawBusy = false
   717  	if err := task.run(); err != nil {
   718  		if dmSawBusy {
   719  			return ErrBusy
   720  		}
   721  		return fmt.Errorf("devicemapper: Error running DeleteDevice %s", err)
   722  	}
   723  	return nil
   724  }
   725  
   726  // ActivateDevice activates the device identified by the specified
   727  // poolName, name and deviceID with the specified size.
   728  func ActivateDevice(poolName string, name string, deviceID int, size uint64) error {
   729  	return activateDevice(poolName, name, deviceID, size, "")
   730  }
   731  
   732  // ActivateDeviceWithExternal activates the device identified by the specified
   733  // poolName, name and deviceID with the specified size.
   734  func ActivateDeviceWithExternal(poolName string, name string, deviceID int, size uint64, external string) error {
   735  	return activateDevice(poolName, name, deviceID, size, external)
   736  }
   737  
   738  func activateDevice(poolName string, name string, deviceID int, size uint64, external string) error {
   739  	task, err := TaskCreateNamed(deviceCreate, name)
   740  	if task == nil {
   741  		return err
   742  	}
   743  
   744  	var params string
   745  	if len(external) > 0 {
   746  		params = fmt.Sprintf("%s %d %s", poolName, deviceID, external)
   747  	} else {
   748  		params = fmt.Sprintf("%s %d", poolName, deviceID)
   749  	}
   750  	if err := task.addTarget(0, size/512, "thin", params); err != nil {
   751  		return fmt.Errorf("devicemapper: Can't add target %s", err)
   752  	}
   753  	if err := task.setAddNode(addNodeOnCreate); err != nil {
   754  		return fmt.Errorf("devicemapper: Can't add node %s", err)
   755  	}
   756  
   757  	cookie := new(uint)
   758  	if err := task.setCookie(cookie, 0); err != nil {
   759  		return fmt.Errorf("devicemapper: Can't set cookie %s", err)
   760  	}
   761  
   762  	if err := task.run(); err != nil {
   763  		return fmt.Errorf("devicemapper: Error running deviceCreate (ActivateDevice) %s", err)
   764  	}
   765  
   766  	return UdevWait(cookie)
   767  }
   768  
   769  // CreateSnapDeviceRaw creates a snapshot device. Caller needs to suspend and resume the origin device if it is active.
   770  func CreateSnapDeviceRaw(poolName string, deviceID int, baseDeviceID int) error {
   771  	task, err := TaskCreateNamed(deviceTargetMsg, poolName)
   772  	if task == nil {
   773  		return err
   774  	}
   775  
   776  	if err := task.setSector(0); err != nil {
   777  		return fmt.Errorf("devicemapper: Can't set sector %s", err)
   778  	}
   779  
   780  	if err := task.setMessage(fmt.Sprintf("create_snap %d %d", deviceID, baseDeviceID)); err != nil {
   781  		return fmt.Errorf("devicemapper: Can't set message %s", err)
   782  	}
   783  
   784  	dmSawExist = false // reset before the task is run
   785  	if err := task.run(); err != nil {
   786  		// Caller wants to know about ErrDeviceIDExists so that it can try with a different device id.
   787  		if dmSawExist {
   788  			return ErrDeviceIDExists
   789  		}
   790  		return fmt.Errorf("devicemapper: Error running deviceCreate (CreateSnapDeviceRaw) %s", err)
   791  	}
   792  
   793  	return nil
   794  }
   795  
   796  // CreateSnapDevice creates a snapshot based on the device identified by the baseName and baseDeviceId,
   797  func CreateSnapDevice(poolName string, deviceID int, baseName string, baseDeviceID int) error {
   798  	devinfo, _ := GetInfo(baseName)
   799  	doSuspend := devinfo != nil && devinfo.Exists != 0
   800  
   801  	if doSuspend {
   802  		if err := SuspendDevice(baseName); err != nil {
   803  			return err
   804  		}
   805  	}
   806  
   807  	if err := CreateSnapDeviceRaw(poolName, deviceID, baseDeviceID); err != nil {
   808  		if doSuspend {
   809  			if err2 := ResumeDevice(baseName); err2 != nil {
   810  				return fmt.Errorf("CreateSnapDeviceRaw Error: (%v): ResumeDevice Error: (%v)", err, err2)
   811  			}
   812  		}
   813  		return err
   814  	}
   815  
   816  	if doSuspend {
   817  		if err := ResumeDevice(baseName); err != nil {
   818  			return err
   819  		}
   820  	}
   821  
   822  	return nil
   823  }