github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/pkg/devicemapper/devmapper.go (about)

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