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