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