github.com/stevegt/moby@v1.13.1/pkg/devicemapper/devmapper.go (about)

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