github.com/guilhermebr/docker@v1.4.2-0.20150428121140-67da055cebca/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  type DevmapperLogger interface {
    17  	DMLog(level int, file string, line int, dmError int, message string)
    18  }
    19  
    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  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  	ErrTaskSetRo              = errors.New("dm_task_set_ro 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  	ErrTaskSetCookie          = errors.New("dm_task_set_cookie failed")
    59  	ErrNilCookie              = errors.New("cookie ptr can't be nil")
    60  	ErrAttachLoopbackDevice   = errors.New("loopback mounting failed")
    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  	ErrCreateRemoveTask       = errors.New("Can't create task of type DeviceRemove")
    66  	ErrRunRemoveDevice        = errors.New("running RemoveDevice failed")
    67  	ErrInvalidAddNode         = errors.New("Invalid AddNode type")
    68  	ErrGetLoopbackBackingFile = errors.New("Unable to get loopback backing file")
    69  	ErrLoopbackSetCapacity    = errors.New("Unable set loopback capacity")
    70  	ErrBusy                   = errors.New("Device is Busy")
    71  	ErrDeviceIdExists         = errors.New("Device Id Exists")
    72  
    73  	dmSawBusy  bool
    74  	dmSawExist bool
    75  )
    76  
    77  type (
    78  	Task struct {
    79  		unmanaged *CDmTask
    80  	}
    81  	Deps struct {
    82  		Count  uint32
    83  		Filler uint32
    84  		Device []uint64
    85  	}
    86  	Info struct {
    87  		Exists        int
    88  		Suspended     int
    89  		LiveTable     int
    90  		InactiveTable int
    91  		OpenCount     int32
    92  		EventNr       uint32
    93  		Major         uint32
    94  		Minor         uint32
    95  		ReadOnly      int
    96  		TargetCount   int32
    97  	}
    98  	TaskType    int
    99  	AddNodeType int
   100  )
   101  
   102  // Returns whether error conveys the information about device Id already
   103  // exist or not. This will be true if device creation or snap creation
   104  // operation fails if device or snap device already exists in pool.
   105  // Current implementation is little crude as it scans the error string
   106  // for exact pattern match. Replacing it with more robust implementation
   107  // is desirable.
   108  func DeviceIdExists(err error) bool {
   109  	return fmt.Sprint(err) == fmt.Sprint(ErrDeviceIdExists)
   110  }
   111  
   112  func (t *Task) destroy() {
   113  	if t != nil {
   114  		DmTaskDestroy(t.unmanaged)
   115  		runtime.SetFinalizer(t, nil)
   116  	}
   117  }
   118  
   119  // TaskCreateNamed is a convenience function for TaskCreate when a name
   120  // will be set on the task as well
   121  func TaskCreateNamed(t TaskType, name string) (*Task, error) {
   122  	task := TaskCreate(t)
   123  	if task == nil {
   124  		return nil, fmt.Errorf("Can't create task of type %d", int(t))
   125  	}
   126  	if err := task.SetName(name); err != nil {
   127  		return nil, fmt.Errorf("Can't set task name %s", name)
   128  	}
   129  	return task, nil
   130  }
   131  
   132  // TaskCreate initializes a devicemapper task of tasktype
   133  func TaskCreate(tasktype TaskType) *Task {
   134  	Ctask := DmTaskCreate(int(tasktype))
   135  	if Ctask == nil {
   136  		return nil
   137  	}
   138  	task := &Task{unmanaged: Ctask}
   139  	runtime.SetFinalizer(task, (*Task).destroy)
   140  	return task
   141  }
   142  
   143  func (t *Task) Run() error {
   144  	if res := DmTaskRun(t.unmanaged); res != 1 {
   145  		return ErrTaskRun
   146  	}
   147  	return nil
   148  }
   149  
   150  func (t *Task) SetName(name string) error {
   151  	if res := DmTaskSetName(t.unmanaged, name); res != 1 {
   152  		return ErrTaskSetName
   153  	}
   154  	return nil
   155  }
   156  
   157  func (t *Task) SetMessage(message string) error {
   158  	if res := DmTaskSetMessage(t.unmanaged, message); res != 1 {
   159  		return ErrTaskSetMessage
   160  	}
   161  	return nil
   162  }
   163  
   164  func (t *Task) SetSector(sector uint64) error {
   165  	if res := DmTaskSetSector(t.unmanaged, sector); res != 1 {
   166  		return ErrTaskSetSector
   167  	}
   168  	return nil
   169  }
   170  
   171  func (t *Task) SetCookie(cookie *uint, flags uint16) error {
   172  	if cookie == nil {
   173  		return ErrNilCookie
   174  	}
   175  	if res := DmTaskSetCookie(t.unmanaged, cookie, flags); res != 1 {
   176  		return ErrTaskSetCookie
   177  	}
   178  	return nil
   179  }
   180  
   181  func (t *Task) SetAddNode(addNode AddNodeType) error {
   182  	if addNode != AddNodeOnResume && addNode != AddNodeOnCreate {
   183  		return ErrInvalidAddNode
   184  	}
   185  	if res := DmTaskSetAddNode(t.unmanaged, addNode); res != 1 {
   186  		return ErrTaskSetAddNode
   187  	}
   188  	return nil
   189  }
   190  
   191  func (t *Task) SetRo() error {
   192  	if res := DmTaskSetRo(t.unmanaged); res != 1 {
   193  		return ErrTaskSetRo
   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) GetDriverVersion() (string, error) {
   223  	res := DmTaskGetDriverVersion(t.unmanaged)
   224  	if res == "" {
   225  		return "", ErrTaskGetDriverVersion
   226  	}
   227  	return res, nil
   228  }
   229  
   230  func (t *Task) GetNextTarget(next unsafe.Pointer) (nextPtr unsafe.Pointer, start uint64,
   231  	length uint64, targetType string, params string) {
   232  
   233  	return DmGetNextTarget(t.unmanaged, next, &start, &length,
   234  			&targetType, &params),
   235  		start, length, targetType, params
   236  }
   237  
   238  func getLoopbackBackingFile(file *os.File) (uint64, uint64, error) {
   239  	loopInfo, err := ioctlLoopGetStatus64(file.Fd())
   240  	if err != nil {
   241  		logrus.Errorf("Error get loopback backing file: %s", err)
   242  		return 0, 0, ErrGetLoopbackBackingFile
   243  	}
   244  	return loopInfo.loDevice, loopInfo.loInode, nil
   245  }
   246  
   247  func LoopbackSetCapacity(file *os.File) error {
   248  	if err := ioctlLoopSetCapacity(file.Fd(), 0); err != nil {
   249  		logrus.Errorf("Error loopbackSetCapacity: %s", err)
   250  		return ErrLoopbackSetCapacity
   251  	}
   252  	return nil
   253  }
   254  
   255  func FindLoopDeviceFor(file *os.File) *os.File {
   256  	stat, err := file.Stat()
   257  	if err != nil {
   258  		return nil
   259  	}
   260  	targetInode := stat.Sys().(*syscall.Stat_t).Ino
   261  	targetDevice := stat.Sys().(*syscall.Stat_t).Dev
   262  
   263  	for i := 0; true; i++ {
   264  		path := fmt.Sprintf("/dev/loop%d", i)
   265  
   266  		file, err := os.OpenFile(path, os.O_RDWR, 0)
   267  		if err != nil {
   268  			if os.IsNotExist(err) {
   269  				return nil
   270  			}
   271  
   272  			// Ignore all errors until the first not-exist
   273  			// we want to continue looking for the file
   274  			continue
   275  		}
   276  
   277  		dev, inode, err := getLoopbackBackingFile(file)
   278  		if err == nil && dev == targetDevice && inode == targetInode {
   279  			return file
   280  		}
   281  		file.Close()
   282  	}
   283  
   284  	return nil
   285  }
   286  
   287  func UdevWait(cookie *uint) error {
   288  	if res := DmUdevWait(*cookie); res != 1 {
   289  		logrus.Debugf("Failed to wait on udev cookie %d", *cookie)
   290  		return ErrUdevWait
   291  	}
   292  	return nil
   293  }
   294  
   295  func LogInitVerbose(level int) {
   296  	DmLogInitVerbose(level)
   297  }
   298  
   299  var dmLogger DevmapperLogger = nil
   300  
   301  // initialize the logger for the device mapper library
   302  func LogInit(logger DevmapperLogger) {
   303  	dmLogger = logger
   304  	LogWithErrnoInit()
   305  }
   306  
   307  func SetDevDir(dir string) error {
   308  	if res := DmSetDevDir(dir); res != 1 {
   309  		logrus.Debugf("Error dm_set_dev_dir")
   310  		return ErrSetDevDir
   311  	}
   312  	return nil
   313  }
   314  
   315  func GetLibraryVersion() (string, error) {
   316  	var version string
   317  	if res := DmGetLibraryVersion(&version); res != 1 {
   318  		return "", ErrGetLibraryVersion
   319  	}
   320  	return version, nil
   321  }
   322  
   323  // UdevSyncSupported returns whether device-mapper is able to sync with udev
   324  //
   325  // This is essential otherwise race conditions can arise where both udev and
   326  // device-mapper attempt to create and destroy devices.
   327  func UdevSyncSupported() bool {
   328  	return DmUdevGetSyncSupport() != 0
   329  }
   330  
   331  // UdevSetSyncSupport allows setting whether the udev sync should be enabled.
   332  // The return bool indicates the state of whether the sync is enabled.
   333  func UdevSetSyncSupport(enable bool) bool {
   334  	if enable {
   335  		DmUdevSetSyncSupport(1)
   336  	} else {
   337  		DmUdevSetSyncSupport(0)
   338  	}
   339  
   340  	return UdevSyncSupported()
   341  }
   342  
   343  // CookieSupported returns whether the version of device-mapper supports the
   344  // use of cookie's in the tasks.
   345  // This is largely a lower level call that other functions use.
   346  func CookieSupported() bool {
   347  	return DmCookieSupported() != 0
   348  }
   349  
   350  // Useful helper for cleanup
   351  func RemoveDevice(name string) error {
   352  	task, err := TaskCreateNamed(DeviceRemove, name)
   353  	if task == nil {
   354  		return err
   355  	}
   356  
   357  	var cookie uint = 0
   358  	if err := task.SetCookie(&cookie, 0); err != nil {
   359  		return fmt.Errorf("Can not set cookie: %s", err)
   360  	}
   361  	defer UdevWait(&cookie)
   362  
   363  	dmSawBusy = false // reset before the task is run
   364  	if err = task.Run(); err != nil {
   365  		if dmSawBusy {
   366  			return ErrBusy
   367  		}
   368  		return fmt.Errorf("Error running RemoveDevice %s", err)
   369  	}
   370  
   371  	return nil
   372  }
   373  
   374  func GetBlockDeviceSize(file *os.File) (uint64, error) {
   375  	size, err := ioctlBlkGetSize64(file.Fd())
   376  	if err != nil {
   377  		logrus.Errorf("Error getblockdevicesize: %s", err)
   378  		return 0, ErrGetBlockSize
   379  	}
   380  	return uint64(size), nil
   381  }
   382  
   383  func BlockDeviceDiscard(path string) error {
   384  	file, err := os.OpenFile(path, os.O_RDWR, 0)
   385  	if err != nil {
   386  		return err
   387  	}
   388  	defer file.Close()
   389  
   390  	size, err := GetBlockDeviceSize(file)
   391  	if err != nil {
   392  		return err
   393  	}
   394  
   395  	if err := ioctlBlkDiscard(file.Fd(), 0, size); err != nil {
   396  		return err
   397  	}
   398  
   399  	// Without this sometimes the remove of the device that happens after
   400  	// discard fails with EBUSY.
   401  	syscall.Sync()
   402  
   403  	return nil
   404  }
   405  
   406  // This is the programmatic example of "dmsetup create"
   407  func CreatePool(poolName string, dataFile, metadataFile *os.File, poolBlockSize uint32) error {
   408  	task, err := TaskCreateNamed(DeviceCreate, poolName)
   409  	if task == nil {
   410  		return err
   411  	}
   412  
   413  	size, err := GetBlockDeviceSize(dataFile)
   414  	if err != nil {
   415  		return fmt.Errorf("Can't get data size %s", err)
   416  	}
   417  
   418  	params := fmt.Sprintf("%s %s %d 32768 1 skip_block_zeroing", metadataFile.Name(), dataFile.Name(), poolBlockSize)
   419  	if err := task.AddTarget(0, size/512, "thin-pool", params); err != nil {
   420  		return fmt.Errorf("Can't add target %s", err)
   421  	}
   422  
   423  	var cookie uint = 0
   424  	var flags uint16 = DmUdevDisableSubsystemRulesFlag | DmUdevDisableDiskRulesFlag | DmUdevDisableOtherRulesFlag
   425  	if err := task.SetCookie(&cookie, flags); err != nil {
   426  		return fmt.Errorf("Can't set cookie %s", err)
   427  	}
   428  	defer UdevWait(&cookie)
   429  
   430  	if err := task.Run(); err != nil {
   431  		return fmt.Errorf("Error running DeviceCreate (CreatePool) %s", err)
   432  	}
   433  
   434  	return nil
   435  }
   436  
   437  func ReloadPool(poolName string, dataFile, metadataFile *os.File, poolBlockSize uint32) error {
   438  	task, err := TaskCreateNamed(DeviceReload, poolName)
   439  	if task == nil {
   440  		return err
   441  	}
   442  
   443  	size, err := GetBlockDeviceSize(dataFile)
   444  	if err != nil {
   445  		return fmt.Errorf("Can't get data size %s", err)
   446  	}
   447  
   448  	params := fmt.Sprintf("%s %s %d 32768 1 skip_block_zeroing", metadataFile.Name(), dataFile.Name(), poolBlockSize)
   449  	if err := task.AddTarget(0, size/512, "thin-pool", params); err != nil {
   450  		return fmt.Errorf("Can't add target %s", err)
   451  	}
   452  
   453  	if err := task.Run(); err != nil {
   454  		return fmt.Errorf("Error running DeviceCreate %s", err)
   455  	}
   456  
   457  	return nil
   458  }
   459  
   460  func GetDeps(name string) (*Deps, error) {
   461  	task, err := TaskCreateNamed(DeviceDeps, name)
   462  	if task == nil {
   463  		return nil, err
   464  	}
   465  	if err := task.Run(); err != nil {
   466  		return nil, err
   467  	}
   468  	return task.GetDeps()
   469  }
   470  
   471  func GetInfo(name string) (*Info, error) {
   472  	task, err := TaskCreateNamed(DeviceInfo, name)
   473  	if task == nil {
   474  		return nil, err
   475  	}
   476  	if err := task.Run(); err != nil {
   477  		return nil, err
   478  	}
   479  	return task.GetInfo()
   480  }
   481  
   482  func GetDriverVersion() (string, error) {
   483  	task := TaskCreate(DeviceVersion)
   484  	if task == nil {
   485  		return "", fmt.Errorf("Can't create DeviceVersion task")
   486  	}
   487  	if err := task.Run(); err != nil {
   488  		return "", err
   489  	}
   490  	return task.GetDriverVersion()
   491  }
   492  
   493  func GetStatus(name string) (uint64, uint64, string, string, error) {
   494  	task, err := TaskCreateNamed(DeviceStatus, name)
   495  	if task == nil {
   496  		logrus.Debugf("GetStatus: Error TaskCreateNamed: %s", err)
   497  		return 0, 0, "", "", err
   498  	}
   499  	if err := task.Run(); err != nil {
   500  		logrus.Debugf("GetStatus: Error Run: %s", err)
   501  		return 0, 0, "", "", err
   502  	}
   503  
   504  	devinfo, err := task.GetInfo()
   505  	if err != nil {
   506  		logrus.Debugf("GetStatus: Error GetInfo: %s", err)
   507  		return 0, 0, "", "", err
   508  	}
   509  	if devinfo.Exists == 0 {
   510  		logrus.Debugf("GetStatus: Non existing device %s", name)
   511  		return 0, 0, "", "", fmt.Errorf("Non existing device %s", name)
   512  	}
   513  
   514  	_, start, length, targetType, params := task.GetNextTarget(unsafe.Pointer(nil))
   515  	return start, length, targetType, params, nil
   516  }
   517  
   518  func SetTransactionId(poolName string, oldId uint64, newId uint64) error {
   519  	task, err := TaskCreateNamed(DeviceTargetMsg, poolName)
   520  	if task == nil {
   521  		return err
   522  	}
   523  
   524  	if err := task.SetSector(0); err != nil {
   525  		return fmt.Errorf("Can't set sector %s", err)
   526  	}
   527  
   528  	if err := task.SetMessage(fmt.Sprintf("set_transaction_id %d %d", oldId, newId)); err != nil {
   529  		return fmt.Errorf("Can't set message %s", err)
   530  	}
   531  
   532  	if err := task.Run(); err != nil {
   533  		return fmt.Errorf("Error running SetTransactionId %s", err)
   534  	}
   535  	return nil
   536  }
   537  
   538  func SuspendDevice(name string) error {
   539  	task, err := TaskCreateNamed(DeviceSuspend, name)
   540  	if task == nil {
   541  		return err
   542  	}
   543  	if err := task.Run(); err != nil {
   544  		return fmt.Errorf("Error running DeviceSuspend %s", err)
   545  	}
   546  	return nil
   547  }
   548  
   549  func ResumeDevice(name string) error {
   550  	task, err := TaskCreateNamed(DeviceResume, name)
   551  	if task == nil {
   552  		return err
   553  	}
   554  
   555  	var cookie uint = 0
   556  	if err := task.SetCookie(&cookie, 0); err != nil {
   557  		return fmt.Errorf("Can't set cookie %s", err)
   558  	}
   559  	defer UdevWait(&cookie)
   560  
   561  	if err := task.Run(); err != nil {
   562  		return fmt.Errorf("Error running DeviceResume %s", err)
   563  	}
   564  
   565  	return nil
   566  }
   567  
   568  func CreateDevice(poolName string, deviceId int) error {
   569  	logrus.Debugf("[devmapper] CreateDevice(poolName=%v, deviceId=%v)", poolName, deviceId)
   570  	task, err := TaskCreateNamed(DeviceTargetMsg, poolName)
   571  	if task == nil {
   572  		return err
   573  	}
   574  
   575  	if err := task.SetSector(0); err != nil {
   576  		return fmt.Errorf("Can't set sector %s", err)
   577  	}
   578  
   579  	if err := task.SetMessage(fmt.Sprintf("create_thin %d", deviceId)); err != nil {
   580  		return fmt.Errorf("Can't set message %s", err)
   581  	}
   582  
   583  	dmSawExist = false // reset before the task is run
   584  	if err := task.Run(); err != nil {
   585  		// Caller wants to know about ErrDeviceIdExists so that it can try with a different device id.
   586  		if dmSawExist {
   587  			return ErrDeviceIdExists
   588  		}
   589  
   590  		return fmt.Errorf("Error running CreateDevice %s", err)
   591  
   592  	}
   593  	return nil
   594  }
   595  
   596  func DeleteDevice(poolName string, deviceId int) error {
   597  	task, err := TaskCreateNamed(DeviceTargetMsg, poolName)
   598  	if task == nil {
   599  		return err
   600  	}
   601  
   602  	if err := task.SetSector(0); err != nil {
   603  		return fmt.Errorf("Can't set sector %s", err)
   604  	}
   605  
   606  	if err := task.SetMessage(fmt.Sprintf("delete %d", deviceId)); err != nil {
   607  		return fmt.Errorf("Can't set message %s", err)
   608  	}
   609  
   610  	if err := task.Run(); err != nil {
   611  		return fmt.Errorf("Error running DeleteDevice %s", err)
   612  	}
   613  	return nil
   614  }
   615  
   616  func ActivateDevice(poolName string, name string, deviceId int, size uint64) error {
   617  	task, err := TaskCreateNamed(DeviceCreate, name)
   618  	if task == nil {
   619  		return err
   620  	}
   621  
   622  	params := fmt.Sprintf("%s %d", poolName, deviceId)
   623  	if err := task.AddTarget(0, size/512, "thin", params); err != nil {
   624  		return fmt.Errorf("Can't add target %s", err)
   625  	}
   626  	if err := task.SetAddNode(AddNodeOnCreate); err != nil {
   627  		return fmt.Errorf("Can't add node %s", err)
   628  	}
   629  
   630  	var cookie uint = 0
   631  	if err := task.SetCookie(&cookie, 0); err != nil {
   632  		return fmt.Errorf("Can't set cookie %s", err)
   633  	}
   634  
   635  	defer UdevWait(&cookie)
   636  
   637  	if err := task.Run(); err != nil {
   638  		return fmt.Errorf("Error running DeviceCreate (ActivateDevice) %s", err)
   639  	}
   640  
   641  	return nil
   642  }
   643  
   644  func CreateSnapDevice(poolName string, deviceId int, baseName string, baseDeviceId int) error {
   645  	devinfo, _ := GetInfo(baseName)
   646  	doSuspend := devinfo != nil && devinfo.Exists != 0
   647  
   648  	if doSuspend {
   649  		if err := SuspendDevice(baseName); err != nil {
   650  			return err
   651  		}
   652  	}
   653  
   654  	task, err := TaskCreateNamed(DeviceTargetMsg, poolName)
   655  	if task == nil {
   656  		if doSuspend {
   657  			ResumeDevice(baseName)
   658  		}
   659  		return err
   660  	}
   661  
   662  	if err := task.SetSector(0); err != nil {
   663  		if doSuspend {
   664  			ResumeDevice(baseName)
   665  		}
   666  		return fmt.Errorf("Can't set sector %s", err)
   667  	}
   668  
   669  	if err := task.SetMessage(fmt.Sprintf("create_snap %d %d", deviceId, baseDeviceId)); err != nil {
   670  		if doSuspend {
   671  			ResumeDevice(baseName)
   672  		}
   673  		return fmt.Errorf("Can't set message %s", err)
   674  	}
   675  
   676  	dmSawExist = false // reset before the task is run
   677  	if err := task.Run(); err != nil {
   678  		if doSuspend {
   679  			ResumeDevice(baseName)
   680  		}
   681  		// Caller wants to know about ErrDeviceIdExists so that it can try with a different device id.
   682  		if dmSawExist {
   683  			return ErrDeviceIdExists
   684  		}
   685  
   686  		return fmt.Errorf("Error running DeviceCreate (createSnapDevice) %s", err)
   687  
   688  	}
   689  
   690  	if doSuspend {
   691  		if err := ResumeDevice(baseName); err != nil {
   692  			return err
   693  		}
   694  	}
   695  
   696  	return nil
   697  }