github.com/stevegt/moby@v1.13.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 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.Debug("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 // set a task cookie and disable library fallback, or else libdevmapper will 362 // disable udev dm rules and delete the symlink under /dev/mapper by itself, 363 // even if the removal is deferred by the kernel. 364 var cookie uint 365 var flags uint16 366 flags = DmUdevDisableLibraryFallback 367 if err := task.setCookie(&cookie, flags); err != nil { 368 return fmt.Errorf("devicemapper: Can not set cookie: %s", err) 369 } 370 371 // libdevmapper and udev relies on System V semaphore for synchronization, 372 // semaphores created in `task.setCookie` will be cleaned up in `UdevWait`. 373 // So these two function call must come in pairs, otherwise semaphores will 374 // be leaked, and the limit of number of semaphores defined in `/proc/sys/kernel/sem` 375 // will be reached, which will eventually make all follwing calls to 'task.SetCookie' 376 // fail. 377 // this call will not wait for the deferred removal's final executing, since no 378 // udev event will be generated, and the semaphore's value will not be incremented 379 // by udev, what UdevWait is just cleaning up the semaphore. 380 defer UdevWait(&cookie) 381 382 if err = task.run(); err != nil { 383 return fmt.Errorf("devicemapper: Error running RemoveDeviceDeferred %s", err) 384 } 385 386 return nil 387 } 388 389 // CancelDeferredRemove cancels a deferred remove for a device. 390 func CancelDeferredRemove(deviceName string) error { 391 task, err := TaskCreateNamed(deviceTargetMsg, deviceName) 392 if task == nil { 393 return err 394 } 395 396 if err := task.setSector(0); err != nil { 397 return fmt.Errorf("devicemapper: Can't set sector %s", err) 398 } 399 400 if err := task.setMessage(fmt.Sprintf("@cancel_deferred_remove")); err != nil { 401 return fmt.Errorf("devicemapper: Can't set message %s", err) 402 } 403 404 dmSawBusy = false 405 dmSawEnxio = false 406 if err := task.run(); err != nil { 407 // A device might be being deleted already 408 if dmSawBusy { 409 return ErrBusy 410 } else if dmSawEnxio { 411 return ErrEnxio 412 } 413 return fmt.Errorf("devicemapper: Error running CancelDeferredRemove %s", err) 414 415 } 416 return nil 417 } 418 419 // GetBlockDeviceSize returns the size of a block device identified by the specified file. 420 func GetBlockDeviceSize(file *os.File) (uint64, error) { 421 size, err := ioctlBlkGetSize64(file.Fd()) 422 if err != nil { 423 logrus.Errorf("devicemapper: Error getblockdevicesize: %s", err) 424 return 0, ErrGetBlockSize 425 } 426 return uint64(size), nil 427 } 428 429 // BlockDeviceDiscard runs discard for the given path. 430 // This is used as a workaround for the kernel not discarding block so 431 // on the thin pool when we remove a thinp device, so we do it 432 // manually 433 func BlockDeviceDiscard(path string) error { 434 file, err := os.OpenFile(path, os.O_RDWR, 0) 435 if err != nil { 436 return err 437 } 438 defer file.Close() 439 440 size, err := GetBlockDeviceSize(file) 441 if err != nil { 442 return err 443 } 444 445 if err := ioctlBlkDiscard(file.Fd(), 0, size); err != nil { 446 return err 447 } 448 449 // Without this sometimes the remove of the device that happens after 450 // discard fails with EBUSY. 451 syscall.Sync() 452 453 return nil 454 } 455 456 // CreatePool is the programmatic example of "dmsetup create". 457 // It creates a device with the specified poolName, data and metadata file and block size. 458 func CreatePool(poolName string, dataFile, metadataFile *os.File, poolBlockSize uint32) error { 459 task, err := TaskCreateNamed(deviceCreate, poolName) 460 if task == nil { 461 return err 462 } 463 464 size, err := GetBlockDeviceSize(dataFile) 465 if err != nil { 466 return fmt.Errorf("devicemapper: Can't get data size %s", err) 467 } 468 469 params := fmt.Sprintf("%s %s %d 32768 1 skip_block_zeroing", metadataFile.Name(), dataFile.Name(), poolBlockSize) 470 if err := task.addTarget(0, size/512, "thin-pool", params); err != nil { 471 return fmt.Errorf("devicemapper: Can't add target %s", err) 472 } 473 474 var cookie uint 475 var flags uint16 476 flags = DmUdevDisableSubsystemRulesFlag | DmUdevDisableDiskRulesFlag | DmUdevDisableOtherRulesFlag 477 if err := task.setCookie(&cookie, flags); err != nil { 478 return fmt.Errorf("devicemapper: Can't set cookie %s", err) 479 } 480 defer UdevWait(&cookie) 481 482 if err := task.run(); err != nil { 483 return fmt.Errorf("devicemapper: Error running deviceCreate (CreatePool) %s", err) 484 } 485 486 return nil 487 } 488 489 // ReloadPool is the programmatic example of "dmsetup reload". 490 // It reloads the table with the specified poolName, data and metadata file and block size. 491 func ReloadPool(poolName string, dataFile, metadataFile *os.File, poolBlockSize uint32) error { 492 task, err := TaskCreateNamed(deviceReload, poolName) 493 if task == nil { 494 return err 495 } 496 497 size, err := GetBlockDeviceSize(dataFile) 498 if err != nil { 499 return fmt.Errorf("devicemapper: Can't get data size %s", err) 500 } 501 502 params := fmt.Sprintf("%s %s %d 32768 1 skip_block_zeroing", metadataFile.Name(), dataFile.Name(), poolBlockSize) 503 if err := task.addTarget(0, size/512, "thin-pool", params); err != nil { 504 return fmt.Errorf("devicemapper: Can't add target %s", err) 505 } 506 507 if err := task.run(); err != nil { 508 return fmt.Errorf("devicemapper: Error running deviceCreate %s", err) 509 } 510 511 return nil 512 } 513 514 // GetDeps is the programmatic example of "dmsetup deps". 515 // It outputs a list of devices referenced by the live table for the specified device. 516 func GetDeps(name string) (*Deps, error) { 517 task, err := TaskCreateNamed(deviceDeps, name) 518 if task == nil { 519 return nil, err 520 } 521 if err := task.run(); err != nil { 522 return nil, err 523 } 524 return task.getDeps() 525 } 526 527 // GetInfo is the programmatic example of "dmsetup info". 528 // It outputs some brief information about the device. 529 func GetInfo(name string) (*Info, error) { 530 task, err := TaskCreateNamed(deviceInfo, name) 531 if task == nil { 532 return nil, err 533 } 534 if err := task.run(); err != nil { 535 return nil, err 536 } 537 return task.getInfo() 538 } 539 540 // GetInfoWithDeferred is the programmatic example of "dmsetup info", but deferred. 541 // It outputs some brief information about the device. 542 func GetInfoWithDeferred(name string) (*Info, error) { 543 task, err := TaskCreateNamed(deviceInfo, name) 544 if task == nil { 545 return nil, err 546 } 547 if err := task.run(); err != nil { 548 return nil, err 549 } 550 return task.getInfoWithDeferred() 551 } 552 553 // GetDriverVersion is the programmatic example of "dmsetup version". 554 // It outputs version information of the driver. 555 func GetDriverVersion() (string, error) { 556 task := TaskCreate(deviceVersion) 557 if task == nil { 558 return "", fmt.Errorf("devicemapper: Can't create deviceVersion task") 559 } 560 if err := task.run(); err != nil { 561 return "", err 562 } 563 return task.getDriverVersion() 564 } 565 566 // GetStatus is the programmatic example of "dmsetup status". 567 // It outputs status information for the specified device name. 568 func GetStatus(name string) (uint64, uint64, string, string, error) { 569 task, err := TaskCreateNamed(deviceStatus, name) 570 if task == nil { 571 logrus.Debugf("devicemapper: GetStatus() Error TaskCreateNamed: %s", err) 572 return 0, 0, "", "", err 573 } 574 if err := task.run(); err != nil { 575 logrus.Debugf("devicemapper: GetStatus() Error Run: %s", err) 576 return 0, 0, "", "", err 577 } 578 579 devinfo, err := task.getInfo() 580 if err != nil { 581 logrus.Debugf("devicemapper: GetStatus() Error GetInfo: %s", err) 582 return 0, 0, "", "", err 583 } 584 if devinfo.Exists == 0 { 585 logrus.Debugf("devicemapper: GetStatus() Non existing device %s", name) 586 return 0, 0, "", "", fmt.Errorf("devicemapper: Non existing device %s", name) 587 } 588 589 _, start, length, targetType, params := task.getNextTarget(unsafe.Pointer(nil)) 590 return start, length, targetType, params, nil 591 } 592 593 // GetTable is the programmatic example for "dmsetup table". 594 // It outputs the current table for the specified device name. 595 func GetTable(name string) (uint64, uint64, string, string, error) { 596 task, err := TaskCreateNamed(deviceTable, name) 597 if task == nil { 598 logrus.Debugf("devicemapper: GetTable() Error TaskCreateNamed: %s", err) 599 return 0, 0, "", "", err 600 } 601 if err := task.run(); err != nil { 602 logrus.Debugf("devicemapper: GetTable() Error Run: %s", err) 603 return 0, 0, "", "", err 604 } 605 606 devinfo, err := task.getInfo() 607 if err != nil { 608 logrus.Debugf("devicemapper: GetTable() Error GetInfo: %s", err) 609 return 0, 0, "", "", err 610 } 611 if devinfo.Exists == 0 { 612 logrus.Debugf("devicemapper: GetTable() Non existing device %s", name) 613 return 0, 0, "", "", fmt.Errorf("devicemapper: Non existing device %s", name) 614 } 615 616 _, start, length, targetType, params := task.getNextTarget(unsafe.Pointer(nil)) 617 return start, length, targetType, params, nil 618 } 619 620 // SetTransactionID sets a transaction id for the specified device name. 621 func SetTransactionID(poolName string, oldID uint64, newID uint64) error { 622 task, err := TaskCreateNamed(deviceTargetMsg, poolName) 623 if task == nil { 624 return err 625 } 626 627 if err := task.setSector(0); err != nil { 628 return fmt.Errorf("devicemapper: Can't set sector %s", err) 629 } 630 631 if err := task.setMessage(fmt.Sprintf("set_transaction_id %d %d", oldID, newID)); err != nil { 632 return fmt.Errorf("devicemapper: Can't set message %s", err) 633 } 634 635 if err := task.run(); err != nil { 636 return fmt.Errorf("devicemapper: Error running SetTransactionID %s", err) 637 } 638 return nil 639 } 640 641 // SuspendDevice is the programmatic example of "dmsetup suspend". 642 // It suspends the specified device. 643 func SuspendDevice(name string) error { 644 task, err := TaskCreateNamed(deviceSuspend, name) 645 if task == nil { 646 return err 647 } 648 if err := task.run(); err != nil { 649 return fmt.Errorf("devicemapper: Error running deviceSuspend %s", err) 650 } 651 return nil 652 } 653 654 // ResumeDevice is the programmatic example of "dmsetup resume". 655 // It un-suspends the specified device. 656 func ResumeDevice(name string) error { 657 task, err := TaskCreateNamed(deviceResume, name) 658 if task == nil { 659 return err 660 } 661 662 var cookie uint 663 if err := task.setCookie(&cookie, 0); err != nil { 664 return fmt.Errorf("devicemapper: Can't set cookie %s", err) 665 } 666 defer UdevWait(&cookie) 667 668 if err := task.run(); err != nil { 669 return fmt.Errorf("devicemapper: Error running deviceResume %s", err) 670 } 671 672 return nil 673 } 674 675 // CreateDevice creates a device with the specified poolName with the specified device id. 676 func CreateDevice(poolName string, deviceID int) error { 677 logrus.Debugf("devicemapper: CreateDevice(poolName=%v, deviceID=%v)", poolName, deviceID) 678 task, err := TaskCreateNamed(deviceTargetMsg, poolName) 679 if task == nil { 680 return err 681 } 682 683 if err := task.setSector(0); err != nil { 684 return fmt.Errorf("devicemapper: Can't set sector %s", err) 685 } 686 687 if err := task.setMessage(fmt.Sprintf("create_thin %d", deviceID)); err != nil { 688 return fmt.Errorf("devicemapper: Can't set message %s", err) 689 } 690 691 dmSawExist = false // reset before the task is run 692 if err := task.run(); err != nil { 693 // Caller wants to know about ErrDeviceIDExists so that it can try with a different device id. 694 if dmSawExist { 695 return ErrDeviceIDExists 696 } 697 698 return fmt.Errorf("devicemapper: Error running CreateDevice %s", err) 699 700 } 701 return nil 702 } 703 704 // DeleteDevice deletes a device with the specified poolName with the specified device id. 705 func DeleteDevice(poolName string, deviceID int) error { 706 task, err := TaskCreateNamed(deviceTargetMsg, poolName) 707 if task == nil { 708 return err 709 } 710 711 if err := task.setSector(0); err != nil { 712 return fmt.Errorf("devicemapper: Can't set sector %s", err) 713 } 714 715 if err := task.setMessage(fmt.Sprintf("delete %d", deviceID)); err != nil { 716 return fmt.Errorf("devicemapper: Can't set message %s", err) 717 } 718 719 dmSawBusy = false 720 if err := task.run(); err != nil { 721 if dmSawBusy { 722 return ErrBusy 723 } 724 return fmt.Errorf("devicemapper: Error running DeleteDevice %s", err) 725 } 726 return nil 727 } 728 729 // ActivateDevice activates the device identified by the specified 730 // poolName, name and deviceID with the specified size. 731 func ActivateDevice(poolName string, name string, deviceID int, size uint64) error { 732 return activateDevice(poolName, name, deviceID, size, "") 733 } 734 735 // ActivateDeviceWithExternal activates the device identified by the specified 736 // poolName, name and deviceID with the specified size. 737 func ActivateDeviceWithExternal(poolName string, name string, deviceID int, size uint64, external string) error { 738 return activateDevice(poolName, name, deviceID, size, external) 739 } 740 741 func activateDevice(poolName string, name string, deviceID int, size uint64, external string) error { 742 task, err := TaskCreateNamed(deviceCreate, name) 743 if task == nil { 744 return err 745 } 746 747 var params string 748 if len(external) > 0 { 749 params = fmt.Sprintf("%s %d %s", poolName, deviceID, external) 750 } else { 751 params = fmt.Sprintf("%s %d", poolName, deviceID) 752 } 753 if err := task.addTarget(0, size/512, "thin", params); err != nil { 754 return fmt.Errorf("devicemapper: Can't add target %s", err) 755 } 756 if err := task.setAddNode(addNodeOnCreate); err != nil { 757 return fmt.Errorf("devicemapper: Can't add node %s", err) 758 } 759 760 var cookie uint 761 if err := task.setCookie(&cookie, 0); err != nil { 762 return fmt.Errorf("devicemapper: Can't set cookie %s", err) 763 } 764 765 defer UdevWait(&cookie) 766 767 if err := task.run(); err != nil { 768 return fmt.Errorf("devicemapper: Error running deviceCreate (ActivateDevice) %s", err) 769 } 770 771 return nil 772 } 773 774 // CreateSnapDeviceRaw creates a snapshot device. Caller needs to suspend and resume the origin device if it is active. 775 func CreateSnapDeviceRaw(poolName string, deviceID int, baseDeviceID int) error { 776 task, err := TaskCreateNamed(deviceTargetMsg, poolName) 777 if task == nil { 778 return err 779 } 780 781 if err := task.setSector(0); err != nil { 782 return fmt.Errorf("devicemapper: Can't set sector %s", err) 783 } 784 785 if err := task.setMessage(fmt.Sprintf("create_snap %d %d", deviceID, baseDeviceID)); err != nil { 786 return fmt.Errorf("devicemapper: Can't set message %s", err) 787 } 788 789 dmSawExist = false // reset before the task is run 790 if err := task.run(); err != nil { 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 return fmt.Errorf("devicemapper: Error running deviceCreate (createSnapDevice) %s", err) 796 } 797 798 return nil 799 } 800 801 // CreateSnapDevice creates a snapshot based on the device identified by the baseName and baseDeviceId, 802 func CreateSnapDevice(poolName string, deviceID int, baseName string, baseDeviceID int) error { 803 devinfo, _ := GetInfo(baseName) 804 doSuspend := devinfo != nil && devinfo.Exists != 0 805 806 if doSuspend { 807 if err := SuspendDevice(baseName); err != nil { 808 return err 809 } 810 } 811 812 if err := CreateSnapDeviceRaw(poolName, deviceID, baseDeviceID); err != nil { 813 if doSuspend { 814 if err2 := ResumeDevice(baseName); err2 != nil { 815 return fmt.Errorf("CreateSnapDeviceRaw Error: (%v): ResumeDevice Error: (%v)", err, err2) 816 } 817 } 818 return err 819 } 820 821 if doSuspend { 822 if err := ResumeDevice(baseName); err != nil { 823 return err 824 } 825 } 826 827 return nil 828 }