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