github.com/reds/docker@v1.11.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 // 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, ¶ms), 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.Debugf("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 if err = task.run(); err != nil { 362 return fmt.Errorf("devicemapper: Error running RemoveDeviceDeferred %s", err) 363 } 364 365 return nil 366 } 367 368 // CancelDeferredRemove cancels a deferred remove for a device. 369 func CancelDeferredRemove(deviceName string) error { 370 task, err := TaskCreateNamed(deviceTargetMsg, deviceName) 371 if task == nil { 372 return err 373 } 374 375 if err := task.setSector(0); err != nil { 376 return fmt.Errorf("devicemapper: Can't set sector %s", err) 377 } 378 379 if err := task.setMessage(fmt.Sprintf("@cancel_deferred_remove")); err != nil { 380 return fmt.Errorf("devicemapper: Can't set message %s", err) 381 } 382 383 dmSawBusy = false 384 dmSawEnxio = false 385 if err := task.run(); err != nil { 386 // A device might be being deleted already 387 if dmSawBusy { 388 return ErrBusy 389 } else if dmSawEnxio { 390 return ErrEnxio 391 } 392 return fmt.Errorf("devicemapper: Error running CancelDeferredRemove %s", err) 393 394 } 395 return nil 396 } 397 398 // GetBlockDeviceSize returns the size of a block device identified by the specified file. 399 func GetBlockDeviceSize(file *os.File) (uint64, error) { 400 size, err := ioctlBlkGetSize64(file.Fd()) 401 if err != nil { 402 logrus.Errorf("devicemapper: Error getblockdevicesize: %s", err) 403 return 0, ErrGetBlockSize 404 } 405 return uint64(size), nil 406 } 407 408 // BlockDeviceDiscard runs discard for the given path. 409 // This is used as a workaround for the kernel not discarding block so 410 // on the thin pool when we remove a thinp device, so we do it 411 // manually 412 func BlockDeviceDiscard(path string) error { 413 file, err := os.OpenFile(path, os.O_RDWR, 0) 414 if err != nil { 415 return err 416 } 417 defer file.Close() 418 419 size, err := GetBlockDeviceSize(file) 420 if err != nil { 421 return err 422 } 423 424 if err := ioctlBlkDiscard(file.Fd(), 0, size); err != nil { 425 return err 426 } 427 428 // Without this sometimes the remove of the device that happens after 429 // discard fails with EBUSY. 430 syscall.Sync() 431 432 return nil 433 } 434 435 // CreatePool is the programmatic example of "dmsetup create". 436 // It creates a device with the specified poolName, data and metadata file and block size. 437 func CreatePool(poolName string, dataFile, metadataFile *os.File, poolBlockSize uint32) error { 438 task, err := TaskCreateNamed(deviceCreate, poolName) 439 if task == nil { 440 return err 441 } 442 443 size, err := GetBlockDeviceSize(dataFile) 444 if err != nil { 445 return fmt.Errorf("devicemapper: 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("devicemapper: Can't add target %s", err) 451 } 452 453 var cookie uint 454 var flags uint16 455 flags = DmUdevDisableSubsystemRulesFlag | DmUdevDisableDiskRulesFlag | DmUdevDisableOtherRulesFlag 456 if err := task.setCookie(&cookie, flags); err != nil { 457 return fmt.Errorf("devicemapper: Can't set cookie %s", err) 458 } 459 defer UdevWait(&cookie) 460 461 if err := task.run(); err != nil { 462 return fmt.Errorf("devicemapper: Error running deviceCreate (CreatePool) %s", err) 463 } 464 465 return nil 466 } 467 468 // ReloadPool is the programmatic example of "dmsetup reload". 469 // It reloads the table with the specified poolName, data and metadata file and block size. 470 func ReloadPool(poolName string, dataFile, metadataFile *os.File, poolBlockSize uint32) error { 471 task, err := TaskCreateNamed(deviceReload, poolName) 472 if task == nil { 473 return err 474 } 475 476 size, err := GetBlockDeviceSize(dataFile) 477 if err != nil { 478 return fmt.Errorf("devicemapper: Can't get data size %s", err) 479 } 480 481 params := fmt.Sprintf("%s %s %d 32768 1 skip_block_zeroing", metadataFile.Name(), dataFile.Name(), poolBlockSize) 482 if err := task.addTarget(0, size/512, "thin-pool", params); err != nil { 483 return fmt.Errorf("devicemapper: Can't add target %s", err) 484 } 485 486 if err := task.run(); err != nil { 487 return fmt.Errorf("devicemapper: Error running deviceCreate %s", err) 488 } 489 490 return nil 491 } 492 493 // GetDeps is the programmatic example of "dmsetup deps". 494 // It outputs a list of devices referenced by the live table for the specified device. 495 func GetDeps(name string) (*Deps, error) { 496 task, err := TaskCreateNamed(deviceDeps, name) 497 if task == nil { 498 return nil, err 499 } 500 if err := task.run(); err != nil { 501 return nil, err 502 } 503 return task.getDeps() 504 } 505 506 // GetInfo is the programmatic example of "dmsetup info". 507 // It outputs some brief information about the device. 508 func GetInfo(name string) (*Info, error) { 509 task, err := TaskCreateNamed(deviceInfo, name) 510 if task == nil { 511 return nil, err 512 } 513 if err := task.run(); err != nil { 514 return nil, err 515 } 516 return task.getInfo() 517 } 518 519 // GetInfoWithDeferred is the programmatic example of "dmsetup info", but deferred. 520 // It outputs some brief information about the device. 521 func GetInfoWithDeferred(name string) (*Info, error) { 522 task, err := TaskCreateNamed(deviceInfo, 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.getInfoWithDeferred() 530 } 531 532 // GetDriverVersion is the programmatic example of "dmsetup version". 533 // It outputs version information of the driver. 534 func GetDriverVersion() (string, error) { 535 task := TaskCreate(deviceVersion) 536 if task == nil { 537 return "", fmt.Errorf("devicemapper: Can't create deviceVersion task") 538 } 539 if err := task.run(); err != nil { 540 return "", err 541 } 542 return task.getDriverVersion() 543 } 544 545 // GetStatus is the programmatic example of "dmsetup status". 546 // It outputs status information for the specified device name. 547 func GetStatus(name string) (uint64, uint64, string, string, error) { 548 task, err := TaskCreateNamed(deviceStatus, name) 549 if task == nil { 550 logrus.Debugf("devicemapper: GetStatus() Error TaskCreateNamed: %s", err) 551 return 0, 0, "", "", err 552 } 553 if err := task.run(); err != nil { 554 logrus.Debugf("devicemapper: GetStatus() Error Run: %s", err) 555 return 0, 0, "", "", err 556 } 557 558 devinfo, err := task.getInfo() 559 if err != nil { 560 logrus.Debugf("devicemapper: GetStatus() Error GetInfo: %s", err) 561 return 0, 0, "", "", err 562 } 563 if devinfo.Exists == 0 { 564 logrus.Debugf("devicemapper: GetStatus() Non existing device %s", name) 565 return 0, 0, "", "", fmt.Errorf("devicemapper: Non existing device %s", name) 566 } 567 568 _, start, length, targetType, params := task.getNextTarget(unsafe.Pointer(nil)) 569 return start, length, targetType, params, nil 570 } 571 572 // GetTable is the programmatic example for "dmsetup table". 573 // It outputs the current table for the specified device name. 574 func GetTable(name string) (uint64, uint64, string, string, error) { 575 task, err := TaskCreateNamed(deviceTable, name) 576 if task == nil { 577 logrus.Debugf("devicemapper: GetTable() Error TaskCreateNamed: %s", err) 578 return 0, 0, "", "", err 579 } 580 if err := task.run(); err != nil { 581 logrus.Debugf("devicemapper: GetTable() Error Run: %s", err) 582 return 0, 0, "", "", err 583 } 584 585 devinfo, err := task.getInfo() 586 if err != nil { 587 logrus.Debugf("devicemapper: GetTable() Error GetInfo: %s", err) 588 return 0, 0, "", "", err 589 } 590 if devinfo.Exists == 0 { 591 logrus.Debugf("devicemapper: GetTable() Non existing device %s", name) 592 return 0, 0, "", "", fmt.Errorf("devicemapper: Non existing device %s", name) 593 } 594 595 _, start, length, targetType, params := task.getNextTarget(unsafe.Pointer(nil)) 596 return start, length, targetType, params, nil 597 } 598 599 // SetTransactionID sets a transaction id for the specified device name. 600 func SetTransactionID(poolName string, oldID uint64, newID uint64) error { 601 task, err := TaskCreateNamed(deviceTargetMsg, poolName) 602 if task == nil { 603 return err 604 } 605 606 if err := task.setSector(0); err != nil { 607 return fmt.Errorf("devicemapper: Can't set sector %s", err) 608 } 609 610 if err := task.setMessage(fmt.Sprintf("set_transaction_id %d %d", oldID, newID)); err != nil { 611 return fmt.Errorf("devicemapper: Can't set message %s", err) 612 } 613 614 if err := task.run(); err != nil { 615 return fmt.Errorf("devicemapper: Error running SetTransactionID %s", err) 616 } 617 return nil 618 } 619 620 // SuspendDevice is the programmatic example of "dmsetup suspend". 621 // It suspends the specified device. 622 func SuspendDevice(name string) error { 623 task, err := TaskCreateNamed(deviceSuspend, name) 624 if task == nil { 625 return err 626 } 627 if err := task.run(); err != nil { 628 return fmt.Errorf("devicemapper: Error running deviceSuspend %s", err) 629 } 630 return nil 631 } 632 633 // ResumeDevice is the programmatic example of "dmsetup resume". 634 // It un-suspends the specified device. 635 func ResumeDevice(name string) error { 636 task, err := TaskCreateNamed(deviceResume, name) 637 if task == nil { 638 return err 639 } 640 641 var cookie uint 642 if err := task.setCookie(&cookie, 0); err != nil { 643 return fmt.Errorf("devicemapper: Can't set cookie %s", err) 644 } 645 defer UdevWait(&cookie) 646 647 if err := task.run(); err != nil { 648 return fmt.Errorf("devicemapper: Error running deviceResume %s", err) 649 } 650 651 return nil 652 } 653 654 // CreateDevice creates a device with the specified poolName with the specified device id. 655 func CreateDevice(poolName string, deviceID int) error { 656 logrus.Debugf("devicemapper: CreateDevice(poolName=%v, deviceID=%v)", poolName, deviceID) 657 task, err := TaskCreateNamed(deviceTargetMsg, poolName) 658 if task == nil { 659 return err 660 } 661 662 if err := task.setSector(0); err != nil { 663 return fmt.Errorf("devicemapper: Can't set sector %s", err) 664 } 665 666 if err := task.setMessage(fmt.Sprintf("create_thin %d", deviceID)); err != nil { 667 return fmt.Errorf("devicemapper: Can't set message %s", err) 668 } 669 670 dmSawExist = false // reset before the task is run 671 if err := task.run(); err != nil { 672 // Caller wants to know about ErrDeviceIDExists so that it can try with a different device id. 673 if dmSawExist { 674 return ErrDeviceIDExists 675 } 676 677 return fmt.Errorf("devicemapper: Error running CreateDevice %s", err) 678 679 } 680 return nil 681 } 682 683 // DeleteDevice deletes a device with the specified poolName with the specified device id. 684 func DeleteDevice(poolName string, deviceID int) error { 685 task, err := TaskCreateNamed(deviceTargetMsg, poolName) 686 if task == nil { 687 return err 688 } 689 690 if err := task.setSector(0); err != nil { 691 return fmt.Errorf("devicemapper: Can't set sector %s", err) 692 } 693 694 if err := task.setMessage(fmt.Sprintf("delete %d", deviceID)); err != nil { 695 return fmt.Errorf("devicemapper: Can't set message %s", err) 696 } 697 698 dmSawBusy = false 699 if err := task.run(); err != nil { 700 if dmSawBusy { 701 return ErrBusy 702 } 703 return fmt.Errorf("devicemapper: Error running DeleteDevice %s", err) 704 } 705 return nil 706 } 707 708 // ActivateDevice activates the device identified by the specified 709 // poolName, name and deviceID with the specified size. 710 func ActivateDevice(poolName string, name string, deviceID int, size uint64) error { 711 return activateDevice(poolName, name, deviceID, size, "") 712 } 713 714 // ActivateDeviceWithExternal activates the device identified by the specified 715 // poolName, name and deviceID with the specified size. 716 func ActivateDeviceWithExternal(poolName string, name string, deviceID int, size uint64, external string) error { 717 return activateDevice(poolName, name, deviceID, size, external) 718 } 719 720 func activateDevice(poolName string, name string, deviceID int, size uint64, external string) error { 721 task, err := TaskCreateNamed(deviceCreate, name) 722 if task == nil { 723 return err 724 } 725 726 var params string 727 if len(external) > 0 { 728 params = fmt.Sprintf("%s %d %s", poolName, deviceID, external) 729 } else { 730 params = fmt.Sprintf("%s %d", poolName, deviceID) 731 } 732 if err := task.addTarget(0, size/512, "thin", params); err != nil { 733 return fmt.Errorf("devicemapper: Can't add target %s", err) 734 } 735 if err := task.setAddNode(addNodeOnCreate); err != nil { 736 return fmt.Errorf("devicemapper: Can't add node %s", err) 737 } 738 739 var cookie uint 740 if err := task.setCookie(&cookie, 0); err != nil { 741 return fmt.Errorf("devicemapper: Can't set cookie %s", err) 742 } 743 744 defer UdevWait(&cookie) 745 746 if err := task.run(); err != nil { 747 return fmt.Errorf("devicemapper: Error running deviceCreate (ActivateDevice) %s", err) 748 } 749 750 return nil 751 } 752 753 // CreateSnapDevice creates a snapshot based on the device identified by the baseName and baseDeviceId, 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("devicemapper: 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("devicemapper: 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("devicemapper: 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 }