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