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