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