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