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