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