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