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