github.com/guilhermebr/docker@v1.4.2-0.20150428121140-67da055cebca/pkg/devicemapper/devmapper.go (about) 1 // +build linux 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 type DevmapperLogger interface { 17 DMLog(level int, file string, line int, dmError int, message string) 18 } 19 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 var ( 48 ErrTaskRun = errors.New("dm_task_run failed") 49 ErrTaskSetName = errors.New("dm_task_set_name failed") 50 ErrTaskSetMessage = errors.New("dm_task_set_message failed") 51 ErrTaskSetAddNode = errors.New("dm_task_set_add_node failed") 52 ErrTaskSetRo = errors.New("dm_task_set_ro 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 ErrTaskSetCookie = errors.New("dm_task_set_cookie failed") 59 ErrNilCookie = errors.New("cookie ptr can't be nil") 60 ErrAttachLoopbackDevice = errors.New("loopback mounting failed") 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 ErrCreateRemoveTask = errors.New("Can't create task of type DeviceRemove") 66 ErrRunRemoveDevice = errors.New("running RemoveDevice failed") 67 ErrInvalidAddNode = errors.New("Invalid AddNode type") 68 ErrGetLoopbackBackingFile = errors.New("Unable to get loopback backing file") 69 ErrLoopbackSetCapacity = errors.New("Unable set loopback capacity") 70 ErrBusy = errors.New("Device is Busy") 71 ErrDeviceIdExists = errors.New("Device Id Exists") 72 73 dmSawBusy bool 74 dmSawExist bool 75 ) 76 77 type ( 78 Task struct { 79 unmanaged *CDmTask 80 } 81 Deps struct { 82 Count uint32 83 Filler uint32 84 Device []uint64 85 } 86 Info struct { 87 Exists int 88 Suspended int 89 LiveTable int 90 InactiveTable int 91 OpenCount int32 92 EventNr uint32 93 Major uint32 94 Minor uint32 95 ReadOnly int 96 TargetCount int32 97 } 98 TaskType int 99 AddNodeType int 100 ) 101 102 // Returns whether error conveys the information about device Id already 103 // exist or not. This will be true if device creation or snap creation 104 // operation fails if device or snap device already exists in pool. 105 // Current implementation is little crude as it scans the error string 106 // for exact pattern match. Replacing it with more robust implementation 107 // is desirable. 108 func DeviceIdExists(err error) bool { 109 return fmt.Sprint(err) == fmt.Sprint(ErrDeviceIdExists) 110 } 111 112 func (t *Task) destroy() { 113 if t != nil { 114 DmTaskDestroy(t.unmanaged) 115 runtime.SetFinalizer(t, nil) 116 } 117 } 118 119 // TaskCreateNamed is a convenience function for TaskCreate when a name 120 // will be set on the task as well 121 func TaskCreateNamed(t TaskType, name string) (*Task, error) { 122 task := TaskCreate(t) 123 if task == nil { 124 return nil, fmt.Errorf("Can't create task of type %d", int(t)) 125 } 126 if err := task.SetName(name); err != nil { 127 return nil, fmt.Errorf("Can't set task name %s", name) 128 } 129 return task, nil 130 } 131 132 // TaskCreate initializes a devicemapper task of tasktype 133 func TaskCreate(tasktype TaskType) *Task { 134 Ctask := DmTaskCreate(int(tasktype)) 135 if Ctask == nil { 136 return nil 137 } 138 task := &Task{unmanaged: Ctask} 139 runtime.SetFinalizer(task, (*Task).destroy) 140 return task 141 } 142 143 func (t *Task) Run() error { 144 if res := DmTaskRun(t.unmanaged); res != 1 { 145 return ErrTaskRun 146 } 147 return nil 148 } 149 150 func (t *Task) SetName(name string) error { 151 if res := DmTaskSetName(t.unmanaged, name); res != 1 { 152 return ErrTaskSetName 153 } 154 return nil 155 } 156 157 func (t *Task) SetMessage(message string) error { 158 if res := DmTaskSetMessage(t.unmanaged, message); res != 1 { 159 return ErrTaskSetMessage 160 } 161 return nil 162 } 163 164 func (t *Task) SetSector(sector uint64) error { 165 if res := DmTaskSetSector(t.unmanaged, sector); res != 1 { 166 return ErrTaskSetSector 167 } 168 return nil 169 } 170 171 func (t *Task) SetCookie(cookie *uint, flags uint16) error { 172 if cookie == nil { 173 return ErrNilCookie 174 } 175 if res := DmTaskSetCookie(t.unmanaged, cookie, flags); res != 1 { 176 return ErrTaskSetCookie 177 } 178 return nil 179 } 180 181 func (t *Task) SetAddNode(addNode AddNodeType) error { 182 if addNode != AddNodeOnResume && addNode != AddNodeOnCreate { 183 return ErrInvalidAddNode 184 } 185 if res := DmTaskSetAddNode(t.unmanaged, addNode); res != 1 { 186 return ErrTaskSetAddNode 187 } 188 return nil 189 } 190 191 func (t *Task) SetRo() error { 192 if res := DmTaskSetRo(t.unmanaged); res != 1 { 193 return ErrTaskSetRo 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) GetDriverVersion() (string, error) { 223 res := DmTaskGetDriverVersion(t.unmanaged) 224 if res == "" { 225 return "", ErrTaskGetDriverVersion 226 } 227 return res, nil 228 } 229 230 func (t *Task) GetNextTarget(next unsafe.Pointer) (nextPtr unsafe.Pointer, start uint64, 231 length uint64, targetType string, params string) { 232 233 return DmGetNextTarget(t.unmanaged, next, &start, &length, 234 &targetType, ¶ms), 235 start, length, targetType, params 236 } 237 238 func getLoopbackBackingFile(file *os.File) (uint64, uint64, error) { 239 loopInfo, err := ioctlLoopGetStatus64(file.Fd()) 240 if err != nil { 241 logrus.Errorf("Error get loopback backing file: %s", err) 242 return 0, 0, ErrGetLoopbackBackingFile 243 } 244 return loopInfo.loDevice, loopInfo.loInode, nil 245 } 246 247 func LoopbackSetCapacity(file *os.File) error { 248 if err := ioctlLoopSetCapacity(file.Fd(), 0); err != nil { 249 logrus.Errorf("Error loopbackSetCapacity: %s", err) 250 return ErrLoopbackSetCapacity 251 } 252 return nil 253 } 254 255 func FindLoopDeviceFor(file *os.File) *os.File { 256 stat, err := file.Stat() 257 if err != nil { 258 return nil 259 } 260 targetInode := stat.Sys().(*syscall.Stat_t).Ino 261 targetDevice := stat.Sys().(*syscall.Stat_t).Dev 262 263 for i := 0; true; i++ { 264 path := fmt.Sprintf("/dev/loop%d", i) 265 266 file, err := os.OpenFile(path, os.O_RDWR, 0) 267 if err != nil { 268 if os.IsNotExist(err) { 269 return nil 270 } 271 272 // Ignore all errors until the first not-exist 273 // we want to continue looking for the file 274 continue 275 } 276 277 dev, inode, err := getLoopbackBackingFile(file) 278 if err == nil && dev == targetDevice && inode == targetInode { 279 return file 280 } 281 file.Close() 282 } 283 284 return nil 285 } 286 287 func UdevWait(cookie *uint) error { 288 if res := DmUdevWait(*cookie); res != 1 { 289 logrus.Debugf("Failed to wait on udev cookie %d", *cookie) 290 return ErrUdevWait 291 } 292 return nil 293 } 294 295 func LogInitVerbose(level int) { 296 DmLogInitVerbose(level) 297 } 298 299 var dmLogger DevmapperLogger = nil 300 301 // initialize the logger for the device mapper library 302 func LogInit(logger DevmapperLogger) { 303 dmLogger = logger 304 LogWithErrnoInit() 305 } 306 307 func SetDevDir(dir string) error { 308 if res := DmSetDevDir(dir); res != 1 { 309 logrus.Debugf("Error dm_set_dev_dir") 310 return ErrSetDevDir 311 } 312 return nil 313 } 314 315 func GetLibraryVersion() (string, error) { 316 var version string 317 if res := DmGetLibraryVersion(&version); res != 1 { 318 return "", ErrGetLibraryVersion 319 } 320 return version, nil 321 } 322 323 // UdevSyncSupported returns whether device-mapper is able to sync with udev 324 // 325 // This is essential otherwise race conditions can arise where both udev and 326 // device-mapper attempt to create and destroy devices. 327 func UdevSyncSupported() bool { 328 return DmUdevGetSyncSupport() != 0 329 } 330 331 // UdevSetSyncSupport allows setting whether the udev sync should be enabled. 332 // The return bool indicates the state of whether the sync is enabled. 333 func UdevSetSyncSupport(enable bool) bool { 334 if enable { 335 DmUdevSetSyncSupport(1) 336 } else { 337 DmUdevSetSyncSupport(0) 338 } 339 340 return UdevSyncSupported() 341 } 342 343 // CookieSupported returns whether the version of device-mapper supports the 344 // use of cookie's in the tasks. 345 // This is largely a lower level call that other functions use. 346 func CookieSupported() bool { 347 return DmCookieSupported() != 0 348 } 349 350 // Useful helper for cleanup 351 func RemoveDevice(name string) error { 352 task, err := TaskCreateNamed(DeviceRemove, name) 353 if task == nil { 354 return err 355 } 356 357 var cookie uint = 0 358 if err := task.SetCookie(&cookie, 0); err != nil { 359 return fmt.Errorf("Can not set cookie: %s", err) 360 } 361 defer UdevWait(&cookie) 362 363 dmSawBusy = false // reset before the task is run 364 if err = task.Run(); err != nil { 365 if dmSawBusy { 366 return ErrBusy 367 } 368 return fmt.Errorf("Error running RemoveDevice %s", err) 369 } 370 371 return nil 372 } 373 374 func GetBlockDeviceSize(file *os.File) (uint64, error) { 375 size, err := ioctlBlkGetSize64(file.Fd()) 376 if err != nil { 377 logrus.Errorf("Error getblockdevicesize: %s", err) 378 return 0, ErrGetBlockSize 379 } 380 return uint64(size), nil 381 } 382 383 func BlockDeviceDiscard(path string) error { 384 file, err := os.OpenFile(path, os.O_RDWR, 0) 385 if err != nil { 386 return err 387 } 388 defer file.Close() 389 390 size, err := GetBlockDeviceSize(file) 391 if err != nil { 392 return err 393 } 394 395 if err := ioctlBlkDiscard(file.Fd(), 0, size); err != nil { 396 return err 397 } 398 399 // Without this sometimes the remove of the device that happens after 400 // discard fails with EBUSY. 401 syscall.Sync() 402 403 return nil 404 } 405 406 // This is the programmatic example of "dmsetup create" 407 func CreatePool(poolName string, dataFile, metadataFile *os.File, poolBlockSize uint32) error { 408 task, err := TaskCreateNamed(DeviceCreate, poolName) 409 if task == nil { 410 return err 411 } 412 413 size, err := GetBlockDeviceSize(dataFile) 414 if err != nil { 415 return fmt.Errorf("Can't get data size %s", err) 416 } 417 418 params := fmt.Sprintf("%s %s %d 32768 1 skip_block_zeroing", metadataFile.Name(), dataFile.Name(), poolBlockSize) 419 if err := task.AddTarget(0, size/512, "thin-pool", params); err != nil { 420 return fmt.Errorf("Can't add target %s", err) 421 } 422 423 var cookie uint = 0 424 var flags uint16 = DmUdevDisableSubsystemRulesFlag | DmUdevDisableDiskRulesFlag | DmUdevDisableOtherRulesFlag 425 if err := task.SetCookie(&cookie, flags); err != nil { 426 return fmt.Errorf("Can't set cookie %s", err) 427 } 428 defer UdevWait(&cookie) 429 430 if err := task.Run(); err != nil { 431 return fmt.Errorf("Error running DeviceCreate (CreatePool) %s", err) 432 } 433 434 return nil 435 } 436 437 func ReloadPool(poolName string, dataFile, metadataFile *os.File, poolBlockSize uint32) error { 438 task, err := TaskCreateNamed(DeviceReload, poolName) 439 if task == nil { 440 return err 441 } 442 443 size, err := GetBlockDeviceSize(dataFile) 444 if err != nil { 445 return fmt.Errorf("Can't get data size %s", err) 446 } 447 448 params := fmt.Sprintf("%s %s %d 32768 1 skip_block_zeroing", metadataFile.Name(), dataFile.Name(), poolBlockSize) 449 if err := task.AddTarget(0, size/512, "thin-pool", params); err != nil { 450 return fmt.Errorf("Can't add target %s", err) 451 } 452 453 if err := task.Run(); err != nil { 454 return fmt.Errorf("Error running DeviceCreate %s", err) 455 } 456 457 return nil 458 } 459 460 func GetDeps(name string) (*Deps, error) { 461 task, err := TaskCreateNamed(DeviceDeps, name) 462 if task == nil { 463 return nil, err 464 } 465 if err := task.Run(); err != nil { 466 return nil, err 467 } 468 return task.GetDeps() 469 } 470 471 func GetInfo(name string) (*Info, error) { 472 task, err := TaskCreateNamed(DeviceInfo, name) 473 if task == nil { 474 return nil, err 475 } 476 if err := task.Run(); err != nil { 477 return nil, err 478 } 479 return task.GetInfo() 480 } 481 482 func GetDriverVersion() (string, error) { 483 task := TaskCreate(DeviceVersion) 484 if task == nil { 485 return "", fmt.Errorf("Can't create DeviceVersion task") 486 } 487 if err := task.Run(); err != nil { 488 return "", err 489 } 490 return task.GetDriverVersion() 491 } 492 493 func GetStatus(name string) (uint64, uint64, string, string, error) { 494 task, err := TaskCreateNamed(DeviceStatus, name) 495 if task == nil { 496 logrus.Debugf("GetStatus: Error TaskCreateNamed: %s", err) 497 return 0, 0, "", "", err 498 } 499 if err := task.Run(); err != nil { 500 logrus.Debugf("GetStatus: Error Run: %s", err) 501 return 0, 0, "", "", err 502 } 503 504 devinfo, err := task.GetInfo() 505 if err != nil { 506 logrus.Debugf("GetStatus: Error GetInfo: %s", err) 507 return 0, 0, "", "", err 508 } 509 if devinfo.Exists == 0 { 510 logrus.Debugf("GetStatus: Non existing device %s", name) 511 return 0, 0, "", "", fmt.Errorf("Non existing device %s", name) 512 } 513 514 _, start, length, targetType, params := task.GetNextTarget(unsafe.Pointer(nil)) 515 return start, length, targetType, params, nil 516 } 517 518 func SetTransactionId(poolName string, oldId uint64, newId uint64) error { 519 task, err := TaskCreateNamed(DeviceTargetMsg, poolName) 520 if task == nil { 521 return err 522 } 523 524 if err := task.SetSector(0); err != nil { 525 return fmt.Errorf("Can't set sector %s", err) 526 } 527 528 if err := task.SetMessage(fmt.Sprintf("set_transaction_id %d %d", oldId, newId)); err != nil { 529 return fmt.Errorf("Can't set message %s", err) 530 } 531 532 if err := task.Run(); err != nil { 533 return fmt.Errorf("Error running SetTransactionId %s", err) 534 } 535 return nil 536 } 537 538 func SuspendDevice(name string) error { 539 task, err := TaskCreateNamed(DeviceSuspend, name) 540 if task == nil { 541 return err 542 } 543 if err := task.Run(); err != nil { 544 return fmt.Errorf("Error running DeviceSuspend %s", err) 545 } 546 return nil 547 } 548 549 func ResumeDevice(name string) error { 550 task, err := TaskCreateNamed(DeviceResume, name) 551 if task == nil { 552 return err 553 } 554 555 var cookie uint = 0 556 if err := task.SetCookie(&cookie, 0); err != nil { 557 return fmt.Errorf("Can't set cookie %s", err) 558 } 559 defer UdevWait(&cookie) 560 561 if err := task.Run(); err != nil { 562 return fmt.Errorf("Error running DeviceResume %s", err) 563 } 564 565 return nil 566 } 567 568 func CreateDevice(poolName string, deviceId int) error { 569 logrus.Debugf("[devmapper] CreateDevice(poolName=%v, deviceId=%v)", poolName, deviceId) 570 task, err := TaskCreateNamed(DeviceTargetMsg, poolName) 571 if task == nil { 572 return err 573 } 574 575 if err := task.SetSector(0); err != nil { 576 return fmt.Errorf("Can't set sector %s", err) 577 } 578 579 if err := task.SetMessage(fmt.Sprintf("create_thin %d", deviceId)); err != nil { 580 return fmt.Errorf("Can't set message %s", err) 581 } 582 583 dmSawExist = false // reset before the task is run 584 if err := task.Run(); err != nil { 585 // Caller wants to know about ErrDeviceIdExists so that it can try with a different device id. 586 if dmSawExist { 587 return ErrDeviceIdExists 588 } 589 590 return fmt.Errorf("Error running CreateDevice %s", err) 591 592 } 593 return nil 594 } 595 596 func DeleteDevice(poolName string, deviceId int) error { 597 task, err := TaskCreateNamed(DeviceTargetMsg, poolName) 598 if task == nil { 599 return err 600 } 601 602 if err := task.SetSector(0); err != nil { 603 return fmt.Errorf("Can't set sector %s", err) 604 } 605 606 if err := task.SetMessage(fmt.Sprintf("delete %d", deviceId)); err != nil { 607 return fmt.Errorf("Can't set message %s", err) 608 } 609 610 if err := task.Run(); err != nil { 611 return fmt.Errorf("Error running DeleteDevice %s", err) 612 } 613 return nil 614 } 615 616 func ActivateDevice(poolName string, name string, deviceId int, size uint64) error { 617 task, err := TaskCreateNamed(DeviceCreate, name) 618 if task == nil { 619 return err 620 } 621 622 params := fmt.Sprintf("%s %d", poolName, deviceId) 623 if err := task.AddTarget(0, size/512, "thin", params); err != nil { 624 return fmt.Errorf("Can't add target %s", err) 625 } 626 if err := task.SetAddNode(AddNodeOnCreate); err != nil { 627 return fmt.Errorf("Can't add node %s", err) 628 } 629 630 var cookie uint = 0 631 if err := task.SetCookie(&cookie, 0); err != nil { 632 return fmt.Errorf("Can't set cookie %s", err) 633 } 634 635 defer UdevWait(&cookie) 636 637 if err := task.Run(); err != nil { 638 return fmt.Errorf("Error running DeviceCreate (ActivateDevice) %s", err) 639 } 640 641 return nil 642 } 643 644 func CreateSnapDevice(poolName string, deviceId int, baseName string, baseDeviceId int) error { 645 devinfo, _ := GetInfo(baseName) 646 doSuspend := devinfo != nil && devinfo.Exists != 0 647 648 if doSuspend { 649 if err := SuspendDevice(baseName); err != nil { 650 return err 651 } 652 } 653 654 task, err := TaskCreateNamed(DeviceTargetMsg, poolName) 655 if task == nil { 656 if doSuspend { 657 ResumeDevice(baseName) 658 } 659 return err 660 } 661 662 if err := task.SetSector(0); err != nil { 663 if doSuspend { 664 ResumeDevice(baseName) 665 } 666 return fmt.Errorf("Can't set sector %s", err) 667 } 668 669 if err := task.SetMessage(fmt.Sprintf("create_snap %d %d", deviceId, baseDeviceId)); err != nil { 670 if doSuspend { 671 ResumeDevice(baseName) 672 } 673 return fmt.Errorf("Can't set message %s", err) 674 } 675 676 dmSawExist = false // reset before the task is run 677 if err := task.Run(); err != nil { 678 if doSuspend { 679 ResumeDevice(baseName) 680 } 681 // Caller wants to know about ErrDeviceIdExists so that it can try with a different device id. 682 if dmSawExist { 683 return ErrDeviceIdExists 684 } 685 686 return fmt.Errorf("Error running DeviceCreate (createSnapDevice) %s", err) 687 688 } 689 690 if doSuspend { 691 if err := ResumeDevice(baseName); err != nil { 692 return err 693 } 694 } 695 696 return nil 697 }