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