github.com/titanous/docker@v1.4.1/daemon/graphdriver/devmapper/deviceset.go (about) 1 // +build linux 2 3 package devmapper 4 5 import ( 6 "encoding/json" 7 "errors" 8 "fmt" 9 "io" 10 "io/ioutil" 11 "os" 12 "os/exec" 13 "path" 14 "path/filepath" 15 "strconv" 16 "strings" 17 "sync" 18 "syscall" 19 "time" 20 21 log "github.com/Sirupsen/logrus" 22 "github.com/docker/docker/daemon/graphdriver" 23 "github.com/docker/docker/pkg/devicemapper" 24 "github.com/docker/docker/pkg/parsers" 25 "github.com/docker/docker/pkg/units" 26 "github.com/docker/libcontainer/label" 27 ) 28 29 var ( 30 DefaultDataLoopbackSize int64 = 100 * 1024 * 1024 * 1024 31 DefaultMetaDataLoopbackSize int64 = 2 * 1024 * 1024 * 1024 32 DefaultBaseFsSize uint64 = 10 * 1024 * 1024 * 1024 33 DefaultThinpBlockSize uint32 = 128 // 64K = 128 512b sectors 34 MaxDeviceId int = 0xffffff // 24 bit, pool limit 35 DeviceIdMapSz int = (MaxDeviceId + 1) / 8 36 ) 37 38 const deviceSetMetaFile string = "deviceset-metadata" 39 const transactionMetaFile string = "transaction-metadata" 40 41 type Transaction struct { 42 OpenTransactionId uint64 `json:"open_transaction_id"` 43 DeviceIdHash string `json:"device_hash"` 44 DeviceId int `json:"device_id"` 45 } 46 47 type DevInfo struct { 48 Hash string `json:"-"` 49 DeviceId int `json:"device_id"` 50 Size uint64 `json:"size"` 51 TransactionId uint64 `json:"transaction_id"` 52 Initialized bool `json:"initialized"` 53 devices *DeviceSet `json:"-"` 54 55 mountCount int `json:"-"` 56 mountPath string `json:"-"` 57 58 // The global DeviceSet lock guarantees that we serialize all 59 // the calls to libdevmapper (which is not threadsafe), but we 60 // sometimes release that lock while sleeping. In that case 61 // this per-device lock is still held, protecting against 62 // other accesses to the device that we're doing the wait on. 63 // 64 // WARNING: In order to avoid AB-BA deadlocks when releasing 65 // the global lock while holding the per-device locks all 66 // device locks must be aquired *before* the device lock, and 67 // multiple device locks should be aquired parent before child. 68 lock sync.Mutex `json:"-"` 69 } 70 71 type MetaData struct { 72 Devices map[string]*DevInfo `json:"Devices"` 73 devicesLock sync.Mutex `json:"-"` // Protects all read/writes to Devices map 74 } 75 76 type DeviceSet struct { 77 MetaData `json:"-"` 78 sync.Mutex `json:"-"` // Protects Devices map and serializes calls into libdevmapper 79 root string 80 devicePrefix string 81 TransactionId uint64 `json:"-"` 82 NextDeviceId int `json:"next_device_id"` 83 deviceIdMap []byte 84 85 // Options 86 dataLoopbackSize int64 87 metaDataLoopbackSize int64 88 baseFsSize uint64 89 filesystem string 90 mountOptions string 91 mkfsArgs []string 92 dataDevice string 93 metadataDevice string 94 doBlkDiscard bool 95 thinpBlockSize uint32 96 thinPoolDevice string 97 Transaction `json:"-"` 98 } 99 100 type DiskUsage struct { 101 Used uint64 102 Total uint64 103 } 104 105 type Status struct { 106 PoolName string 107 DataLoopback string 108 MetadataLoopback string 109 Data DiskUsage 110 Metadata DiskUsage 111 SectorSize uint64 112 } 113 114 type DevStatus struct { 115 DeviceId int 116 Size uint64 117 TransactionId uint64 118 SizeInSectors uint64 119 MappedSectors uint64 120 HighestMappedSector uint64 121 } 122 123 func getDevName(name string) string { 124 return "/dev/mapper/" + name 125 } 126 127 func (info *DevInfo) Name() string { 128 hash := info.Hash 129 if hash == "" { 130 hash = "base" 131 } 132 return fmt.Sprintf("%s-%s", info.devices.devicePrefix, hash) 133 } 134 135 func (info *DevInfo) DevName() string { 136 return getDevName(info.Name()) 137 } 138 139 func (devices *DeviceSet) loopbackDir() string { 140 return path.Join(devices.root, "devicemapper") 141 } 142 143 func (devices *DeviceSet) metadataDir() string { 144 return path.Join(devices.root, "metadata") 145 } 146 147 func (devices *DeviceSet) metadataFile(info *DevInfo) string { 148 file := info.Hash 149 if file == "" { 150 file = "base" 151 } 152 return path.Join(devices.metadataDir(), file) 153 } 154 155 func (devices *DeviceSet) transactionMetaFile() string { 156 return path.Join(devices.metadataDir(), transactionMetaFile) 157 } 158 159 func (devices *DeviceSet) deviceSetMetaFile() string { 160 return path.Join(devices.metadataDir(), deviceSetMetaFile) 161 } 162 163 func (devices *DeviceSet) oldMetadataFile() string { 164 return path.Join(devices.loopbackDir(), "json") 165 } 166 167 func (devices *DeviceSet) getPoolName() string { 168 if devices.thinPoolDevice == "" { 169 return devices.devicePrefix + "-pool" 170 } 171 return devices.thinPoolDevice 172 } 173 174 func (devices *DeviceSet) getPoolDevName() string { 175 return getDevName(devices.getPoolName()) 176 } 177 178 func (devices *DeviceSet) hasImage(name string) bool { 179 dirname := devices.loopbackDir() 180 filename := path.Join(dirname, name) 181 182 _, err := os.Stat(filename) 183 return err == nil 184 } 185 186 // ensureImage creates a sparse file of <size> bytes at the path 187 // <root>/devicemapper/<name>. 188 // If the file already exists, it does nothing. 189 // Either way it returns the full path. 190 func (devices *DeviceSet) ensureImage(name string, size int64) (string, error) { 191 dirname := devices.loopbackDir() 192 filename := path.Join(dirname, name) 193 194 if err := os.MkdirAll(dirname, 0700); err != nil && !os.IsExist(err) { 195 return "", err 196 } 197 198 if _, err := os.Stat(filename); err != nil { 199 if !os.IsNotExist(err) { 200 return "", err 201 } 202 log.Debugf("Creating loopback file %s for device-manage use", filename) 203 file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0600) 204 if err != nil { 205 return "", err 206 } 207 defer file.Close() 208 209 if err = file.Truncate(size); err != nil { 210 return "", err 211 } 212 } 213 return filename, nil 214 } 215 216 func (devices *DeviceSet) allocateTransactionId() uint64 { 217 devices.OpenTransactionId = devices.TransactionId + 1 218 return devices.OpenTransactionId 219 } 220 221 func (devices *DeviceSet) updatePoolTransactionId() error { 222 if err := devicemapper.SetTransactionId(devices.getPoolDevName(), devices.TransactionId, devices.OpenTransactionId); err != nil { 223 return fmt.Errorf("Error setting devmapper transaction ID: %s", err) 224 } 225 devices.TransactionId = devices.OpenTransactionId 226 return nil 227 } 228 229 func (devices *DeviceSet) removeMetadata(info *DevInfo) error { 230 if err := os.RemoveAll(devices.metadataFile(info)); err != nil { 231 return fmt.Errorf("Error removing metadata file %s: %s", devices.metadataFile(info), err) 232 } 233 return nil 234 } 235 236 // Given json data and file path, write it to disk 237 func (devices *DeviceSet) writeMetaFile(jsonData []byte, filePath string) error { 238 tmpFile, err := ioutil.TempFile(devices.metadataDir(), ".tmp") 239 if err != nil { 240 return fmt.Errorf("Error creating metadata file: %s", err) 241 } 242 243 n, err := tmpFile.Write(jsonData) 244 if err != nil { 245 return fmt.Errorf("Error writing metadata to %s: %s", tmpFile.Name(), err) 246 } 247 if n < len(jsonData) { 248 return io.ErrShortWrite 249 } 250 if err := tmpFile.Sync(); err != nil { 251 return fmt.Errorf("Error syncing metadata file %s: %s", tmpFile.Name(), err) 252 } 253 if err := tmpFile.Close(); err != nil { 254 return fmt.Errorf("Error closing metadata file %s: %s", tmpFile.Name(), err) 255 } 256 if err := os.Rename(tmpFile.Name(), filePath); err != nil { 257 return fmt.Errorf("Error committing metadata file %s: %s", tmpFile.Name(), err) 258 } 259 260 return nil 261 } 262 263 func (devices *DeviceSet) saveMetadata(info *DevInfo) error { 264 jsonData, err := json.Marshal(info) 265 if err != nil { 266 return fmt.Errorf("Error encoding metadata to json: %s", err) 267 } 268 if err := devices.writeMetaFile(jsonData, devices.metadataFile(info)); err != nil { 269 return err 270 } 271 return nil 272 } 273 274 func (devices *DeviceSet) markDeviceIdUsed(deviceId int) { 275 var mask byte 276 i := deviceId % 8 277 mask = 1 << uint(i) 278 devices.deviceIdMap[deviceId/8] = devices.deviceIdMap[deviceId/8] | mask 279 } 280 281 func (devices *DeviceSet) markDeviceIdFree(deviceId int) { 282 var mask byte 283 i := deviceId % 8 284 mask = ^(1 << uint(i)) 285 devices.deviceIdMap[deviceId/8] = devices.deviceIdMap[deviceId/8] & mask 286 } 287 288 func (devices *DeviceSet) isDeviceIdFree(deviceId int) bool { 289 var mask byte 290 i := deviceId % 8 291 mask = (1 << uint(i)) 292 if (devices.deviceIdMap[deviceId/8] & mask) != 0 { 293 return false 294 } 295 return true 296 } 297 298 func (devices *DeviceSet) lookupDevice(hash string) (*DevInfo, error) { 299 devices.devicesLock.Lock() 300 defer devices.devicesLock.Unlock() 301 info := devices.Devices[hash] 302 if info == nil { 303 info = devices.loadMetadata(hash) 304 if info == nil { 305 return nil, fmt.Errorf("Unknown device %s", hash) 306 } 307 308 devices.Devices[hash] = info 309 } 310 return info, nil 311 } 312 313 func (devices *DeviceSet) deviceFileWalkFunction(path string, finfo os.FileInfo) error { 314 315 // Skip some of the meta files which are not device files. 316 if strings.HasSuffix(finfo.Name(), ".migrated") { 317 log.Debugf("Skipping file %s", path) 318 return nil 319 } 320 321 if finfo.Name() == deviceSetMetaFile { 322 log.Debugf("Skipping file %s", path) 323 return nil 324 } 325 326 log.Debugf("Loading data for file %s", path) 327 328 hash := finfo.Name() 329 if hash == "base" { 330 hash = "" 331 } 332 333 dinfo := devices.loadMetadata(hash) 334 if dinfo == nil { 335 return fmt.Errorf("Error loading device metadata file %s", hash) 336 } 337 338 if dinfo.DeviceId > MaxDeviceId { 339 log.Errorf("Warning: Ignoring Invalid DeviceId=%d", dinfo.DeviceId) 340 return nil 341 } 342 343 devices.Lock() 344 devices.markDeviceIdUsed(dinfo.DeviceId) 345 devices.Unlock() 346 347 log.Debugf("Added deviceId=%d to DeviceIdMap", dinfo.DeviceId) 348 return nil 349 } 350 351 func (devices *DeviceSet) constructDeviceIdMap() error { 352 log.Debugf("[deviceset] constructDeviceIdMap()") 353 defer log.Debugf("[deviceset] constructDeviceIdMap() END") 354 355 var scan = func(path string, info os.FileInfo, err error) error { 356 if err != nil { 357 log.Debugf("Can't walk the file %s", path) 358 return nil 359 } 360 361 // Skip any directories 362 if info.IsDir() { 363 return nil 364 } 365 366 return devices.deviceFileWalkFunction(path, info) 367 } 368 369 return filepath.Walk(devices.metadataDir(), scan) 370 } 371 372 func (devices *DeviceSet) unregisterDevice(id int, hash string) error { 373 log.Debugf("unregisterDevice(%v, %v)", id, hash) 374 info := &DevInfo{ 375 Hash: hash, 376 DeviceId: id, 377 } 378 379 devices.devicesLock.Lock() 380 delete(devices.Devices, hash) 381 devices.devicesLock.Unlock() 382 383 if err := devices.removeMetadata(info); err != nil { 384 log.Debugf("Error removing meta data: %s", err) 385 return err 386 } 387 388 return nil 389 } 390 391 func (devices *DeviceSet) registerDevice(id int, hash string, size uint64, transactionId uint64) (*DevInfo, error) { 392 log.Debugf("registerDevice(%v, %v)", id, hash) 393 info := &DevInfo{ 394 Hash: hash, 395 DeviceId: id, 396 Size: size, 397 TransactionId: transactionId, 398 Initialized: false, 399 devices: devices, 400 } 401 402 devices.devicesLock.Lock() 403 devices.Devices[hash] = info 404 devices.devicesLock.Unlock() 405 406 if err := devices.saveMetadata(info); err != nil { 407 // Try to remove unused device 408 devices.devicesLock.Lock() 409 delete(devices.Devices, hash) 410 devices.devicesLock.Unlock() 411 return nil, err 412 } 413 414 return info, nil 415 } 416 417 func (devices *DeviceSet) activateDeviceIfNeeded(info *DevInfo) error { 418 log.Debugf("activateDeviceIfNeeded(%v)", info.Hash) 419 420 if devinfo, _ := devicemapper.GetInfo(info.Name()); devinfo != nil && devinfo.Exists != 0 { 421 return nil 422 } 423 424 return devicemapper.ActivateDevice(devices.getPoolDevName(), info.Name(), info.DeviceId, info.Size) 425 } 426 427 func (devices *DeviceSet) createFilesystem(info *DevInfo) error { 428 devname := info.DevName() 429 430 args := []string{} 431 for _, arg := range devices.mkfsArgs { 432 args = append(args, arg) 433 } 434 435 args = append(args, devname) 436 437 var err error 438 switch devices.filesystem { 439 case "xfs": 440 err = exec.Command("mkfs.xfs", args...).Run() 441 case "ext4": 442 err = exec.Command("mkfs.ext4", append([]string{"-E", "nodiscard,lazy_itable_init=0,lazy_journal_init=0"}, args...)...).Run() 443 if err != nil { 444 err = exec.Command("mkfs.ext4", append([]string{"-E", "nodiscard,lazy_itable_init=0"}, args...)...).Run() 445 } 446 if err != nil { 447 return err 448 } 449 err = exec.Command("tune2fs", append([]string{"-c", "-1", "-i", "0"}, devname)...).Run() 450 default: 451 err = fmt.Errorf("Unsupported filesystem type %s", devices.filesystem) 452 } 453 if err != nil { 454 return err 455 } 456 457 return nil 458 } 459 460 func (devices *DeviceSet) migrateOldMetaData() error { 461 // Migrate old metadatafile 462 jsonData, err := ioutil.ReadFile(devices.oldMetadataFile()) 463 if err != nil && !os.IsNotExist(err) { 464 return err 465 } 466 467 if jsonData != nil { 468 m := MetaData{Devices: make(map[string]*DevInfo)} 469 470 if err := json.Unmarshal(jsonData, &m); err != nil { 471 return err 472 } 473 474 for hash, info := range m.Devices { 475 info.Hash = hash 476 devices.saveMetadata(info) 477 } 478 if err := os.Rename(devices.oldMetadataFile(), devices.oldMetadataFile()+".migrated"); err != nil { 479 return err 480 } 481 482 } 483 484 return nil 485 } 486 487 func (devices *DeviceSet) initMetaData() error { 488 if err := devices.migrateOldMetaData(); err != nil { 489 return err 490 } 491 492 _, transactionId, _, _, _, _, err := devices.poolStatus() 493 if err != nil { 494 return err 495 } 496 497 devices.TransactionId = transactionId 498 499 if err := devices.constructDeviceIdMap(); err != nil { 500 return err 501 } 502 503 if err := devices.processPendingTransaction(); err != nil { 504 return err 505 } 506 return nil 507 } 508 509 func (devices *DeviceSet) incNextDeviceId() { 510 // Ids are 24bit, so wrap around 511 devices.NextDeviceId = (devices.NextDeviceId + 1) & MaxDeviceId 512 } 513 514 func (devices *DeviceSet) getNextFreeDeviceId() (int, error) { 515 devices.incNextDeviceId() 516 for i := 0; i <= MaxDeviceId; i++ { 517 if devices.isDeviceIdFree(devices.NextDeviceId) { 518 devices.markDeviceIdUsed(devices.NextDeviceId) 519 return devices.NextDeviceId, nil 520 } 521 devices.incNextDeviceId() 522 } 523 524 return 0, fmt.Errorf("Unable to find a free device Id") 525 } 526 527 func (devices *DeviceSet) createRegisterDevice(hash string) (*DevInfo, error) { 528 deviceId, err := devices.getNextFreeDeviceId() 529 if err != nil { 530 return nil, err 531 } 532 533 if err := devices.openTransaction(hash, deviceId); err != nil { 534 log.Debugf("Error opening transaction hash = %s deviceId = %d", hash, deviceId) 535 devices.markDeviceIdFree(deviceId) 536 return nil, err 537 } 538 539 for { 540 if err := devicemapper.CreateDevice(devices.getPoolDevName(), deviceId); err != nil { 541 if devicemapper.DeviceIdExists(err) { 542 // Device Id already exists. This should not 543 // happen. Now we have a mechianism to find 544 // a free device Id. So something is not right. 545 // Give a warning and continue. 546 log.Errorf("Warning: Device Id %d exists in pool but it is supposed to be unused", deviceId) 547 deviceId, err = devices.getNextFreeDeviceId() 548 if err != nil { 549 return nil, err 550 } 551 // Save new device id into transaction 552 devices.refreshTransaction(deviceId) 553 continue 554 } 555 log.Debugf("Error creating device: %s", err) 556 devices.markDeviceIdFree(deviceId) 557 return nil, err 558 } 559 break 560 } 561 562 log.Debugf("Registering device (id %v) with FS size %v", deviceId, devices.baseFsSize) 563 info, err := devices.registerDevice(deviceId, hash, devices.baseFsSize, devices.OpenTransactionId) 564 if err != nil { 565 _ = devicemapper.DeleteDevice(devices.getPoolDevName(), deviceId) 566 devices.markDeviceIdFree(deviceId) 567 return nil, err 568 } 569 570 if err := devices.closeTransaction(); err != nil { 571 devices.unregisterDevice(deviceId, hash) 572 devicemapper.DeleteDevice(devices.getPoolDevName(), deviceId) 573 devices.markDeviceIdFree(deviceId) 574 return nil, err 575 } 576 return info, nil 577 } 578 579 func (devices *DeviceSet) createRegisterSnapDevice(hash string, baseInfo *DevInfo) error { 580 deviceId, err := devices.getNextFreeDeviceId() 581 if err != nil { 582 return err 583 } 584 585 if err := devices.openTransaction(hash, deviceId); err != nil { 586 log.Debugf("Error opening transaction hash = %s deviceId = %d", hash, deviceId) 587 devices.markDeviceIdFree(deviceId) 588 return err 589 } 590 591 for { 592 if err := devicemapper.CreateSnapDevice(devices.getPoolDevName(), deviceId, baseInfo.Name(), baseInfo.DeviceId); err != nil { 593 if devicemapper.DeviceIdExists(err) { 594 // Device Id already exists. This should not 595 // happen. Now we have a mechianism to find 596 // a free device Id. So something is not right. 597 // Give a warning and continue. 598 log.Errorf("Warning: Device Id %d exists in pool but it is supposed to be unused", deviceId) 599 deviceId, err = devices.getNextFreeDeviceId() 600 if err != nil { 601 return err 602 } 603 // Save new device id into transaction 604 devices.refreshTransaction(deviceId) 605 continue 606 } 607 log.Debugf("Error creating snap device: %s", err) 608 devices.markDeviceIdFree(deviceId) 609 return err 610 } 611 break 612 } 613 614 if _, err := devices.registerDevice(deviceId, hash, baseInfo.Size, devices.OpenTransactionId); err != nil { 615 devicemapper.DeleteDevice(devices.getPoolDevName(), deviceId) 616 devices.markDeviceIdFree(deviceId) 617 log.Debugf("Error registering device: %s", err) 618 return err 619 } 620 621 if err := devices.closeTransaction(); err != nil { 622 devices.unregisterDevice(deviceId, hash) 623 devicemapper.DeleteDevice(devices.getPoolDevName(), deviceId) 624 devices.markDeviceIdFree(deviceId) 625 return err 626 } 627 return nil 628 } 629 630 func (devices *DeviceSet) loadMetadata(hash string) *DevInfo { 631 info := &DevInfo{Hash: hash, devices: devices} 632 633 jsonData, err := ioutil.ReadFile(devices.metadataFile(info)) 634 if err != nil { 635 return nil 636 } 637 638 if err := json.Unmarshal(jsonData, &info); err != nil { 639 return nil 640 } 641 642 return info 643 } 644 645 func (devices *DeviceSet) setupBaseImage() error { 646 oldInfo, _ := devices.lookupDevice("") 647 if oldInfo != nil && oldInfo.Initialized { 648 return nil 649 } 650 651 if oldInfo != nil && !oldInfo.Initialized { 652 log.Debugf("Removing uninitialized base image") 653 if err := devices.DeleteDevice(""); err != nil { 654 return err 655 } 656 } 657 658 if devices.thinPoolDevice != "" && oldInfo == nil { 659 _, transactionId, dataUsed, _, _, _, err := devices.poolStatus() 660 if err != nil { 661 return err 662 } 663 if dataUsed != 0 { 664 return fmt.Errorf("Unable to take ownership of thin-pool (%s) that already has used data blocks", 665 devices.thinPoolDevice) 666 } 667 if transactionId != 0 { 668 return fmt.Errorf("Unable to take ownership of thin-pool (%s) with non-zero transaction Id", 669 devices.thinPoolDevice) 670 } 671 } 672 673 log.Debugf("Initializing base device-mapper thin volume") 674 675 // Create initial device 676 info, err := devices.createRegisterDevice("") 677 if err != nil { 678 return err 679 } 680 681 log.Debugf("Creating filesystem on base device-mapper thin volume") 682 683 if err = devices.activateDeviceIfNeeded(info); err != nil { 684 return err 685 } 686 687 if err := devices.createFilesystem(info); err != nil { 688 return err 689 } 690 691 info.Initialized = true 692 if err = devices.saveMetadata(info); err != nil { 693 info.Initialized = false 694 return err 695 } 696 697 return nil 698 } 699 700 func setCloseOnExec(name string) { 701 if fileInfos, _ := ioutil.ReadDir("/proc/self/fd"); fileInfos != nil { 702 for _, i := range fileInfos { 703 link, _ := os.Readlink(filepath.Join("/proc/self/fd", i.Name())) 704 if link == name { 705 fd, err := strconv.Atoi(i.Name()) 706 if err == nil { 707 syscall.CloseOnExec(fd) 708 } 709 } 710 } 711 } 712 } 713 714 func (devices *DeviceSet) DMLog(level int, file string, line int, dmError int, message string) { 715 if level >= 7 { 716 return // Ignore _LOG_DEBUG 717 } 718 719 // FIXME(vbatts) push this back into ./pkg/devicemapper/ 720 log.Debugf("libdevmapper(%d): %s:%d (%d) %s", level, file, line, dmError, message) 721 } 722 723 func major(device uint64) uint64 { 724 return (device >> 8) & 0xfff 725 } 726 727 func minor(device uint64) uint64 { 728 return (device & 0xff) | ((device >> 12) & 0xfff00) 729 } 730 731 func (devices *DeviceSet) ResizePool(size int64) error { 732 dirname := devices.loopbackDir() 733 datafilename := path.Join(dirname, "data") 734 if len(devices.dataDevice) > 0 { 735 datafilename = devices.dataDevice 736 } 737 metadatafilename := path.Join(dirname, "metadata") 738 if len(devices.metadataDevice) > 0 { 739 metadatafilename = devices.metadataDevice 740 } 741 742 datafile, err := os.OpenFile(datafilename, os.O_RDWR, 0) 743 if datafile == nil { 744 return err 745 } 746 defer datafile.Close() 747 748 fi, err := datafile.Stat() 749 if fi == nil { 750 return err 751 } 752 753 if fi.Size() > size { 754 return fmt.Errorf("Can't shrink file") 755 } 756 757 dataloopback := devicemapper.FindLoopDeviceFor(datafile) 758 if dataloopback == nil { 759 return fmt.Errorf("Unable to find loopback mount for: %s", datafilename) 760 } 761 defer dataloopback.Close() 762 763 metadatafile, err := os.OpenFile(metadatafilename, os.O_RDWR, 0) 764 if metadatafile == nil { 765 return err 766 } 767 defer metadatafile.Close() 768 769 metadataloopback := devicemapper.FindLoopDeviceFor(metadatafile) 770 if metadataloopback == nil { 771 return fmt.Errorf("Unable to find loopback mount for: %s", metadatafilename) 772 } 773 defer metadataloopback.Close() 774 775 // Grow loopback file 776 if err := datafile.Truncate(size); err != nil { 777 return fmt.Errorf("Unable to grow loopback file: %s", err) 778 } 779 780 // Reload size for loopback device 781 if err := devicemapper.LoopbackSetCapacity(dataloopback); err != nil { 782 return fmt.Errorf("Unable to update loopback capacity: %s", err) 783 } 784 785 // Suspend the pool 786 if err := devicemapper.SuspendDevice(devices.getPoolName()); err != nil { 787 return fmt.Errorf("Unable to suspend pool: %s", err) 788 } 789 790 // Reload with the new block sizes 791 if err := devicemapper.ReloadPool(devices.getPoolName(), dataloopback, metadataloopback, devices.thinpBlockSize); err != nil { 792 return fmt.Errorf("Unable to reload pool: %s", err) 793 } 794 795 // Resume the pool 796 if err := devicemapper.ResumeDevice(devices.getPoolName()); err != nil { 797 return fmt.Errorf("Unable to resume pool: %s", err) 798 } 799 800 return nil 801 } 802 803 func (devices *DeviceSet) loadTransactionMetaData() error { 804 jsonData, err := ioutil.ReadFile(devices.transactionMetaFile()) 805 if err != nil { 806 // There is no active transaction. This will be the case 807 // during upgrade. 808 if os.IsNotExist(err) { 809 devices.OpenTransactionId = devices.TransactionId 810 return nil 811 } 812 return err 813 } 814 815 json.Unmarshal(jsonData, &devices.Transaction) 816 return nil 817 } 818 819 func (devices *DeviceSet) saveTransactionMetaData() error { 820 jsonData, err := json.Marshal(&devices.Transaction) 821 if err != nil { 822 return fmt.Errorf("Error encoding metadata to json: %s", err) 823 } 824 825 return devices.writeMetaFile(jsonData, devices.transactionMetaFile()) 826 } 827 828 func (devices *DeviceSet) removeTransactionMetaData() error { 829 if err := os.RemoveAll(devices.transactionMetaFile()); err != nil { 830 return err 831 } 832 return nil 833 } 834 835 func (devices *DeviceSet) rollbackTransaction() error { 836 log.Debugf("Rolling back open transaction: TransactionId=%d hash=%s device_id=%d", devices.OpenTransactionId, devices.DeviceIdHash, devices.DeviceId) 837 838 // A device id might have already been deleted before transaction 839 // closed. In that case this call will fail. Just leave a message 840 // in case of failure. 841 if err := devicemapper.DeleteDevice(devices.getPoolDevName(), devices.DeviceId); err != nil { 842 log.Errorf("Warning: Unable to delete device: %s", err) 843 } 844 845 dinfo := &DevInfo{Hash: devices.DeviceIdHash} 846 if err := devices.removeMetadata(dinfo); err != nil { 847 log.Errorf("Warning: Unable to remove meta data: %s", err) 848 } else { 849 devices.markDeviceIdFree(devices.DeviceId) 850 } 851 852 if err := devices.removeTransactionMetaData(); err != nil { 853 log.Errorf("Warning: Unable to remove transaction meta file %s: %s", devices.transactionMetaFile(), err) 854 } 855 856 return nil 857 } 858 859 func (devices *DeviceSet) processPendingTransaction() error { 860 if err := devices.loadTransactionMetaData(); err != nil { 861 return err 862 } 863 864 // If there was open transaction but pool transaction Id is same 865 // as open transaction Id, nothing to roll back. 866 if devices.TransactionId == devices.OpenTransactionId { 867 return nil 868 } 869 870 // If open transaction Id is less than pool transaction Id, something 871 // is wrong. Bail out. 872 if devices.OpenTransactionId < devices.TransactionId { 873 log.Errorf("Warning: Open Transaction id %d is less than pool transaction id %d", devices.OpenTransactionId, devices.TransactionId) 874 return nil 875 } 876 877 // Pool transaction Id is not same as open transaction. There is 878 // a transaction which was not completed. 879 if err := devices.rollbackTransaction(); err != nil { 880 return fmt.Errorf("Rolling back open transaction failed: %s", err) 881 } 882 883 devices.OpenTransactionId = devices.TransactionId 884 return nil 885 } 886 887 func (devices *DeviceSet) loadDeviceSetMetaData() error { 888 jsonData, err := ioutil.ReadFile(devices.deviceSetMetaFile()) 889 if err != nil { 890 // For backward compatibility return success if file does 891 // not exist. 892 if os.IsNotExist(err) { 893 return nil 894 } 895 return err 896 } 897 898 return json.Unmarshal(jsonData, devices) 899 } 900 901 func (devices *DeviceSet) saveDeviceSetMetaData() error { 902 jsonData, err := json.Marshal(devices) 903 if err != nil { 904 return fmt.Errorf("Error encoding metadata to json: %s", err) 905 } 906 907 return devices.writeMetaFile(jsonData, devices.deviceSetMetaFile()) 908 } 909 910 func (devices *DeviceSet) openTransaction(hash string, DeviceId int) error { 911 devices.allocateTransactionId() 912 devices.DeviceIdHash = hash 913 devices.DeviceId = DeviceId 914 if err := devices.saveTransactionMetaData(); err != nil { 915 return fmt.Errorf("Error saving transaction meta data: %s", err) 916 } 917 return nil 918 } 919 920 func (devices *DeviceSet) refreshTransaction(DeviceId int) error { 921 devices.DeviceId = DeviceId 922 if err := devices.saveTransactionMetaData(); err != nil { 923 return fmt.Errorf("Error saving transaction meta data: %s", err) 924 } 925 return nil 926 } 927 928 func (devices *DeviceSet) closeTransaction() error { 929 if err := devices.updatePoolTransactionId(); err != nil { 930 log.Debugf("Failed to close Transaction") 931 return err 932 } 933 return nil 934 } 935 936 func (devices *DeviceSet) initDevmapper(doInit bool) error { 937 // give ourselves to libdm as a log handler 938 devicemapper.LogInit(devices) 939 940 _, err := devicemapper.GetDriverVersion() 941 if err != nil { 942 // Can't even get driver version, assume not supported 943 return graphdriver.ErrNotSupported 944 } 945 946 if err := os.MkdirAll(devices.metadataDir(), 0700); err != nil && !os.IsExist(err) { 947 return err 948 } 949 950 // Set the device prefix from the device id and inode of the docker root dir 951 952 st, err := os.Stat(devices.root) 953 if err != nil { 954 return fmt.Errorf("Error looking up dir %s: %s", devices.root, err) 955 } 956 sysSt := st.Sys().(*syscall.Stat_t) 957 // "reg-" stands for "regular file". 958 // In the future we might use "dev-" for "device file", etc. 959 // docker-maj,min[-inode] stands for: 960 // - Managed by docker 961 // - The target of this device is at major <maj> and minor <min> 962 // - If <inode> is defined, use that file inside the device as a loopback image. Otherwise use the device itself. 963 devices.devicePrefix = fmt.Sprintf("docker-%d:%d-%d", major(sysSt.Dev), minor(sysSt.Dev), sysSt.Ino) 964 log.Debugf("Generated prefix: %s", devices.devicePrefix) 965 966 // Check for the existence of the thin-pool device 967 log.Debugf("Checking for existence of the pool '%s'", devices.getPoolName()) 968 info, err := devicemapper.GetInfo(devices.getPoolName()) 969 if info == nil { 970 log.Debugf("Error device devicemapper.GetInfo: %s", err) 971 return err 972 } 973 974 // It seems libdevmapper opens this without O_CLOEXEC, and go exec will not close files 975 // that are not Close-on-exec, and lxc-start will die if it inherits any unexpected files, 976 // so we add this badhack to make sure it closes itself 977 setCloseOnExec("/dev/mapper/control") 978 979 // Make sure the sparse images exist in <root>/devicemapper/data and 980 // <root>/devicemapper/metadata 981 982 createdLoopback := false 983 984 // If the pool doesn't exist, create it 985 if info.Exists == 0 && devices.thinPoolDevice == "" { 986 log.Debugf("Pool doesn't exist. Creating it.") 987 988 var ( 989 dataFile *os.File 990 metadataFile *os.File 991 ) 992 993 if devices.dataDevice == "" { 994 // Make sure the sparse images exist in <root>/devicemapper/data 995 996 hasData := devices.hasImage("data") 997 998 if !doInit && !hasData { 999 return errors.New("Loopback data file not found") 1000 } 1001 1002 if !hasData { 1003 createdLoopback = true 1004 } 1005 1006 data, err := devices.ensureImage("data", devices.dataLoopbackSize) 1007 if err != nil { 1008 log.Debugf("Error device ensureImage (data): %s", err) 1009 return err 1010 } 1011 1012 dataFile, err = devicemapper.AttachLoopDevice(data) 1013 if err != nil { 1014 return err 1015 } 1016 } else { 1017 dataFile, err = os.OpenFile(devices.dataDevice, os.O_RDWR, 0600) 1018 if err != nil { 1019 return err 1020 } 1021 } 1022 defer dataFile.Close() 1023 1024 if devices.metadataDevice == "" { 1025 // Make sure the sparse images exist in <root>/devicemapper/metadata 1026 1027 hasMetadata := devices.hasImage("metadata") 1028 1029 if !doInit && !hasMetadata { 1030 return errors.New("Loopback metadata file not found") 1031 } 1032 1033 if !hasMetadata { 1034 createdLoopback = true 1035 } 1036 1037 metadata, err := devices.ensureImage("metadata", devices.metaDataLoopbackSize) 1038 if err != nil { 1039 log.Debugf("Error device ensureImage (metadata): %s", err) 1040 return err 1041 } 1042 1043 metadataFile, err = devicemapper.AttachLoopDevice(metadata) 1044 if err != nil { 1045 return err 1046 } 1047 } else { 1048 metadataFile, err = os.OpenFile(devices.metadataDevice, os.O_RDWR, 0600) 1049 if err != nil { 1050 return err 1051 } 1052 } 1053 defer metadataFile.Close() 1054 1055 if err := devicemapper.CreatePool(devices.getPoolName(), dataFile, metadataFile, devices.thinpBlockSize); err != nil { 1056 return err 1057 } 1058 } 1059 1060 // If we didn't just create the data or metadata image, we need to 1061 // load the transaction id and migrate old metadata 1062 if !createdLoopback { 1063 if err = devices.initMetaData(); err != nil { 1064 return err 1065 } 1066 } 1067 1068 // Right now this loads only NextDeviceId. If there is more metatadata 1069 // down the line, we might have to move it earlier. 1070 if err = devices.loadDeviceSetMetaData(); err != nil { 1071 return err 1072 } 1073 1074 // Setup the base image 1075 if doInit { 1076 if err := devices.setupBaseImage(); err != nil { 1077 log.Debugf("Error device setupBaseImage: %s", err) 1078 return err 1079 } 1080 } 1081 1082 return nil 1083 } 1084 1085 func (devices *DeviceSet) AddDevice(hash, baseHash string) error { 1086 log.Debugf("[deviceset] AddDevice() hash=%s basehash=%s", hash, baseHash) 1087 defer log.Debugf("[deviceset] AddDevice END") 1088 1089 baseInfo, err := devices.lookupDevice(baseHash) 1090 if err != nil { 1091 return err 1092 } 1093 1094 baseInfo.lock.Lock() 1095 defer baseInfo.lock.Unlock() 1096 1097 devices.Lock() 1098 defer devices.Unlock() 1099 1100 if info, _ := devices.lookupDevice(hash); info != nil { 1101 return fmt.Errorf("device %s already exists", hash) 1102 } 1103 1104 if err := devices.createRegisterSnapDevice(hash, baseInfo); err != nil { 1105 return err 1106 } 1107 1108 return nil 1109 } 1110 1111 func (devices *DeviceSet) deleteDevice(info *DevInfo) error { 1112 if devices.doBlkDiscard { 1113 // This is a workaround for the kernel not discarding block so 1114 // on the thin pool when we remove a thinp device, so we do it 1115 // manually 1116 if err := devices.activateDeviceIfNeeded(info); err == nil { 1117 if err := devicemapper.BlockDeviceDiscard(info.DevName()); err != nil { 1118 log.Debugf("Error discarding block on device: %s (ignoring)", err) 1119 } 1120 } 1121 } 1122 1123 devinfo, _ := devicemapper.GetInfo(info.Name()) 1124 if devinfo != nil && devinfo.Exists != 0 { 1125 if err := devices.removeDeviceAndWait(info.Name()); err != nil { 1126 log.Debugf("Error removing device: %s", err) 1127 return err 1128 } 1129 } 1130 1131 if err := devices.openTransaction(info.Hash, info.DeviceId); err != nil { 1132 log.Debugf("Error opening transaction hash = %s deviceId = %d", "", info.DeviceId) 1133 return err 1134 } 1135 1136 if err := devicemapper.DeleteDevice(devices.getPoolDevName(), info.DeviceId); err != nil { 1137 log.Debugf("Error deleting device: %s", err) 1138 return err 1139 } 1140 1141 if err := devices.unregisterDevice(info.DeviceId, info.Hash); err != nil { 1142 return err 1143 } 1144 1145 if err := devices.closeTransaction(); err != nil { 1146 return err 1147 } 1148 1149 devices.markDeviceIdFree(info.DeviceId) 1150 1151 return nil 1152 } 1153 1154 func (devices *DeviceSet) DeleteDevice(hash string) error { 1155 info, err := devices.lookupDevice(hash) 1156 if err != nil { 1157 return err 1158 } 1159 1160 info.lock.Lock() 1161 defer info.lock.Unlock() 1162 1163 devices.Lock() 1164 defer devices.Unlock() 1165 1166 return devices.deleteDevice(info) 1167 } 1168 1169 func (devices *DeviceSet) deactivatePool() error { 1170 log.Debugf("[devmapper] deactivatePool()") 1171 defer log.Debugf("[devmapper] deactivatePool END") 1172 devname := devices.getPoolDevName() 1173 1174 devinfo, err := devicemapper.GetInfo(devname) 1175 if err != nil { 1176 return err 1177 } 1178 if d, err := devicemapper.GetDeps(devname); err == nil { 1179 // Access to more Debug output 1180 log.Debugf("[devmapper] devicemapper.GetDeps() %s: %#v", devname, d) 1181 } 1182 if devinfo.Exists != 0 { 1183 return devicemapper.RemoveDevice(devname) 1184 } 1185 1186 return nil 1187 } 1188 1189 func (devices *DeviceSet) deactivateDevice(info *DevInfo) error { 1190 log.Debugf("[devmapper] deactivateDevice(%s)", info.Hash) 1191 defer log.Debugf("[devmapper] deactivateDevice END") 1192 1193 // Wait for the unmount to be effective, 1194 // by watching the value of Info.OpenCount for the device 1195 if err := devices.waitClose(info); err != nil { 1196 log.Errorf("Warning: error waiting for device %s to close: %s", info.Hash, err) 1197 } 1198 1199 devinfo, err := devicemapper.GetInfo(info.Name()) 1200 if err != nil { 1201 return err 1202 } 1203 if devinfo.Exists != 0 { 1204 if err := devices.removeDeviceAndWait(info.Name()); err != nil { 1205 return err 1206 } 1207 } 1208 1209 return nil 1210 } 1211 1212 // Issues the underlying dm remove operation and then waits 1213 // for it to finish. 1214 func (devices *DeviceSet) removeDeviceAndWait(devname string) error { 1215 var err error 1216 1217 for i := 0; i < 1000; i++ { 1218 err = devicemapper.RemoveDevice(devname) 1219 if err == nil { 1220 break 1221 } 1222 if err != devicemapper.ErrBusy { 1223 return err 1224 } 1225 1226 // If we see EBUSY it may be a transient error, 1227 // sleep a bit a retry a few times. 1228 devices.Unlock() 1229 time.Sleep(10 * time.Millisecond) 1230 devices.Lock() 1231 } 1232 if err != nil { 1233 return err 1234 } 1235 1236 if err := devices.waitRemove(devname); err != nil { 1237 return err 1238 } 1239 return nil 1240 } 1241 1242 // waitRemove blocks until either: 1243 // a) the device registered at <device_set_prefix>-<hash> is removed, 1244 // or b) the 10 second timeout expires. 1245 func (devices *DeviceSet) waitRemove(devname string) error { 1246 log.Debugf("[deviceset %s] waitRemove(%s)", devices.devicePrefix, devname) 1247 defer log.Debugf("[deviceset %s] waitRemove(%s) END", devices.devicePrefix, devname) 1248 i := 0 1249 for ; i < 1000; i++ { 1250 devinfo, err := devicemapper.GetInfo(devname) 1251 if err != nil { 1252 // If there is an error we assume the device doesn't exist. 1253 // The error might actually be something else, but we can't differentiate. 1254 return nil 1255 } 1256 if i%100 == 0 { 1257 log.Debugf("Waiting for removal of %s: exists=%d", devname, devinfo.Exists) 1258 } 1259 if devinfo.Exists == 0 { 1260 break 1261 } 1262 1263 devices.Unlock() 1264 time.Sleep(10 * time.Millisecond) 1265 devices.Lock() 1266 } 1267 if i == 1000 { 1268 return fmt.Errorf("Timeout while waiting for device %s to be removed", devname) 1269 } 1270 return nil 1271 } 1272 1273 // waitClose blocks until either: 1274 // a) the device registered at <device_set_prefix>-<hash> is closed, 1275 // or b) the 10 second timeout expires. 1276 func (devices *DeviceSet) waitClose(info *DevInfo) error { 1277 i := 0 1278 for ; i < 1000; i++ { 1279 devinfo, err := devicemapper.GetInfo(info.Name()) 1280 if err != nil { 1281 return err 1282 } 1283 if i%100 == 0 { 1284 log.Debugf("Waiting for unmount of %s: opencount=%d", info.Hash, devinfo.OpenCount) 1285 } 1286 if devinfo.OpenCount == 0 { 1287 break 1288 } 1289 devices.Unlock() 1290 time.Sleep(10 * time.Millisecond) 1291 devices.Lock() 1292 } 1293 if i == 1000 { 1294 return fmt.Errorf("Timeout while waiting for device %s to close", info.Hash) 1295 } 1296 return nil 1297 } 1298 1299 func (devices *DeviceSet) Shutdown() error { 1300 log.Debugf("[deviceset %s] shutdown()", devices.devicePrefix) 1301 log.Debugf("[devmapper] Shutting down DeviceSet: %s", devices.root) 1302 defer log.Debugf("[deviceset %s] shutdown END", devices.devicePrefix) 1303 1304 var devs []*DevInfo 1305 1306 devices.devicesLock.Lock() 1307 for _, info := range devices.Devices { 1308 devs = append(devs, info) 1309 } 1310 devices.devicesLock.Unlock() 1311 1312 for _, info := range devs { 1313 info.lock.Lock() 1314 if info.mountCount > 0 { 1315 // We use MNT_DETACH here in case it is still busy in some running 1316 // container. This means it'll go away from the global scope directly, 1317 // and the device will be released when that container dies. 1318 if err := syscall.Unmount(info.mountPath, syscall.MNT_DETACH); err != nil { 1319 log.Debugf("Shutdown unmounting %s, error: %s", info.mountPath, err) 1320 } 1321 1322 devices.Lock() 1323 if err := devices.deactivateDevice(info); err != nil { 1324 log.Debugf("Shutdown deactivate %s , error: %s", info.Hash, err) 1325 } 1326 devices.Unlock() 1327 } 1328 info.lock.Unlock() 1329 } 1330 1331 info, _ := devices.lookupDevice("") 1332 if info != nil { 1333 info.lock.Lock() 1334 devices.Lock() 1335 if err := devices.deactivateDevice(info); err != nil { 1336 log.Debugf("Shutdown deactivate base , error: %s", err) 1337 } 1338 devices.Unlock() 1339 info.lock.Unlock() 1340 } 1341 1342 devices.Lock() 1343 if devices.thinPoolDevice == "" { 1344 if err := devices.deactivatePool(); err != nil { 1345 log.Debugf("Shutdown deactivate pool , error: %s", err) 1346 } 1347 } 1348 1349 devices.saveDeviceSetMetaData() 1350 devices.Unlock() 1351 1352 return nil 1353 } 1354 1355 func (devices *DeviceSet) MountDevice(hash, path, mountLabel string) error { 1356 info, err := devices.lookupDevice(hash) 1357 if err != nil { 1358 return err 1359 } 1360 1361 info.lock.Lock() 1362 defer info.lock.Unlock() 1363 1364 devices.Lock() 1365 defer devices.Unlock() 1366 1367 if info.mountCount > 0 { 1368 if path != info.mountPath { 1369 return fmt.Errorf("Trying to mount devmapper device in multple places (%s, %s)", info.mountPath, path) 1370 } 1371 1372 info.mountCount++ 1373 return nil 1374 } 1375 1376 if err := devices.activateDeviceIfNeeded(info); err != nil { 1377 return fmt.Errorf("Error activating devmapper device for '%s': %s", hash, err) 1378 } 1379 1380 var flags uintptr = syscall.MS_MGC_VAL 1381 1382 fstype, err := ProbeFsType(info.DevName()) 1383 if err != nil { 1384 return err 1385 } 1386 1387 options := "" 1388 1389 if fstype == "xfs" { 1390 // XFS needs nouuid or it can't mount filesystems with the same fs 1391 options = joinMountOptions(options, "nouuid") 1392 } 1393 1394 options = joinMountOptions(options, devices.mountOptions) 1395 options = joinMountOptions(options, label.FormatMountLabel("", mountLabel)) 1396 1397 err = syscall.Mount(info.DevName(), path, fstype, flags, joinMountOptions("discard", options)) 1398 if err != nil && err == syscall.EINVAL { 1399 err = syscall.Mount(info.DevName(), path, fstype, flags, options) 1400 } 1401 if err != nil { 1402 return fmt.Errorf("Error mounting '%s' on '%s': %s", info.DevName(), path, err) 1403 } 1404 1405 info.mountCount = 1 1406 info.mountPath = path 1407 1408 return nil 1409 } 1410 1411 func (devices *DeviceSet) UnmountDevice(hash string) error { 1412 log.Debugf("[devmapper] UnmountDevice(hash=%s)", hash) 1413 defer log.Debugf("[devmapper] UnmountDevice END") 1414 1415 info, err := devices.lookupDevice(hash) 1416 if err != nil { 1417 return err 1418 } 1419 1420 info.lock.Lock() 1421 defer info.lock.Unlock() 1422 1423 devices.Lock() 1424 defer devices.Unlock() 1425 1426 if info.mountCount == 0 { 1427 return fmt.Errorf("UnmountDevice: device not-mounted id %s\n", hash) 1428 } 1429 1430 info.mountCount-- 1431 if info.mountCount > 0 { 1432 return nil 1433 } 1434 1435 log.Debugf("[devmapper] Unmount(%s)", info.mountPath) 1436 if err := syscall.Unmount(info.mountPath, 0); err != nil { 1437 return err 1438 } 1439 log.Debugf("[devmapper] Unmount done") 1440 1441 if err := devices.deactivateDevice(info); err != nil { 1442 return err 1443 } 1444 1445 info.mountPath = "" 1446 1447 return nil 1448 } 1449 1450 func (devices *DeviceSet) HasDevice(hash string) bool { 1451 devices.Lock() 1452 defer devices.Unlock() 1453 1454 info, _ := devices.lookupDevice(hash) 1455 return info != nil 1456 } 1457 1458 func (devices *DeviceSet) HasActivatedDevice(hash string) bool { 1459 info, _ := devices.lookupDevice(hash) 1460 if info == nil { 1461 return false 1462 } 1463 1464 info.lock.Lock() 1465 defer info.lock.Unlock() 1466 1467 devices.Lock() 1468 defer devices.Unlock() 1469 1470 devinfo, _ := devicemapper.GetInfo(info.Name()) 1471 return devinfo != nil && devinfo.Exists != 0 1472 } 1473 1474 func (devices *DeviceSet) List() []string { 1475 devices.Lock() 1476 defer devices.Unlock() 1477 1478 devices.devicesLock.Lock() 1479 ids := make([]string, len(devices.Devices)) 1480 i := 0 1481 for k := range devices.Devices { 1482 ids[i] = k 1483 i++ 1484 } 1485 devices.devicesLock.Unlock() 1486 1487 return ids 1488 } 1489 1490 func (devices *DeviceSet) deviceStatus(devName string) (sizeInSectors, mappedSectors, highestMappedSector uint64, err error) { 1491 var params string 1492 _, sizeInSectors, _, params, err = devicemapper.GetStatus(devName) 1493 if err != nil { 1494 return 1495 } 1496 if _, err = fmt.Sscanf(params, "%d %d", &mappedSectors, &highestMappedSector); err == nil { 1497 return 1498 } 1499 return 1500 } 1501 1502 func (devices *DeviceSet) GetDeviceStatus(hash string) (*DevStatus, error) { 1503 info, err := devices.lookupDevice(hash) 1504 if err != nil { 1505 return nil, err 1506 } 1507 1508 info.lock.Lock() 1509 defer info.lock.Unlock() 1510 1511 devices.Lock() 1512 defer devices.Unlock() 1513 1514 status := &DevStatus{ 1515 DeviceId: info.DeviceId, 1516 Size: info.Size, 1517 TransactionId: info.TransactionId, 1518 } 1519 1520 if err := devices.activateDeviceIfNeeded(info); err != nil { 1521 return nil, fmt.Errorf("Error activating devmapper device for '%s': %s", hash, err) 1522 } 1523 1524 if sizeInSectors, mappedSectors, highestMappedSector, err := devices.deviceStatus(info.DevName()); err != nil { 1525 return nil, err 1526 } else { 1527 status.SizeInSectors = sizeInSectors 1528 status.MappedSectors = mappedSectors 1529 status.HighestMappedSector = highestMappedSector 1530 } 1531 1532 return status, nil 1533 } 1534 1535 func (devices *DeviceSet) poolStatus() (totalSizeInSectors, transactionId, dataUsed, dataTotal, metadataUsed, metadataTotal uint64, err error) { 1536 var params string 1537 if _, totalSizeInSectors, _, params, err = devicemapper.GetStatus(devices.getPoolName()); err == nil { 1538 _, err = fmt.Sscanf(params, "%d %d/%d %d/%d", &transactionId, &metadataUsed, &metadataTotal, &dataUsed, &dataTotal) 1539 } 1540 return 1541 } 1542 1543 func (devices *DeviceSet) Status() *Status { 1544 devices.Lock() 1545 defer devices.Unlock() 1546 1547 status := &Status{} 1548 1549 status.PoolName = devices.getPoolName() 1550 if len(devices.dataDevice) > 0 { 1551 status.DataLoopback = devices.dataDevice 1552 } else { 1553 status.DataLoopback = path.Join(devices.loopbackDir(), "data") 1554 } 1555 if len(devices.metadataDevice) > 0 { 1556 status.MetadataLoopback = devices.metadataDevice 1557 } else { 1558 status.MetadataLoopback = path.Join(devices.loopbackDir(), "metadata") 1559 } 1560 1561 totalSizeInSectors, _, dataUsed, dataTotal, metadataUsed, metadataTotal, err := devices.poolStatus() 1562 if err == nil { 1563 // Convert from blocks to bytes 1564 blockSizeInSectors := totalSizeInSectors / dataTotal 1565 1566 status.Data.Used = dataUsed * blockSizeInSectors * 512 1567 status.Data.Total = dataTotal * blockSizeInSectors * 512 1568 1569 // metadata blocks are always 4k 1570 status.Metadata.Used = metadataUsed * 4096 1571 status.Metadata.Total = metadataTotal * 4096 1572 1573 status.SectorSize = blockSizeInSectors * 512 1574 } 1575 1576 return status 1577 } 1578 1579 func NewDeviceSet(root string, doInit bool, options []string) (*DeviceSet, error) { 1580 devicemapper.SetDevDir("/dev") 1581 1582 devices := &DeviceSet{ 1583 root: root, 1584 MetaData: MetaData{Devices: make(map[string]*DevInfo)}, 1585 dataLoopbackSize: DefaultDataLoopbackSize, 1586 metaDataLoopbackSize: DefaultMetaDataLoopbackSize, 1587 baseFsSize: DefaultBaseFsSize, 1588 filesystem: "ext4", 1589 doBlkDiscard: true, 1590 thinpBlockSize: DefaultThinpBlockSize, 1591 deviceIdMap: make([]byte, DeviceIdMapSz), 1592 } 1593 1594 foundBlkDiscard := false 1595 for _, option := range options { 1596 key, val, err := parsers.ParseKeyValueOpt(option) 1597 if err != nil { 1598 return nil, err 1599 } 1600 key = strings.ToLower(key) 1601 switch key { 1602 case "dm.basesize": 1603 size, err := units.RAMInBytes(val) 1604 if err != nil { 1605 return nil, err 1606 } 1607 devices.baseFsSize = uint64(size) 1608 case "dm.loopdatasize": 1609 size, err := units.RAMInBytes(val) 1610 if err != nil { 1611 return nil, err 1612 } 1613 devices.dataLoopbackSize = size 1614 case "dm.loopmetadatasize": 1615 size, err := units.RAMInBytes(val) 1616 if err != nil { 1617 return nil, err 1618 } 1619 devices.metaDataLoopbackSize = size 1620 case "dm.fs": 1621 if val != "ext4" && val != "xfs" { 1622 return nil, fmt.Errorf("Unsupported filesystem %s\n", val) 1623 } 1624 devices.filesystem = val 1625 case "dm.mkfsarg": 1626 devices.mkfsArgs = append(devices.mkfsArgs, val) 1627 case "dm.mountopt": 1628 devices.mountOptions = joinMountOptions(devices.mountOptions, val) 1629 case "dm.metadatadev": 1630 devices.metadataDevice = val 1631 case "dm.datadev": 1632 devices.dataDevice = val 1633 case "dm.thinpooldev": 1634 devices.thinPoolDevice = strings.TrimPrefix(val, "/dev/mapper/") 1635 case "dm.blkdiscard": 1636 foundBlkDiscard = true 1637 devices.doBlkDiscard, err = strconv.ParseBool(val) 1638 if err != nil { 1639 return nil, err 1640 } 1641 case "dm.blocksize": 1642 size, err := units.RAMInBytes(val) 1643 if err != nil { 1644 return nil, err 1645 } 1646 // convert to 512b sectors 1647 devices.thinpBlockSize = uint32(size) >> 9 1648 default: 1649 return nil, fmt.Errorf("Unknown option %s\n", key) 1650 } 1651 } 1652 1653 // By default, don't do blk discard hack on raw devices, its rarely useful and is expensive 1654 if !foundBlkDiscard && (devices.dataDevice != "" || devices.thinPoolDevice != "") { 1655 devices.doBlkDiscard = false 1656 } 1657 1658 if err := devices.initDevmapper(doInit); err != nil { 1659 return nil, err 1660 } 1661 1662 return devices, nil 1663 }