github.com/torfuzx/docker@v1.8.1/pkg/devicemapper/devmapper.go (about) 1 // +build linux 2 3 package devicemapper 4 5 import ( 6 "errors" 7 "fmt" 8 "os" 9 "runtime" 10 "syscall" 11 "unsafe" 12 13 "github.com/Sirupsen/logrus" 14 ) 15 16 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, ¶ms), 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 }