github.com/fabiokung/docker@v0.11.2-0.20170222101415-4534dcd49497/daemon/graphdriver/devmapper/deviceset.go (about) 1 // +build linux 2 3 package devmapper 4 5 import ( 6 "bufio" 7 "encoding/json" 8 "errors" 9 "fmt" 10 "io" 11 "io/ioutil" 12 "os" 13 "os/exec" 14 "path" 15 "path/filepath" 16 "strconv" 17 "strings" 18 "sync" 19 "syscall" 20 "time" 21 22 "github.com/Sirupsen/logrus" 23 24 "github.com/docker/docker/daemon/graphdriver" 25 "github.com/docker/docker/dockerversion" 26 "github.com/docker/docker/pkg/devicemapper" 27 "github.com/docker/docker/pkg/idtools" 28 "github.com/docker/docker/pkg/loopback" 29 "github.com/docker/docker/pkg/mount" 30 "github.com/docker/docker/pkg/parsers" 31 units "github.com/docker/go-units" 32 33 "github.com/opencontainers/runc/libcontainer/label" 34 ) 35 36 var ( 37 defaultDataLoopbackSize int64 = 100 * 1024 * 1024 * 1024 38 defaultMetaDataLoopbackSize int64 = 2 * 1024 * 1024 * 1024 39 defaultBaseFsSize uint64 = 10 * 1024 * 1024 * 1024 40 defaultThinpBlockSize uint32 = 128 // 64K = 128 512b sectors 41 defaultUdevSyncOverride = false 42 maxDeviceID = 0xffffff // 24 bit, pool limit 43 deviceIDMapSz = (maxDeviceID + 1) / 8 44 // We retry device removal so many a times that even error messages 45 // will fill up console during normal operation. So only log Fatal 46 // messages by default. 47 logLevel = devicemapper.LogLevelFatal 48 driverDeferredRemovalSupport = false 49 enableDeferredRemoval = false 50 enableDeferredDeletion = false 51 userBaseSize = false 52 defaultMinFreeSpacePercent uint32 = 10 53 ) 54 55 const deviceSetMetaFile string = "deviceset-metadata" 56 const transactionMetaFile string = "transaction-metadata" 57 58 type transaction struct { 59 OpenTransactionID uint64 `json:"open_transaction_id"` 60 DeviceIDHash string `json:"device_hash"` 61 DeviceID int `json:"device_id"` 62 } 63 64 type devInfo struct { 65 Hash string `json:"-"` 66 DeviceID int `json:"device_id"` 67 Size uint64 `json:"size"` 68 TransactionID uint64 `json:"transaction_id"` 69 Initialized bool `json:"initialized"` 70 Deleted bool `json:"deleted"` 71 devices *DeviceSet 72 73 // The global DeviceSet lock guarantees that we serialize all 74 // the calls to libdevmapper (which is not threadsafe), but we 75 // sometimes release that lock while sleeping. In that case 76 // this per-device lock is still held, protecting against 77 // other accesses to the device that we're doing the wait on. 78 // 79 // WARNING: In order to avoid AB-BA deadlocks when releasing 80 // the global lock while holding the per-device locks all 81 // device locks must be acquired *before* the device lock, and 82 // multiple device locks should be acquired parent before child. 83 lock sync.Mutex 84 } 85 86 type metaData struct { 87 Devices map[string]*devInfo `json:"Devices"` 88 } 89 90 // DeviceSet holds information about list of devices 91 type DeviceSet struct { 92 metaData `json:"-"` 93 sync.Mutex `json:"-"` // Protects all fields of DeviceSet and serializes calls into libdevmapper 94 root string 95 devicePrefix string 96 TransactionID uint64 `json:"-"` 97 NextDeviceID int `json:"next_device_id"` 98 deviceIDMap []byte 99 100 // Options 101 dataLoopbackSize int64 102 metaDataLoopbackSize int64 103 baseFsSize uint64 104 filesystem string 105 mountOptions string 106 mkfsArgs []string 107 dataDevice string // block or loop dev 108 dataLoopFile string // loopback file, if used 109 metadataDevice string // block or loop dev 110 metadataLoopFile string // loopback file, if used 111 doBlkDiscard bool 112 thinpBlockSize uint32 113 thinPoolDevice string 114 transaction `json:"-"` 115 overrideUdevSyncCheck bool 116 deferredRemove bool // use deferred removal 117 deferredDelete bool // use deferred deletion 118 BaseDeviceUUID string // save UUID of base device 119 BaseDeviceFilesystem string // save filesystem of base device 120 nrDeletedDevices uint // number of deleted devices 121 deletionWorkerTicker *time.Ticker 122 uidMaps []idtools.IDMap 123 gidMaps []idtools.IDMap 124 minFreeSpacePercent uint32 //min free space percentage in thinpool 125 xfsNospaceRetries string // max retries when xfs receives ENOSPC 126 } 127 128 // DiskUsage contains information about disk usage and is used when reporting Status of a device. 129 type DiskUsage struct { 130 // Used bytes on the disk. 131 Used uint64 132 // Total bytes on the disk. 133 Total uint64 134 // Available bytes on the disk. 135 Available uint64 136 } 137 138 // Status returns the information about the device. 139 type Status struct { 140 // PoolName is the name of the data pool. 141 PoolName string 142 // DataFile is the actual block device for data. 143 DataFile string 144 // DataLoopback loopback file, if used. 145 DataLoopback string 146 // MetadataFile is the actual block device for metadata. 147 MetadataFile string 148 // MetadataLoopback is the loopback file, if used. 149 MetadataLoopback string 150 // Data is the disk used for data. 151 Data DiskUsage 152 // Metadata is the disk used for meta data. 153 Metadata DiskUsage 154 // BaseDeviceSize is base size of container and image 155 BaseDeviceSize uint64 156 // BaseDeviceFS is backing filesystem. 157 BaseDeviceFS string 158 // SectorSize size of the vector. 159 SectorSize uint64 160 // UdevSyncSupported is true if sync is supported. 161 UdevSyncSupported bool 162 // DeferredRemoveEnabled is true then the device is not unmounted. 163 DeferredRemoveEnabled bool 164 // True if deferred deletion is enabled. This is different from 165 // deferred removal. "removal" means that device mapper device is 166 // deactivated. Thin device is still in thin pool and can be activated 167 // again. But "deletion" means that thin device will be deleted from 168 // thin pool and it can't be activated again. 169 DeferredDeleteEnabled bool 170 DeferredDeletedDeviceCount uint 171 MinFreeSpace uint64 172 } 173 174 // Structure used to export image/container metadata in docker inspect. 175 type deviceMetadata struct { 176 deviceID int 177 deviceSize uint64 // size in bytes 178 deviceName string // Device name as used during activation 179 } 180 181 // DevStatus returns information about device mounted containing its id, size and sector information. 182 type DevStatus struct { 183 // DeviceID is the id of the device. 184 DeviceID int 185 // Size is the size of the filesystem. 186 Size uint64 187 // TransactionID is a unique integer per device set used to identify an operation on the file system, this number is incremental. 188 TransactionID uint64 189 // SizeInSectors indicates the size of the sectors allocated. 190 SizeInSectors uint64 191 // MappedSectors indicates number of mapped sectors. 192 MappedSectors uint64 193 // HighestMappedSector is the pointer to the highest mapped sector. 194 HighestMappedSector uint64 195 } 196 197 func getDevName(name string) string { 198 return "/dev/mapper/" + name 199 } 200 201 func (info *devInfo) Name() string { 202 hash := info.Hash 203 if hash == "" { 204 hash = "base" 205 } 206 return fmt.Sprintf("%s-%s", info.devices.devicePrefix, hash) 207 } 208 209 func (info *devInfo) DevName() string { 210 return getDevName(info.Name()) 211 } 212 213 func (devices *DeviceSet) loopbackDir() string { 214 return path.Join(devices.root, "devicemapper") 215 } 216 217 func (devices *DeviceSet) metadataDir() string { 218 return path.Join(devices.root, "metadata") 219 } 220 221 func (devices *DeviceSet) metadataFile(info *devInfo) string { 222 file := info.Hash 223 if file == "" { 224 file = "base" 225 } 226 return path.Join(devices.metadataDir(), file) 227 } 228 229 func (devices *DeviceSet) transactionMetaFile() string { 230 return path.Join(devices.metadataDir(), transactionMetaFile) 231 } 232 233 func (devices *DeviceSet) deviceSetMetaFile() string { 234 return path.Join(devices.metadataDir(), deviceSetMetaFile) 235 } 236 237 func (devices *DeviceSet) oldMetadataFile() string { 238 return path.Join(devices.loopbackDir(), "json") 239 } 240 241 func (devices *DeviceSet) getPoolName() string { 242 if devices.thinPoolDevice == "" { 243 return devices.devicePrefix + "-pool" 244 } 245 return devices.thinPoolDevice 246 } 247 248 func (devices *DeviceSet) getPoolDevName() string { 249 return getDevName(devices.getPoolName()) 250 } 251 252 func (devices *DeviceSet) hasImage(name string) bool { 253 dirname := devices.loopbackDir() 254 filename := path.Join(dirname, name) 255 256 _, err := os.Stat(filename) 257 return err == nil 258 } 259 260 // ensureImage creates a sparse file of <size> bytes at the path 261 // <root>/devicemapper/<name>. 262 // If the file already exists and new size is larger than its current size, it grows to the new size. 263 // Either way it returns the full path. 264 func (devices *DeviceSet) ensureImage(name string, size int64) (string, error) { 265 dirname := devices.loopbackDir() 266 filename := path.Join(dirname, name) 267 268 uid, gid, err := idtools.GetRootUIDGID(devices.uidMaps, devices.gidMaps) 269 if err != nil { 270 return "", err 271 } 272 if err := idtools.MkdirAllAs(dirname, 0700, uid, gid); err != nil && !os.IsExist(err) { 273 return "", err 274 } 275 276 if fi, err := os.Stat(filename); err != nil { 277 if !os.IsNotExist(err) { 278 return "", err 279 } 280 logrus.Debugf("devmapper: Creating loopback file %s for device-manage use", filename) 281 file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0600) 282 if err != nil { 283 return "", err 284 } 285 defer file.Close() 286 287 if err := file.Truncate(size); err != nil { 288 return "", err 289 } 290 } else { 291 if fi.Size() < size { 292 file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0600) 293 if err != nil { 294 return "", err 295 } 296 defer file.Close() 297 if err := file.Truncate(size); err != nil { 298 return "", fmt.Errorf("devmapper: Unable to grow loopback file %s: %v", filename, err) 299 } 300 } else if fi.Size() > size { 301 logrus.Warnf("devmapper: Can't shrink loopback file %s", filename) 302 } 303 } 304 return filename, nil 305 } 306 307 func (devices *DeviceSet) allocateTransactionID() uint64 { 308 devices.OpenTransactionID = devices.TransactionID + 1 309 return devices.OpenTransactionID 310 } 311 312 func (devices *DeviceSet) updatePoolTransactionID() error { 313 if err := devicemapper.SetTransactionID(devices.getPoolDevName(), devices.TransactionID, devices.OpenTransactionID); err != nil { 314 return fmt.Errorf("devmapper: Error setting devmapper transaction ID: %s", err) 315 } 316 devices.TransactionID = devices.OpenTransactionID 317 return nil 318 } 319 320 func (devices *DeviceSet) removeMetadata(info *devInfo) error { 321 if err := os.RemoveAll(devices.metadataFile(info)); err != nil { 322 return fmt.Errorf("devmapper: Error removing metadata file %s: %s", devices.metadataFile(info), err) 323 } 324 return nil 325 } 326 327 // Given json data and file path, write it to disk 328 func (devices *DeviceSet) writeMetaFile(jsonData []byte, filePath string) error { 329 tmpFile, err := ioutil.TempFile(devices.metadataDir(), ".tmp") 330 if err != nil { 331 return fmt.Errorf("devmapper: Error creating metadata file: %s", err) 332 } 333 334 n, err := tmpFile.Write(jsonData) 335 if err != nil { 336 return fmt.Errorf("devmapper: Error writing metadata to %s: %s", tmpFile.Name(), err) 337 } 338 if n < len(jsonData) { 339 return io.ErrShortWrite 340 } 341 if err := tmpFile.Sync(); err != nil { 342 return fmt.Errorf("devmapper: Error syncing metadata file %s: %s", tmpFile.Name(), err) 343 } 344 if err := tmpFile.Close(); err != nil { 345 return fmt.Errorf("devmapper: Error closing metadata file %s: %s", tmpFile.Name(), err) 346 } 347 if err := os.Rename(tmpFile.Name(), filePath); err != nil { 348 return fmt.Errorf("devmapper: Error committing metadata file %s: %s", tmpFile.Name(), err) 349 } 350 351 return nil 352 } 353 354 func (devices *DeviceSet) saveMetadata(info *devInfo) error { 355 jsonData, err := json.Marshal(info) 356 if err != nil { 357 return fmt.Errorf("devmapper: Error encoding metadata to json: %s", err) 358 } 359 if err := devices.writeMetaFile(jsonData, devices.metadataFile(info)); err != nil { 360 return err 361 } 362 return nil 363 } 364 365 func (devices *DeviceSet) markDeviceIDUsed(deviceID int) { 366 var mask byte 367 i := deviceID % 8 368 mask = 1 << uint(i) 369 devices.deviceIDMap[deviceID/8] = devices.deviceIDMap[deviceID/8] | mask 370 } 371 372 func (devices *DeviceSet) markDeviceIDFree(deviceID int) { 373 var mask byte 374 i := deviceID % 8 375 mask = ^(1 << uint(i)) 376 devices.deviceIDMap[deviceID/8] = devices.deviceIDMap[deviceID/8] & mask 377 } 378 379 func (devices *DeviceSet) isDeviceIDFree(deviceID int) bool { 380 var mask byte 381 i := deviceID % 8 382 mask = (1 << uint(i)) 383 return (devices.deviceIDMap[deviceID/8] & mask) == 0 384 } 385 386 // Should be called with devices.Lock() held. 387 func (devices *DeviceSet) lookupDevice(hash string) (*devInfo, error) { 388 info := devices.Devices[hash] 389 if info == nil { 390 info = devices.loadMetadata(hash) 391 if info == nil { 392 return nil, fmt.Errorf("devmapper: Unknown device %s", hash) 393 } 394 395 devices.Devices[hash] = info 396 } 397 return info, nil 398 } 399 400 func (devices *DeviceSet) lookupDeviceWithLock(hash string) (*devInfo, error) { 401 devices.Lock() 402 defer devices.Unlock() 403 info, err := devices.lookupDevice(hash) 404 return info, err 405 } 406 407 // This function relies on that device hash map has been loaded in advance. 408 // Should be called with devices.Lock() held. 409 func (devices *DeviceSet) constructDeviceIDMap() { 410 logrus.Debug("devmapper: constructDeviceIDMap()") 411 defer logrus.Debug("devmapper: constructDeviceIDMap() END") 412 413 for _, info := range devices.Devices { 414 devices.markDeviceIDUsed(info.DeviceID) 415 logrus.Debugf("devmapper: Added deviceId=%d to DeviceIdMap", info.DeviceID) 416 } 417 } 418 419 func (devices *DeviceSet) deviceFileWalkFunction(path string, finfo os.FileInfo) error { 420 421 // Skip some of the meta files which are not device files. 422 if strings.HasSuffix(finfo.Name(), ".migrated") { 423 logrus.Debugf("devmapper: Skipping file %s", path) 424 return nil 425 } 426 427 if strings.HasPrefix(finfo.Name(), ".") { 428 logrus.Debugf("devmapper: Skipping file %s", path) 429 return nil 430 } 431 432 if finfo.Name() == deviceSetMetaFile { 433 logrus.Debugf("devmapper: Skipping file %s", path) 434 return nil 435 } 436 437 if finfo.Name() == transactionMetaFile { 438 logrus.Debugf("devmapper: Skipping file %s", path) 439 return nil 440 } 441 442 logrus.Debugf("devmapper: Loading data for file %s", path) 443 444 hash := finfo.Name() 445 if hash == "base" { 446 hash = "" 447 } 448 449 // Include deleted devices also as cleanup delete device logic 450 // will go through it and see if there are any deleted devices. 451 if _, err := devices.lookupDevice(hash); err != nil { 452 return fmt.Errorf("devmapper: Error looking up device %s:%v", hash, err) 453 } 454 455 return nil 456 } 457 458 func (devices *DeviceSet) loadDeviceFilesOnStart() error { 459 logrus.Debug("devmapper: loadDeviceFilesOnStart()") 460 defer logrus.Debug("devmapper: loadDeviceFilesOnStart() END") 461 462 var scan = func(path string, info os.FileInfo, err error) error { 463 if err != nil { 464 logrus.Debugf("devmapper: Can't walk the file %s", path) 465 return nil 466 } 467 468 // Skip any directories 469 if info.IsDir() { 470 return nil 471 } 472 473 return devices.deviceFileWalkFunction(path, info) 474 } 475 476 return filepath.Walk(devices.metadataDir(), scan) 477 } 478 479 // Should be called with devices.Lock() held. 480 func (devices *DeviceSet) unregisterDevice(hash string) error { 481 logrus.Debugf("devmapper: unregisterDevice(%v)", hash) 482 info := &devInfo{ 483 Hash: hash, 484 } 485 486 delete(devices.Devices, hash) 487 488 if err := devices.removeMetadata(info); err != nil { 489 logrus.Debugf("devmapper: Error removing metadata: %s", err) 490 return err 491 } 492 493 return nil 494 } 495 496 // Should be called with devices.Lock() held. 497 func (devices *DeviceSet) registerDevice(id int, hash string, size uint64, transactionID uint64) (*devInfo, error) { 498 logrus.Debugf("devmapper: registerDevice(%v, %v)", id, hash) 499 info := &devInfo{ 500 Hash: hash, 501 DeviceID: id, 502 Size: size, 503 TransactionID: transactionID, 504 Initialized: false, 505 devices: devices, 506 } 507 508 devices.Devices[hash] = info 509 510 if err := devices.saveMetadata(info); err != nil { 511 // Try to remove unused device 512 delete(devices.Devices, hash) 513 return nil, err 514 } 515 516 return info, nil 517 } 518 519 func (devices *DeviceSet) activateDeviceIfNeeded(info *devInfo, ignoreDeleted bool) error { 520 logrus.Debugf("devmapper: activateDeviceIfNeeded(%v)", info.Hash) 521 522 if info.Deleted && !ignoreDeleted { 523 return fmt.Errorf("devmapper: Can't activate device %v as it is marked for deletion", info.Hash) 524 } 525 526 // Make sure deferred removal on device is canceled, if one was 527 // scheduled. 528 if err := devices.cancelDeferredRemovalIfNeeded(info); err != nil { 529 return fmt.Errorf("devmapper: Device Deferred Removal Cancellation Failed: %s", err) 530 } 531 532 if devinfo, _ := devicemapper.GetInfo(info.Name()); devinfo != nil && devinfo.Exists != 0 { 533 return nil 534 } 535 536 return devicemapper.ActivateDevice(devices.getPoolDevName(), info.Name(), info.DeviceID, info.Size) 537 } 538 539 // Return true only if kernel supports xfs and mkfs.xfs is available 540 func xfsSupported() bool { 541 // Make sure mkfs.xfs is available 542 if _, err := exec.LookPath("mkfs.xfs"); err != nil { 543 return false 544 } 545 546 // Check if kernel supports xfs filesystem or not. 547 exec.Command("modprobe", "xfs").Run() 548 549 f, err := os.Open("/proc/filesystems") 550 if err != nil { 551 logrus.Warnf("devmapper: Could not check if xfs is supported: %v", err) 552 return false 553 } 554 defer f.Close() 555 556 s := bufio.NewScanner(f) 557 for s.Scan() { 558 if strings.HasSuffix(s.Text(), "\txfs") { 559 return true 560 } 561 } 562 563 if err := s.Err(); err != nil { 564 logrus.Warnf("devmapper: Could not check if xfs is supported: %v", err) 565 } 566 return false 567 } 568 569 func determineDefaultFS() string { 570 if xfsSupported() { 571 return "xfs" 572 } 573 574 logrus.Warn("devmapper: XFS is not supported in your system. Either the kernel doesn't support it or mkfs.xfs is not in your PATH. Defaulting to ext4 filesystem") 575 return "ext4" 576 } 577 578 func (devices *DeviceSet) createFilesystem(info *devInfo) (err error) { 579 devname := info.DevName() 580 581 args := []string{} 582 args = append(args, devices.mkfsArgs...) 583 584 args = append(args, devname) 585 586 if devices.filesystem == "" { 587 devices.filesystem = determineDefaultFS() 588 } 589 if err := devices.saveBaseDeviceFilesystem(devices.filesystem); err != nil { 590 return err 591 } 592 593 logrus.Infof("devmapper: Creating filesystem %s on device %s", devices.filesystem, info.Name()) 594 defer func() { 595 if err != nil { 596 logrus.Infof("devmapper: Error while creating filesystem %s on device %s: %v", devices.filesystem, info.Name(), err) 597 } else { 598 logrus.Infof("devmapper: Successfully created filesystem %s on device %s", devices.filesystem, info.Name()) 599 } 600 }() 601 602 switch devices.filesystem { 603 case "xfs": 604 err = exec.Command("mkfs.xfs", args...).Run() 605 case "ext4": 606 err = exec.Command("mkfs.ext4", append([]string{"-E", "nodiscard,lazy_itable_init=0,lazy_journal_init=0"}, args...)...).Run() 607 if err != nil { 608 err = exec.Command("mkfs.ext4", append([]string{"-E", "nodiscard,lazy_itable_init=0"}, args...)...).Run() 609 } 610 if err != nil { 611 return err 612 } 613 err = exec.Command("tune2fs", append([]string{"-c", "-1", "-i", "0"}, devname)...).Run() 614 default: 615 err = fmt.Errorf("devmapper: Unsupported filesystem type %s", devices.filesystem) 616 } 617 return 618 } 619 620 func (devices *DeviceSet) migrateOldMetaData() error { 621 // Migrate old metadata file 622 jsonData, err := ioutil.ReadFile(devices.oldMetadataFile()) 623 if err != nil && !os.IsNotExist(err) { 624 return err 625 } 626 627 if jsonData != nil { 628 m := metaData{Devices: make(map[string]*devInfo)} 629 630 if err := json.Unmarshal(jsonData, &m); err != nil { 631 return err 632 } 633 634 for hash, info := range m.Devices { 635 info.Hash = hash 636 devices.saveMetadata(info) 637 } 638 if err := os.Rename(devices.oldMetadataFile(), devices.oldMetadataFile()+".migrated"); err != nil { 639 return err 640 } 641 642 } 643 644 return nil 645 } 646 647 // Cleanup deleted devices. It assumes that all the devices have been 648 // loaded in the hash table. 649 func (devices *DeviceSet) cleanupDeletedDevices() error { 650 devices.Lock() 651 652 // If there are no deleted devices, there is nothing to do. 653 if devices.nrDeletedDevices == 0 { 654 devices.Unlock() 655 return nil 656 } 657 658 var deletedDevices []*devInfo 659 660 for _, info := range devices.Devices { 661 if !info.Deleted { 662 continue 663 } 664 logrus.Debugf("devmapper: Found deleted device %s.", info.Hash) 665 deletedDevices = append(deletedDevices, info) 666 } 667 668 // Delete the deleted devices. DeleteDevice() first takes the info lock 669 // and then devices.Lock(). So drop it to avoid deadlock. 670 devices.Unlock() 671 672 for _, info := range deletedDevices { 673 // This will again try deferred deletion. 674 if err := devices.DeleteDevice(info.Hash, false); err != nil { 675 logrus.Warnf("devmapper: Deletion of device %s, device_id=%v failed:%v", info.Hash, info.DeviceID, err) 676 } 677 } 678 679 return nil 680 } 681 682 func (devices *DeviceSet) countDeletedDevices() { 683 for _, info := range devices.Devices { 684 if !info.Deleted { 685 continue 686 } 687 devices.nrDeletedDevices++ 688 } 689 } 690 691 func (devices *DeviceSet) startDeviceDeletionWorker() { 692 // Deferred deletion is not enabled. Don't do anything. 693 if !devices.deferredDelete { 694 return 695 } 696 697 logrus.Debug("devmapper: Worker to cleanup deleted devices started") 698 for range devices.deletionWorkerTicker.C { 699 devices.cleanupDeletedDevices() 700 } 701 } 702 703 func (devices *DeviceSet) initMetaData() error { 704 devices.Lock() 705 defer devices.Unlock() 706 707 if err := devices.migrateOldMetaData(); err != nil { 708 return err 709 } 710 711 _, transactionID, _, _, _, _, err := devices.poolStatus() 712 if err != nil { 713 return err 714 } 715 716 devices.TransactionID = transactionID 717 718 if err := devices.loadDeviceFilesOnStart(); err != nil { 719 return fmt.Errorf("devmapper: Failed to load device files:%v", err) 720 } 721 722 devices.constructDeviceIDMap() 723 devices.countDeletedDevices() 724 725 if err := devices.processPendingTransaction(); err != nil { 726 return err 727 } 728 729 // Start a goroutine to cleanup Deleted Devices 730 go devices.startDeviceDeletionWorker() 731 return nil 732 } 733 734 func (devices *DeviceSet) incNextDeviceID() { 735 // IDs are 24bit, so wrap around 736 devices.NextDeviceID = (devices.NextDeviceID + 1) & maxDeviceID 737 } 738 739 func (devices *DeviceSet) getNextFreeDeviceID() (int, error) { 740 devices.incNextDeviceID() 741 for i := 0; i <= maxDeviceID; i++ { 742 if devices.isDeviceIDFree(devices.NextDeviceID) { 743 devices.markDeviceIDUsed(devices.NextDeviceID) 744 return devices.NextDeviceID, nil 745 } 746 devices.incNextDeviceID() 747 } 748 749 return 0, fmt.Errorf("devmapper: Unable to find a free device ID") 750 } 751 752 func (devices *DeviceSet) poolHasFreeSpace() error { 753 if devices.minFreeSpacePercent == 0 { 754 return nil 755 } 756 757 _, _, dataUsed, dataTotal, metadataUsed, metadataTotal, err := devices.poolStatus() 758 if err != nil { 759 return err 760 } 761 762 minFreeData := (dataTotal * uint64(devices.minFreeSpacePercent)) / 100 763 if minFreeData < 1 { 764 minFreeData = 1 765 } 766 dataFree := dataTotal - dataUsed 767 if dataFree < minFreeData { 768 return fmt.Errorf("devmapper: Thin Pool has %v free data blocks which is less than minimum required %v free data blocks. Create more free space in thin pool or use dm.min_free_space option to change behavior", (dataTotal - dataUsed), minFreeData) 769 } 770 771 minFreeMetadata := (metadataTotal * uint64(devices.minFreeSpacePercent)) / 100 772 if minFreeMetadata < 1 { 773 minFreeMetadata = 1 774 } 775 776 metadataFree := metadataTotal - metadataUsed 777 if metadataFree < minFreeMetadata { 778 return fmt.Errorf("devmapper: Thin Pool has %v free metadata blocks which is less than minimum required %v free metadata blocks. Create more free metadata space in thin pool or use dm.min_free_space option to change behavior", (metadataTotal - metadataUsed), minFreeMetadata) 779 } 780 781 return nil 782 } 783 784 func (devices *DeviceSet) createRegisterDevice(hash string) (*devInfo, error) { 785 devices.Lock() 786 defer devices.Unlock() 787 788 deviceID, err := devices.getNextFreeDeviceID() 789 if err != nil { 790 return nil, err 791 } 792 793 if err := devices.openTransaction(hash, deviceID); err != nil { 794 logrus.Debugf("devmapper: Error opening transaction hash = %s deviceID = %d", hash, deviceID) 795 devices.markDeviceIDFree(deviceID) 796 return nil, err 797 } 798 799 for { 800 if err := devicemapper.CreateDevice(devices.getPoolDevName(), deviceID); err != nil { 801 if devicemapper.DeviceIDExists(err) { 802 // Device ID already exists. This should not 803 // happen. Now we have a mechanism to find 804 // a free device ID. So something is not right. 805 // Give a warning and continue. 806 logrus.Errorf("devmapper: Device ID %d exists in pool but it is supposed to be unused", deviceID) 807 deviceID, err = devices.getNextFreeDeviceID() 808 if err != nil { 809 return nil, err 810 } 811 // Save new device id into transaction 812 devices.refreshTransaction(deviceID) 813 continue 814 } 815 logrus.Debugf("devmapper: Error creating device: %s", err) 816 devices.markDeviceIDFree(deviceID) 817 return nil, err 818 } 819 break 820 } 821 822 logrus.Debugf("devmapper: Registering device (id %v) with FS size %v", deviceID, devices.baseFsSize) 823 info, err := devices.registerDevice(deviceID, hash, devices.baseFsSize, devices.OpenTransactionID) 824 if err != nil { 825 _ = devicemapper.DeleteDevice(devices.getPoolDevName(), deviceID) 826 devices.markDeviceIDFree(deviceID) 827 return nil, err 828 } 829 830 if err := devices.closeTransaction(); err != nil { 831 devices.unregisterDevice(hash) 832 devicemapper.DeleteDevice(devices.getPoolDevName(), deviceID) 833 devices.markDeviceIDFree(deviceID) 834 return nil, err 835 } 836 return info, nil 837 } 838 839 func (devices *DeviceSet) takeSnapshot(hash string, baseInfo *devInfo, size uint64) error { 840 var ( 841 devinfo *devicemapper.Info 842 err error 843 ) 844 845 if err = devices.poolHasFreeSpace(); err != nil { 846 return err 847 } 848 849 if devices.deferredRemove { 850 devinfo, err = devicemapper.GetInfoWithDeferred(baseInfo.Name()) 851 if err != nil { 852 return err 853 } 854 if devinfo != nil && devinfo.DeferredRemove != 0 { 855 err = devices.cancelDeferredRemoval(baseInfo) 856 if err != nil { 857 // If Error is ErrEnxio. Device is probably already gone. Continue. 858 if err != devicemapper.ErrEnxio { 859 return err 860 } 861 } else { 862 defer devices.deactivateDevice(baseInfo) 863 } 864 } 865 } else { 866 devinfo, err = devicemapper.GetInfo(baseInfo.Name()) 867 if err != nil { 868 return err 869 } 870 } 871 872 doSuspend := devinfo != nil && devinfo.Exists != 0 873 874 if doSuspend { 875 if err = devicemapper.SuspendDevice(baseInfo.Name()); err != nil { 876 return err 877 } 878 defer devicemapper.ResumeDevice(baseInfo.Name()) 879 } 880 881 if err = devices.createRegisterSnapDevice(hash, baseInfo, size); err != nil { 882 return err 883 } 884 885 return nil 886 } 887 888 func (devices *DeviceSet) createRegisterSnapDevice(hash string, baseInfo *devInfo, size uint64) error { 889 deviceID, err := devices.getNextFreeDeviceID() 890 if err != nil { 891 return err 892 } 893 894 if err := devices.openTransaction(hash, deviceID); err != nil { 895 logrus.Debugf("devmapper: Error opening transaction hash = %s deviceID = %d", hash, deviceID) 896 devices.markDeviceIDFree(deviceID) 897 return err 898 } 899 900 for { 901 if err := devicemapper.CreateSnapDeviceRaw(devices.getPoolDevName(), deviceID, baseInfo.DeviceID); err != nil { 902 if devicemapper.DeviceIDExists(err) { 903 // Device ID already exists. This should not 904 // happen. Now we have a mechanism to find 905 // a free device ID. So something is not right. 906 // Give a warning and continue. 907 logrus.Errorf("devmapper: Device ID %d exists in pool but it is supposed to be unused", deviceID) 908 deviceID, err = devices.getNextFreeDeviceID() 909 if err != nil { 910 return err 911 } 912 // Save new device id into transaction 913 devices.refreshTransaction(deviceID) 914 continue 915 } 916 logrus.Debugf("devmapper: Error creating snap device: %s", err) 917 devices.markDeviceIDFree(deviceID) 918 return err 919 } 920 break 921 } 922 923 if _, err := devices.registerDevice(deviceID, hash, size, devices.OpenTransactionID); err != nil { 924 devicemapper.DeleteDevice(devices.getPoolDevName(), deviceID) 925 devices.markDeviceIDFree(deviceID) 926 logrus.Debugf("devmapper: Error registering device: %s", err) 927 return err 928 } 929 930 if err := devices.closeTransaction(); err != nil { 931 devices.unregisterDevice(hash) 932 devicemapper.DeleteDevice(devices.getPoolDevName(), deviceID) 933 devices.markDeviceIDFree(deviceID) 934 return err 935 } 936 return nil 937 } 938 939 func (devices *DeviceSet) loadMetadata(hash string) *devInfo { 940 info := &devInfo{Hash: hash, devices: devices} 941 942 jsonData, err := ioutil.ReadFile(devices.metadataFile(info)) 943 if err != nil { 944 logrus.Debugf("devmapper: Failed to read %s with err: %v", devices.metadataFile(info), err) 945 return nil 946 } 947 948 if err := json.Unmarshal(jsonData, &info); err != nil { 949 logrus.Debugf("devmapper: Failed to unmarshal devInfo from %s with err: %v", devices.metadataFile(info), err) 950 return nil 951 } 952 953 if info.DeviceID > maxDeviceID { 954 logrus.Errorf("devmapper: Ignoring Invalid DeviceId=%d", info.DeviceID) 955 return nil 956 } 957 958 return info 959 } 960 961 func getDeviceUUID(device string) (string, error) { 962 out, err := exec.Command("blkid", "-s", "UUID", "-o", "value", device).Output() 963 if err != nil { 964 return "", fmt.Errorf("devmapper: Failed to find uuid for device %s:%v", device, err) 965 } 966 967 uuid := strings.TrimSuffix(string(out), "\n") 968 uuid = strings.TrimSpace(uuid) 969 logrus.Debugf("devmapper: UUID for device: %s is:%s", device, uuid) 970 return uuid, nil 971 } 972 973 func (devices *DeviceSet) getBaseDeviceSize() uint64 { 974 info, _ := devices.lookupDevice("") 975 if info == nil { 976 return 0 977 } 978 return info.Size 979 } 980 981 func (devices *DeviceSet) getBaseDeviceFS() string { 982 return devices.BaseDeviceFilesystem 983 } 984 985 func (devices *DeviceSet) verifyBaseDeviceUUIDFS(baseInfo *devInfo) error { 986 devices.Lock() 987 defer devices.Unlock() 988 989 if err := devices.activateDeviceIfNeeded(baseInfo, false); err != nil { 990 return err 991 } 992 defer devices.deactivateDevice(baseInfo) 993 994 uuid, err := getDeviceUUID(baseInfo.DevName()) 995 if err != nil { 996 return err 997 } 998 999 if devices.BaseDeviceUUID != uuid { 1000 return fmt.Errorf("devmapper: Current Base Device UUID:%s does not match with stored UUID:%s. Possibly using a different thin pool than last invocation", uuid, devices.BaseDeviceUUID) 1001 } 1002 1003 if devices.BaseDeviceFilesystem == "" { 1004 fsType, err := ProbeFsType(baseInfo.DevName()) 1005 if err != nil { 1006 return err 1007 } 1008 if err := devices.saveBaseDeviceFilesystem(fsType); err != nil { 1009 return err 1010 } 1011 } 1012 1013 // If user specified a filesystem using dm.fs option and current 1014 // file system of base image is not same, warn user that dm.fs 1015 // will be ignored. 1016 if devices.BaseDeviceFilesystem != devices.filesystem { 1017 logrus.Warnf("devmapper: Base device already exists and has filesystem %s on it. User specified filesystem %s will be ignored.", devices.BaseDeviceFilesystem, devices.filesystem) 1018 devices.filesystem = devices.BaseDeviceFilesystem 1019 } 1020 return nil 1021 } 1022 1023 func (devices *DeviceSet) saveBaseDeviceFilesystem(fs string) error { 1024 devices.BaseDeviceFilesystem = fs 1025 return devices.saveDeviceSetMetaData() 1026 } 1027 1028 func (devices *DeviceSet) saveBaseDeviceUUID(baseInfo *devInfo) error { 1029 devices.Lock() 1030 defer devices.Unlock() 1031 1032 if err := devices.activateDeviceIfNeeded(baseInfo, false); err != nil { 1033 return err 1034 } 1035 defer devices.deactivateDevice(baseInfo) 1036 1037 uuid, err := getDeviceUUID(baseInfo.DevName()) 1038 if err != nil { 1039 return err 1040 } 1041 1042 devices.BaseDeviceUUID = uuid 1043 return devices.saveDeviceSetMetaData() 1044 } 1045 1046 func (devices *DeviceSet) createBaseImage() error { 1047 logrus.Debug("devmapper: Initializing base device-mapper thin volume") 1048 1049 // Create initial device 1050 info, err := devices.createRegisterDevice("") 1051 if err != nil { 1052 return err 1053 } 1054 1055 logrus.Debug("devmapper: Creating filesystem on base device-mapper thin volume") 1056 1057 if err := devices.activateDeviceIfNeeded(info, false); err != nil { 1058 return err 1059 } 1060 1061 if err := devices.createFilesystem(info); err != nil { 1062 return err 1063 } 1064 1065 info.Initialized = true 1066 if err := devices.saveMetadata(info); err != nil { 1067 info.Initialized = false 1068 return err 1069 } 1070 1071 if err := devices.saveBaseDeviceUUID(info); err != nil { 1072 return fmt.Errorf("devmapper: Could not query and save base device UUID:%v", err) 1073 } 1074 1075 return nil 1076 } 1077 1078 // Returns if thin pool device exists or not. If device exists, also makes 1079 // sure it is a thin pool device and not some other type of device. 1080 func (devices *DeviceSet) thinPoolExists(thinPoolDevice string) (bool, error) { 1081 logrus.Debugf("devmapper: Checking for existence of the pool %s", thinPoolDevice) 1082 1083 info, err := devicemapper.GetInfo(thinPoolDevice) 1084 if err != nil { 1085 return false, fmt.Errorf("devmapper: GetInfo() on device %s failed: %v", thinPoolDevice, err) 1086 } 1087 1088 // Device does not exist. 1089 if info.Exists == 0 { 1090 return false, nil 1091 } 1092 1093 _, _, deviceType, _, err := devicemapper.GetStatus(thinPoolDevice) 1094 if err != nil { 1095 return false, fmt.Errorf("devmapper: GetStatus() on device %s failed: %v", thinPoolDevice, err) 1096 } 1097 1098 if deviceType != "thin-pool" { 1099 return false, fmt.Errorf("devmapper: Device %s is not a thin pool", thinPoolDevice) 1100 } 1101 1102 return true, nil 1103 } 1104 1105 func (devices *DeviceSet) checkThinPool() error { 1106 _, transactionID, dataUsed, _, _, _, err := devices.poolStatus() 1107 if err != nil { 1108 return err 1109 } 1110 if dataUsed != 0 { 1111 return fmt.Errorf("devmapper: Unable to take ownership of thin-pool (%s) that already has used data blocks", 1112 devices.thinPoolDevice) 1113 } 1114 if transactionID != 0 { 1115 return fmt.Errorf("devmapper: Unable to take ownership of thin-pool (%s) with non-zero transaction ID", 1116 devices.thinPoolDevice) 1117 } 1118 return nil 1119 } 1120 1121 // Base image is initialized properly. Either save UUID for first time (for 1122 // upgrade case or verify UUID. 1123 func (devices *DeviceSet) setupVerifyBaseImageUUIDFS(baseInfo *devInfo) error { 1124 // If BaseDeviceUUID is nil (upgrade case), save it and return success. 1125 if devices.BaseDeviceUUID == "" { 1126 if err := devices.saveBaseDeviceUUID(baseInfo); err != nil { 1127 return fmt.Errorf("devmapper: Could not query and save base device UUID:%v", err) 1128 } 1129 return nil 1130 } 1131 1132 if err := devices.verifyBaseDeviceUUIDFS(baseInfo); err != nil { 1133 return fmt.Errorf("devmapper: Base Device UUID and Filesystem verification failed: %v", err) 1134 } 1135 1136 return nil 1137 } 1138 1139 func (devices *DeviceSet) checkGrowBaseDeviceFS(info *devInfo) error { 1140 1141 if !userBaseSize { 1142 return nil 1143 } 1144 1145 if devices.baseFsSize < devices.getBaseDeviceSize() { 1146 return fmt.Errorf("devmapper: Base device size cannot be smaller than %s", units.HumanSize(float64(devices.getBaseDeviceSize()))) 1147 } 1148 1149 if devices.baseFsSize == devices.getBaseDeviceSize() { 1150 return nil 1151 } 1152 1153 info.lock.Lock() 1154 defer info.lock.Unlock() 1155 1156 devices.Lock() 1157 defer devices.Unlock() 1158 1159 info.Size = devices.baseFsSize 1160 1161 if err := devices.saveMetadata(info); err != nil { 1162 // Try to remove unused device 1163 delete(devices.Devices, info.Hash) 1164 return err 1165 } 1166 1167 return devices.growFS(info) 1168 } 1169 1170 func (devices *DeviceSet) growFS(info *devInfo) error { 1171 if err := devices.activateDeviceIfNeeded(info, false); err != nil { 1172 return fmt.Errorf("Error activating devmapper device: %s", err) 1173 } 1174 1175 defer devices.deactivateDevice(info) 1176 1177 fsMountPoint := "/run/docker/mnt" 1178 if _, err := os.Stat(fsMountPoint); os.IsNotExist(err) { 1179 if err := os.MkdirAll(fsMountPoint, 0700); err != nil { 1180 return err 1181 } 1182 defer os.RemoveAll(fsMountPoint) 1183 } 1184 1185 options := "" 1186 if devices.BaseDeviceFilesystem == "xfs" { 1187 // XFS needs nouuid or it can't mount filesystems with the same fs 1188 options = joinMountOptions(options, "nouuid") 1189 } 1190 options = joinMountOptions(options, devices.mountOptions) 1191 1192 if err := mount.Mount(info.DevName(), fsMountPoint, devices.BaseDeviceFilesystem, options); err != nil { 1193 return fmt.Errorf("Error mounting '%s' on '%s': %s", info.DevName(), fsMountPoint, err) 1194 } 1195 1196 defer syscall.Unmount(fsMountPoint, syscall.MNT_DETACH) 1197 1198 switch devices.BaseDeviceFilesystem { 1199 case "ext4": 1200 if out, err := exec.Command("resize2fs", info.DevName()).CombinedOutput(); err != nil { 1201 return fmt.Errorf("Failed to grow rootfs:%v:%s", err, string(out)) 1202 } 1203 case "xfs": 1204 if out, err := exec.Command("xfs_growfs", info.DevName()).CombinedOutput(); err != nil { 1205 return fmt.Errorf("Failed to grow rootfs:%v:%s", err, string(out)) 1206 } 1207 default: 1208 return fmt.Errorf("Unsupported filesystem type %s", devices.BaseDeviceFilesystem) 1209 } 1210 return nil 1211 } 1212 1213 func (devices *DeviceSet) setupBaseImage() error { 1214 oldInfo, _ := devices.lookupDeviceWithLock("") 1215 1216 // base image already exists. If it is initialized properly, do UUID 1217 // verification and return. Otherwise remove image and set it up 1218 // fresh. 1219 1220 if oldInfo != nil { 1221 if oldInfo.Initialized && !oldInfo.Deleted { 1222 if err := devices.setupVerifyBaseImageUUIDFS(oldInfo); err != nil { 1223 return err 1224 } 1225 1226 if err := devices.checkGrowBaseDeviceFS(oldInfo); err != nil { 1227 return err 1228 } 1229 1230 return nil 1231 } 1232 1233 logrus.Debug("devmapper: Removing uninitialized base image") 1234 // If previous base device is in deferred delete state, 1235 // that needs to be cleaned up first. So don't try 1236 // deferred deletion. 1237 if err := devices.DeleteDevice("", true); err != nil { 1238 return err 1239 } 1240 } 1241 1242 // If we are setting up base image for the first time, make sure 1243 // thin pool is empty. 1244 if devices.thinPoolDevice != "" && oldInfo == nil { 1245 if err := devices.checkThinPool(); err != nil { 1246 return err 1247 } 1248 } 1249 1250 // Create new base image device 1251 if err := devices.createBaseImage(); err != nil { 1252 return err 1253 } 1254 1255 return nil 1256 } 1257 1258 func setCloseOnExec(name string) { 1259 if fileInfos, _ := ioutil.ReadDir("/proc/self/fd"); fileInfos != nil { 1260 for _, i := range fileInfos { 1261 link, _ := os.Readlink(filepath.Join("/proc/self/fd", i.Name())) 1262 if link == name { 1263 fd, err := strconv.Atoi(i.Name()) 1264 if err == nil { 1265 syscall.CloseOnExec(fd) 1266 } 1267 } 1268 } 1269 } 1270 } 1271 1272 // DMLog implements logging using DevMapperLogger interface. 1273 func (devices *DeviceSet) DMLog(level int, file string, line int, dmError int, message string) { 1274 // By default libdm sends us all the messages including debug ones. 1275 // We need to filter out messages here and figure out which one 1276 // should be printed. 1277 if level > logLevel { 1278 return 1279 } 1280 1281 // FIXME(vbatts) push this back into ./pkg/devicemapper/ 1282 if level <= devicemapper.LogLevelErr { 1283 logrus.Errorf("libdevmapper(%d): %s:%d (%d) %s", level, file, line, dmError, message) 1284 } else if level <= devicemapper.LogLevelInfo { 1285 logrus.Infof("libdevmapper(%d): %s:%d (%d) %s", level, file, line, dmError, message) 1286 } else { 1287 // FIXME(vbatts) push this back into ./pkg/devicemapper/ 1288 logrus.Debugf("libdevmapper(%d): %s:%d (%d) %s", level, file, line, dmError, message) 1289 } 1290 } 1291 1292 func major(device uint64) uint64 { 1293 return (device >> 8) & 0xfff 1294 } 1295 1296 func minor(device uint64) uint64 { 1297 return (device & 0xff) | ((device >> 12) & 0xfff00) 1298 } 1299 1300 // ResizePool increases the size of the pool. 1301 func (devices *DeviceSet) ResizePool(size int64) error { 1302 dirname := devices.loopbackDir() 1303 datafilename := path.Join(dirname, "data") 1304 if len(devices.dataDevice) > 0 { 1305 datafilename = devices.dataDevice 1306 } 1307 metadatafilename := path.Join(dirname, "metadata") 1308 if len(devices.metadataDevice) > 0 { 1309 metadatafilename = devices.metadataDevice 1310 } 1311 1312 datafile, err := os.OpenFile(datafilename, os.O_RDWR, 0) 1313 if datafile == nil { 1314 return err 1315 } 1316 defer datafile.Close() 1317 1318 fi, err := datafile.Stat() 1319 if fi == nil { 1320 return err 1321 } 1322 1323 if fi.Size() > size { 1324 return fmt.Errorf("devmapper: Can't shrink file") 1325 } 1326 1327 dataloopback := loopback.FindLoopDeviceFor(datafile) 1328 if dataloopback == nil { 1329 return fmt.Errorf("devmapper: Unable to find loopback mount for: %s", datafilename) 1330 } 1331 defer dataloopback.Close() 1332 1333 metadatafile, err := os.OpenFile(metadatafilename, os.O_RDWR, 0) 1334 if metadatafile == nil { 1335 return err 1336 } 1337 defer metadatafile.Close() 1338 1339 metadataloopback := loopback.FindLoopDeviceFor(metadatafile) 1340 if metadataloopback == nil { 1341 return fmt.Errorf("devmapper: Unable to find loopback mount for: %s", metadatafilename) 1342 } 1343 defer metadataloopback.Close() 1344 1345 // Grow loopback file 1346 if err := datafile.Truncate(size); err != nil { 1347 return fmt.Errorf("devmapper: Unable to grow loopback file: %s", err) 1348 } 1349 1350 // Reload size for loopback device 1351 if err := loopback.SetCapacity(dataloopback); err != nil { 1352 return fmt.Errorf("Unable to update loopback capacity: %s", err) 1353 } 1354 1355 // Suspend the pool 1356 if err := devicemapper.SuspendDevice(devices.getPoolName()); err != nil { 1357 return fmt.Errorf("devmapper: Unable to suspend pool: %s", err) 1358 } 1359 1360 // Reload with the new block sizes 1361 if err := devicemapper.ReloadPool(devices.getPoolName(), dataloopback, metadataloopback, devices.thinpBlockSize); err != nil { 1362 return fmt.Errorf("devmapper: Unable to reload pool: %s", err) 1363 } 1364 1365 // Resume the pool 1366 if err := devicemapper.ResumeDevice(devices.getPoolName()); err != nil { 1367 return fmt.Errorf("devmapper: Unable to resume pool: %s", err) 1368 } 1369 1370 return nil 1371 } 1372 1373 func (devices *DeviceSet) loadTransactionMetaData() error { 1374 jsonData, err := ioutil.ReadFile(devices.transactionMetaFile()) 1375 if err != nil { 1376 // There is no active transaction. This will be the case 1377 // during upgrade. 1378 if os.IsNotExist(err) { 1379 devices.OpenTransactionID = devices.TransactionID 1380 return nil 1381 } 1382 return err 1383 } 1384 1385 json.Unmarshal(jsonData, &devices.transaction) 1386 return nil 1387 } 1388 1389 func (devices *DeviceSet) saveTransactionMetaData() error { 1390 jsonData, err := json.Marshal(&devices.transaction) 1391 if err != nil { 1392 return fmt.Errorf("devmapper: Error encoding metadata to json: %s", err) 1393 } 1394 1395 return devices.writeMetaFile(jsonData, devices.transactionMetaFile()) 1396 } 1397 1398 func (devices *DeviceSet) removeTransactionMetaData() error { 1399 return os.RemoveAll(devices.transactionMetaFile()) 1400 } 1401 1402 func (devices *DeviceSet) rollbackTransaction() error { 1403 logrus.Debugf("devmapper: Rolling back open transaction: TransactionID=%d hash=%s device_id=%d", devices.OpenTransactionID, devices.DeviceIDHash, devices.DeviceID) 1404 1405 // A device id might have already been deleted before transaction 1406 // closed. In that case this call will fail. Just leave a message 1407 // in case of failure. 1408 if err := devicemapper.DeleteDevice(devices.getPoolDevName(), devices.DeviceID); err != nil { 1409 logrus.Errorf("devmapper: Unable to delete device: %s", err) 1410 } 1411 1412 dinfo := &devInfo{Hash: devices.DeviceIDHash} 1413 if err := devices.removeMetadata(dinfo); err != nil { 1414 logrus.Errorf("devmapper: Unable to remove metadata: %s", err) 1415 } else { 1416 devices.markDeviceIDFree(devices.DeviceID) 1417 } 1418 1419 if err := devices.removeTransactionMetaData(); err != nil { 1420 logrus.Errorf("devmapper: Unable to remove transaction meta file %s: %s", devices.transactionMetaFile(), err) 1421 } 1422 1423 return nil 1424 } 1425 1426 func (devices *DeviceSet) processPendingTransaction() error { 1427 if err := devices.loadTransactionMetaData(); err != nil { 1428 return err 1429 } 1430 1431 // If there was open transaction but pool transaction ID is same 1432 // as open transaction ID, nothing to roll back. 1433 if devices.TransactionID == devices.OpenTransactionID { 1434 return nil 1435 } 1436 1437 // If open transaction ID is less than pool transaction ID, something 1438 // is wrong. Bail out. 1439 if devices.OpenTransactionID < devices.TransactionID { 1440 logrus.Errorf("devmapper: Open Transaction id %d is less than pool transaction id %d", devices.OpenTransactionID, devices.TransactionID) 1441 return nil 1442 } 1443 1444 // Pool transaction ID is not same as open transaction. There is 1445 // a transaction which was not completed. 1446 if err := devices.rollbackTransaction(); err != nil { 1447 return fmt.Errorf("devmapper: Rolling back open transaction failed: %s", err) 1448 } 1449 1450 devices.OpenTransactionID = devices.TransactionID 1451 return nil 1452 } 1453 1454 func (devices *DeviceSet) loadDeviceSetMetaData() error { 1455 jsonData, err := ioutil.ReadFile(devices.deviceSetMetaFile()) 1456 if err != nil { 1457 // For backward compatibility return success if file does 1458 // not exist. 1459 if os.IsNotExist(err) { 1460 return nil 1461 } 1462 return err 1463 } 1464 1465 return json.Unmarshal(jsonData, devices) 1466 } 1467 1468 func (devices *DeviceSet) saveDeviceSetMetaData() error { 1469 jsonData, err := json.Marshal(devices) 1470 if err != nil { 1471 return fmt.Errorf("devmapper: Error encoding metadata to json: %s", err) 1472 } 1473 1474 return devices.writeMetaFile(jsonData, devices.deviceSetMetaFile()) 1475 } 1476 1477 func (devices *DeviceSet) openTransaction(hash string, DeviceID int) error { 1478 devices.allocateTransactionID() 1479 devices.DeviceIDHash = hash 1480 devices.DeviceID = DeviceID 1481 if err := devices.saveTransactionMetaData(); err != nil { 1482 return fmt.Errorf("devmapper: Error saving transaction metadata: %s", err) 1483 } 1484 return nil 1485 } 1486 1487 func (devices *DeviceSet) refreshTransaction(DeviceID int) error { 1488 devices.DeviceID = DeviceID 1489 if err := devices.saveTransactionMetaData(); err != nil { 1490 return fmt.Errorf("devmapper: Error saving transaction metadata: %s", err) 1491 } 1492 return nil 1493 } 1494 1495 func (devices *DeviceSet) closeTransaction() error { 1496 if err := devices.updatePoolTransactionID(); err != nil { 1497 logrus.Debug("devmapper: Failed to close Transaction") 1498 return err 1499 } 1500 return nil 1501 } 1502 1503 func determineDriverCapabilities(version string) error { 1504 /* 1505 * Driver version 4.27.0 and greater support deferred activation 1506 * feature. 1507 */ 1508 1509 logrus.Debugf("devicemapper: driver version is %s", version) 1510 1511 versionSplit := strings.Split(version, ".") 1512 major, err := strconv.Atoi(versionSplit[0]) 1513 if err != nil { 1514 return graphdriver.ErrNotSupported 1515 } 1516 1517 if major > 4 { 1518 driverDeferredRemovalSupport = true 1519 return nil 1520 } 1521 1522 if major < 4 { 1523 return nil 1524 } 1525 1526 minor, err := strconv.Atoi(versionSplit[1]) 1527 if err != nil { 1528 return graphdriver.ErrNotSupported 1529 } 1530 1531 /* 1532 * If major is 4 and minor is 27, then there is no need to 1533 * check for patch level as it can not be less than 0. 1534 */ 1535 if minor >= 27 { 1536 driverDeferredRemovalSupport = true 1537 return nil 1538 } 1539 1540 return nil 1541 } 1542 1543 // Determine the major and minor number of loopback device 1544 func getDeviceMajorMinor(file *os.File) (uint64, uint64, error) { 1545 stat, err := file.Stat() 1546 if err != nil { 1547 return 0, 0, err 1548 } 1549 1550 dev := stat.Sys().(*syscall.Stat_t).Rdev 1551 majorNum := major(dev) 1552 minorNum := minor(dev) 1553 1554 logrus.Debugf("devmapper: Major:Minor for device: %s is:%v:%v", file.Name(), majorNum, minorNum) 1555 return majorNum, minorNum, nil 1556 } 1557 1558 // Given a file which is backing file of a loop back device, find the 1559 // loopback device name and its major/minor number. 1560 func getLoopFileDeviceMajMin(filename string) (string, uint64, uint64, error) { 1561 file, err := os.Open(filename) 1562 if err != nil { 1563 logrus.Debugf("devmapper: Failed to open file %s", filename) 1564 return "", 0, 0, err 1565 } 1566 1567 defer file.Close() 1568 loopbackDevice := loopback.FindLoopDeviceFor(file) 1569 if loopbackDevice == nil { 1570 return "", 0, 0, fmt.Errorf("devmapper: Unable to find loopback mount for: %s", filename) 1571 } 1572 defer loopbackDevice.Close() 1573 1574 Major, Minor, err := getDeviceMajorMinor(loopbackDevice) 1575 if err != nil { 1576 return "", 0, 0, err 1577 } 1578 return loopbackDevice.Name(), Major, Minor, nil 1579 } 1580 1581 // Get the major/minor numbers of thin pool data and metadata devices 1582 func (devices *DeviceSet) getThinPoolDataMetaMajMin() (uint64, uint64, uint64, uint64, error) { 1583 var params, poolDataMajMin, poolMetadataMajMin string 1584 1585 _, _, _, params, err := devicemapper.GetTable(devices.getPoolName()) 1586 if err != nil { 1587 return 0, 0, 0, 0, err 1588 } 1589 1590 if _, err = fmt.Sscanf(params, "%s %s", &poolMetadataMajMin, &poolDataMajMin); err != nil { 1591 return 0, 0, 0, 0, err 1592 } 1593 1594 logrus.Debugf("devmapper: poolDataMajMin=%s poolMetaMajMin=%s\n", poolDataMajMin, poolMetadataMajMin) 1595 1596 poolDataMajMinorSplit := strings.Split(poolDataMajMin, ":") 1597 poolDataMajor, err := strconv.ParseUint(poolDataMajMinorSplit[0], 10, 32) 1598 if err != nil { 1599 return 0, 0, 0, 0, err 1600 } 1601 1602 poolDataMinor, err := strconv.ParseUint(poolDataMajMinorSplit[1], 10, 32) 1603 if err != nil { 1604 return 0, 0, 0, 0, err 1605 } 1606 1607 poolMetadataMajMinorSplit := strings.Split(poolMetadataMajMin, ":") 1608 poolMetadataMajor, err := strconv.ParseUint(poolMetadataMajMinorSplit[0], 10, 32) 1609 if err != nil { 1610 return 0, 0, 0, 0, err 1611 } 1612 1613 poolMetadataMinor, err := strconv.ParseUint(poolMetadataMajMinorSplit[1], 10, 32) 1614 if err != nil { 1615 return 0, 0, 0, 0, err 1616 } 1617 1618 return poolDataMajor, poolDataMinor, poolMetadataMajor, poolMetadataMinor, nil 1619 } 1620 1621 func (devices *DeviceSet) loadThinPoolLoopBackInfo() error { 1622 poolDataMajor, poolDataMinor, poolMetadataMajor, poolMetadataMinor, err := devices.getThinPoolDataMetaMajMin() 1623 if err != nil { 1624 return err 1625 } 1626 1627 dirname := devices.loopbackDir() 1628 1629 // data device has not been passed in. So there should be a data file 1630 // which is being mounted as loop device. 1631 if devices.dataDevice == "" { 1632 datafilename := path.Join(dirname, "data") 1633 dataLoopDevice, dataMajor, dataMinor, err := getLoopFileDeviceMajMin(datafilename) 1634 if err != nil { 1635 return err 1636 } 1637 1638 // Compare the two 1639 if poolDataMajor == dataMajor && poolDataMinor == dataMinor { 1640 devices.dataDevice = dataLoopDevice 1641 devices.dataLoopFile = datafilename 1642 } 1643 1644 } 1645 1646 // metadata device has not been passed in. So there should be a 1647 // metadata file which is being mounted as loop device. 1648 if devices.metadataDevice == "" { 1649 metadatafilename := path.Join(dirname, "metadata") 1650 metadataLoopDevice, metadataMajor, metadataMinor, err := getLoopFileDeviceMajMin(metadatafilename) 1651 if err != nil { 1652 return err 1653 } 1654 if poolMetadataMajor == metadataMajor && poolMetadataMinor == metadataMinor { 1655 devices.metadataDevice = metadataLoopDevice 1656 devices.metadataLoopFile = metadatafilename 1657 } 1658 } 1659 1660 return nil 1661 } 1662 1663 func (devices *DeviceSet) enableDeferredRemovalDeletion() error { 1664 1665 // If user asked for deferred removal then check both libdm library 1666 // and kernel driver support deferred removal otherwise error out. 1667 if enableDeferredRemoval { 1668 if !driverDeferredRemovalSupport { 1669 return fmt.Errorf("devmapper: Deferred removal can not be enabled as kernel does not support it") 1670 } 1671 if !devicemapper.LibraryDeferredRemovalSupport { 1672 return fmt.Errorf("devmapper: Deferred removal can not be enabled as libdm does not support it") 1673 } 1674 logrus.Debug("devmapper: Deferred removal support enabled.") 1675 devices.deferredRemove = true 1676 } 1677 1678 if enableDeferredDeletion { 1679 if !devices.deferredRemove { 1680 return fmt.Errorf("devmapper: Deferred deletion can not be enabled as deferred removal is not enabled. Enable deferred removal using --storage-opt dm.use_deferred_removal=true parameter") 1681 } 1682 logrus.Debug("devmapper: Deferred deletion support enabled.") 1683 devices.deferredDelete = true 1684 } 1685 return nil 1686 } 1687 1688 func (devices *DeviceSet) initDevmapper(doInit bool) error { 1689 // give ourselves to libdm as a log handler 1690 devicemapper.LogInit(devices) 1691 1692 version, err := devicemapper.GetDriverVersion() 1693 if err != nil { 1694 // Can't even get driver version, assume not supported 1695 return graphdriver.ErrNotSupported 1696 } 1697 1698 if err := determineDriverCapabilities(version); err != nil { 1699 return graphdriver.ErrNotSupported 1700 } 1701 1702 if err := devices.enableDeferredRemovalDeletion(); err != nil { 1703 return err 1704 } 1705 1706 // https://github.com/docker/docker/issues/4036 1707 if supported := devicemapper.UdevSetSyncSupport(true); !supported { 1708 if dockerversion.IAmStatic == "true" { 1709 logrus.Error("devmapper: Udev sync is not supported. This will lead to data loss and unexpected behavior. Install a dynamic binary to use devicemapper or select a different storage driver. For more information, see https://docs.docker.com/engine/reference/commandline/dockerd/#storage-driver-options") 1710 } else { 1711 logrus.Error("devmapper: Udev sync is not supported. This will lead to data loss and unexpected behavior. Install a more recent version of libdevmapper or select a different storage driver. For more information, see https://docs.docker.com/engine/reference/commandline/dockerd/#storage-driver-options") 1712 } 1713 1714 if !devices.overrideUdevSyncCheck { 1715 return graphdriver.ErrNotSupported 1716 } 1717 } 1718 1719 //create the root dir of the devmapper driver ownership to match this 1720 //daemon's remapped root uid/gid so containers can start properly 1721 uid, gid, err := idtools.GetRootUIDGID(devices.uidMaps, devices.gidMaps) 1722 if err != nil { 1723 return err 1724 } 1725 if err := idtools.MkdirAs(devices.root, 0700, uid, gid); err != nil && !os.IsExist(err) { 1726 return err 1727 } 1728 if err := os.MkdirAll(devices.metadataDir(), 0700); err != nil && !os.IsExist(err) { 1729 return err 1730 } 1731 1732 // Set the device prefix from the device id and inode of the docker root dir 1733 1734 st, err := os.Stat(devices.root) 1735 if err != nil { 1736 return fmt.Errorf("devmapper: Error looking up dir %s: %s", devices.root, err) 1737 } 1738 sysSt := st.Sys().(*syscall.Stat_t) 1739 // "reg-" stands for "regular file". 1740 // In the future we might use "dev-" for "device file", etc. 1741 // docker-maj,min[-inode] stands for: 1742 // - Managed by docker 1743 // - The target of this device is at major <maj> and minor <min> 1744 // - If <inode> is defined, use that file inside the device as a loopback image. Otherwise use the device itself. 1745 devices.devicePrefix = fmt.Sprintf("docker-%d:%d-%d", major(sysSt.Dev), minor(sysSt.Dev), sysSt.Ino) 1746 logrus.Debugf("devmapper: Generated prefix: %s", devices.devicePrefix) 1747 1748 // Check for the existence of the thin-pool device 1749 poolExists, err := devices.thinPoolExists(devices.getPoolName()) 1750 if err != nil { 1751 return err 1752 } 1753 1754 // It seems libdevmapper opens this without O_CLOEXEC, and go exec will not close files 1755 // that are not Close-on-exec, 1756 // so we add this badhack to make sure it closes itself 1757 setCloseOnExec("/dev/mapper/control") 1758 1759 // Make sure the sparse images exist in <root>/devicemapper/data and 1760 // <root>/devicemapper/metadata 1761 1762 createdLoopback := false 1763 1764 // If the pool doesn't exist, create it 1765 if !poolExists && devices.thinPoolDevice == "" { 1766 logrus.Debug("devmapper: Pool doesn't exist. Creating it.") 1767 1768 var ( 1769 dataFile *os.File 1770 metadataFile *os.File 1771 ) 1772 1773 if devices.dataDevice == "" { 1774 // Make sure the sparse images exist in <root>/devicemapper/data 1775 1776 hasData := devices.hasImage("data") 1777 1778 if !doInit && !hasData { 1779 return errors.New("loopback data file not found") 1780 } 1781 1782 if !hasData { 1783 createdLoopback = true 1784 } 1785 1786 data, err := devices.ensureImage("data", devices.dataLoopbackSize) 1787 if err != nil { 1788 logrus.Debugf("devmapper: Error device ensureImage (data): %s", err) 1789 return err 1790 } 1791 1792 dataFile, err = loopback.AttachLoopDevice(data) 1793 if err != nil { 1794 return err 1795 } 1796 devices.dataLoopFile = data 1797 devices.dataDevice = dataFile.Name() 1798 } else { 1799 dataFile, err = os.OpenFile(devices.dataDevice, os.O_RDWR, 0600) 1800 if err != nil { 1801 return err 1802 } 1803 } 1804 defer dataFile.Close() 1805 1806 if devices.metadataDevice == "" { 1807 // Make sure the sparse images exist in <root>/devicemapper/metadata 1808 1809 hasMetadata := devices.hasImage("metadata") 1810 1811 if !doInit && !hasMetadata { 1812 return errors.New("loopback metadata file not found") 1813 } 1814 1815 if !hasMetadata { 1816 createdLoopback = true 1817 } 1818 1819 metadata, err := devices.ensureImage("metadata", devices.metaDataLoopbackSize) 1820 if err != nil { 1821 logrus.Debugf("devmapper: Error device ensureImage (metadata): %s", err) 1822 return err 1823 } 1824 1825 metadataFile, err = loopback.AttachLoopDevice(metadata) 1826 if err != nil { 1827 return err 1828 } 1829 devices.metadataLoopFile = metadata 1830 devices.metadataDevice = metadataFile.Name() 1831 } else { 1832 metadataFile, err = os.OpenFile(devices.metadataDevice, os.O_RDWR, 0600) 1833 if err != nil { 1834 return err 1835 } 1836 } 1837 defer metadataFile.Close() 1838 1839 if err := devicemapper.CreatePool(devices.getPoolName(), dataFile, metadataFile, devices.thinpBlockSize); err != nil { 1840 return err 1841 } 1842 } 1843 1844 // Pool already exists and caller did not pass us a pool. That means 1845 // we probably created pool earlier and could not remove it as some 1846 // containers were still using it. Detect some of the properties of 1847 // pool, like is it using loop devices. 1848 if poolExists && devices.thinPoolDevice == "" { 1849 if err := devices.loadThinPoolLoopBackInfo(); err != nil { 1850 logrus.Debugf("devmapper: Failed to load thin pool loopback device information:%v", err) 1851 return err 1852 } 1853 } 1854 1855 // If we didn't just create the data or metadata image, we need to 1856 // load the transaction id and migrate old metadata 1857 if !createdLoopback { 1858 if err := devices.initMetaData(); err != nil { 1859 return err 1860 } 1861 } 1862 1863 if devices.thinPoolDevice == "" { 1864 if devices.metadataLoopFile != "" || devices.dataLoopFile != "" { 1865 logrus.Warn("devmapper: Usage of loopback devices is strongly discouraged for production use. Please use `--storage-opt dm.thinpooldev` or use `man docker` to refer to dm.thinpooldev section.") 1866 } 1867 } 1868 1869 // Right now this loads only NextDeviceID. If there is more metadata 1870 // down the line, we might have to move it earlier. 1871 if err := devices.loadDeviceSetMetaData(); err != nil { 1872 return err 1873 } 1874 1875 // Setup the base image 1876 if doInit { 1877 if err := devices.setupBaseImage(); err != nil { 1878 logrus.Debugf("devmapper: Error device setupBaseImage: %s", err) 1879 return err 1880 } 1881 } 1882 1883 return nil 1884 } 1885 1886 // AddDevice adds a device and registers in the hash. 1887 func (devices *DeviceSet) AddDevice(hash, baseHash string, storageOpt map[string]string) error { 1888 logrus.Debugf("devmapper: AddDevice START(hash=%s basehash=%s)", hash, baseHash) 1889 defer logrus.Debugf("devmapper: AddDevice END(hash=%s basehash=%s)", hash, baseHash) 1890 1891 // If a deleted device exists, return error. 1892 baseInfo, err := devices.lookupDeviceWithLock(baseHash) 1893 if err != nil { 1894 return err 1895 } 1896 1897 if baseInfo.Deleted { 1898 return fmt.Errorf("devmapper: Base device %v has been marked for deferred deletion", baseInfo.Hash) 1899 } 1900 1901 baseInfo.lock.Lock() 1902 defer baseInfo.lock.Unlock() 1903 1904 devices.Lock() 1905 defer devices.Unlock() 1906 1907 // Also include deleted devices in case hash of new device is 1908 // same as one of the deleted devices. 1909 if info, _ := devices.lookupDevice(hash); info != nil { 1910 return fmt.Errorf("devmapper: device %s already exists. Deleted=%v", hash, info.Deleted) 1911 } 1912 1913 size, err := devices.parseStorageOpt(storageOpt) 1914 if err != nil { 1915 return err 1916 } 1917 1918 if size == 0 { 1919 size = baseInfo.Size 1920 } 1921 1922 if size < baseInfo.Size { 1923 return fmt.Errorf("devmapper: Container size cannot be smaller than %s", units.HumanSize(float64(baseInfo.Size))) 1924 } 1925 1926 if err := devices.takeSnapshot(hash, baseInfo, size); err != nil { 1927 return err 1928 } 1929 1930 // Grow the container rootfs. 1931 if size > baseInfo.Size { 1932 info, err := devices.lookupDevice(hash) 1933 if err != nil { 1934 return err 1935 } 1936 1937 if err := devices.growFS(info); err != nil { 1938 return err 1939 } 1940 } 1941 1942 return nil 1943 } 1944 1945 func (devices *DeviceSet) parseStorageOpt(storageOpt map[string]string) (uint64, error) { 1946 1947 // Read size to change the block device size per container. 1948 for key, val := range storageOpt { 1949 key := strings.ToLower(key) 1950 switch key { 1951 case "size": 1952 size, err := units.RAMInBytes(val) 1953 if err != nil { 1954 return 0, err 1955 } 1956 return uint64(size), nil 1957 default: 1958 return 0, fmt.Errorf("Unknown option %s", key) 1959 } 1960 } 1961 1962 return 0, nil 1963 } 1964 1965 func (devices *DeviceSet) markForDeferredDeletion(info *devInfo) error { 1966 // If device is already in deleted state, there is nothing to be done. 1967 if info.Deleted { 1968 return nil 1969 } 1970 1971 logrus.Debugf("devmapper: Marking device %s for deferred deletion.", info.Hash) 1972 1973 info.Deleted = true 1974 1975 // save device metadata to reflect deleted state. 1976 if err := devices.saveMetadata(info); err != nil { 1977 info.Deleted = false 1978 return err 1979 } 1980 1981 devices.nrDeletedDevices++ 1982 return nil 1983 } 1984 1985 // Should be called with devices.Lock() held. 1986 func (devices *DeviceSet) deleteTransaction(info *devInfo, syncDelete bool) error { 1987 if err := devices.openTransaction(info.Hash, info.DeviceID); err != nil { 1988 logrus.Debugf("devmapper: Error opening transaction hash = %s deviceId = %d", "", info.DeviceID) 1989 return err 1990 } 1991 1992 defer devices.closeTransaction() 1993 1994 err := devicemapper.DeleteDevice(devices.getPoolDevName(), info.DeviceID) 1995 if err != nil { 1996 // If syncDelete is true, we want to return error. If deferred 1997 // deletion is not enabled, we return an error. If error is 1998 // something other then EBUSY, return an error. 1999 if syncDelete || !devices.deferredDelete || err != devicemapper.ErrBusy { 2000 logrus.Debugf("devmapper: Error deleting device: %s", err) 2001 return err 2002 } 2003 } 2004 2005 if err == nil { 2006 if err := devices.unregisterDevice(info.Hash); err != nil { 2007 return err 2008 } 2009 // If device was already in deferred delete state that means 2010 // deletion was being tried again later. Reduce the deleted 2011 // device count. 2012 if info.Deleted { 2013 devices.nrDeletedDevices-- 2014 } 2015 devices.markDeviceIDFree(info.DeviceID) 2016 } else { 2017 if err := devices.markForDeferredDeletion(info); err != nil { 2018 return err 2019 } 2020 } 2021 2022 return nil 2023 } 2024 2025 // Issue discard only if device open count is zero. 2026 func (devices *DeviceSet) issueDiscard(info *devInfo) error { 2027 logrus.Debugf("devmapper: issueDiscard START(device: %s).", info.Hash) 2028 defer logrus.Debugf("devmapper: issueDiscard END(device: %s).", info.Hash) 2029 // This is a workaround for the kernel not discarding block so 2030 // on the thin pool when we remove a thinp device, so we do it 2031 // manually. 2032 // Even if device is deferred deleted, activate it and issue 2033 // discards. 2034 if err := devices.activateDeviceIfNeeded(info, true); err != nil { 2035 return err 2036 } 2037 2038 devinfo, err := devicemapper.GetInfo(info.Name()) 2039 if err != nil { 2040 return err 2041 } 2042 2043 if devinfo.OpenCount != 0 { 2044 logrus.Debugf("devmapper: Device: %s is in use. OpenCount=%d. Not issuing discards.", info.Hash, devinfo.OpenCount) 2045 return nil 2046 } 2047 2048 if err := devicemapper.BlockDeviceDiscard(info.DevName()); err != nil { 2049 logrus.Debugf("devmapper: Error discarding block on device: %s (ignoring)", err) 2050 } 2051 return nil 2052 } 2053 2054 // Should be called with devices.Lock() held. 2055 func (devices *DeviceSet) deleteDevice(info *devInfo, syncDelete bool) error { 2056 if devices.doBlkDiscard { 2057 devices.issueDiscard(info) 2058 } 2059 2060 // Try to deactivate device in case it is active. 2061 if err := devices.deactivateDevice(info); err != nil { 2062 logrus.Debugf("devmapper: Error deactivating device: %s", err) 2063 return err 2064 } 2065 2066 if err := devices.deleteTransaction(info, syncDelete); err != nil { 2067 return err 2068 } 2069 2070 return nil 2071 } 2072 2073 // DeleteDevice will return success if device has been marked for deferred 2074 // removal. If one wants to override that and want DeleteDevice() to fail if 2075 // device was busy and could not be deleted, set syncDelete=true. 2076 func (devices *DeviceSet) DeleteDevice(hash string, syncDelete bool) error { 2077 logrus.Debugf("devmapper: DeleteDevice START(hash=%v syncDelete=%v)", hash, syncDelete) 2078 defer logrus.Debugf("devmapper: DeleteDevice END(hash=%v syncDelete=%v)", hash, syncDelete) 2079 info, err := devices.lookupDeviceWithLock(hash) 2080 if err != nil { 2081 return err 2082 } 2083 2084 info.lock.Lock() 2085 defer info.lock.Unlock() 2086 2087 devices.Lock() 2088 defer devices.Unlock() 2089 2090 return devices.deleteDevice(info, syncDelete) 2091 } 2092 2093 func (devices *DeviceSet) deactivatePool() error { 2094 logrus.Debug("devmapper: deactivatePool() START") 2095 defer logrus.Debug("devmapper: deactivatePool() END") 2096 devname := devices.getPoolDevName() 2097 2098 devinfo, err := devicemapper.GetInfo(devname) 2099 if err != nil { 2100 return err 2101 } 2102 2103 if devinfo.Exists == 0 { 2104 return nil 2105 } 2106 if err := devicemapper.RemoveDevice(devname); err != nil { 2107 return err 2108 } 2109 2110 if d, err := devicemapper.GetDeps(devname); err == nil { 2111 logrus.Warnf("devmapper: device %s still has %d active dependents", devname, d.Count) 2112 } 2113 2114 return nil 2115 } 2116 2117 func (devices *DeviceSet) deactivateDevice(info *devInfo) error { 2118 logrus.Debugf("devmapper: deactivateDevice START(%s)", info.Hash) 2119 defer logrus.Debugf("devmapper: deactivateDevice END(%s)", info.Hash) 2120 2121 devinfo, err := devicemapper.GetInfo(info.Name()) 2122 if err != nil { 2123 return err 2124 } 2125 2126 if devinfo.Exists == 0 { 2127 return nil 2128 } 2129 2130 if devices.deferredRemove { 2131 if err := devicemapper.RemoveDeviceDeferred(info.Name()); err != nil { 2132 return err 2133 } 2134 } else { 2135 if err := devices.removeDevice(info.Name()); err != nil { 2136 return err 2137 } 2138 } 2139 return nil 2140 } 2141 2142 // Issues the underlying dm remove operation. 2143 func (devices *DeviceSet) removeDevice(devname string) error { 2144 var err error 2145 2146 logrus.Debugf("devmapper: removeDevice START(%s)", devname) 2147 defer logrus.Debugf("devmapper: removeDevice END(%s)", devname) 2148 2149 for i := 0; i < 200; i++ { 2150 err = devicemapper.RemoveDevice(devname) 2151 if err == nil { 2152 break 2153 } 2154 if err != devicemapper.ErrBusy { 2155 return err 2156 } 2157 2158 // If we see EBUSY it may be a transient error, 2159 // sleep a bit a retry a few times. 2160 devices.Unlock() 2161 time.Sleep(100 * time.Millisecond) 2162 devices.Lock() 2163 } 2164 2165 return err 2166 } 2167 2168 func (devices *DeviceSet) cancelDeferredRemovalIfNeeded(info *devInfo) error { 2169 if !devices.deferredRemove { 2170 return nil 2171 } 2172 2173 logrus.Debugf("devmapper: cancelDeferredRemovalIfNeeded START(%s)", info.Name()) 2174 defer logrus.Debugf("devmapper: cancelDeferredRemovalIfNeeded END(%s)", info.Name()) 2175 2176 devinfo, err := devicemapper.GetInfoWithDeferred(info.Name()) 2177 if err != nil { 2178 return err 2179 } 2180 2181 if devinfo != nil && devinfo.DeferredRemove == 0 { 2182 return nil 2183 } 2184 2185 // Cancel deferred remove 2186 if err := devices.cancelDeferredRemoval(info); err != nil { 2187 // If Error is ErrEnxio. Device is probably already gone. Continue. 2188 if err != devicemapper.ErrEnxio { 2189 return err 2190 } 2191 } 2192 return nil 2193 } 2194 2195 func (devices *DeviceSet) cancelDeferredRemoval(info *devInfo) error { 2196 logrus.Debugf("devmapper: cancelDeferredRemoval START(%s)", info.Name()) 2197 defer logrus.Debugf("devmapper: cancelDeferredRemoval END(%s)", info.Name()) 2198 2199 var err error 2200 2201 // Cancel deferred remove 2202 for i := 0; i < 100; i++ { 2203 err = devicemapper.CancelDeferredRemove(info.Name()) 2204 if err != nil { 2205 if err == devicemapper.ErrBusy { 2206 // If we see EBUSY it may be a transient error, 2207 // sleep a bit a retry a few times. 2208 devices.Unlock() 2209 time.Sleep(100 * time.Millisecond) 2210 devices.Lock() 2211 continue 2212 } 2213 } 2214 break 2215 } 2216 return err 2217 } 2218 2219 // Shutdown shuts down the device by unmounting the root. 2220 func (devices *DeviceSet) Shutdown(home string) error { 2221 logrus.Debugf("devmapper: [deviceset %s] Shutdown()", devices.devicePrefix) 2222 logrus.Debugf("devmapper: Shutting down DeviceSet: %s", devices.root) 2223 defer logrus.Debugf("devmapper: [deviceset %s] Shutdown() END", devices.devicePrefix) 2224 2225 // Stop deletion worker. This should start delivering new events to 2226 // ticker channel. That means no new instance of cleanupDeletedDevice() 2227 // will run after this call. If one instance is already running at 2228 // the time of the call, it must be holding devices.Lock() and 2229 // we will block on this lock till cleanup function exits. 2230 devices.deletionWorkerTicker.Stop() 2231 2232 devices.Lock() 2233 // Save DeviceSet Metadata first. Docker kills all threads if they 2234 // don't finish in certain time. It is possible that Shutdown() 2235 // routine does not finish in time as we loop trying to deactivate 2236 // some devices while these are busy. In that case shutdown() routine 2237 // will be killed and we will not get a chance to save deviceset 2238 // metadata. Hence save this early before trying to deactivate devices. 2239 devices.saveDeviceSetMetaData() 2240 2241 // ignore the error since it's just a best effort to not try to unmount something that's mounted 2242 mounts, _ := mount.GetMounts() 2243 mounted := make(map[string]bool, len(mounts)) 2244 for _, mnt := range mounts { 2245 mounted[mnt.Mountpoint] = true 2246 } 2247 2248 if err := filepath.Walk(path.Join(home, "mnt"), func(p string, info os.FileInfo, err error) error { 2249 if err != nil { 2250 return err 2251 } 2252 if !info.IsDir() { 2253 return nil 2254 } 2255 2256 if mounted[p] { 2257 // We use MNT_DETACH here in case it is still busy in some running 2258 // container. This means it'll go away from the global scope directly, 2259 // and the device will be released when that container dies. 2260 if err := syscall.Unmount(p, syscall.MNT_DETACH); err != nil { 2261 logrus.Debugf("devmapper: Shutdown unmounting %s, error: %s", p, err) 2262 } 2263 } 2264 2265 if devInfo, err := devices.lookupDevice(path.Base(p)); err != nil { 2266 logrus.Debugf("devmapper: Shutdown lookup device %s, error: %s", path.Base(p), err) 2267 } else { 2268 if err := devices.deactivateDevice(devInfo); err != nil { 2269 logrus.Debugf("devmapper: Shutdown deactivate %s , error: %s", devInfo.Hash, err) 2270 } 2271 } 2272 2273 return nil 2274 }); err != nil && !os.IsNotExist(err) { 2275 devices.Unlock() 2276 return err 2277 } 2278 2279 devices.Unlock() 2280 2281 info, _ := devices.lookupDeviceWithLock("") 2282 if info != nil { 2283 info.lock.Lock() 2284 devices.Lock() 2285 if err := devices.deactivateDevice(info); err != nil { 2286 logrus.Debugf("devmapper: Shutdown deactivate base , error: %s", err) 2287 } 2288 devices.Unlock() 2289 info.lock.Unlock() 2290 } 2291 2292 devices.Lock() 2293 if devices.thinPoolDevice == "" { 2294 if err := devices.deactivatePool(); err != nil { 2295 logrus.Debugf("devmapper: Shutdown deactivate pool , error: %s", err) 2296 } 2297 } 2298 devices.Unlock() 2299 2300 return nil 2301 } 2302 2303 // Recent XFS changes allow changing behavior of filesystem in case of errors. 2304 // When thin pool gets full and XFS gets ENOSPC error, currently it tries 2305 // IO infinitely and sometimes it can block the container process 2306 // and process can't be killWith 0 value, XFS will not retry upon error 2307 // and instead will shutdown filesystem. 2308 2309 func (devices *DeviceSet) xfsSetNospaceRetries(info *devInfo) error { 2310 dmDevicePath, err := os.Readlink(info.DevName()) 2311 if err != nil { 2312 return fmt.Errorf("devmapper: readlink failed for device %v:%v", info.DevName(), err) 2313 } 2314 2315 dmDeviceName := path.Base(dmDevicePath) 2316 filePath := "/sys/fs/xfs/" + dmDeviceName + "/error/metadata/ENOSPC/max_retries" 2317 maxRetriesFile, err := os.OpenFile(filePath, os.O_WRONLY, 0) 2318 if err != nil { 2319 return fmt.Errorf("devmapper: user specified daemon option dm.xfs_nospace_max_retries but it does not seem to be supported on this system :%v", err) 2320 } 2321 defer maxRetriesFile.Close() 2322 2323 // Set max retries to 0 2324 _, err = maxRetriesFile.WriteString(devices.xfsNospaceRetries) 2325 if err != nil { 2326 return fmt.Errorf("devmapper: Failed to write string %v to file %v:%v", devices.xfsNospaceRetries, filePath, err) 2327 } 2328 return nil 2329 } 2330 2331 // MountDevice mounts the device if not already mounted. 2332 func (devices *DeviceSet) MountDevice(hash, path, mountLabel string) error { 2333 info, err := devices.lookupDeviceWithLock(hash) 2334 if err != nil { 2335 return err 2336 } 2337 2338 if info.Deleted { 2339 return fmt.Errorf("devmapper: Can't mount device %v as it has been marked for deferred deletion", info.Hash) 2340 } 2341 2342 info.lock.Lock() 2343 defer info.lock.Unlock() 2344 2345 devices.Lock() 2346 defer devices.Unlock() 2347 2348 if err := devices.activateDeviceIfNeeded(info, false); err != nil { 2349 return fmt.Errorf("devmapper: Error activating devmapper device for '%s': %s", hash, err) 2350 } 2351 2352 fstype, err := ProbeFsType(info.DevName()) 2353 if err != nil { 2354 return err 2355 } 2356 2357 options := "" 2358 2359 if fstype == "xfs" { 2360 // XFS needs nouuid or it can't mount filesystems with the same fs 2361 options = joinMountOptions(options, "nouuid") 2362 } 2363 2364 options = joinMountOptions(options, devices.mountOptions) 2365 options = joinMountOptions(options, label.FormatMountLabel("", mountLabel)) 2366 2367 if err := mount.Mount(info.DevName(), path, fstype, options); err != nil { 2368 return fmt.Errorf("devmapper: Error mounting '%s' on '%s': %s", info.DevName(), path, err) 2369 } 2370 2371 if fstype == "xfs" && devices.xfsNospaceRetries != "" { 2372 if err := devices.xfsSetNospaceRetries(info); err != nil { 2373 syscall.Unmount(path, syscall.MNT_DETACH) 2374 devices.deactivateDevice(info) 2375 return err 2376 } 2377 } 2378 2379 return nil 2380 } 2381 2382 // UnmountDevice unmounts the device and removes it from hash. 2383 func (devices *DeviceSet) UnmountDevice(hash, mountPath string) error { 2384 logrus.Debugf("devmapper: UnmountDevice START(hash=%s)", hash) 2385 defer logrus.Debugf("devmapper: UnmountDevice END(hash=%s)", hash) 2386 2387 info, err := devices.lookupDeviceWithLock(hash) 2388 if err != nil { 2389 return err 2390 } 2391 2392 info.lock.Lock() 2393 defer info.lock.Unlock() 2394 2395 devices.Lock() 2396 defer devices.Unlock() 2397 2398 logrus.Debugf("devmapper: Unmount(%s)", mountPath) 2399 if err := syscall.Unmount(mountPath, syscall.MNT_DETACH); err != nil { 2400 return err 2401 } 2402 logrus.Debug("devmapper: Unmount done") 2403 2404 return devices.deactivateDevice(info) 2405 } 2406 2407 // HasDevice returns true if the device metadata exists. 2408 func (devices *DeviceSet) HasDevice(hash string) bool { 2409 info, _ := devices.lookupDeviceWithLock(hash) 2410 return info != nil 2411 } 2412 2413 // List returns a list of device ids. 2414 func (devices *DeviceSet) List() []string { 2415 devices.Lock() 2416 defer devices.Unlock() 2417 2418 ids := make([]string, len(devices.Devices)) 2419 i := 0 2420 for k := range devices.Devices { 2421 ids[i] = k 2422 i++ 2423 } 2424 return ids 2425 } 2426 2427 func (devices *DeviceSet) deviceStatus(devName string) (sizeInSectors, mappedSectors, highestMappedSector uint64, err error) { 2428 var params string 2429 _, sizeInSectors, _, params, err = devicemapper.GetStatus(devName) 2430 if err != nil { 2431 return 2432 } 2433 if _, err = fmt.Sscanf(params, "%d %d", &mappedSectors, &highestMappedSector); err == nil { 2434 return 2435 } 2436 return 2437 } 2438 2439 // GetDeviceStatus provides size, mapped sectors 2440 func (devices *DeviceSet) GetDeviceStatus(hash string) (*DevStatus, error) { 2441 info, err := devices.lookupDeviceWithLock(hash) 2442 if err != nil { 2443 return nil, err 2444 } 2445 2446 info.lock.Lock() 2447 defer info.lock.Unlock() 2448 2449 devices.Lock() 2450 defer devices.Unlock() 2451 2452 status := &DevStatus{ 2453 DeviceID: info.DeviceID, 2454 Size: info.Size, 2455 TransactionID: info.TransactionID, 2456 } 2457 2458 if err := devices.activateDeviceIfNeeded(info, false); err != nil { 2459 return nil, fmt.Errorf("devmapper: Error activating devmapper device for '%s': %s", hash, err) 2460 } 2461 2462 sizeInSectors, mappedSectors, highestMappedSector, err := devices.deviceStatus(info.DevName()) 2463 2464 if err != nil { 2465 return nil, err 2466 } 2467 2468 status.SizeInSectors = sizeInSectors 2469 status.MappedSectors = mappedSectors 2470 status.HighestMappedSector = highestMappedSector 2471 2472 return status, nil 2473 } 2474 2475 func (devices *DeviceSet) poolStatus() (totalSizeInSectors, transactionID, dataUsed, dataTotal, metadataUsed, metadataTotal uint64, err error) { 2476 var params string 2477 if _, totalSizeInSectors, _, params, err = devicemapper.GetStatus(devices.getPoolName()); err == nil { 2478 _, err = fmt.Sscanf(params, "%d %d/%d %d/%d", &transactionID, &metadataUsed, &metadataTotal, &dataUsed, &dataTotal) 2479 } 2480 return 2481 } 2482 2483 // DataDevicePath returns the path to the data storage for this deviceset, 2484 // regardless of loopback or block device 2485 func (devices *DeviceSet) DataDevicePath() string { 2486 return devices.dataDevice 2487 } 2488 2489 // MetadataDevicePath returns the path to the metadata storage for this deviceset, 2490 // regardless of loopback or block device 2491 func (devices *DeviceSet) MetadataDevicePath() string { 2492 return devices.metadataDevice 2493 } 2494 2495 func (devices *DeviceSet) getUnderlyingAvailableSpace(loopFile string) (uint64, error) { 2496 buf := new(syscall.Statfs_t) 2497 if err := syscall.Statfs(loopFile, buf); err != nil { 2498 logrus.Warnf("devmapper: Couldn't stat loopfile filesystem %v: %v", loopFile, err) 2499 return 0, err 2500 } 2501 return buf.Bfree * uint64(buf.Bsize), nil 2502 } 2503 2504 func (devices *DeviceSet) isRealFile(loopFile string) (bool, error) { 2505 if loopFile != "" { 2506 fi, err := os.Stat(loopFile) 2507 if err != nil { 2508 logrus.Warnf("devmapper: Couldn't stat loopfile %v: %v", loopFile, err) 2509 return false, err 2510 } 2511 return fi.Mode().IsRegular(), nil 2512 } 2513 return false, nil 2514 } 2515 2516 // Status returns the current status of this deviceset 2517 func (devices *DeviceSet) Status() *Status { 2518 devices.Lock() 2519 defer devices.Unlock() 2520 2521 status := &Status{} 2522 2523 status.PoolName = devices.getPoolName() 2524 status.DataFile = devices.DataDevicePath() 2525 status.DataLoopback = devices.dataLoopFile 2526 status.MetadataFile = devices.MetadataDevicePath() 2527 status.MetadataLoopback = devices.metadataLoopFile 2528 status.UdevSyncSupported = devicemapper.UdevSyncSupported() 2529 status.DeferredRemoveEnabled = devices.deferredRemove 2530 status.DeferredDeleteEnabled = devices.deferredDelete 2531 status.DeferredDeletedDeviceCount = devices.nrDeletedDevices 2532 status.BaseDeviceSize = devices.getBaseDeviceSize() 2533 status.BaseDeviceFS = devices.getBaseDeviceFS() 2534 2535 totalSizeInSectors, _, dataUsed, dataTotal, metadataUsed, metadataTotal, err := devices.poolStatus() 2536 if err == nil { 2537 // Convert from blocks to bytes 2538 blockSizeInSectors := totalSizeInSectors / dataTotal 2539 2540 status.Data.Used = dataUsed * blockSizeInSectors * 512 2541 status.Data.Total = dataTotal * blockSizeInSectors * 512 2542 status.Data.Available = status.Data.Total - status.Data.Used 2543 2544 // metadata blocks are always 4k 2545 status.Metadata.Used = metadataUsed * 4096 2546 status.Metadata.Total = metadataTotal * 4096 2547 status.Metadata.Available = status.Metadata.Total - status.Metadata.Used 2548 2549 status.SectorSize = blockSizeInSectors * 512 2550 2551 if check, _ := devices.isRealFile(devices.dataLoopFile); check { 2552 actualSpace, err := devices.getUnderlyingAvailableSpace(devices.dataLoopFile) 2553 if err == nil && actualSpace < status.Data.Available { 2554 status.Data.Available = actualSpace 2555 } 2556 } 2557 2558 if check, _ := devices.isRealFile(devices.metadataLoopFile); check { 2559 actualSpace, err := devices.getUnderlyingAvailableSpace(devices.metadataLoopFile) 2560 if err == nil && actualSpace < status.Metadata.Available { 2561 status.Metadata.Available = actualSpace 2562 } 2563 } 2564 2565 minFreeData := (dataTotal * uint64(devices.minFreeSpacePercent)) / 100 2566 status.MinFreeSpace = minFreeData * blockSizeInSectors * 512 2567 } 2568 2569 return status 2570 } 2571 2572 // Status returns the current status of this deviceset 2573 func (devices *DeviceSet) exportDeviceMetadata(hash string) (*deviceMetadata, error) { 2574 info, err := devices.lookupDeviceWithLock(hash) 2575 if err != nil { 2576 return nil, err 2577 } 2578 2579 info.lock.Lock() 2580 defer info.lock.Unlock() 2581 2582 metadata := &deviceMetadata{info.DeviceID, info.Size, info.Name()} 2583 return metadata, nil 2584 } 2585 2586 // NewDeviceSet creates the device set based on the options provided. 2587 func NewDeviceSet(root string, doInit bool, options []string, uidMaps, gidMaps []idtools.IDMap) (*DeviceSet, error) { 2588 devicemapper.SetDevDir("/dev") 2589 2590 devices := &DeviceSet{ 2591 root: root, 2592 metaData: metaData{Devices: make(map[string]*devInfo)}, 2593 dataLoopbackSize: defaultDataLoopbackSize, 2594 metaDataLoopbackSize: defaultMetaDataLoopbackSize, 2595 baseFsSize: defaultBaseFsSize, 2596 overrideUdevSyncCheck: defaultUdevSyncOverride, 2597 doBlkDiscard: true, 2598 thinpBlockSize: defaultThinpBlockSize, 2599 deviceIDMap: make([]byte, deviceIDMapSz), 2600 deletionWorkerTicker: time.NewTicker(time.Second * 30), 2601 uidMaps: uidMaps, 2602 gidMaps: gidMaps, 2603 minFreeSpacePercent: defaultMinFreeSpacePercent, 2604 } 2605 2606 foundBlkDiscard := false 2607 for _, option := range options { 2608 key, val, err := parsers.ParseKeyValueOpt(option) 2609 if err != nil { 2610 return nil, err 2611 } 2612 key = strings.ToLower(key) 2613 switch key { 2614 case "dm.basesize": 2615 size, err := units.RAMInBytes(val) 2616 if err != nil { 2617 return nil, err 2618 } 2619 userBaseSize = true 2620 devices.baseFsSize = uint64(size) 2621 case "dm.loopdatasize": 2622 size, err := units.RAMInBytes(val) 2623 if err != nil { 2624 return nil, err 2625 } 2626 devices.dataLoopbackSize = size 2627 case "dm.loopmetadatasize": 2628 size, err := units.RAMInBytes(val) 2629 if err != nil { 2630 return nil, err 2631 } 2632 devices.metaDataLoopbackSize = size 2633 case "dm.fs": 2634 if val != "ext4" && val != "xfs" { 2635 return nil, fmt.Errorf("devmapper: Unsupported filesystem %s\n", val) 2636 } 2637 devices.filesystem = val 2638 case "dm.mkfsarg": 2639 devices.mkfsArgs = append(devices.mkfsArgs, val) 2640 case "dm.mountopt": 2641 devices.mountOptions = joinMountOptions(devices.mountOptions, val) 2642 case "dm.metadatadev": 2643 devices.metadataDevice = val 2644 case "dm.datadev": 2645 devices.dataDevice = val 2646 case "dm.thinpooldev": 2647 devices.thinPoolDevice = strings.TrimPrefix(val, "/dev/mapper/") 2648 case "dm.blkdiscard": 2649 foundBlkDiscard = true 2650 devices.doBlkDiscard, err = strconv.ParseBool(val) 2651 if err != nil { 2652 return nil, err 2653 } 2654 case "dm.blocksize": 2655 size, err := units.RAMInBytes(val) 2656 if err != nil { 2657 return nil, err 2658 } 2659 // convert to 512b sectors 2660 devices.thinpBlockSize = uint32(size) >> 9 2661 case "dm.override_udev_sync_check": 2662 devices.overrideUdevSyncCheck, err = strconv.ParseBool(val) 2663 if err != nil { 2664 return nil, err 2665 } 2666 2667 case "dm.use_deferred_removal": 2668 enableDeferredRemoval, err = strconv.ParseBool(val) 2669 if err != nil { 2670 return nil, err 2671 } 2672 2673 case "dm.use_deferred_deletion": 2674 enableDeferredDeletion, err = strconv.ParseBool(val) 2675 if err != nil { 2676 return nil, err 2677 } 2678 2679 case "dm.min_free_space": 2680 if !strings.HasSuffix(val, "%") { 2681 return nil, fmt.Errorf("devmapper: Option dm.min_free_space requires %% suffix") 2682 } 2683 2684 valstring := strings.TrimSuffix(val, "%") 2685 minFreeSpacePercent, err := strconv.ParseUint(valstring, 10, 32) 2686 if err != nil { 2687 return nil, err 2688 } 2689 2690 if minFreeSpacePercent >= 100 { 2691 return nil, fmt.Errorf("devmapper: Invalid value %v for option dm.min_free_space", val) 2692 } 2693 2694 devices.minFreeSpacePercent = uint32(minFreeSpacePercent) 2695 case "dm.xfs_nospace_max_retries": 2696 _, err := strconv.ParseUint(val, 10, 64) 2697 if err != nil { 2698 return nil, err 2699 } 2700 devices.xfsNospaceRetries = val 2701 default: 2702 return nil, fmt.Errorf("devmapper: Unknown option %s\n", key) 2703 } 2704 } 2705 2706 // By default, don't do blk discard hack on raw devices, its rarely useful and is expensive 2707 if !foundBlkDiscard && (devices.dataDevice != "" || devices.thinPoolDevice != "") { 2708 devices.doBlkDiscard = false 2709 } 2710 2711 if err := devices.initDevmapper(doInit); err != nil { 2712 return nil, err 2713 } 2714 2715 return devices, nil 2716 }