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