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