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