github.com/docker/engine@v22.0.0-20211208180946-d456264580cf+incompatible/pkg/devicemapper/devmapper.go (about)

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