devmapper: Add a new option dm.min_free_space_percent
| ... | ... |
@@ -43,11 +43,12 @@ var ( |
| 43 | 43 |
// We retry device removal so many a times that even error messages |
| 44 | 44 |
// will fill up console during normal operation. So only log Fatal |
| 45 | 45 |
// messages by default. |
| 46 |
- logLevel = devicemapper.LogLevelFatal |
|
| 47 |
- driverDeferredRemovalSupport = false |
|
| 48 |
- enableDeferredRemoval = false |
|
| 49 |
- enableDeferredDeletion = false |
|
| 50 |
- userBaseSize = false |
|
| 46 |
+ logLevel = devicemapper.LogLevelFatal |
|
| 47 |
+ driverDeferredRemovalSupport = false |
|
| 48 |
+ enableDeferredRemoval = false |
|
| 49 |
+ enableDeferredDeletion = false |
|
| 50 |
+ userBaseSize = false |
|
| 51 |
+ defaultMinFreeSpacePercent uint32 = 10 |
|
| 51 | 52 |
) |
| 52 | 53 |
|
| 53 | 54 |
const deviceSetMetaFile string = "deviceset-metadata" |
| ... | ... |
@@ -122,6 +123,7 @@ type DeviceSet struct {
|
| 122 | 122 |
deletionWorkerTicker *time.Ticker |
| 123 | 123 |
uidMaps []idtools.IDMap |
| 124 | 124 |
gidMaps []idtools.IDMap |
| 125 |
+ minFreeSpacePercent uint32 //min free space percentage in thinpool |
|
| 125 | 126 |
} |
| 126 | 127 |
|
| 127 | 128 |
// DiskUsage contains information about disk usage and is used when reporting Status of a device. |
| ... | ... |
@@ -753,6 +755,38 @@ func (devices *DeviceSet) getNextFreeDeviceID() (int, error) {
|
| 753 | 753 |
return 0, fmt.Errorf("devmapper: Unable to find a free device ID")
|
| 754 | 754 |
} |
| 755 | 755 |
|
| 756 |
+func (devices *DeviceSet) poolHasFreeSpace() error {
|
|
| 757 |
+ if devices.minFreeSpacePercent == 0 {
|
|
| 758 |
+ return nil |
|
| 759 |
+ } |
|
| 760 |
+ |
|
| 761 |
+ _, _, dataUsed, dataTotal, metadataUsed, metadataTotal, err := devices.poolStatus() |
|
| 762 |
+ if err != nil {
|
|
| 763 |
+ return err |
|
| 764 |
+ } |
|
| 765 |
+ |
|
| 766 |
+ minFreeData := (dataTotal * uint64(devices.minFreeSpacePercent)) / 100 |
|
| 767 |
+ if minFreeData < 1 {
|
|
| 768 |
+ minFreeData = 1 |
|
| 769 |
+ } |
|
| 770 |
+ dataFree := dataTotal - dataUsed |
|
| 771 |
+ if dataFree < minFreeData {
|
|
| 772 |
+ return fmt.Errorf("devmapper: Thin Pool has %v free data blocks which is less than minimum required %v free data blocks. Create more free space in thin pool or use dm.min_free_space option to change behavior", (dataTotal - dataUsed), minFreeData)
|
|
| 773 |
+ } |
|
| 774 |
+ |
|
| 775 |
+ minFreeMetadata := (metadataTotal * uint64(devices.minFreeSpacePercent)) / 100 |
|
| 776 |
+ if minFreeMetadata < 1 {
|
|
| 777 |
+ minFreeData = 1 |
|
| 778 |
+ } |
|
| 779 |
+ |
|
| 780 |
+ metadataFree := metadataTotal - metadataUsed |
|
| 781 |
+ if metadataFree < minFreeMetadata {
|
|
| 782 |
+ return fmt.Errorf("devmapper: Thin Pool has %v free metadata blocks which is less than minimum required %v free metadata blocks. Create more free metadata space in thin pool or use dm.min_free_space option to change behavior", (metadataTotal - metadataUsed), minFreeMetadata)
|
|
| 783 |
+ } |
|
| 784 |
+ |
|
| 785 |
+ return nil |
|
| 786 |
+} |
|
| 787 |
+ |
|
| 756 | 788 |
func (devices *DeviceSet) createRegisterDevice(hash string) (*devInfo, error) {
|
| 757 | 789 |
devices.Lock() |
| 758 | 790 |
defer devices.Unlock() |
| ... | ... |
@@ -809,6 +843,10 @@ func (devices *DeviceSet) createRegisterDevice(hash string) (*devInfo, error) {
|
| 809 | 809 |
} |
| 810 | 810 |
|
| 811 | 811 |
func (devices *DeviceSet) createRegisterSnapDevice(hash string, baseInfo *devInfo) error {
|
| 812 |
+ if err := devices.poolHasFreeSpace(); err != nil {
|
|
| 813 |
+ return err |
|
| 814 |
+ } |
|
| 815 |
+ |
|
| 812 | 816 |
deviceID, err := devices.getNextFreeDeviceID() |
| 813 | 817 |
if err != nil {
|
| 814 | 818 |
return err |
| ... | ... |
@@ -2437,6 +2475,7 @@ func NewDeviceSet(root string, doInit bool, options []string, uidMaps, gidMaps [ |
| 2437 | 2437 |
deletionWorkerTicker: time.NewTicker(time.Second * 30), |
| 2438 | 2438 |
uidMaps: uidMaps, |
| 2439 | 2439 |
gidMaps: gidMaps, |
| 2440 |
+ minFreeSpacePercent: defaultMinFreeSpacePercent, |
|
| 2440 | 2441 |
} |
| 2441 | 2442 |
|
| 2442 | 2443 |
foundBlkDiscard := false |
| ... | ... |
@@ -2512,6 +2551,22 @@ func NewDeviceSet(root string, doInit bool, options []string, uidMaps, gidMaps [ |
| 2512 | 2512 |
return nil, err |
| 2513 | 2513 |
} |
| 2514 | 2514 |
|
| 2515 |
+ case "dm.min_free_space": |
|
| 2516 |
+ if !strings.HasSuffix(val, "%") {
|
|
| 2517 |
+ return nil, fmt.Errorf("devmapper: Option dm.min_free_space requires %% suffix")
|
|
| 2518 |
+ } |
|
| 2519 |
+ |
|
| 2520 |
+ valstring := strings.TrimSuffix(val, "%") |
|
| 2521 |
+ minFreeSpacePercent, err := strconv.ParseUint(valstring, 10, 32) |
|
| 2522 |
+ if err != nil {
|
|
| 2523 |
+ return nil, err |
|
| 2524 |
+ } |
|
| 2525 |
+ |
|
| 2526 |
+ if minFreeSpacePercent >= 100 {
|
|
| 2527 |
+ return nil, fmt.Errorf("devmapper: Invalid value %v for option dm.min_free_space", val)
|
|
| 2528 |
+ } |
|
| 2529 |
+ |
|
| 2530 |
+ devices.minFreeSpacePercent = uint32(minFreeSpacePercent) |
|
| 2515 | 2531 |
default: |
| 2516 | 2532 |
return nil, fmt.Errorf("devmapper: Unknown option %s\n", key)
|
| 2517 | 2533 |
} |
| ... | ... |
@@ -438,6 +438,32 @@ options for `zfs` start with `zfs`. |
| 438 | 438 |
when unintentional leaking of mount point happens across multiple mount |
| 439 | 439 |
namespaces. |
| 440 | 440 |
|
| 441 |
+* `dm.min_free_space` |
|
| 442 |
+ |
|
| 443 |
+ Specifies the min free space percent in thin pool require for new device |
|
| 444 |
+ creation to succeed. This check applies to both free data space as well |
|
| 445 |
+ as free metadata space. Valid values are from 0% - 99%. Value 0% disables |
|
| 446 |
+ free space checking logic. If user does not specify a value for this optoin, |
|
| 447 |
+ then default value for this option is 10%. |
|
| 448 |
+ |
|
| 449 |
+ Whenever a new thin pool device is created (during docker pull or |
|
| 450 |
+ during container creation), docker will check minimum free space is |
|
| 451 |
+ available as specified by this parameter. If that is not the case, then |
|
| 452 |
+ device creation will fail and docker operation will fail. |
|
| 453 |
+ |
|
| 454 |
+ One will have to create more free space in thin pool to recover from the |
|
| 455 |
+ error. Either delete some of the images and containers from thin pool and |
|
| 456 |
+ create free space or add more storage to thin pool. |
|
| 457 |
+ |
|
| 458 |
+ For lvm thin pool, one can add more storage to volume group container thin |
|
| 459 |
+ pool and that should automatically resolve it. If loop devices are being |
|
| 460 |
+ used, then stop docker, grow the size of loop files and restart docker and |
|
| 461 |
+ that should resolve the issue. |
|
| 462 |
+ |
|
| 463 |
+ Example use: |
|
| 464 |
+ |
|
| 465 |
+ $ docker daemon --storage-opt dm.min_free_space_percent=10% |
|
| 466 |
+ |
|
| 441 | 467 |
Currently supported options of `zfs`: |
| 442 | 468 |
|
| 443 | 469 |
* `zfs.fsname` |
| ... | ... |
@@ -475,6 +475,30 @@ By default docker will pick up the zfs filesystem where docker graph |
| 475 | 475 |
|
| 476 | 476 |
Example use: `docker daemon -s zfs --storage-opt zfs.fsname=zroot/docker` |
| 477 | 477 |
|
| 478 |
+#### dm.min_free_space |
|
| 479 |
+ |
|
| 480 |
+Specifies the min free space percent in thin pool require for new device |
|
| 481 |
+creation to succeed. This check applies to both free data space as well |
|
| 482 |
+as free metadata space. Valid values are from 0% - 99%. Value 0% disables |
|
| 483 |
+free space checking logic. If user does not specify a value for this optoin, |
|
| 484 |
+then default value for this option is 10%. |
|
| 485 |
+ |
|
| 486 |
+Whenever a new thin pool device is created (during docker pull or |
|
| 487 |
+during container creation), docker will check minimum free space is |
|
| 488 |
+available as specified by this parameter. If that is not the case, then |
|
| 489 |
+device creation will fail and docker operation will fail. |
|
| 490 |
+ |
|
| 491 |
+One will have to create more free space in thin pool to recover from the |
|
| 492 |
+error. Either delete some of the images and containers from thin pool and |
|
| 493 |
+create free space or add more storage to thin pool. |
|
| 494 |
+ |
|
| 495 |
+For lvm thin pool, one can add more storage to volume group container thin |
|
| 496 |
+pool and that should automatically resolve it. If loop devices are being |
|
| 497 |
+used, then stop docker, grow the size of loop files and restart docker and |
|
| 498 |
+that should resolve the issue. |
|
| 499 |
+ |
|
| 500 |
+Example use: `docker daemon --storage-opt dm.min_free_space_percent=10%` |
|
| 501 |
+ |
|
| 478 | 502 |
# CLUSTER STORE OPTIONS |
| 479 | 503 |
|
| 480 | 504 |
The daemon uses libkv to advertise |