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