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