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