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