Browse Source

remove deprecated devicemapper storage-driver

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Sebastiaan van Stijn 3 years ago
parent
commit
dc11d2a2d8
59 changed files with 33 additions and 5597 deletions
  1. 0 1
      .github/CODEOWNERS
  2. 1 1
      Makefile
  3. 1 1
      api/swagger.yaml
  4. 0 5
      contrib/check-config.sh
  5. 0 14
      contrib/docker-device-tool/README.md
  6. 0 169
      contrib/docker-device-tool/device_tool.go
  7. 0 4
      contrib/docker-device-tool/device_tool_windows.go
  8. 0 98
      daemon/graphdriver/devmapper/README.md
  9. 0 230
      daemon/graphdriver/devmapper/device_setup.go
  10. 0 2811
      daemon/graphdriver/devmapper/deviceset.go
  11. 0 106
      daemon/graphdriver/devmapper/devmapper_doc.go
  12. 0 208
      daemon/graphdriver/devmapper/devmapper_test.go
  13. 0 244
      daemon/graphdriver/devmapper/driver.go
  14. 0 67
      daemon/graphdriver/devmapper/mount.go
  15. 1 5
      daemon/graphdriver/driver.go
  16. 1 1
      daemon/graphdriver/driver_linux.go
  17. 0 9
      daemon/graphdriver/register/register_devicemapper.go
  18. 1 1
      daemon/info.go
  19. 1 1
      docs/api/v1.18.md
  20. 1 1
      docs/api/v1.19.md
  21. 1 1
      docs/api/v1.20.md
  22. 1 1
      docs/api/v1.21.md
  23. 1 1
      docs/api/v1.22.md
  24. 1 1
      docs/api/v1.23.md
  25. 1 1
      docs/api/v1.24.md
  26. 1 1
      docs/api/v1.25.yaml
  27. 1 1
      docs/api/v1.26.yaml
  28. 1 1
      docs/api/v1.27.yaml
  29. 1 1
      docs/api/v1.28.yaml
  30. 1 1
      docs/api/v1.29.yaml
  31. 1 1
      docs/api/v1.30.yaml
  32. 1 1
      docs/api/v1.31.yaml
  33. 1 1
      docs/api/v1.32.yaml
  34. 1 1
      docs/api/v1.33.yaml
  35. 1 1
      docs/api/v1.34.yaml
  36. 1 1
      docs/api/v1.35.yaml
  37. 1 1
      docs/api/v1.36.yaml
  38. 1 1
      docs/api/v1.37.yaml
  39. 1 1
      docs/api/v1.38.yaml
  40. 1 1
      docs/api/v1.39.yaml
  41. 1 1
      docs/api/v1.40.yaml
  42. 1 1
      docs/api/v1.41.yaml
  43. 1 1
      docs/contributing/set-up-dev-env.md
  44. 0 24
      integration-cli/docker_cli_create_test.go
  45. 0 72
      integration-cli/docker_cli_daemon_test.go
  46. 0 49
      integration-cli/docker_cli_inspect_test.go
  47. 0 4
      integration-cli/requirements_test.go
  48. 0 34
      integration/container/stop_linux_test.go
  49. 0 811
      pkg/devicemapper/devmapper.go
  50. 0 126
      pkg/devicemapper/devmapper_log.go
  51. 0 246
      pkg/devicemapper/devmapper_wrapper.go
  52. 0 7
      pkg/devicemapper/devmapper_wrapper_dynamic.go
  53. 0 35
      pkg/devicemapper/devmapper_wrapper_dynamic_deferred_remove.go
  54. 0 128
      pkg/devicemapper/devmapper_wrapper_dynamic_dlsym_deferred_remove.go
  55. 0 17
      pkg/devicemapper/devmapper_wrapper_no_deferred_remove.go
  56. 0 29
      pkg/devicemapper/ioctl.go
  57. 0 11
      pkg/devicemapper/log.go
  58. 0 1
      project/ISSUE-TRIAGE.md
  59. 3 3
      project/PACKAGERS.md

+ 0 - 1
.github/CODEOWNERS

@@ -5,7 +5,6 @@
 
 
 builder/**                              @tonistiigi
 builder/**                              @tonistiigi
 contrib/mkimage/**                      @tianon
 contrib/mkimage/**                      @tianon
-daemon/graphdriver/devmapper/**         @rhvgoyal
 daemon/graphdriver/overlay2/**          @dmcgowan
 daemon/graphdriver/overlay2/**          @dmcgowan
 daemon/graphdriver/windows/**           @johnstep
 daemon/graphdriver/windows/**           @johnstep
 daemon/logger/awslogs/**                @samuelkarp  
 daemon/logger/awslogs/**                @samuelkarp  

+ 1 - 1
Makefile

@@ -28,7 +28,7 @@ export VALIDATE_ORIGIN_BRANCH
 # option of "go build". For example, a built-in graphdriver priority list
 # option of "go build". For example, a built-in graphdriver priority list
 # can be changed during build time like this:
 # can be changed during build time like this:
 #
 #
-# make DOCKER_LDFLAGS="-X github.com/docker/docker/daemon/graphdriver.priority=overlay2,devicemapper" dynbinary
+# make DOCKER_LDFLAGS="-X github.com/docker/docker/daemon/graphdriver.priority=overlay2,zfs" dynbinary
 #
 #
 DOCKER_ENVS := \
 DOCKER_ENVS := \
 	-e BUILD_APT_MIRROR \
 	-e BUILD_APT_MIRROR \

+ 1 - 1
api/swagger.yaml

@@ -6561,7 +6561,7 @@ paths:
                 StopSignal: "SIGTERM"
                 StopSignal: "SIGTERM"
                 StopTimeout: 10
                 StopTimeout: 10
               Created: "2015-01-06T15:47:31.485331387Z"
               Created: "2015-01-06T15:47:31.485331387Z"
-              Driver: "devicemapper"
+              Driver: "overlay2"
               ExecIDs:
               ExecIDs:
                 - "b35395de42bc8abd327f9dd65d913b9ba28c74d2f0734eeeae84fa1c616a0fca"
                 - "b35395de42bc8abd327f9dd65d913b9ba28c74d2f0734eeeae84fa1c616a0fca"
                 - "3fc1232e5cd20c8de182ed81178503dc6437f4e7ef12b52cc5e8de020652f1c4"
                 - "3fc1232e5cd20c8de182ed81178503dc6437f4e7ef12b52cc5e8de020652f1c4"

+ 0 - 5
contrib/check-config.sh

@@ -374,11 +374,6 @@ check_flags BTRFS_FS_POSIX_ACL | sed 's/^/    /'
 [ "$EXITCODE" = 0 ] && STORAGE=0
 [ "$EXITCODE" = 0 ] && STORAGE=0
 EXITCODE=0
 EXITCODE=0
 
 
-echo "  - \"$(wrap_color 'devicemapper' blue)\":"
-check_flags BLK_DEV_DM DM_THIN_PROVISIONING | sed 's/^/    /'
-[ "$EXITCODE" = 0 ] && STORAGE=0
-EXITCODE=0
-
 echo "  - \"$(wrap_color 'overlay' blue)\":"
 echo "  - \"$(wrap_color 'overlay' blue)\":"
 check_flags OVERLAY_FS | sed 's/^/    /'
 check_flags OVERLAY_FS | sed 's/^/    /'
 [ "$EXITCODE" = 0 ] && STORAGE=0
 [ "$EXITCODE" = 0 ] && STORAGE=0

+ 0 - 14
contrib/docker-device-tool/README.md

@@ -1,14 +0,0 @@
-Docker device tool for devicemapper storage driver backend
-===================
-
-The ./contrib/docker-device-tool contains a tool to manipulate devicemapper thin-pool.
-
-Compile
-========
-
-    $ make shell
-    ## inside build container
-    $ go build contrib/docker-device-tool/device_tool.go
-
-    # if devicemapper version is old and compilation fails, compile with `libdm_no_deferred_remove` tag
-    $ go build -tags libdm_no_deferred_remove contrib/docker-device-tool/device_tool.go

+ 0 - 169
contrib/docker-device-tool/device_tool.go

@@ -1,169 +0,0 @@
-//go:build !windows
-// +build !windows
-
-package main
-
-import (
-	"flag"
-	"fmt"
-	"os"
-	"path"
-	"sort"
-	"strconv"
-	"strings"
-
-	"github.com/docker/docker/daemon/graphdriver/devmapper"
-	"github.com/docker/docker/pkg/devicemapper"
-	"github.com/docker/docker/pkg/idtools"
-	"github.com/sirupsen/logrus"
-)
-
-func usage() {
-	fmt.Fprintf(os.Stderr, "Usage: %s <flags>  [status] | [list] | [device id]  | [resize new-pool-size] | [snap new-id base-id] | [remove id] | [mount id mountpoint]\n", os.Args[0])
-	flag.PrintDefaults()
-	os.Exit(1)
-}
-
-func byteSizeFromString(arg string) (int64, error) {
-	digits := ""
-	rest := ""
-	last := strings.LastIndexAny(arg, "0123456789")
-	if last >= 0 {
-		digits = arg[:last+1]
-		rest = arg[last+1:]
-	}
-
-	val, err := strconv.ParseInt(digits, 10, 64)
-	if err != nil {
-		return val, err
-	}
-
-	rest = strings.ToLower(strings.TrimSpace(rest))
-
-	var multiplier int64
-	switch rest {
-	case "":
-		multiplier = 1
-	case "k", "kb":
-		multiplier = 1024
-	case "m", "mb":
-		multiplier = 1024 * 1024
-	case "g", "gb":
-		multiplier = 1024 * 1024 * 1024
-	case "t", "tb":
-		multiplier = 1024 * 1024 * 1024 * 1024
-	default:
-		return 0, fmt.Errorf("Unknown size unit: %s", rest)
-	}
-
-	return val * multiplier, nil
-}
-
-func main() {
-	root := flag.String("r", "/var/lib/docker", "Docker root dir")
-	flDebug := flag.Bool("D", false, "Debug mode")
-
-	flag.Parse()
-
-	if *flDebug {
-		os.Setenv("DEBUG", "1")
-		logrus.SetLevel(logrus.DebugLevel)
-	}
-
-	if flag.NArg() < 1 {
-		usage()
-	}
-
-	args := flag.Args()
-
-	home := path.Join(*root, "devicemapper")
-	devices, err := devmapper.NewDeviceSet(home, false, nil, idtools.IdentityMapping{})
-	if err != nil {
-		fmt.Println("Can't initialize device mapper: ", err)
-		os.Exit(1)
-	}
-
-	switch args[0] {
-	case "status":
-		status := devices.Status()
-		fmt.Printf("Pool name: %s\n", status.PoolName)
-		fmt.Printf("Data Loopback file: %s\n", status.DataLoopback)
-		fmt.Printf("Metadata Loopback file: %s\n", status.MetadataLoopback)
-		fmt.Printf("Sector size: %d\n", status.SectorSize)
-		fmt.Printf("Data use: %d of %d (%.1f %%)\n", status.Data.Used, status.Data.Total, 100.0*float64(status.Data.Used)/float64(status.Data.Total))
-		fmt.Printf("Metadata use: %d of %d (%.1f %%)\n", status.Metadata.Used, status.Metadata.Total, 100.0*float64(status.Metadata.Used)/float64(status.Metadata.Total))
-	case "list":
-		ids := devices.List()
-		sort.Strings(ids)
-		for _, id := range ids {
-			fmt.Println(id)
-		}
-	case "device":
-		if flag.NArg() < 2 {
-			usage()
-		}
-		status, err := devices.GetDeviceStatus(args[1])
-		if err != nil {
-			fmt.Println("Can't get device info: ", err)
-			os.Exit(1)
-		}
-		fmt.Printf("Id: %d\n", status.DeviceID)
-		fmt.Printf("Size: %d\n", status.Size)
-		fmt.Printf("Transaction Id: %d\n", status.TransactionID)
-		fmt.Printf("Size in Sectors: %d\n", status.SizeInSectors)
-		fmt.Printf("Mapped Sectors: %d\n", status.MappedSectors)
-		fmt.Printf("Highest Mapped Sector: %d\n", status.HighestMappedSector)
-	case "resize":
-		if flag.NArg() < 2 {
-			usage()
-		}
-
-		size, err := byteSizeFromString(args[1])
-		if err != nil {
-			fmt.Println("Invalid size: ", err)
-			os.Exit(1)
-		}
-
-		err = devices.ResizePool(size)
-		if err != nil {
-			fmt.Println("Error resizing pool: ", err)
-			os.Exit(1)
-		}
-
-	case "snap":
-		if flag.NArg() < 3 {
-			usage()
-		}
-
-		err := devices.AddDevice(args[1], args[2], nil)
-		if err != nil {
-			fmt.Println("Can't create snap device: ", err)
-			os.Exit(1)
-		}
-	case "remove":
-		if flag.NArg() < 2 {
-			usage()
-		}
-
-		err := devicemapper.RemoveDevice(args[1])
-		if err != nil {
-			fmt.Println("Can't remove device: ", err)
-			os.Exit(1)
-		}
-	case "mount":
-		if flag.NArg() < 3 {
-			usage()
-		}
-
-		err := devices.MountDevice(args[1], args[2], "")
-		if err != nil {
-			fmt.Println("Can't mount device: ", err)
-			os.Exit(1)
-		}
-	default:
-		fmt.Printf("Unknown command %s\n", args[0])
-		usage()
-
-		os.Exit(1)
-	}
-}

+ 0 - 4
contrib/docker-device-tool/device_tool_windows.go

@@ -1,4 +0,0 @@
-package main
-
-func main() {
-}

+ 0 - 98
daemon/graphdriver/devmapper/README.md

@@ -1,98 +0,0 @@
-# devicemapper - a storage backend based on Device Mapper
-
-## Theory of operation
-
-The device mapper graphdriver uses the device mapper thin provisioning
-module (dm-thinp) to implement CoW snapshots. The preferred model is
-to have a thin pool reserved outside of Docker and passed to the
-daemon via the `--storage-opt dm.thinpooldev` option. Alternatively,
-the device mapper graphdriver can setup a block device to handle this
-for you via the `--storage-opt dm.directlvm_device` option.
-
-As a fallback if no thin pool is provided, loopback files will be
-created.  Loopback is very slow, but can be used without any
-pre-configuration of storage.  It is strongly recommended that you do
-not use loopback in production.  Ensure your Docker daemon has a
-`--storage-opt dm.thinpooldev` argument provided.
-
-In loopback, a thin pool is created at `/var/lib/docker/devicemapper`
-(devicemapper graph location) based on two block devices, one for
-data and one for metadata. By default these block devices are created
-automatically by using loopback mounts of automatically created sparse
-files.
-
-The default loopback files used are
-`/var/lib/docker/devicemapper/devicemapper/data` and
-`/var/lib/docker/devicemapper/devicemapper/metadata`. Additional metadata
-required to map from docker entities to the corresponding devicemapper
-volumes is stored in the `/var/lib/docker/devicemapper/devicemapper/json`
-file (encoded as Json).
-
-In order to support multiple devicemapper graphs on a system, the thin
-pool will be named something like: `docker-0:33-19478248-pool`, where
-the `0:33` part is the minor/major device nr and `19478248` is the
-inode number of the `/var/lib/docker/devicemapper` directory.
-
-On the thin pool, docker automatically creates a base thin device,
-called something like `docker-0:33-19478248-base` of a fixed
-size. This is automatically formatted with an empty filesystem on
-creation. This device is the base of all docker images and
-containers. All base images are snapshots of this device and those
-images are then in turn used as snapshots for other images and
-eventually containers.
-
-## Information on `docker info`
-
-As of docker-1.4.1, `docker info` when using the `devicemapper` storage driver
-will display something like:
-
-	$ sudo docker info
-	[...]
-	Storage Driver: devicemapper
-	 Pool Name: docker-253:1-17538953-pool
-	 Pool Blocksize: 65.54 kB
-	 Base Device Size: 107.4 GB
-	 Data file: /dev/loop4
-	 Metadata file: /dev/loop4
-	 Data Space Used: 2.536 GB
-	 Data Space Total: 107.4 GB
-	 Data Space Available: 104.8 GB
-	 Metadata Space Used: 7.93 MB
-	 Metadata Space Total: 2.147 GB
-	 Metadata Space Available: 2.14 GB
-	 Udev Sync Supported: true
-	 Data loop file: /home/docker/devicemapper/devicemapper/data
-	 Metadata loop file: /home/docker/devicemapper/devicemapper/metadata
-	 Library Version: 1.02.82-git (2013-10-04)
-	[...]
-
-### status items
-
-Each item in the indented section under `Storage Driver: devicemapper` are
-status information about the driver.
- *  `Pool Name` name of the devicemapper pool for this driver.
- *  `Pool Blocksize` tells the blocksize the thin pool was initialized with. This only changes on creation.
- *  `Base Device Size` tells the maximum size of a container and image
- *  `Data file` blockdevice file used for the devicemapper data
- *  `Metadata file` blockdevice file used for the devicemapper metadata
- *  `Data Space Used` tells how much of `Data file` is currently used
- *  `Data Space Total` tells max size the `Data file`
- *  `Data Space Available` tells how much free space there is in the `Data file`. If you are using a loop device this will report the actual space available to the loop device on the underlying filesystem.
- *  `Metadata Space Used` tells how much of `Metadata file` is currently used
- *  `Metadata Space Total` tells max size the `Metadata file`
- *  `Metadata Space Available` tells how much free space there is in the `Metadata file`. If you are using a loop device this will report the actual space available to the loop device on the underlying filesystem.
- *  `Udev Sync Supported` tells whether devicemapper is able to sync with Udev. Should be `true`.
- *  `Data loop file` file attached to `Data file`, if loopback device is used
- *  `Metadata loop file` file attached to `Metadata file`, if loopback device is used
- *  `Library Version` from the libdevmapper used
-
-## About the devicemapper options
-
-The devicemapper backend supports some options that you can specify
-when starting the docker daemon using the `--storage-opt` flags.
-This uses the `dm` prefix and would be used something like `dockerd --storage-opt dm.foo=bar`.
-
-These options are currently documented both in [the man
-page](../../../man/docker.1.md) and in [the online
-documentation](https://docs.docker.com/engine/reference/commandline/dockerd/#/storage-driver-options).
-If you add an options, update both the `man` page and the documentation.

+ 0 - 230
daemon/graphdriver/devmapper/device_setup.go

@@ -1,230 +0,0 @@
-package devmapper // import "github.com/docker/docker/daemon/graphdriver/devmapper"
-
-import (
-	"bufio"
-	"bytes"
-	"encoding/json"
-	"fmt"
-	"os"
-	"os/exec"
-	"path/filepath"
-	"reflect"
-	"strings"
-
-	"github.com/pkg/errors"
-	"github.com/sirupsen/logrus"
-)
-
-type directLVMConfig struct {
-	Device              string
-	ThinpPercent        uint64
-	ThinpMetaPercent    uint64
-	AutoExtendPercent   uint64
-	AutoExtendThreshold uint64
-}
-
-var (
-	errThinpPercentMissing = errors.New("must set both `dm.thinp_percent` and `dm.thinp_metapercent` if either is specified")
-	errThinpPercentTooBig  = errors.New("combined `dm.thinp_percent` and `dm.thinp_metapercent` must not be greater than 100")
-	errMissingSetupDevice  = errors.New("must provide device path in `dm.directlvm_device` in order to configure direct-lvm")
-)
-
-func validateLVMConfig(cfg directLVMConfig) error {
-	if reflect.DeepEqual(cfg, directLVMConfig{}) {
-		return nil
-	}
-	if cfg.Device == "" {
-		return errMissingSetupDevice
-	}
-	if (cfg.ThinpPercent > 0 && cfg.ThinpMetaPercent == 0) || cfg.ThinpMetaPercent > 0 && cfg.ThinpPercent == 0 {
-		return errThinpPercentMissing
-	}
-
-	if cfg.ThinpPercent+cfg.ThinpMetaPercent > 100 {
-		return errThinpPercentTooBig
-	}
-	return nil
-}
-
-func checkDevAvailable(dev string) error {
-	lvmScan, err := exec.LookPath("lvmdiskscan")
-	if err != nil {
-		logrus.Debug("could not find lvmdiskscan")
-		return nil
-	}
-
-	out, err := exec.Command(lvmScan).CombinedOutput()
-	if err != nil {
-		logrus.WithError(err).Error(string(out))
-		return nil
-	}
-
-	if !bytes.Contains(out, []byte(dev)) {
-		return errors.Errorf("%s is not available for use with devicemapper", dev)
-	}
-	return nil
-}
-
-func checkDevInVG(dev string) error {
-	pvDisplay, err := exec.LookPath("pvdisplay")
-	if err != nil {
-		logrus.Debug("could not find pvdisplay")
-		return nil
-	}
-
-	out, err := exec.Command(pvDisplay, dev).CombinedOutput()
-	if err != nil {
-		logrus.WithError(err).Error(string(out))
-		return nil
-	}
-
-	scanner := bufio.NewScanner(bytes.NewReader(bytes.TrimSpace(out)))
-	for scanner.Scan() {
-		fields := strings.SplitAfter(strings.TrimSpace(scanner.Text()), "VG Name")
-		if len(fields) > 1 {
-			// got "VG Name" line"
-			vg := strings.TrimSpace(fields[1])
-			if len(vg) > 0 {
-				return errors.Errorf("%s is already part of a volume group %q: must remove this device from any volume group or provide a different device", dev, vg)
-			}
-			logrus.Error(fields)
-			break
-		}
-	}
-	return nil
-}
-
-func checkDevHasFS(dev string) error {
-	blkid, err := exec.LookPath("blkid")
-	if err != nil {
-		logrus.Debug("could not find blkid")
-		return nil
-	}
-
-	out, err := exec.Command(blkid, dev).CombinedOutput()
-	if err != nil {
-		logrus.WithError(err).Error(string(out))
-		return nil
-	}
-
-	fields := bytes.Fields(out)
-	for _, f := range fields {
-		kv := bytes.Split(f, []byte{'='})
-		if bytes.Equal(kv[0], []byte("TYPE")) {
-			v := bytes.Trim(kv[1], "\"")
-			if len(v) > 0 {
-				return errors.Errorf("%s has a filesystem already, use dm.directlvm_device_force=true if you want to wipe the device", dev)
-			}
-			return nil
-		}
-	}
-	return nil
-}
-
-func verifyBlockDevice(dev string, force bool) error {
-	if err := checkDevAvailable(dev); err != nil {
-		return err
-	}
-	if err := checkDevInVG(dev); err != nil {
-		return err
-	}
-	if force {
-		return nil
-	}
-	return checkDevHasFS(dev)
-}
-
-func readLVMConfig(root string) (directLVMConfig, error) {
-	var cfg directLVMConfig
-
-	p := filepath.Join(root, "setup-config.json")
-	b, err := os.ReadFile(p)
-	if err != nil {
-		if os.IsNotExist(err) {
-			return cfg, nil
-		}
-		return cfg, errors.Wrap(err, "error reading existing setup config")
-	}
-
-	// check if this is just an empty file, no need to produce a json error later if so
-	if len(b) == 0 {
-		return cfg, nil
-	}
-
-	err = json.Unmarshal(b, &cfg)
-	return cfg, errors.Wrap(err, "error unmarshaling previous device setup config")
-}
-
-func writeLVMConfig(root string, cfg directLVMConfig) error {
-	p := filepath.Join(root, "setup-config.json")
-	b, err := json.Marshal(cfg)
-	if err != nil {
-		return errors.Wrap(err, "error marshalling direct lvm config")
-	}
-	err = os.WriteFile(p, b, 0600)
-	return errors.Wrap(err, "error writing direct lvm config to file")
-}
-
-func setupDirectLVM(cfg directLVMConfig) error {
-	lvmProfileDir := "/etc/lvm/profile"
-	binaries := []string{"pvcreate", "vgcreate", "lvcreate", "lvconvert", "lvchange", "thin_check"}
-
-	for _, bin := range binaries {
-		if _, err := exec.LookPath(bin); err != nil {
-			return errors.Wrap(err, "error looking up command `"+bin+"` while setting up direct lvm")
-		}
-	}
-
-	err := os.MkdirAll(lvmProfileDir, 0755)
-	if err != nil {
-		return errors.Wrap(err, "error creating lvm profile directory")
-	}
-
-	if cfg.AutoExtendPercent == 0 {
-		cfg.AutoExtendPercent = 20
-	}
-
-	if cfg.AutoExtendThreshold == 0 {
-		cfg.AutoExtendThreshold = 80
-	}
-
-	if cfg.ThinpPercent == 0 {
-		cfg.ThinpPercent = 95
-	}
-	if cfg.ThinpMetaPercent == 0 {
-		cfg.ThinpMetaPercent = 1
-	}
-
-	out, err := exec.Command("pvcreate", "-f", cfg.Device).CombinedOutput()
-	if err != nil {
-		return errors.Wrap(err, string(out))
-	}
-
-	out, err = exec.Command("vgcreate", "docker", cfg.Device).CombinedOutput()
-	if err != nil {
-		return errors.Wrap(err, string(out))
-	}
-
-	out, err = exec.Command("lvcreate", "--wipesignatures", "y", "-n", "thinpool", "docker", "--extents", fmt.Sprintf("%d%%VG", cfg.ThinpPercent)).CombinedOutput()
-	if err != nil {
-		return errors.Wrap(err, string(out))
-	}
-	out, err = exec.Command("lvcreate", "--wipesignatures", "y", "-n", "thinpoolmeta", "docker", "--extents", fmt.Sprintf("%d%%VG", cfg.ThinpMetaPercent)).CombinedOutput()
-	if err != nil {
-		return errors.Wrap(err, string(out))
-	}
-
-	out, err = exec.Command("lvconvert", "-y", "--zero", "n", "-c", "512K", "--thinpool", "docker/thinpool", "--poolmetadata", "docker/thinpoolmeta").CombinedOutput()
-	if err != nil {
-		return errors.Wrap(err, string(out))
-	}
-
-	profile := fmt.Sprintf("activation{\nthin_pool_autoextend_threshold=%d\nthin_pool_autoextend_percent=%d\n}", cfg.AutoExtendThreshold, cfg.AutoExtendPercent)
-	err = os.WriteFile(lvmProfileDir+"/docker-thinpool.profile", []byte(profile), 0600)
-	if err != nil {
-		return errors.Wrap(err, "error writing docker thinp autoextend profile")
-	}
-
-	out, err = exec.Command("lvchange", "--metadataprofile", "docker-thinpool", "docker/thinpool").CombinedOutput()
-	return errors.Wrap(err, string(out))
-}

+ 0 - 2811
daemon/graphdriver/devmapper/deviceset.go

@@ -1,2811 +0,0 @@
-//go:build linux
-// +build linux
-
-package devmapper // import "github.com/docker/docker/daemon/graphdriver/devmapper"
-
-import (
-	"bufio"
-	"encoding/json"
-	"fmt"
-	"io"
-	"os"
-	"os/exec"
-	"path"
-	"path/filepath"
-	"reflect"
-	"strconv"
-	"strings"
-	"sync"
-	"time"
-
-	"github.com/docker/docker/daemon/graphdriver"
-	"github.com/docker/docker/pkg/devicemapper"
-	"github.com/docker/docker/pkg/dmesg"
-	"github.com/docker/docker/pkg/idtools"
-	"github.com/docker/docker/pkg/loopback"
-	"github.com/docker/docker/pkg/parsers"
-	"github.com/docker/docker/pkg/parsers/kernel"
-	units "github.com/docker/go-units"
-	"github.com/moby/sys/mount"
-	"github.com/opencontainers/selinux/go-selinux/label"
-	"github.com/pkg/errors"
-	"github.com/sirupsen/logrus"
-	"golang.org/x/sys/unix"
-)
-
-var (
-	defaultDataLoopbackSize      int64  = 100 * 1024 * 1024 * 1024
-	defaultMetaDataLoopbackSize  int64  = 2 * 1024 * 1024 * 1024
-	defaultBaseFsSize            uint64 = 10 * 1024 * 1024 * 1024
-	defaultThinpBlockSize        uint32 = 128 // 64K = 128 512b sectors
-	defaultUdevSyncOverride             = false
-	maxDeviceID                         = 0xffffff // 24 bit, pool limit
-	deviceIDMapSz                       = (maxDeviceID + 1) / 8
-	driverDeferredRemovalSupport        = false
-	enableDeferredRemoval               = false
-	enableDeferredDeletion              = false
-	userBaseSize                        = false
-	defaultMinFreeSpacePercent   uint32 = 10
-	lvmSetupConfigForce          bool
-)
-
-const deviceSetMetaFile = "deviceset-metadata"
-const transactionMetaFile = "transaction-metadata"
-
-type transaction struct {
-	OpenTransactionID uint64 `json:"open_transaction_id"`
-	DeviceIDHash      string `json:"device_hash"`
-	DeviceID          int    `json:"device_id"`
-}
-
-type devInfo struct {
-	Hash          string `json:"-"`
-	DeviceID      int    `json:"device_id"`
-	Size          uint64 `json:"size"`
-	TransactionID uint64 `json:"transaction_id"`
-	Initialized   bool   `json:"initialized"`
-	Deleted       bool   `json:"deleted"`
-	devices       *DeviceSet
-
-	// The global DeviceSet lock guarantees that we serialize all
-	// the calls to libdevmapper (which is not threadsafe), but we
-	// sometimes release that lock while sleeping. In that case
-	// this per-device lock is still held, protecting against
-	// other accesses to the device that we're doing the wait on.
-	//
-	// WARNING: In order to avoid AB-BA deadlocks when releasing
-	// the global lock while holding the per-device locks all
-	// device locks must be acquired *before* the device lock, and
-	// multiple device locks should be acquired parent before child.
-	lock sync.Mutex
-}
-
-type metaData struct {
-	Devices map[string]*devInfo `json:"Devices"`
-}
-
-// DeviceSet holds information about list of devices
-type DeviceSet struct {
-	metaData      `json:"-"`
-	sync.Mutex    `json:"-"` // Protects all fields of DeviceSet and serializes calls into libdevmapper
-	root          string
-	devicePrefix  string
-	TransactionID uint64 `json:"-"`
-	NextDeviceID  int    `json:"next_device_id"`
-	deviceIDMap   []byte
-
-	// Options
-	dataLoopbackSize      int64
-	metaDataLoopbackSize  int64
-	baseFsSize            uint64
-	filesystem            string
-	mountOptions          string
-	mkfsArgs              []string
-	dataDevice            string // block or loop dev
-	dataLoopFile          string // loopback file, if used
-	metadataDevice        string // block or loop dev
-	metadataLoopFile      string // loopback file, if used
-	doBlkDiscard          bool
-	thinpBlockSize        uint32
-	thinPoolDevice        string
-	transaction           `json:"-"`
-	overrideUdevSyncCheck bool
-	deferredRemove        bool   // use deferred removal
-	deferredDelete        bool   // use deferred deletion
-	BaseDeviceUUID        string // save UUID of base device
-	BaseDeviceFilesystem  string // save filesystem of base device
-	nrDeletedDevices      uint   // number of deleted devices
-	deletionWorkerTicker  *time.Ticker
-	idMap                 idtools.IdentityMapping
-	minFreeSpacePercent   uint32 // min free space percentage in thinpool
-	xfsNospaceRetries     string // max retries when xfs receives ENOSPC
-	lvmSetupConfig        directLVMConfig
-}
-
-// DiskUsage contains information about disk usage and is used when reporting Status of a device.
-type DiskUsage struct {
-	// Used bytes on the disk.
-	Used uint64
-	// Total bytes on the disk.
-	Total uint64
-	// Available bytes on the disk.
-	Available uint64
-}
-
-// Status returns the information about the device.
-type Status struct {
-	// PoolName is the name of the data pool.
-	PoolName string
-	// DataFile is the actual block device for data.
-	DataFile string
-	// DataLoopback loopback file, if used.
-	DataLoopback string
-	// MetadataFile is the actual block device for metadata.
-	MetadataFile string
-	// MetadataLoopback is the loopback file, if used.
-	MetadataLoopback string
-	// Data is the disk used for data.
-	Data DiskUsage
-	// Metadata is the disk used for meta data.
-	Metadata DiskUsage
-	// BaseDeviceSize is base size of container and image
-	BaseDeviceSize uint64
-	// BaseDeviceFS is backing filesystem.
-	BaseDeviceFS string
-	// SectorSize size of the vector.
-	SectorSize uint64
-	// UdevSyncSupported is true if sync is supported.
-	UdevSyncSupported bool
-	// DeferredRemoveEnabled is true then the device is not unmounted.
-	DeferredRemoveEnabled bool
-	// True if deferred deletion is enabled. This is different from
-	// deferred removal. "removal" means that device mapper device is
-	// deactivated. Thin device is still in thin pool and can be activated
-	// again. But "deletion" means that thin device will be deleted from
-	// thin pool and it can't be activated again.
-	DeferredDeleteEnabled      bool
-	DeferredDeletedDeviceCount uint
-	MinFreeSpace               uint64
-}
-
-// Structure used to export image/container metadata in docker inspect.
-type deviceMetadata struct {
-	deviceID   int
-	deviceSize uint64 // size in bytes
-	deviceName string // Device name as used during activation
-}
-
-// DevStatus returns information about device mounted containing its id, size and sector information.
-type DevStatus struct {
-	// DeviceID is the id of the device.
-	DeviceID int
-	// Size is the size of the filesystem.
-	Size uint64
-	// TransactionID is a unique integer per device set used to identify an operation on the file system, this number is incremental.
-	TransactionID uint64
-	// SizeInSectors indicates the size of the sectors allocated.
-	SizeInSectors uint64
-	// MappedSectors indicates number of mapped sectors.
-	MappedSectors uint64
-	// HighestMappedSector is the pointer to the highest mapped sector.
-	HighestMappedSector uint64
-}
-
-func getDevName(name string) string {
-	return "/dev/mapper/" + name
-}
-
-func (info *devInfo) Name() string {
-	hash := info.Hash
-	if hash == "" {
-		hash = "base"
-	}
-	return fmt.Sprintf("%s-%s", info.devices.devicePrefix, hash)
-}
-
-func (info *devInfo) DevName() string {
-	return getDevName(info.Name())
-}
-
-func (devices *DeviceSet) loopbackDir() string {
-	return path.Join(devices.root, "devicemapper")
-}
-
-func (devices *DeviceSet) metadataDir() string {
-	return path.Join(devices.root, "metadata")
-}
-
-func (devices *DeviceSet) metadataFile(info *devInfo) string {
-	file := info.Hash
-	if file == "" {
-		file = "base"
-	}
-	return path.Join(devices.metadataDir(), file)
-}
-
-func (devices *DeviceSet) transactionMetaFile() string {
-	return path.Join(devices.metadataDir(), transactionMetaFile)
-}
-
-func (devices *DeviceSet) deviceSetMetaFile() string {
-	return path.Join(devices.metadataDir(), deviceSetMetaFile)
-}
-
-func (devices *DeviceSet) oldMetadataFile() string {
-	return path.Join(devices.loopbackDir(), "json")
-}
-
-func (devices *DeviceSet) getPoolName() string {
-	if devices.thinPoolDevice == "" {
-		return devices.devicePrefix + "-pool"
-	}
-	return devices.thinPoolDevice
-}
-
-func (devices *DeviceSet) getPoolDevName() string {
-	return getDevName(devices.getPoolName())
-}
-
-func (devices *DeviceSet) hasImage(name string) bool {
-	dirname := devices.loopbackDir()
-	filename := path.Join(dirname, name)
-
-	_, err := os.Stat(filename)
-	return err == nil
-}
-
-// ensureImage creates a sparse file of <size> bytes at the path
-// <root>/devicemapper/<name>.
-// If the file already exists and new size is larger than its current size, it grows to the new size.
-// Either way it returns the full path.
-func (devices *DeviceSet) ensureImage(name string, size int64) (string, error) {
-	dirname := devices.loopbackDir()
-	filename := path.Join(dirname, name)
-
-	if err := idtools.MkdirAllAndChown(dirname, 0700, devices.idMap.RootPair()); err != nil {
-		return "", err
-	}
-
-	if fi, err := os.Stat(filename); err != nil {
-		if !os.IsNotExist(err) {
-			return "", err
-		}
-		logrus.WithField("storage-driver", "devicemapper").Debugf("Creating loopback file %s for device-manage use", filename)
-		file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0600)
-		if err != nil {
-			return "", err
-		}
-		defer file.Close()
-
-		if err := file.Truncate(size); err != nil {
-			return "", err
-		}
-	} else {
-		if fi.Size() < size {
-			file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0600)
-			if err != nil {
-				return "", err
-			}
-			defer file.Close()
-			if err := file.Truncate(size); err != nil {
-				return "", fmt.Errorf("devmapper: Unable to grow loopback file %s: %v", filename, err)
-			}
-		} else if fi.Size() > size {
-			logrus.WithField("storage-driver", "devicemapper").Warnf("Can't shrink loopback file %s", filename)
-		}
-	}
-	return filename, nil
-}
-
-func (devices *DeviceSet) allocateTransactionID() uint64 {
-	devices.OpenTransactionID = devices.TransactionID + 1
-	return devices.OpenTransactionID
-}
-
-func (devices *DeviceSet) updatePoolTransactionID() error {
-	if err := devicemapper.SetTransactionID(devices.getPoolDevName(), devices.TransactionID, devices.OpenTransactionID); err != nil {
-		return fmt.Errorf("devmapper: Error setting devmapper transaction ID: %s", err)
-	}
-	devices.TransactionID = devices.OpenTransactionID
-	return nil
-}
-
-func (devices *DeviceSet) removeMetadata(info *devInfo) error {
-	if err := os.RemoveAll(devices.metadataFile(info)); err != nil {
-		return fmt.Errorf("devmapper: Error removing metadata file %s: %s", devices.metadataFile(info), err)
-	}
-	return nil
-}
-
-// Given json data and file path, write it to disk
-func (devices *DeviceSet) writeMetaFile(jsonData []byte, filePath string) error {
-	tmpFile, err := os.CreateTemp(devices.metadataDir(), ".tmp")
-	if err != nil {
-		return fmt.Errorf("devmapper: Error creating metadata file: %s", err)
-	}
-
-	n, err := tmpFile.Write(jsonData)
-	if err != nil {
-		return fmt.Errorf("devmapper: Error writing metadata to %s: %s", tmpFile.Name(), err)
-	}
-	if n < len(jsonData) {
-		return io.ErrShortWrite
-	}
-	if err := tmpFile.Sync(); err != nil {
-		return fmt.Errorf("devmapper: Error syncing metadata file %s: %s", tmpFile.Name(), err)
-	}
-	if err := tmpFile.Close(); err != nil {
-		return fmt.Errorf("devmapper: Error closing metadata file %s: %s", tmpFile.Name(), err)
-	}
-	if err := os.Rename(tmpFile.Name(), filePath); err != nil {
-		return fmt.Errorf("devmapper: Error committing metadata file %s: %s", tmpFile.Name(), err)
-	}
-
-	return nil
-}
-
-func (devices *DeviceSet) saveMetadata(info *devInfo) error {
-	jsonData, err := json.Marshal(info)
-	if err != nil {
-		return fmt.Errorf("devmapper: Error encoding metadata to json: %s", err)
-	}
-	return devices.writeMetaFile(jsonData, devices.metadataFile(info))
-}
-
-func (devices *DeviceSet) markDeviceIDUsed(deviceID int) {
-	var mask byte
-	i := deviceID % 8
-	mask = 1 << uint(i)
-	devices.deviceIDMap[deviceID/8] = devices.deviceIDMap[deviceID/8] | mask
-}
-
-func (devices *DeviceSet) markDeviceIDFree(deviceID int) {
-	var mask byte
-	i := deviceID % 8
-	mask = ^(1 << uint(i))
-	devices.deviceIDMap[deviceID/8] = devices.deviceIDMap[deviceID/8] & mask
-}
-
-func (devices *DeviceSet) isDeviceIDFree(deviceID int) bool {
-	var mask byte
-	i := deviceID % 8
-	mask = (1 << uint(i))
-	return (devices.deviceIDMap[deviceID/8] & mask) == 0
-}
-
-// Should be called with devices.Lock() held.
-func (devices *DeviceSet) lookupDevice(hash string) (*devInfo, error) {
-	info := devices.Devices[hash]
-	if info == nil {
-		info = devices.loadMetadata(hash)
-		if info == nil {
-			return nil, fmt.Errorf("devmapper: Unknown device %s", hash)
-		}
-
-		devices.Devices[hash] = info
-	}
-	return info, nil
-}
-
-func (devices *DeviceSet) lookupDeviceWithLock(hash string) (*devInfo, error) {
-	devices.Lock()
-	defer devices.Unlock()
-	info, err := devices.lookupDevice(hash)
-	return info, err
-}
-
-// This function relies on that device hash map has been loaded in advance.
-// Should be called with devices.Lock() held.
-func (devices *DeviceSet) constructDeviceIDMap() {
-	logrus.WithField("storage-driver", "devicemapper").Debug("constructDeviceIDMap()")
-	defer logrus.WithField("storage-driver", "devicemapper").Debug("constructDeviceIDMap() END")
-
-	for _, info := range devices.Devices {
-		devices.markDeviceIDUsed(info.DeviceID)
-		logrus.WithField("storage-driver", "devicemapper").Debugf("Added deviceId=%d to DeviceIdMap", info.DeviceID)
-	}
-}
-
-func (devices *DeviceSet) deviceFileWalkFunction(path string, name string) error {
-	logger := logrus.WithField("storage-driver", "devicemapper")
-
-	// Skip some of the meta files which are not device files.
-	if strings.HasSuffix(name, ".migrated") {
-		logger.Debugf("Skipping file %s", path)
-		return nil
-	}
-
-	if strings.HasPrefix(name, ".") {
-		logger.Debugf("Skipping file %s", path)
-		return nil
-	}
-
-	if name == deviceSetMetaFile {
-		logger.Debugf("Skipping file %s", path)
-		return nil
-	}
-
-	if name == transactionMetaFile {
-		logger.Debugf("Skipping file %s", path)
-		return nil
-	}
-
-	logger.Debugf("Loading data for file %s", path)
-
-	hash := name
-	if hash == "base" {
-		hash = ""
-	}
-
-	// Include deleted devices also as cleanup delete device logic
-	// will go through it and see if there are any deleted devices.
-	if _, err := devices.lookupDevice(hash); err != nil {
-		return fmt.Errorf("devmapper: Error looking up device %s:%v", hash, err)
-	}
-
-	return nil
-}
-
-func (devices *DeviceSet) loadDeviceFilesOnStart() error {
-	logrus.WithField("storage-driver", "devicemapper").Debug("loadDeviceFilesOnStart()")
-	defer logrus.WithField("storage-driver", "devicemapper").Debug("loadDeviceFilesOnStart() END")
-
-	var scan = func(path string, info os.DirEntry, err error) error {
-		if err != nil {
-			logrus.WithField("storage-driver", "devicemapper").Debugf("Can't walk the file %s", path)
-			return nil
-		}
-
-		// Skip any directories
-		if info.IsDir() {
-			return nil
-		}
-
-		return devices.deviceFileWalkFunction(path, info.Name())
-	}
-
-	return filepath.WalkDir(devices.metadataDir(), scan)
-}
-
-// Should be called with devices.Lock() held.
-func (devices *DeviceSet) unregisterDevice(hash string) error {
-	logrus.WithField("storage-driver", "devicemapper").Debugf("unregisterDevice(%v)", hash)
-	info := &devInfo{
-		Hash: hash,
-	}
-
-	delete(devices.Devices, hash)
-
-	if err := devices.removeMetadata(info); err != nil {
-		logrus.WithField("storage-driver", "devicemapper").Debugf("Error removing metadata: %s", err)
-		return err
-	}
-
-	return nil
-}
-
-// Should be called with devices.Lock() held.
-func (devices *DeviceSet) registerDevice(id int, hash string, size uint64, transactionID uint64) (*devInfo, error) {
-	logrus.WithField("storage-driver", "devicemapper").Debugf("registerDevice(%v, %v)", id, hash)
-	info := &devInfo{
-		Hash:          hash,
-		DeviceID:      id,
-		Size:          size,
-		TransactionID: transactionID,
-		Initialized:   false,
-		devices:       devices,
-	}
-
-	devices.Devices[hash] = info
-
-	if err := devices.saveMetadata(info); err != nil {
-		// Try to remove unused device
-		delete(devices.Devices, hash)
-		return nil, err
-	}
-
-	return info, nil
-}
-
-func (devices *DeviceSet) activateDeviceIfNeeded(info *devInfo, ignoreDeleted bool) error {
-	logrus.WithField("storage-driver", "devicemapper").Debugf("activateDeviceIfNeeded(%v)", info.Hash)
-
-	if info.Deleted && !ignoreDeleted {
-		return fmt.Errorf("devmapper: Can't activate device %v as it is marked for deletion", info.Hash)
-	}
-
-	// Make sure deferred removal on device is canceled, if one was
-	// scheduled.
-	if err := devices.cancelDeferredRemovalIfNeeded(info); err != nil {
-		return fmt.Errorf("devmapper: Device Deferred Removal Cancellation Failed: %s", err)
-	}
-
-	if devinfo, _ := devicemapper.GetInfo(info.Name()); devinfo != nil && devinfo.Exists != 0 {
-		return nil
-	}
-
-	return devicemapper.ActivateDevice(devices.getPoolDevName(), info.Name(), info.DeviceID, info.Size)
-}
-
-// xfsSupported checks if xfs is supported, returns nil if it is, otherwise an error
-func xfsSupported() error {
-	// Make sure mkfs.xfs is available
-	if _, err := exec.LookPath("mkfs.xfs"); err != nil {
-		return err // error text is descriptive enough
-	}
-
-	mountTarget, err := os.MkdirTemp("", "supportsXFS")
-	if err != nil {
-		return errors.Wrapf(err, "error checking for xfs support")
-	}
-
-	/* The mounting will fail--after the module has been loaded.*/
-	defer os.RemoveAll(mountTarget)
-	unix.Mount("none", mountTarget, "xfs", 0, "")
-
-	f, err := os.Open("/proc/filesystems")
-	if err != nil {
-		return errors.Wrapf(err, "error checking for xfs support")
-	}
-	defer f.Close()
-
-	s := bufio.NewScanner(f)
-	for s.Scan() {
-		if strings.HasSuffix(s.Text(), "\txfs") {
-			return nil
-		}
-	}
-
-	if err := s.Err(); err != nil {
-		return errors.Wrapf(err, "error checking for xfs support")
-	}
-
-	return errors.New(`kernel does not support xfs, or "modprobe xfs" failed`)
-}
-
-func determineDefaultFS() string {
-	err := xfsSupported()
-	if err == nil {
-		return "xfs"
-	}
-
-	logrus.WithField("storage-driver", "devicemapper").Warnf("XFS is not supported in your system (%v). Defaulting to ext4 filesystem", err)
-	return "ext4"
-}
-
-// mkfsOptions tries to figure out whether some additional mkfs options are required
-func mkfsOptions(fs string) []string {
-	if fs == "xfs" && !kernel.CheckKernelVersion(3, 16, 0) {
-		// For kernels earlier than 3.16 (and newer xfsutils),
-		// some xfs features need to be explicitly disabled.
-		return []string{"-m", "crc=0,finobt=0"}
-	}
-
-	return []string{}
-}
-
-func (devices *DeviceSet) createFilesystem(info *devInfo) (err error) {
-	devname := info.DevName()
-
-	if devices.filesystem == "" {
-		devices.filesystem = determineDefaultFS()
-	}
-	if err := devices.saveBaseDeviceFilesystem(devices.filesystem); err != nil {
-		return err
-	}
-
-	args := mkfsOptions(devices.filesystem)
-	args = append(args, devices.mkfsArgs...)
-	args = append(args, devname)
-
-	logrus.WithField("storage-driver", "devicemapper").Infof("Creating filesystem %s on device %s, mkfs args: %v", devices.filesystem, info.Name(), args)
-	defer func() {
-		if err != nil {
-			logrus.WithField("storage-driver", "devicemapper").Infof("Error while creating filesystem %s on device %s: %v", devices.filesystem, info.Name(), err)
-		} else {
-			logrus.WithField("storage-driver", "devicemapper").Infof("Successfully created filesystem %s on device %s", devices.filesystem, info.Name())
-		}
-	}()
-
-	switch devices.filesystem {
-	case "xfs":
-		err = exec.Command("mkfs.xfs", args...).Run()
-	case "ext4":
-		err = exec.Command("mkfs.ext4", append([]string{"-E", "nodiscard,lazy_itable_init=0,lazy_journal_init=0"}, args...)...).Run()
-		if err != nil {
-			err = exec.Command("mkfs.ext4", append([]string{"-E", "nodiscard,lazy_itable_init=0"}, args...)...).Run()
-		}
-		if err != nil {
-			return err
-		}
-		err = exec.Command("tune2fs", append([]string{"-c", "-1", "-i", "0"}, devname)...).Run()
-	default:
-		err = fmt.Errorf("devmapper: Unsupported filesystem type %s", devices.filesystem)
-	}
-	return
-}
-
-func (devices *DeviceSet) migrateOldMetaData() error {
-	// Migrate old metadata file
-	jsonData, err := os.ReadFile(devices.oldMetadataFile())
-	if err != nil && !os.IsNotExist(err) {
-		return err
-	}
-
-	if jsonData != nil {
-		m := metaData{Devices: make(map[string]*devInfo)}
-
-		if err := json.Unmarshal(jsonData, &m); err != nil {
-			return err
-		}
-
-		for hash, info := range m.Devices {
-			info.Hash = hash
-			devices.saveMetadata(info)
-		}
-		if err := os.Rename(devices.oldMetadataFile(), devices.oldMetadataFile()+".migrated"); err != nil {
-			return err
-		}
-	}
-
-	return nil
-}
-
-// Cleanup deleted devices. It assumes that all the devices have been
-// loaded in the hash table.
-func (devices *DeviceSet) cleanupDeletedDevices() error {
-	devices.Lock()
-
-	// If there are no deleted devices, there is nothing to do.
-	if devices.nrDeletedDevices == 0 {
-		devices.Unlock()
-		return nil
-	}
-
-	var deletedDevices []*devInfo
-
-	for _, info := range devices.Devices {
-		if !info.Deleted {
-			continue
-		}
-		logrus.WithField("storage-driver", "devicemapper").Debugf("Found deleted device %s.", info.Hash)
-		deletedDevices = append(deletedDevices, info)
-	}
-
-	// Delete the deleted devices. DeleteDevice() first takes the info lock
-	// and then devices.Lock(). So drop it to avoid deadlock.
-	devices.Unlock()
-
-	for _, info := range deletedDevices {
-		// This will again try deferred deletion.
-		if err := devices.DeleteDevice(info.Hash, false); err != nil {
-			logrus.WithField("storage-driver", "devicemapper").Warnf("Deletion of device %s, device_id=%v failed:%v", info.Hash, info.DeviceID, err)
-		}
-	}
-
-	return nil
-}
-
-func (devices *DeviceSet) countDeletedDevices() {
-	for _, info := range devices.Devices {
-		if !info.Deleted {
-			continue
-		}
-		devices.nrDeletedDevices++
-	}
-}
-
-func (devices *DeviceSet) startDeviceDeletionWorker() {
-	// Deferred deletion is not enabled. Don't do anything.
-	if !devices.deferredDelete {
-		return
-	}
-
-	logrus.WithField("storage-driver", "devicemapper").Debug("Worker to cleanup deleted devices started")
-	for range devices.deletionWorkerTicker.C {
-		devices.cleanupDeletedDevices()
-	}
-}
-
-func (devices *DeviceSet) initMetaData() error {
-	devices.Lock()
-	defer devices.Unlock()
-
-	if err := devices.migrateOldMetaData(); err != nil {
-		return err
-	}
-
-	_, transactionID, _, _, _, _, err := devices.poolStatus()
-	if err != nil {
-		return err
-	}
-
-	devices.TransactionID = transactionID
-
-	if err := devices.loadDeviceFilesOnStart(); err != nil {
-		return fmt.Errorf("devmapper: Failed to load device files:%v", err)
-	}
-
-	devices.constructDeviceIDMap()
-	devices.countDeletedDevices()
-
-	if err := devices.processPendingTransaction(); err != nil {
-		return err
-	}
-
-	// Start a goroutine to cleanup Deleted Devices
-	go devices.startDeviceDeletionWorker()
-	return nil
-}
-
-func (devices *DeviceSet) incNextDeviceID() {
-	// IDs are 24bit, so wrap around
-	devices.NextDeviceID = (devices.NextDeviceID + 1) & maxDeviceID
-}
-
-func (devices *DeviceSet) getNextFreeDeviceID() (int, error) {
-	devices.incNextDeviceID()
-	for i := 0; i <= maxDeviceID; i++ {
-		if devices.isDeviceIDFree(devices.NextDeviceID) {
-			devices.markDeviceIDUsed(devices.NextDeviceID)
-			return devices.NextDeviceID, nil
-		}
-		devices.incNextDeviceID()
-	}
-
-	return 0, fmt.Errorf("devmapper: Unable to find a free device ID")
-}
-
-func (devices *DeviceSet) poolHasFreeSpace() error {
-	if devices.minFreeSpacePercent == 0 {
-		return nil
-	}
-
-	_, _, dataUsed, dataTotal, metadataUsed, metadataTotal, err := devices.poolStatus()
-	if err != nil {
-		return err
-	}
-
-	minFreeData := (dataTotal * uint64(devices.minFreeSpacePercent)) / 100
-	if minFreeData < 1 {
-		minFreeData = 1
-	}
-	dataFree := dataTotal - dataUsed
-	if dataFree < minFreeData {
-		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)
-	}
-
-	minFreeMetadata := (metadataTotal * uint64(devices.minFreeSpacePercent)) / 100
-	if minFreeMetadata < 1 {
-		minFreeMetadata = 1
-	}
-
-	metadataFree := metadataTotal - metadataUsed
-	if metadataFree < minFreeMetadata {
-		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)
-	}
-
-	return nil
-}
-
-func (devices *DeviceSet) createRegisterDevice(hash string) (*devInfo, error) {
-	devices.Lock()
-	defer devices.Unlock()
-
-	deviceID, err := devices.getNextFreeDeviceID()
-	if err != nil {
-		return nil, err
-	}
-
-	logger := logrus.WithField("storage-driver", "devicemapper")
-
-	if err := devices.openTransaction(hash, deviceID); err != nil {
-		logger.Debugf("Error opening transaction hash = %s deviceID = %d", hash, deviceID)
-		devices.markDeviceIDFree(deviceID)
-		return nil, err
-	}
-
-	for {
-		if err := devicemapper.CreateDevice(devices.getPoolDevName(), deviceID); err != nil {
-			if devicemapper.DeviceIDExists(err) {
-				// Device ID already exists. This should not
-				// happen. Now we have a mechanism to find
-				// a free device ID. So something is not right.
-				// Give a warning and continue.
-				logger.Errorf("Device ID %d exists in pool but it is supposed to be unused", deviceID)
-				deviceID, err = devices.getNextFreeDeviceID()
-				if err != nil {
-					return nil, err
-				}
-				// Save new device id into transaction
-				devices.refreshTransaction(deviceID)
-				continue
-			}
-			logger.Debugf("Error creating device: %s", err)
-			devices.markDeviceIDFree(deviceID)
-			return nil, err
-		}
-		break
-	}
-
-	logger.Debugf("Registering device (id %v) with FS size %v", deviceID, devices.baseFsSize)
-	info, err := devices.registerDevice(deviceID, hash, devices.baseFsSize, devices.OpenTransactionID)
-	if err != nil {
-		_ = devicemapper.DeleteDevice(devices.getPoolDevName(), deviceID)
-		devices.markDeviceIDFree(deviceID)
-		return nil, err
-	}
-
-	if err := devices.closeTransaction(); err != nil {
-		devices.unregisterDevice(hash)
-		devicemapper.DeleteDevice(devices.getPoolDevName(), deviceID)
-		devices.markDeviceIDFree(deviceID)
-		return nil, err
-	}
-	return info, nil
-}
-
-func (devices *DeviceSet) takeSnapshot(hash string, baseInfo *devInfo, size uint64) error {
-	var (
-		devinfo *devicemapper.Info
-		err     error
-	)
-
-	if err = devices.poolHasFreeSpace(); err != nil {
-		return err
-	}
-
-	if devices.deferredRemove {
-		devinfo, err = devicemapper.GetInfoWithDeferred(baseInfo.Name())
-		if err != nil {
-			return err
-		}
-		if devinfo != nil && devinfo.DeferredRemove != 0 {
-			err = devices.cancelDeferredRemoval(baseInfo)
-			if err != nil {
-				// If Error is ErrEnxio. Device is probably already gone. Continue.
-				if err != devicemapper.ErrEnxio {
-					return err
-				}
-				devinfo = nil
-			} else {
-				defer devices.deactivateDevice(baseInfo)
-			}
-		}
-	} else {
-		devinfo, err = devicemapper.GetInfo(baseInfo.Name())
-		if err != nil {
-			return err
-		}
-	}
-
-	doSuspend := devinfo != nil && devinfo.Exists != 0
-
-	if doSuspend {
-		if err = devicemapper.SuspendDevice(baseInfo.Name()); err != nil {
-			return err
-		}
-		defer devicemapper.ResumeDevice(baseInfo.Name())
-	}
-
-	return devices.createRegisterSnapDevice(hash, baseInfo, size)
-}
-
-func (devices *DeviceSet) createRegisterSnapDevice(hash string, baseInfo *devInfo, size uint64) error {
-	deviceID, err := devices.getNextFreeDeviceID()
-	if err != nil {
-		return err
-	}
-
-	logger := logrus.WithField("storage-driver", "devicemapper")
-
-	if err := devices.openTransaction(hash, deviceID); err != nil {
-		logger.Debugf("Error opening transaction hash = %s deviceID = %d", hash, deviceID)
-		devices.markDeviceIDFree(deviceID)
-		return err
-	}
-
-	for {
-		if err := devicemapper.CreateSnapDeviceRaw(devices.getPoolDevName(), deviceID, baseInfo.DeviceID); err != nil {
-			if devicemapper.DeviceIDExists(err) {
-				// Device ID already exists. This should not
-				// happen. Now we have a mechanism to find
-				// a free device ID. So something is not right.
-				// Give a warning and continue.
-				logger.Errorf("Device ID %d exists in pool but it is supposed to be unused", deviceID)
-				deviceID, err = devices.getNextFreeDeviceID()
-				if err != nil {
-					return err
-				}
-				// Save new device id into transaction
-				devices.refreshTransaction(deviceID)
-				continue
-			}
-			logger.Debugf("Error creating snap device: %s", err)
-			devices.markDeviceIDFree(deviceID)
-			return err
-		}
-		break
-	}
-
-	if _, err := devices.registerDevice(deviceID, hash, size, devices.OpenTransactionID); err != nil {
-		devicemapper.DeleteDevice(devices.getPoolDevName(), deviceID)
-		devices.markDeviceIDFree(deviceID)
-		logger.Debugf("Error registering device: %s", err)
-		return err
-	}
-
-	if err := devices.closeTransaction(); err != nil {
-		devices.unregisterDevice(hash)
-		devicemapper.DeleteDevice(devices.getPoolDevName(), deviceID)
-		devices.markDeviceIDFree(deviceID)
-		return err
-	}
-	return nil
-}
-
-func (devices *DeviceSet) loadMetadata(hash string) *devInfo {
-	info := &devInfo{Hash: hash, devices: devices}
-	logger := logrus.WithField("storage-driver", "devicemapper")
-
-	jsonData, err := os.ReadFile(devices.metadataFile(info))
-	if err != nil {
-		logger.Debugf("Failed to read %s with err: %v", devices.metadataFile(info), err)
-		return nil
-	}
-
-	if err := json.Unmarshal(jsonData, &info); err != nil {
-		logger.Debugf("Failed to unmarshal devInfo from %s with err: %v", devices.metadataFile(info), err)
-		return nil
-	}
-
-	if info.DeviceID > maxDeviceID {
-		logger.Errorf("Ignoring Invalid DeviceId=%d", info.DeviceID)
-		return nil
-	}
-
-	return info
-}
-
-func getDeviceUUID(device string) (string, error) {
-	out, err := exec.Command("blkid", "-s", "UUID", "-o", "value", device).Output()
-	if err != nil {
-		return "", fmt.Errorf("devmapper: Failed to find uuid for device %s:%v", device, err)
-	}
-
-	uuid := strings.TrimSuffix(string(out), "\n")
-	uuid = strings.TrimSpace(uuid)
-	logrus.WithField("storage-driver", "devicemapper").Debugf("UUID for device: %s is:%s", device, uuid)
-	return uuid, nil
-}
-
-func (devices *DeviceSet) getBaseDeviceSize() uint64 {
-	info, _ := devices.lookupDevice("")
-	if info == nil {
-		return 0
-	}
-	return info.Size
-}
-
-func (devices *DeviceSet) getBaseDeviceFS() string {
-	return devices.BaseDeviceFilesystem
-}
-
-func (devices *DeviceSet) verifyBaseDeviceUUIDFS(baseInfo *devInfo) error {
-	devices.Lock()
-	defer devices.Unlock()
-
-	if err := devices.activateDeviceIfNeeded(baseInfo, false); err != nil {
-		return err
-	}
-	defer devices.deactivateDevice(baseInfo)
-
-	uuid, err := getDeviceUUID(baseInfo.DevName())
-	if err != nil {
-		return err
-	}
-
-	if devices.BaseDeviceUUID != uuid {
-		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)
-	}
-
-	if devices.BaseDeviceFilesystem == "" {
-		fsType, err := ProbeFsType(baseInfo.DevName())
-		if err != nil {
-			return err
-		}
-		if err := devices.saveBaseDeviceFilesystem(fsType); err != nil {
-			return err
-		}
-	}
-
-	// If user specified a filesystem using dm.fs option and current
-	// file system of base image is not same, warn user that dm.fs
-	// will be ignored.
-	if devices.BaseDeviceFilesystem != devices.filesystem {
-		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)
-		devices.filesystem = devices.BaseDeviceFilesystem
-	}
-	return nil
-}
-
-func (devices *DeviceSet) saveBaseDeviceFilesystem(fs string) error {
-	devices.BaseDeviceFilesystem = fs
-	return devices.saveDeviceSetMetaData()
-}
-
-func (devices *DeviceSet) saveBaseDeviceUUID(baseInfo *devInfo) error {
-	devices.Lock()
-	defer devices.Unlock()
-
-	if err := devices.activateDeviceIfNeeded(baseInfo, false); err != nil {
-		return err
-	}
-	defer devices.deactivateDevice(baseInfo)
-
-	uuid, err := getDeviceUUID(baseInfo.DevName())
-	if err != nil {
-		return err
-	}
-
-	devices.BaseDeviceUUID = uuid
-	return devices.saveDeviceSetMetaData()
-}
-
-func (devices *DeviceSet) createBaseImage() error {
-	logrus.WithField("storage-driver", "devicemapper").Debug("Initializing base device-mapper thin volume")
-
-	// Create initial device
-	info, err := devices.createRegisterDevice("")
-	if err != nil {
-		return err
-	}
-
-	logrus.WithField("storage-driver", "devicemapper").Debug("Creating filesystem on base device-mapper thin volume")
-
-	if err := devices.activateDeviceIfNeeded(info, false); err != nil {
-		return err
-	}
-
-	if err := devices.createFilesystem(info); err != nil {
-		return err
-	}
-
-	info.Initialized = true
-	if err := devices.saveMetadata(info); err != nil {
-		info.Initialized = false
-		return err
-	}
-
-	if err := devices.saveBaseDeviceUUID(info); err != nil {
-		return fmt.Errorf("devmapper: Could not query and save base device UUID:%v", err)
-	}
-
-	return nil
-}
-
-// Returns if thin pool device exists or not. If device exists, also makes
-// sure it is a thin pool device and not some other type of device.
-func (devices *DeviceSet) thinPoolExists(thinPoolDevice string) (bool, error) {
-	logrus.WithField("storage-driver", "devicemapper").Debugf("Checking for existence of the pool %s", thinPoolDevice)
-
-	info, err := devicemapper.GetInfo(thinPoolDevice)
-	if err != nil {
-		return false, fmt.Errorf("devmapper: GetInfo() on device %s failed: %v", thinPoolDevice, err)
-	}
-
-	// Device does not exist.
-	if info.Exists == 0 {
-		return false, nil
-	}
-
-	_, _, deviceType, _, err := devicemapper.GetStatus(thinPoolDevice)
-	if err != nil {
-		return false, fmt.Errorf("devmapper: GetStatus() on device %s failed: %v", thinPoolDevice, err)
-	}
-
-	if deviceType != "thin-pool" {
-		return false, fmt.Errorf("devmapper: Device %s is not a thin pool", thinPoolDevice)
-	}
-
-	return true, nil
-}
-
-func (devices *DeviceSet) checkThinPool() error {
-	_, transactionID, dataUsed, _, _, _, err := devices.poolStatus()
-	if err != nil {
-		return err
-	}
-	if dataUsed != 0 {
-		return fmt.Errorf("devmapper: Unable to take ownership of thin-pool (%s) that already has used data blocks",
-			devices.thinPoolDevice)
-	}
-	if transactionID != 0 {
-		return fmt.Errorf("devmapper: Unable to take ownership of thin-pool (%s) with non-zero transaction ID",
-			devices.thinPoolDevice)
-	}
-	return nil
-}
-
-// Base image is initialized properly. Either save UUID for first time (for
-// upgrade case or verify UUID.
-func (devices *DeviceSet) setupVerifyBaseImageUUIDFS(baseInfo *devInfo) error {
-	// If BaseDeviceUUID is nil (upgrade case), save it and return success.
-	if devices.BaseDeviceUUID == "" {
-		if err := devices.saveBaseDeviceUUID(baseInfo); err != nil {
-			return fmt.Errorf("devmapper: Could not query and save base device UUID:%v", err)
-		}
-		return nil
-	}
-
-	if err := devices.verifyBaseDeviceUUIDFS(baseInfo); err != nil {
-		return fmt.Errorf("devmapper: Base Device UUID and Filesystem verification failed: %v", err)
-	}
-
-	return nil
-}
-
-func (devices *DeviceSet) checkGrowBaseDeviceFS(info *devInfo) error {
-	if !userBaseSize {
-		return nil
-	}
-
-	if devices.baseFsSize < devices.getBaseDeviceSize() {
-		return fmt.Errorf("devmapper: Base device size cannot be smaller than %s", units.HumanSize(float64(devices.getBaseDeviceSize())))
-	}
-
-	if devices.baseFsSize == devices.getBaseDeviceSize() {
-		return nil
-	}
-
-	info.lock.Lock()
-	defer info.lock.Unlock()
-
-	devices.Lock()
-	defer devices.Unlock()
-
-	info.Size = devices.baseFsSize
-
-	if err := devices.saveMetadata(info); err != nil {
-		// Try to remove unused device
-		delete(devices.Devices, info.Hash)
-		return err
-	}
-
-	return devices.growFS(info)
-}
-
-func (devices *DeviceSet) growFS(info *devInfo) error {
-	if err := devices.activateDeviceIfNeeded(info, false); err != nil {
-		return fmt.Errorf("Error activating devmapper device: %s", err)
-	}
-
-	defer devices.deactivateDevice(info)
-
-	fsMountPoint := "/run/docker/mnt"
-	if _, err := os.Stat(fsMountPoint); os.IsNotExist(err) {
-		if err := os.MkdirAll(fsMountPoint, 0700); err != nil {
-			return err
-		}
-		defer os.RemoveAll(fsMountPoint)
-	}
-
-	options := ""
-	if devices.BaseDeviceFilesystem == "xfs" {
-		// XFS needs nouuid or it can't mount filesystems with the same fs
-		options = joinMountOptions(options, "nouuid")
-	}
-	options = joinMountOptions(options, devices.mountOptions)
-
-	if err := mount.Mount(info.DevName(), fsMountPoint, devices.BaseDeviceFilesystem, options); err != nil {
-		return errors.Wrapf(err, "Failed to mount; dmesg: %s", string(dmesg.Dmesg(256)))
-	}
-
-	defer unix.Unmount(fsMountPoint, unix.MNT_DETACH)
-
-	switch devices.BaseDeviceFilesystem {
-	case "ext4":
-		if out, err := exec.Command("resize2fs", info.DevName()).CombinedOutput(); err != nil {
-			return fmt.Errorf("Failed to grow rootfs:%v:%s", err, string(out))
-		}
-	case "xfs":
-		if out, err := exec.Command("xfs_growfs", info.DevName()).CombinedOutput(); err != nil {
-			return fmt.Errorf("Failed to grow rootfs:%v:%s", err, string(out))
-		}
-	default:
-		return fmt.Errorf("Unsupported filesystem type %s", devices.BaseDeviceFilesystem)
-	}
-	return nil
-}
-
-func (devices *DeviceSet) setupBaseImage() error {
-	oldInfo, _ := devices.lookupDeviceWithLock("")
-
-	// base image already exists. If it is initialized properly, do UUID
-	// verification and return. Otherwise remove image and set it up
-	// fresh.
-
-	if oldInfo != nil {
-		if oldInfo.Initialized && !oldInfo.Deleted {
-			if err := devices.setupVerifyBaseImageUUIDFS(oldInfo); err != nil {
-				return err
-			}
-			return devices.checkGrowBaseDeviceFS(oldInfo)
-		}
-
-		logrus.WithField("storage-driver", "devicemapper").Debug("Removing uninitialized base image")
-		// If previous base device is in deferred delete state,
-		// that needs to be cleaned up first. So don't try
-		// deferred deletion.
-		if err := devices.DeleteDevice("", true); err != nil {
-			return err
-		}
-	}
-
-	// If we are setting up base image for the first time, make sure
-	// thin pool is empty.
-	if devices.thinPoolDevice != "" && oldInfo == nil {
-		if err := devices.checkThinPool(); err != nil {
-			return err
-		}
-	}
-
-	// Create new base image device
-	return devices.createBaseImage()
-}
-
-func setCloseOnExec(name string) {
-	fileInfos, _ := os.ReadDir("/proc/self/fd")
-	for _, i := range fileInfos {
-		link, _ := os.Readlink(filepath.Join("/proc/self/fd", i.Name()))
-		if link == name {
-			fd, err := strconv.Atoi(i.Name())
-			if err == nil {
-				unix.CloseOnExec(fd)
-			}
-		}
-	}
-}
-
-func major(device uint64) uint64 {
-	return (device >> 8) & 0xfff
-}
-
-func minor(device uint64) uint64 {
-	return (device & 0xff) | ((device >> 12) & 0xfff00)
-}
-
-// ResizePool increases the size of the pool.
-func (devices *DeviceSet) ResizePool(size int64) error {
-	dirname := devices.loopbackDir()
-	datafilename := path.Join(dirname, "data")
-	if len(devices.dataDevice) > 0 {
-		datafilename = devices.dataDevice
-	}
-	metadatafilename := path.Join(dirname, "metadata")
-	if len(devices.metadataDevice) > 0 {
-		metadatafilename = devices.metadataDevice
-	}
-
-	datafile, err := os.OpenFile(datafilename, os.O_RDWR, 0)
-	if datafile == nil {
-		return err
-	}
-	defer datafile.Close()
-
-	fi, err := datafile.Stat()
-	if fi == nil {
-		return err
-	}
-
-	if fi.Size() > size {
-		return fmt.Errorf("devmapper: Can't shrink file")
-	}
-
-	dataloopback := loopback.FindLoopDeviceFor(datafile)
-	if dataloopback == nil {
-		return fmt.Errorf("devmapper: Unable to find loopback mount for: %s", datafilename)
-	}
-	defer dataloopback.Close()
-
-	metadatafile, err := os.OpenFile(metadatafilename, os.O_RDWR, 0)
-	if metadatafile == nil {
-		return err
-	}
-	defer metadatafile.Close()
-
-	metadataloopback := loopback.FindLoopDeviceFor(metadatafile)
-	if metadataloopback == nil {
-		return fmt.Errorf("devmapper: Unable to find loopback mount for: %s", metadatafilename)
-	}
-	defer metadataloopback.Close()
-
-	// Grow loopback file
-	if err := datafile.Truncate(size); err != nil {
-		return fmt.Errorf("devmapper: Unable to grow loopback file: %s", err)
-	}
-
-	// Reload size for loopback device
-	if err := loopback.SetCapacity(dataloopback); err != nil {
-		return fmt.Errorf("Unable to update loopback capacity: %s", err)
-	}
-
-	// Suspend the pool
-	if err := devicemapper.SuspendDevice(devices.getPoolName()); err != nil {
-		return fmt.Errorf("devmapper: Unable to suspend pool: %s", err)
-	}
-
-	// Reload with the new block sizes
-	if err := devicemapper.ReloadPool(devices.getPoolName(), dataloopback, metadataloopback, devices.thinpBlockSize); err != nil {
-		return fmt.Errorf("devmapper: Unable to reload pool: %s", err)
-	}
-
-	// Resume the pool
-	if err := devicemapper.ResumeDevice(devices.getPoolName()); err != nil {
-		return fmt.Errorf("devmapper: Unable to resume pool: %s", err)
-	}
-
-	return nil
-}
-
-func (devices *DeviceSet) loadTransactionMetaData() error {
-	jsonData, err := os.ReadFile(devices.transactionMetaFile())
-	if err != nil {
-		// There is no active transaction. This will be the case
-		// during upgrade.
-		if os.IsNotExist(err) {
-			devices.OpenTransactionID = devices.TransactionID
-			return nil
-		}
-		return err
-	}
-
-	json.Unmarshal(jsonData, &devices.transaction)
-	return nil
-}
-
-func (devices *DeviceSet) saveTransactionMetaData() error {
-	jsonData, err := json.Marshal(&devices.transaction)
-	if err != nil {
-		return fmt.Errorf("devmapper: Error encoding metadata to json: %s", err)
-	}
-
-	return devices.writeMetaFile(jsonData, devices.transactionMetaFile())
-}
-
-func (devices *DeviceSet) removeTransactionMetaData() error {
-	return os.RemoveAll(devices.transactionMetaFile())
-}
-
-func (devices *DeviceSet) rollbackTransaction() error {
-	logger := logrus.WithField("storage-driver", "devicemapper")
-
-	logger.Debugf("Rolling back open transaction: TransactionID=%d hash=%s device_id=%d", devices.OpenTransactionID, devices.DeviceIDHash, devices.DeviceID)
-
-	// A device id might have already been deleted before transaction
-	// closed. In that case this call will fail. Just leave a message
-	// in case of failure.
-	if err := devicemapper.DeleteDevice(devices.getPoolDevName(), devices.DeviceID); err != nil {
-		logger.Errorf("Unable to delete device: %s", err)
-	}
-
-	dinfo := &devInfo{Hash: devices.DeviceIDHash}
-	if err := devices.removeMetadata(dinfo); err != nil {
-		logger.Errorf("Unable to remove metadata: %s", err)
-	} else {
-		devices.markDeviceIDFree(devices.DeviceID)
-	}
-
-	if err := devices.removeTransactionMetaData(); err != nil {
-		logger.Errorf("Unable to remove transaction meta file %s: %s", devices.transactionMetaFile(), err)
-	}
-
-	return nil
-}
-
-func (devices *DeviceSet) processPendingTransaction() error {
-	if err := devices.loadTransactionMetaData(); err != nil {
-		return err
-	}
-
-	// If there was open transaction but pool transaction ID is same
-	// as open transaction ID, nothing to roll back.
-	if devices.TransactionID == devices.OpenTransactionID {
-		return nil
-	}
-
-	// If open transaction ID is less than pool transaction ID, something
-	// is wrong. Bail out.
-	if devices.OpenTransactionID < devices.TransactionID {
-		logrus.WithField("storage-driver", "devicemapper").Errorf("Open Transaction id %d is less than pool transaction id %d", devices.OpenTransactionID, devices.TransactionID)
-		return nil
-	}
-
-	// Pool transaction ID is not same as open transaction. There is
-	// a transaction which was not completed.
-	if err := devices.rollbackTransaction(); err != nil {
-		return fmt.Errorf("devmapper: Rolling back open transaction failed: %s", err)
-	}
-
-	devices.OpenTransactionID = devices.TransactionID
-	return nil
-}
-
-func (devices *DeviceSet) loadDeviceSetMetaData() error {
-	jsonData, err := os.ReadFile(devices.deviceSetMetaFile())
-	if err != nil {
-		// For backward compatibility return success if file does
-		// not exist.
-		if os.IsNotExist(err) {
-			return nil
-		}
-		return err
-	}
-
-	return json.Unmarshal(jsonData, devices)
-}
-
-func (devices *DeviceSet) saveDeviceSetMetaData() error {
-	jsonData, err := json.Marshal(devices)
-	if err != nil {
-		return fmt.Errorf("devmapper: Error encoding metadata to json: %s", err)
-	}
-
-	return devices.writeMetaFile(jsonData, devices.deviceSetMetaFile())
-}
-
-func (devices *DeviceSet) openTransaction(hash string, DeviceID int) error {
-	devices.allocateTransactionID()
-	devices.DeviceIDHash = hash
-	devices.DeviceID = DeviceID
-	if err := devices.saveTransactionMetaData(); err != nil {
-		return fmt.Errorf("devmapper: Error saving transaction metadata: %s", err)
-	}
-	return nil
-}
-
-func (devices *DeviceSet) refreshTransaction(DeviceID int) error {
-	devices.DeviceID = DeviceID
-	if err := devices.saveTransactionMetaData(); err != nil {
-		return fmt.Errorf("devmapper: Error saving transaction metadata: %s", err)
-	}
-	return nil
-}
-
-func (devices *DeviceSet) closeTransaction() error {
-	if err := devices.updatePoolTransactionID(); err != nil {
-		logrus.WithField("storage-driver", "devicemapper").Debug("Failed to close Transaction")
-		return err
-	}
-	return nil
-}
-
-func determineDriverCapabilities(version string) error {
-	// Kernel driver version >= 4.27.0 support deferred removal
-
-	logrus.WithField("storage-driver", "devicemapper").Debugf("kernel dm driver version is %s", version)
-
-	versionSplit := strings.Split(version, ".")
-	major, err := strconv.Atoi(versionSplit[0])
-	if err != nil {
-		return graphdriver.ErrNotSupported
-	}
-
-	if major > 4 {
-		driverDeferredRemovalSupport = true
-		return nil
-	}
-
-	if major < 4 {
-		return nil
-	}
-
-	minor, err := strconv.Atoi(versionSplit[1])
-	if err != nil {
-		return graphdriver.ErrNotSupported
-	}
-
-	/*
-	 * If major is 4 and minor is 27, then there is no need to
-	 * check for patch level as it can not be less than 0.
-	 */
-	if minor >= 27 {
-		driverDeferredRemovalSupport = true
-		return nil
-	}
-
-	return nil
-}
-
-// Determine the major and minor number of loopback device
-func getDeviceMajorMinor(file *os.File) (uint64, uint64, error) {
-	var stat unix.Stat_t
-	err := unix.Stat(file.Name(), &stat)
-	if err != nil {
-		return 0, 0, err
-	}
-
-	// the type is 32bit on mips
-	dev := uint64(stat.Rdev) //nolint: unconvert
-	majorNum := major(dev)
-	minorNum := minor(dev)
-
-	logrus.WithField("storage-driver", "devicemapper").Debugf("Major:Minor for device: %s is:%v:%v", file.Name(), majorNum, minorNum)
-	return majorNum, minorNum, nil
-}
-
-// Given a file which is backing file of a loop back device, find the
-// loopback device name and its major/minor number.
-func getLoopFileDeviceMajMin(filename string) (string, uint64, uint64, error) {
-	file, err := os.Open(filename)
-	if err != nil {
-		logrus.WithField("storage-driver", "devicemapper").Debugf("Failed to open file %s", filename)
-		return "", 0, 0, err
-	}
-
-	defer file.Close()
-	loopbackDevice := loopback.FindLoopDeviceFor(file)
-	if loopbackDevice == nil {
-		return "", 0, 0, fmt.Errorf("devmapper: Unable to find loopback mount for: %s", filename)
-	}
-	defer loopbackDevice.Close()
-
-	Major, Minor, err := getDeviceMajorMinor(loopbackDevice)
-	if err != nil {
-		return "", 0, 0, err
-	}
-	return loopbackDevice.Name(), Major, Minor, nil
-}
-
-// Get the major/minor numbers of thin pool data and metadata devices
-func (devices *DeviceSet) getThinPoolDataMetaMajMin() (uint64, uint64, uint64, uint64, error) {
-	var params, poolDataMajMin, poolMetadataMajMin string
-
-	_, _, _, params, err := devicemapper.GetTable(devices.getPoolName())
-	if err != nil {
-		return 0, 0, 0, 0, err
-	}
-
-	if _, err = fmt.Sscanf(params, "%s %s", &poolMetadataMajMin, &poolDataMajMin); err != nil {
-		return 0, 0, 0, 0, err
-	}
-
-	logrus.WithField("storage-driver", "devicemapper").Debugf("poolDataMajMin=%s poolMetaMajMin=%s\n", poolDataMajMin, poolMetadataMajMin)
-
-	poolDataMajMinorSplit := strings.Split(poolDataMajMin, ":")
-	poolDataMajor, err := strconv.ParseUint(poolDataMajMinorSplit[0], 10, 32)
-	if err != nil {
-		return 0, 0, 0, 0, err
-	}
-
-	poolDataMinor, err := strconv.ParseUint(poolDataMajMinorSplit[1], 10, 32)
-	if err != nil {
-		return 0, 0, 0, 0, err
-	}
-
-	poolMetadataMajMinorSplit := strings.Split(poolMetadataMajMin, ":")
-	poolMetadataMajor, err := strconv.ParseUint(poolMetadataMajMinorSplit[0], 10, 32)
-	if err != nil {
-		return 0, 0, 0, 0, err
-	}
-
-	poolMetadataMinor, err := strconv.ParseUint(poolMetadataMajMinorSplit[1], 10, 32)
-	if err != nil {
-		return 0, 0, 0, 0, err
-	}
-
-	return poolDataMajor, poolDataMinor, poolMetadataMajor, poolMetadataMinor, nil
-}
-
-func (devices *DeviceSet) loadThinPoolLoopBackInfo() error {
-	poolDataMajor, poolDataMinor, poolMetadataMajor, poolMetadataMinor, err := devices.getThinPoolDataMetaMajMin()
-	if err != nil {
-		return err
-	}
-
-	dirname := devices.loopbackDir()
-
-	// data device has not been passed in. So there should be a data file
-	// which is being mounted as loop device.
-	if devices.dataDevice == "" {
-		datafilename := path.Join(dirname, "data")
-		dataLoopDevice, dataMajor, dataMinor, err := getLoopFileDeviceMajMin(datafilename)
-		if err != nil {
-			return err
-		}
-
-		// Compare the two
-		if poolDataMajor == dataMajor && poolDataMinor == dataMinor {
-			devices.dataDevice = dataLoopDevice
-			devices.dataLoopFile = datafilename
-		}
-	}
-
-	// metadata device has not been passed in. So there should be a
-	// metadata file which is being mounted as loop device.
-	if devices.metadataDevice == "" {
-		metadatafilename := path.Join(dirname, "metadata")
-		metadataLoopDevice, metadataMajor, metadataMinor, err := getLoopFileDeviceMajMin(metadatafilename)
-		if err != nil {
-			return err
-		}
-		if poolMetadataMajor == metadataMajor && poolMetadataMinor == metadataMinor {
-			devices.metadataDevice = metadataLoopDevice
-			devices.metadataLoopFile = metadatafilename
-		}
-	}
-
-	return nil
-}
-
-func (devices *DeviceSet) enableDeferredRemovalDeletion() error {
-	// If user asked for deferred removal then check both libdm library
-	// and kernel driver support deferred removal otherwise error out.
-	if enableDeferredRemoval {
-		if !driverDeferredRemovalSupport {
-			return fmt.Errorf("devmapper: Deferred removal can not be enabled as kernel does not support it")
-		}
-		if !devicemapper.LibraryDeferredRemovalSupport {
-			return fmt.Errorf("devmapper: Deferred removal can not be enabled as libdm does not support it")
-		}
-		logrus.WithField("storage-driver", "devicemapper").Debug("Deferred removal support enabled.")
-		devices.deferredRemove = true
-	}
-
-	if enableDeferredDeletion {
-		if !devices.deferredRemove {
-			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")
-		}
-		logrus.WithField("storage-driver", "devicemapper").Debug("Deferred deletion support enabled.")
-		devices.deferredDelete = true
-	}
-	return nil
-}
-
-func (devices *DeviceSet) initDevmapper(doInit bool) (retErr error) {
-	if err := devices.enableDeferredRemovalDeletion(); err != nil {
-		return err
-	}
-
-	logger := logrus.WithField("storage-driver", "devicemapper")
-
-	// https://github.com/docker/docker/issues/4036
-	if supported := devicemapper.UdevSetSyncSupport(true); !supported {
-		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/")
-		if !devices.overrideUdevSyncCheck {
-			return graphdriver.ErrNotSupported
-		}
-	}
-
-	// create the root dir of the devmapper driver ownership to match this
-	// daemon's remapped root uid/gid so containers can start properly
-	if err := idtools.MkdirAndChown(devices.root, 0700, devices.idMap.RootPair()); err != nil {
-		return err
-	}
-	if err := os.MkdirAll(devices.metadataDir(), 0700); err != nil {
-		return err
-	}
-
-	prevSetupConfig, err := readLVMConfig(devices.root)
-	if err != nil {
-		return err
-	}
-
-	if !reflect.DeepEqual(devices.lvmSetupConfig, directLVMConfig{}) {
-		if devices.thinPoolDevice != "" {
-			return errors.New("cannot setup direct-lvm when `dm.thinpooldev` is also specified")
-		}
-
-		if !reflect.DeepEqual(prevSetupConfig, devices.lvmSetupConfig) {
-			if !reflect.DeepEqual(prevSetupConfig, directLVMConfig{}) {
-				return errors.New("changing direct-lvm config is not supported")
-			}
-			logger.WithField("direct-lvm-config", devices.lvmSetupConfig).Debugf("Setting up direct lvm mode")
-			if err := verifyBlockDevice(devices.lvmSetupConfig.Device, lvmSetupConfigForce); err != nil {
-				return err
-			}
-			if err := setupDirectLVM(devices.lvmSetupConfig); err != nil {
-				return err
-			}
-			if err := writeLVMConfig(devices.root, devices.lvmSetupConfig); err != nil {
-				return err
-			}
-		}
-		devices.thinPoolDevice = "docker-thinpool"
-		logger.Debugf("Setting dm.thinpooldev to %q", devices.thinPoolDevice)
-	}
-
-	// Set the device prefix from the device id and inode of the docker root dir
-	var st unix.Stat_t
-	if err := unix.Stat(devices.root, &st); err != nil {
-		return fmt.Errorf("devmapper: Error looking up dir %s: %s", devices.root, err)
-	}
-	// "reg-" stands for "regular file".
-	// In the future we might use "dev-" for "device file", etc.
-	// docker-maj,min[-inode] stands for:
-	//	- Managed by docker
-	//	- The target of this device is at major <maj> and minor <min>
-	//	- If <inode> is defined, use that file inside the device as a loopback image. Otherwise use the device itself.
-	// The type Dev in Stat_t is 32bit on mips.
-	devices.devicePrefix = fmt.Sprintf("docker-%d:%d-%d", major(uint64(st.Dev)), minor(uint64(st.Dev)), st.Ino) //nolint: unconvert
-	logger.Debugf("Generated prefix: %s", devices.devicePrefix)
-
-	// Check for the existence of the thin-pool device
-	poolExists, err := devices.thinPoolExists(devices.getPoolName())
-	if err != nil {
-		return err
-	}
-
-	// It seems libdevmapper opens this without O_CLOEXEC, and go exec will not close files
-	// that are not Close-on-exec,
-	// so we add this badhack to make sure it closes itself
-	setCloseOnExec("/dev/mapper/control")
-
-	// Make sure the sparse images exist in <root>/devicemapper/data and
-	// <root>/devicemapper/metadata
-
-	createdLoopback := false
-
-	// If the pool doesn't exist, create it
-	if !poolExists && devices.thinPoolDevice == "" {
-		logger.Debug("Pool doesn't exist. Creating it.")
-
-		var (
-			dataFile     *os.File
-			metadataFile *os.File
-		)
-
-		if devices.dataDevice == "" {
-			// Make sure the sparse images exist in <root>/devicemapper/data
-
-			hasData := devices.hasImage("data")
-
-			if !doInit && !hasData {
-				return errors.New("loopback data file not found")
-			}
-
-			if !hasData {
-				createdLoopback = true
-			}
-
-			data, err := devices.ensureImage("data", devices.dataLoopbackSize)
-			if err != nil {
-				logger.Debugf("Error device ensureImage (data): %s", err)
-				return err
-			}
-
-			dataFile, err = loopback.AttachLoopDevice(data)
-			if err != nil {
-				return err
-			}
-			devices.dataLoopFile = data
-			devices.dataDevice = dataFile.Name()
-		} else {
-			dataFile, err = os.OpenFile(devices.dataDevice, os.O_RDWR, 0600)
-			if err != nil {
-				return err
-			}
-		}
-		defer dataFile.Close()
-
-		if devices.metadataDevice == "" {
-			// Make sure the sparse images exist in <root>/devicemapper/metadata
-
-			hasMetadata := devices.hasImage("metadata")
-
-			if !doInit && !hasMetadata {
-				return errors.New("loopback metadata file not found")
-			}
-
-			if !hasMetadata {
-				createdLoopback = true
-			}
-
-			metadata, err := devices.ensureImage("metadata", devices.metaDataLoopbackSize)
-			if err != nil {
-				logger.Debugf("Error device ensureImage (metadata): %s", err)
-				return err
-			}
-
-			metadataFile, err = loopback.AttachLoopDevice(metadata)
-			if err != nil {
-				return err
-			}
-			devices.metadataLoopFile = metadata
-			devices.metadataDevice = metadataFile.Name()
-		} else {
-			metadataFile, err = os.OpenFile(devices.metadataDevice, os.O_RDWR, 0600)
-			if err != nil {
-				return err
-			}
-		}
-		defer metadataFile.Close()
-
-		if err := devicemapper.CreatePool(devices.getPoolName(), dataFile, metadataFile, devices.thinpBlockSize); err != nil {
-			return err
-		}
-		defer func() {
-			if retErr != nil {
-				err = devices.deactivatePool()
-				if err != nil {
-					logger.Warnf("Failed to deactivatePool: %v", err)
-				}
-			}
-		}()
-	}
-
-	// Pool already exists and caller did not pass us a pool. That means
-	// we probably created pool earlier and could not remove it as some
-	// containers were still using it. Detect some of the properties of
-	// pool, like is it using loop devices.
-	if poolExists && devices.thinPoolDevice == "" {
-		if err := devices.loadThinPoolLoopBackInfo(); err != nil {
-			logger.Debugf("Failed to load thin pool loopback device information:%v", err)
-			return err
-		}
-	}
-
-	// If we didn't just create the data or metadata image, we need to
-	// load the transaction id and migrate old metadata
-	if !createdLoopback {
-		if err := devices.initMetaData(); err != nil {
-			return err
-		}
-	}
-
-	if devices.thinPoolDevice == "" {
-		if devices.metadataLoopFile != "" || devices.dataLoopFile != "" {
-			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.")
-		}
-	}
-
-	// Right now this loads only NextDeviceID. If there is more metadata
-	// down the line, we might have to move it earlier.
-	if err := devices.loadDeviceSetMetaData(); err != nil {
-		return err
-	}
-
-	// Setup the base image
-	if doInit {
-		if err := devices.setupBaseImage(); err != nil {
-			logger.Debugf("Error device setupBaseImage: %s", err)
-			return err
-		}
-	}
-
-	return nil
-}
-
-// AddDevice adds a device and registers in the hash.
-func (devices *DeviceSet) AddDevice(hash, baseHash string, storageOpt map[string]string) error {
-	logrus.WithField("storage-driver", "devicemapper").Debugf("AddDevice START(hash=%s basehash=%s)", hash, baseHash)
-	defer logrus.WithField("storage-driver", "devicemapper").Debugf("AddDevice END(hash=%s basehash=%s)", hash, baseHash)
-
-	// If a deleted device exists, return error.
-	baseInfo, err := devices.lookupDeviceWithLock(baseHash)
-	if err != nil {
-		return err
-	}
-
-	if baseInfo.Deleted {
-		return fmt.Errorf("devmapper: Base device %v has been marked for deferred deletion", baseInfo.Hash)
-	}
-
-	baseInfo.lock.Lock()
-	defer baseInfo.lock.Unlock()
-
-	devices.Lock()
-	defer devices.Unlock()
-
-	// Also include deleted devices in case hash of new device is
-	// same as one of the deleted devices.
-	if info, _ := devices.lookupDevice(hash); info != nil {
-		return fmt.Errorf("devmapper: device %s already exists. Deleted=%v", hash, info.Deleted)
-	}
-
-	size, err := devices.parseStorageOpt(storageOpt)
-	if err != nil {
-		return err
-	}
-
-	if size == 0 {
-		size = baseInfo.Size
-	}
-
-	if size < baseInfo.Size {
-		return fmt.Errorf("devmapper: Container size cannot be smaller than %s", units.HumanSize(float64(baseInfo.Size)))
-	}
-
-	if err := devices.takeSnapshot(hash, baseInfo, size); err != nil {
-		return err
-	}
-
-	// Grow the container rootfs.
-	if size > baseInfo.Size {
-		info, err := devices.lookupDevice(hash)
-		if err != nil {
-			return err
-		}
-
-		if err := devices.growFS(info); err != nil {
-			return err
-		}
-	}
-
-	return nil
-}
-
-func (devices *DeviceSet) parseStorageOpt(storageOpt map[string]string) (uint64, error) {
-	// Read size to change the block device size per container.
-	for key, val := range storageOpt {
-		key := strings.ToLower(key)
-		switch key {
-		case "size":
-			size, err := units.RAMInBytes(val)
-			if err != nil {
-				return 0, err
-			}
-			return uint64(size), nil
-		default:
-			return 0, fmt.Errorf("Unknown option %s", key)
-		}
-	}
-
-	return 0, nil
-}
-
-func (devices *DeviceSet) markForDeferredDeletion(info *devInfo) error {
-	// If device is already in deleted state, there is nothing to be done.
-	if info.Deleted {
-		return nil
-	}
-
-	logrus.WithField("storage-driver", "devicemapper").Debugf("Marking device %s for deferred deletion.", info.Hash)
-
-	info.Deleted = true
-
-	// save device metadata to reflect deleted state.
-	if err := devices.saveMetadata(info); err != nil {
-		info.Deleted = false
-		return err
-	}
-
-	devices.nrDeletedDevices++
-	return nil
-}
-
-// Should be called with devices.Lock() held.
-func (devices *DeviceSet) deleteTransaction(info *devInfo, syncDelete bool) error {
-	if err := devices.openTransaction(info.Hash, info.DeviceID); err != nil {
-		logrus.WithField("storage-driver", "devicemapper").Debugf("Error opening transaction hash = %s deviceId = %d", "", info.DeviceID)
-		return err
-	}
-
-	defer devices.closeTransaction()
-
-	err := devicemapper.DeleteDevice(devices.getPoolDevName(), info.DeviceID)
-	if err != nil {
-		// If syncDelete is true, we want to return error. If deferred
-		// deletion is not enabled, we return an error. If error is
-		// something other then EBUSY, return an error.
-		if syncDelete || !devices.deferredDelete || err != devicemapper.ErrBusy {
-			logrus.WithField("storage-driver", "devicemapper").Debugf("Error deleting device: %s", err)
-			return err
-		}
-	}
-
-	if err == nil {
-		if err := devices.unregisterDevice(info.Hash); err != nil {
-			return err
-		}
-		// If device was already in deferred delete state that means
-		// deletion was being tried again later. Reduce the deleted
-		// device count.
-		if info.Deleted {
-			devices.nrDeletedDevices--
-		}
-		devices.markDeviceIDFree(info.DeviceID)
-	} else {
-		if err := devices.markForDeferredDeletion(info); err != nil {
-			return err
-		}
-	}
-
-	return nil
-}
-
-// Issue discard only if device open count is zero.
-func (devices *DeviceSet) issueDiscard(info *devInfo) error {
-	logger := logrus.WithField("storage-driver", "devicemapper")
-	logger.Debugf("issueDiscard START(device: %s).", info.Hash)
-	defer logger.Debugf("issueDiscard END(device: %s).", info.Hash)
-	// This is a workaround for the kernel not discarding block so
-	// on the thin pool when we remove a thinp device, so we do it
-	// manually.
-	// Even if device is deferred deleted, activate it and issue
-	// discards.
-	if err := devices.activateDeviceIfNeeded(info, true); err != nil {
-		return err
-	}
-
-	devinfo, err := devicemapper.GetInfo(info.Name())
-	if err != nil {
-		return err
-	}
-
-	if devinfo.OpenCount != 0 {
-		logger.Debugf("Device: %s is in use. OpenCount=%d. Not issuing discards.", info.Hash, devinfo.OpenCount)
-		return nil
-	}
-
-	if err := devicemapper.BlockDeviceDiscard(info.DevName()); err != nil {
-		logger.Debugf("Error discarding block on device: %s (ignoring)", err)
-	}
-	return nil
-}
-
-// Should be called with devices.Lock() held.
-func (devices *DeviceSet) deleteDevice(info *devInfo, syncDelete bool) error {
-	if devices.doBlkDiscard {
-		devices.issueDiscard(info)
-	}
-
-	// Try to deactivate device in case it is active.
-	// If deferred removal is enabled and deferred deletion is disabled
-	// then make sure device is removed synchronously. There have been
-	// some cases of device being busy for short duration and we would
-	// rather busy wait for device removal to take care of these cases.
-	deferredRemove := devices.deferredRemove
-	if !devices.deferredDelete {
-		deferredRemove = false
-	}
-
-	if err := devices.deactivateDeviceMode(info, deferredRemove); err != nil {
-		logrus.WithField("storage-driver", "devicemapper").Debugf("Error deactivating device: %s", err)
-		return err
-	}
-
-	return devices.deleteTransaction(info, syncDelete)
-}
-
-// DeleteDevice will return success if device has been marked for deferred
-// removal. If one wants to override that and want DeleteDevice() to fail if
-// device was busy and could not be deleted, set syncDelete=true.
-func (devices *DeviceSet) DeleteDevice(hash string, syncDelete bool) error {
-	logrus.WithField("storage-driver", "devicemapper").Debugf("DeleteDevice START(hash=%v syncDelete=%v)", hash, syncDelete)
-	defer logrus.WithField("storage-driver", "devicemapper").Debugf("DeleteDevice END(hash=%v syncDelete=%v)", hash, syncDelete)
-	info, err := devices.lookupDeviceWithLock(hash)
-	if err != nil {
-		return err
-	}
-
-	info.lock.Lock()
-	defer info.lock.Unlock()
-
-	devices.Lock()
-	defer devices.Unlock()
-
-	return devices.deleteDevice(info, syncDelete)
-}
-
-func (devices *DeviceSet) deactivatePool() error {
-	logrus.WithField("storage-driver", "devicemapper").Debug("deactivatePool() START")
-	defer logrus.WithField("storage-driver", "devicemapper").Debug("deactivatePool() END")
-	devname := devices.getPoolDevName()
-
-	devinfo, err := devicemapper.GetInfo(devname)
-	if err != nil {
-		return err
-	}
-
-	if devinfo.Exists == 0 {
-		return nil
-	}
-	if err := devicemapper.RemoveDevice(devname); err != nil {
-		return err
-	}
-
-	if d, err := devicemapper.GetDeps(devname); err == nil {
-		logrus.WithField("storage-driver", "devicemapper").Warnf("device %s still has %d active dependents", devname, d.Count)
-	}
-
-	return nil
-}
-
-func (devices *DeviceSet) deactivateDevice(info *devInfo) error {
-	return devices.deactivateDeviceMode(info, devices.deferredRemove)
-}
-
-func (devices *DeviceSet) deactivateDeviceMode(info *devInfo, deferredRemove bool) error {
-	var err error
-	logrus.WithField("storage-driver", "devicemapper").Debugf("deactivateDevice START(%s)", info.Hash)
-	defer logrus.WithField("storage-driver", "devicemapper").Debugf("deactivateDevice END(%s)", info.Hash)
-
-	devinfo, err := devicemapper.GetInfo(info.Name())
-	if err != nil {
-		return err
-	}
-
-	if devinfo.Exists == 0 {
-		return nil
-	}
-
-	if deferredRemove {
-		err = devicemapper.RemoveDeviceDeferred(info.Name())
-	} else {
-		err = devices.removeDevice(info.Name())
-	}
-
-	// This function's semantics is such that it does not return an
-	// error if device does not exist. So if device went away by
-	// the time we actually tried to remove it, do not return error.
-	if err != devicemapper.ErrEnxio {
-		return err
-	}
-	return nil
-}
-
-// Issues the underlying dm remove operation.
-func (devices *DeviceSet) removeDevice(devname string) error {
-	var err error
-
-	logrus.WithField("storage-driver", "devicemapper").Debugf("removeDevice START(%s)", devname)
-	defer logrus.WithField("storage-driver", "devicemapper").Debugf("removeDevice END(%s)", devname)
-
-	for i := 0; i < 200; i++ {
-		err = devicemapper.RemoveDevice(devname)
-		if err == nil {
-			break
-		}
-		if err != devicemapper.ErrBusy {
-			return err
-		}
-
-		// If we see EBUSY it may be a transient error,
-		// sleep a bit a retry a few times.
-		devices.Unlock()
-		time.Sleep(100 * time.Millisecond)
-		devices.Lock()
-	}
-
-	return err
-}
-
-func (devices *DeviceSet) cancelDeferredRemovalIfNeeded(info *devInfo) error {
-	if !devices.deferredRemove {
-		return nil
-	}
-
-	logrus.WithField("storage-driver", "devicemapper").Debugf("cancelDeferredRemovalIfNeeded START(%s)", info.Name())
-	defer logrus.WithField("storage-driver", "devicemapper").Debugf("cancelDeferredRemovalIfNeeded END(%s)", info.Name())
-
-	devinfo, err := devicemapper.GetInfoWithDeferred(info.Name())
-	if err != nil {
-		return err
-	}
-
-	if devinfo != nil && devinfo.DeferredRemove == 0 {
-		return nil
-	}
-
-	// Cancel deferred remove
-	if err := devices.cancelDeferredRemoval(info); err != nil {
-		// If Error is ErrEnxio. Device is probably already gone. Continue.
-		if err != devicemapper.ErrEnxio {
-			return err
-		}
-	}
-	return nil
-}
-
-func (devices *DeviceSet) cancelDeferredRemoval(info *devInfo) error {
-	logrus.WithField("storage-driver", "devicemapper").Debugf("cancelDeferredRemoval START(%s)", info.Name())
-	defer logrus.WithField("storage-driver", "devicemapper").Debugf("cancelDeferredRemoval END(%s)", info.Name())
-
-	var err error
-
-	// Cancel deferred remove
-	for i := 0; i < 100; i++ {
-		err = devicemapper.CancelDeferredRemove(info.Name())
-		if err != nil {
-			if err == devicemapper.ErrBusy {
-				// If we see EBUSY it may be a transient error,
-				// sleep a bit a retry a few times.
-				devices.Unlock()
-				time.Sleep(100 * time.Millisecond)
-				devices.Lock()
-				continue
-			}
-		}
-		break
-	}
-	return err
-}
-
-func (devices *DeviceSet) unmountAndDeactivateAll(dir string) {
-	logger := logrus.WithField("storage-driver", "devicemapper")
-
-	files, err := os.ReadDir(dir)
-	if err != nil {
-		logger.Warnf("unmountAndDeactivate: %s", err)
-		return
-	}
-
-	for _, d := range files {
-		if !d.IsDir() {
-			continue
-		}
-
-		name := d.Name()
-		fullname := path.Join(dir, name)
-
-		// We use MNT_DETACH here in case it is still busy in some running
-		// container. This means it'll go away from the global scope directly,
-		// and the device will be released when that container dies.
-		if err := unix.Unmount(fullname, unix.MNT_DETACH); err != nil && err != unix.EINVAL {
-			logger.Warnf("Shutdown unmounting %s, error: %s", fullname, err)
-		}
-
-		if devInfo, err := devices.lookupDevice(name); err != nil {
-			logger.Debugf("Shutdown lookup device %s, error: %s", name, err)
-		} else {
-			if err := devices.deactivateDevice(devInfo); err != nil {
-				logger.Debugf("Shutdown deactivate %s, error: %s", devInfo.Hash, err)
-			}
-		}
-	}
-}
-
-// Shutdown shuts down the device by unmounting the root.
-func (devices *DeviceSet) Shutdown(home string) error {
-	logger := logrus.WithField("storage-driver", "devicemapper")
-
-	logger.Debugf("[deviceset %s] Shutdown()", devices.devicePrefix)
-	logger.Debugf("Shutting down DeviceSet: %s", devices.root)
-	defer logger.Debugf("[deviceset %s] Shutdown() END", devices.devicePrefix)
-
-	// Stop deletion worker. This should start delivering new events to
-	// ticker channel. That means no new instance of cleanupDeletedDevice()
-	// will run after this call. If one instance is already running at
-	// the time of the call, it must be holding devices.Lock() and
-	// we will block on this lock till cleanup function exits.
-	devices.deletionWorkerTicker.Stop()
-
-	devices.Lock()
-	// Save DeviceSet Metadata first. Docker kills all threads if they
-	// don't finish in certain time. It is possible that Shutdown()
-	// routine does not finish in time as we loop trying to deactivate
-	// some devices while these are busy. In that case shutdown() routine
-	// will be killed and we will not get a chance to save deviceset
-	// metadata. Hence save this early before trying to deactivate devices.
-	devices.saveDeviceSetMetaData()
-	devices.unmountAndDeactivateAll(path.Join(home, "mnt"))
-	devices.Unlock()
-
-	info, _ := devices.lookupDeviceWithLock("")
-	if info != nil {
-		info.lock.Lock()
-		devices.Lock()
-		if err := devices.deactivateDevice(info); err != nil {
-			logger.Debugf("Shutdown deactivate base , error: %s", err)
-		}
-		devices.Unlock()
-		info.lock.Unlock()
-	}
-
-	devices.Lock()
-	if devices.thinPoolDevice == "" {
-		if err := devices.deactivatePool(); err != nil {
-			logger.Debugf("Shutdown deactivate pool , error: %s", err)
-		}
-	}
-	devices.Unlock()
-
-	return nil
-}
-
-// Recent XFS changes allow changing behavior of filesystem in case of errors.
-// When thin pool gets full and XFS gets ENOSPC error, currently it tries
-// IO infinitely and sometimes it can block the container process
-// and process can't be killWith 0 value, XFS will not retry upon error
-// and instead will shutdown filesystem.
-
-func (devices *DeviceSet) xfsSetNospaceRetries(info *devInfo) error {
-	dmDevicePath, err := os.Readlink(info.DevName())
-	if err != nil {
-		return fmt.Errorf("devmapper: readlink failed for device %v:%v", info.DevName(), err)
-	}
-
-	dmDeviceName := path.Base(dmDevicePath)
-	filePath := "/sys/fs/xfs/" + dmDeviceName + "/error/metadata/ENOSPC/max_retries"
-	maxRetriesFile, err := os.OpenFile(filePath, os.O_WRONLY, 0)
-	if err != nil {
-		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)
-	}
-	defer maxRetriesFile.Close()
-
-	// Set max retries to 0
-	_, err = maxRetriesFile.WriteString(devices.xfsNospaceRetries)
-	if err != nil {
-		return fmt.Errorf("devmapper: Failed to write string %v to file %v:%v", devices.xfsNospaceRetries, filePath, err)
-	}
-	return nil
-}
-
-// MountDevice mounts the device if not already mounted.
-func (devices *DeviceSet) MountDevice(hash, path, mountLabel string) error {
-	info, err := devices.lookupDeviceWithLock(hash)
-	if err != nil {
-		return err
-	}
-
-	if info.Deleted {
-		return fmt.Errorf("devmapper: Can't mount device %v as it has been marked for deferred deletion", info.Hash)
-	}
-
-	info.lock.Lock()
-	defer info.lock.Unlock()
-
-	devices.Lock()
-	defer devices.Unlock()
-
-	if err := devices.activateDeviceIfNeeded(info, false); err != nil {
-		return fmt.Errorf("devmapper: Error activating devmapper device for '%s': %s", hash, err)
-	}
-
-	fstype, err := ProbeFsType(info.DevName())
-	if err != nil {
-		return err
-	}
-
-	options := ""
-
-	if fstype == "xfs" {
-		// XFS needs nouuid or it can't mount filesystems with the same fs
-		options = joinMountOptions(options, "nouuid")
-	}
-
-	options = joinMountOptions(options, devices.mountOptions)
-	options = joinMountOptions(options, label.FormatMountLabel("", mountLabel))
-
-	if err := mount.Mount(info.DevName(), path, fstype, options); err != nil {
-		return errors.Wrapf(err, "Failed to mount; dmesg: %s", string(dmesg.Dmesg(256)))
-	}
-
-	if fstype == "xfs" && devices.xfsNospaceRetries != "" {
-		if err := devices.xfsSetNospaceRetries(info); err != nil {
-			unix.Unmount(path, unix.MNT_DETACH)
-			devices.deactivateDevice(info)
-			return err
-		}
-	}
-
-	return nil
-}
-
-// UnmountDevice unmounts the device and removes it from hash.
-func (devices *DeviceSet) UnmountDevice(hash, mountPath string) error {
-	logger := logrus.WithField("storage-driver", "devicemapper")
-
-	logger.Debugf("UnmountDevice START(hash=%s)", hash)
-	defer logger.Debugf("UnmountDevice END(hash=%s)", hash)
-
-	info, err := devices.lookupDeviceWithLock(hash)
-	if err != nil {
-		return err
-	}
-
-	info.lock.Lock()
-	defer info.lock.Unlock()
-
-	devices.Lock()
-	defer devices.Unlock()
-
-	logger.Debugf("Unmount(%s)", mountPath)
-	if err := unix.Unmount(mountPath, unix.MNT_DETACH); err != nil {
-		return err
-	}
-	logger.Debug("Unmount done")
-
-	// Remove the mountpoint here. Removing the mountpoint (in newer kernels)
-	// will cause all other instances of this mount in other mount namespaces
-	// to be killed (this is an anti-DoS measure that is necessary for things
-	// like devicemapper). This is necessary to avoid cases where a libdm mount
-	// that is present in another namespace will cause subsequent RemoveDevice
-	// operations to fail. We ignore any errors here because this may fail on
-	// older kernels which don't have
-	// torvalds/linux@8ed936b5671bfb33d89bc60bdcc7cf0470ba52fe applied.
-	if err := os.Remove(mountPath); err != nil {
-		logger.Debugf("error doing a remove on unmounted device %s: %v", mountPath, err)
-	}
-
-	return devices.deactivateDevice(info)
-}
-
-// HasDevice returns true if the device metadata exists.
-func (devices *DeviceSet) HasDevice(hash string) bool {
-	info, _ := devices.lookupDeviceWithLock(hash)
-	return info != nil
-}
-
-// List returns a list of device ids.
-func (devices *DeviceSet) List() []string {
-	devices.Lock()
-	defer devices.Unlock()
-
-	ids := make([]string, len(devices.Devices))
-	i := 0
-	for k := range devices.Devices {
-		ids[i] = k
-		i++
-	}
-	return ids
-}
-
-func (devices *DeviceSet) deviceStatus(devName string) (sizeInSectors, mappedSectors, highestMappedSector uint64, err error) {
-	var params string
-	_, sizeInSectors, _, params, err = devicemapper.GetStatus(devName)
-	if err != nil {
-		return
-	}
-	if _, err = fmt.Sscanf(params, "%d %d", &mappedSectors, &highestMappedSector); err == nil {
-		return
-	}
-	return
-}
-
-// GetDeviceStatus provides size, mapped sectors
-func (devices *DeviceSet) GetDeviceStatus(hash string) (*DevStatus, error) {
-	info, err := devices.lookupDeviceWithLock(hash)
-	if err != nil {
-		return nil, err
-	}
-
-	info.lock.Lock()
-	defer info.lock.Unlock()
-
-	devices.Lock()
-	defer devices.Unlock()
-
-	status := &DevStatus{
-		DeviceID:      info.DeviceID,
-		Size:          info.Size,
-		TransactionID: info.TransactionID,
-	}
-
-	if err := devices.activateDeviceIfNeeded(info, false); err != nil {
-		return nil, fmt.Errorf("devmapper: Error activating devmapper device for '%s': %s", hash, err)
-	}
-
-	sizeInSectors, mappedSectors, highestMappedSector, err := devices.deviceStatus(info.DevName())
-
-	if err != nil {
-		return nil, err
-	}
-
-	status.SizeInSectors = sizeInSectors
-	status.MappedSectors = mappedSectors
-	status.HighestMappedSector = highestMappedSector
-
-	return status, nil
-}
-
-func (devices *DeviceSet) poolStatus() (totalSizeInSectors, transactionID, dataUsed, dataTotal, metadataUsed, metadataTotal uint64, err error) {
-	var params string
-	if _, totalSizeInSectors, _, params, err = devicemapper.GetStatus(devices.getPoolName()); err == nil {
-		_, err = fmt.Sscanf(params, "%d %d/%d %d/%d", &transactionID, &metadataUsed, &metadataTotal, &dataUsed, &dataTotal)
-	}
-	return
-}
-
-// DataDevicePath returns the path to the data storage for this deviceset,
-// regardless of loopback or block device
-func (devices *DeviceSet) DataDevicePath() string {
-	return devices.dataDevice
-}
-
-// MetadataDevicePath returns the path to the metadata storage for this deviceset,
-// regardless of loopback or block device
-func (devices *DeviceSet) MetadataDevicePath() string {
-	return devices.metadataDevice
-}
-
-func (devices *DeviceSet) getUnderlyingAvailableSpace(loopFile string) (uint64, error) {
-	buf := new(unix.Statfs_t)
-	if err := unix.Statfs(loopFile, buf); err != nil {
-		logrus.WithField("storage-driver", "devicemapper").Warnf("Couldn't stat loopfile filesystem %v: %v", loopFile, err)
-		return 0, err
-	}
-	return buf.Bfree * uint64(buf.Bsize), nil
-}
-
-func (devices *DeviceSet) isRealFile(loopFile string) (bool, error) {
-	if loopFile != "" {
-		fi, err := os.Stat(loopFile)
-		if err != nil {
-			logrus.WithField("storage-driver", "devicemapper").Warnf("Couldn't stat loopfile %v: %v", loopFile, err)
-			return false, err
-		}
-		return fi.Mode().IsRegular(), nil
-	}
-	return false, nil
-}
-
-// Status returns the current status of this deviceset
-func (devices *DeviceSet) Status() *Status {
-	devices.Lock()
-	defer devices.Unlock()
-
-	status := &Status{}
-
-	status.PoolName = devices.getPoolName()
-	status.DataFile = devices.DataDevicePath()
-	status.DataLoopback = devices.dataLoopFile
-	status.MetadataFile = devices.MetadataDevicePath()
-	status.MetadataLoopback = devices.metadataLoopFile
-	status.UdevSyncSupported = devicemapper.UdevSyncSupported()
-	status.DeferredRemoveEnabled = devices.deferredRemove
-	status.DeferredDeleteEnabled = devices.deferredDelete
-	status.DeferredDeletedDeviceCount = devices.nrDeletedDevices
-	status.BaseDeviceSize = devices.getBaseDeviceSize()
-	status.BaseDeviceFS = devices.getBaseDeviceFS()
-
-	totalSizeInSectors, _, dataUsed, dataTotal, metadataUsed, metadataTotal, err := devices.poolStatus()
-	if err == nil {
-		// Convert from blocks to bytes
-		blockSizeInSectors := totalSizeInSectors / dataTotal
-
-		status.Data.Used = dataUsed * blockSizeInSectors * 512
-		status.Data.Total = dataTotal * blockSizeInSectors * 512
-		status.Data.Available = status.Data.Total - status.Data.Used
-
-		// metadata blocks are always 4k
-		status.Metadata.Used = metadataUsed * 4096
-		status.Metadata.Total = metadataTotal * 4096
-		status.Metadata.Available = status.Metadata.Total - status.Metadata.Used
-
-		status.SectorSize = blockSizeInSectors * 512
-
-		if check, _ := devices.isRealFile(devices.dataLoopFile); check {
-			actualSpace, err := devices.getUnderlyingAvailableSpace(devices.dataLoopFile)
-			if err == nil && actualSpace < status.Data.Available {
-				status.Data.Available = actualSpace
-			}
-		}
-
-		if check, _ := devices.isRealFile(devices.metadataLoopFile); check {
-			actualSpace, err := devices.getUnderlyingAvailableSpace(devices.metadataLoopFile)
-			if err == nil && actualSpace < status.Metadata.Available {
-				status.Metadata.Available = actualSpace
-			}
-		}
-
-		minFreeData := (dataTotal * uint64(devices.minFreeSpacePercent)) / 100
-		status.MinFreeSpace = minFreeData * blockSizeInSectors * 512
-	}
-
-	return status
-}
-
-// Status returns the current status of this deviceset
-func (devices *DeviceSet) exportDeviceMetadata(hash string) (*deviceMetadata, error) {
-	info, err := devices.lookupDeviceWithLock(hash)
-	if err != nil {
-		return nil, err
-	}
-
-	info.lock.Lock()
-	defer info.lock.Unlock()
-
-	metadata := &deviceMetadata{info.DeviceID, info.Size, info.Name()}
-	return metadata, nil
-}
-
-// NewDeviceSet creates the device set based on the options provided.
-func NewDeviceSet(root string, doInit bool, options []string, idMap idtools.IdentityMapping) (*DeviceSet, error) {
-	devicemapper.SetDevDir("/dev")
-
-	devices := &DeviceSet{
-		root:                  root,
-		metaData:              metaData{Devices: make(map[string]*devInfo)},
-		dataLoopbackSize:      defaultDataLoopbackSize,
-		metaDataLoopbackSize:  defaultMetaDataLoopbackSize,
-		baseFsSize:            defaultBaseFsSize,
-		overrideUdevSyncCheck: defaultUdevSyncOverride,
-		doBlkDiscard:          true,
-		thinpBlockSize:        defaultThinpBlockSize,
-		deviceIDMap:           make([]byte, deviceIDMapSz),
-		deletionWorkerTicker:  time.NewTicker(time.Second * 30),
-		idMap:                 idMap,
-		minFreeSpacePercent:   defaultMinFreeSpacePercent,
-	}
-
-	version, err := devicemapper.GetDriverVersion()
-	if err != nil {
-		// Can't even get driver version, assume not supported
-		return nil, graphdriver.ErrNotSupported
-	}
-
-	if err := determineDriverCapabilities(version); err != nil {
-		return nil, graphdriver.ErrNotSupported
-	}
-
-	if driverDeferredRemovalSupport && devicemapper.LibraryDeferredRemovalSupport {
-		// enable deferred stuff by default
-		enableDeferredDeletion = true
-		enableDeferredRemoval = true
-	}
-
-	foundBlkDiscard := false
-	var lvmSetupConfig directLVMConfig
-	for _, option := range options {
-		key, val, err := parsers.ParseKeyValueOpt(option)
-		if err != nil {
-			return nil, err
-		}
-		key = strings.ToLower(key)
-		switch key {
-		case "dm.basesize":
-			size, err := units.RAMInBytes(val)
-			if err != nil {
-				return nil, err
-			}
-			userBaseSize = true
-			devices.baseFsSize = uint64(size)
-		case "dm.loopdatasize":
-			size, err := units.RAMInBytes(val)
-			if err != nil {
-				return nil, err
-			}
-			devices.dataLoopbackSize = size
-		case "dm.loopmetadatasize":
-			size, err := units.RAMInBytes(val)
-			if err != nil {
-				return nil, err
-			}
-			devices.metaDataLoopbackSize = size
-		case "dm.fs":
-			if val != "ext4" && val != "xfs" {
-				return nil, fmt.Errorf("devmapper: Unsupported filesystem %s", val)
-			}
-			devices.filesystem = val
-		case "dm.mkfsarg":
-			devices.mkfsArgs = append(devices.mkfsArgs, val)
-		case "dm.mountopt":
-			devices.mountOptions = joinMountOptions(devices.mountOptions, val)
-		case "dm.metadatadev":
-			devices.metadataDevice = val
-		case "dm.datadev":
-			devices.dataDevice = val
-		case "dm.thinpooldev":
-			devices.thinPoolDevice = strings.TrimPrefix(val, "/dev/mapper/")
-		case "dm.blkdiscard":
-			foundBlkDiscard = true
-			devices.doBlkDiscard, err = strconv.ParseBool(val)
-			if err != nil {
-				return nil, err
-			}
-		case "dm.blocksize":
-			size, err := units.RAMInBytes(val)
-			if err != nil {
-				return nil, err
-			}
-			// convert to 512b sectors
-			devices.thinpBlockSize = uint32(size) >> 9
-		case "dm.override_udev_sync_check":
-			devices.overrideUdevSyncCheck, err = strconv.ParseBool(val)
-			if err != nil {
-				return nil, err
-			}
-
-		case "dm.use_deferred_removal":
-			enableDeferredRemoval, err = strconv.ParseBool(val)
-			if err != nil {
-				return nil, err
-			}
-
-		case "dm.use_deferred_deletion":
-			enableDeferredDeletion, err = strconv.ParseBool(val)
-			if err != nil {
-				return nil, err
-			}
-
-		case "dm.min_free_space":
-			if !strings.HasSuffix(val, "%") {
-				return nil, fmt.Errorf("devmapper: Option dm.min_free_space requires %% suffix")
-			}
-
-			valstring := strings.TrimSuffix(val, "%")
-			minFreeSpacePercent, err := strconv.ParseUint(valstring, 10, 32)
-			if err != nil {
-				return nil, err
-			}
-
-			if minFreeSpacePercent >= 100 {
-				return nil, fmt.Errorf("devmapper: Invalid value %v for option dm.min_free_space", val)
-			}
-
-			devices.minFreeSpacePercent = uint32(minFreeSpacePercent)
-		case "dm.xfs_nospace_max_retries":
-			_, err := strconv.ParseUint(val, 10, 64)
-			if err != nil {
-				return nil, err
-			}
-			devices.xfsNospaceRetries = val
-		case "dm.directlvm_device":
-			lvmSetupConfig.Device = val
-		case "dm.directlvm_device_force":
-			lvmSetupConfigForce, err = strconv.ParseBool(val)
-			if err != nil {
-				return nil, err
-			}
-		case "dm.thinp_percent":
-			per, err := strconv.ParseUint(strings.TrimSuffix(val, "%"), 10, 32)
-			if err != nil {
-				return nil, errors.Wrapf(err, "could not parse `dm.thinp_percent=%s`", val)
-			}
-			if per >= 100 {
-				return nil, errors.New("dm.thinp_percent must be greater than 0 and less than 100")
-			}
-			lvmSetupConfig.ThinpPercent = per
-		case "dm.thinp_metapercent":
-			per, err := strconv.ParseUint(strings.TrimSuffix(val, "%"), 10, 32)
-			if err != nil {
-				return nil, errors.Wrapf(err, "could not parse `dm.thinp_metapercent=%s`", val)
-			}
-			if per >= 100 {
-				return nil, errors.New("dm.thinp_metapercent must be greater than 0 and less than 100")
-			}
-			lvmSetupConfig.ThinpMetaPercent = per
-		case "dm.thinp_autoextend_percent":
-			per, err := strconv.ParseUint(strings.TrimSuffix(val, "%"), 10, 32)
-			if err != nil {
-				return nil, errors.Wrapf(err, "could not parse `dm.thinp_autoextend_percent=%s`", val)
-			}
-			if per > 100 {
-				return nil, errors.New("dm.thinp_autoextend_percent must be greater than 0 and less than 100")
-			}
-			lvmSetupConfig.AutoExtendPercent = per
-		case "dm.thinp_autoextend_threshold":
-			per, err := strconv.ParseUint(strings.TrimSuffix(val, "%"), 10, 32)
-			if err != nil {
-				return nil, errors.Wrapf(err, "could not parse `dm.thinp_autoextend_threshold=%s`", val)
-			}
-			if per > 100 {
-				return nil, errors.New("dm.thinp_autoextend_threshold must be greater than 0 and less than 100")
-			}
-			lvmSetupConfig.AutoExtendThreshold = per
-		case "dm.libdm_log_level":
-			level, err := strconv.ParseInt(val, 10, 32)
-			if err != nil {
-				return nil, errors.Wrapf(err, "could not parse `dm.libdm_log_level=%s`", val)
-			}
-			if level < devicemapper.LogLevelFatal || level > devicemapper.LogLevelDebug {
-				return nil, errors.Errorf("dm.libdm_log_level must be in range [%d,%d]", devicemapper.LogLevelFatal, devicemapper.LogLevelDebug)
-			}
-			// Register a new logging callback with the specified level.
-			devicemapper.LogInit(devicemapper.DefaultLogger{
-				Level: int(level),
-			})
-		default:
-			return nil, fmt.Errorf("devmapper: Unknown option %s", key)
-		}
-	}
-
-	if err := validateLVMConfig(lvmSetupConfig); err != nil {
-		return nil, err
-	}
-
-	devices.lvmSetupConfig = lvmSetupConfig
-
-	// By default, don't do blk discard hack on raw devices, its rarely useful and is expensive
-	if !foundBlkDiscard && (devices.dataDevice != "" || devices.thinPoolDevice != "") {
-		devices.doBlkDiscard = false
-	}
-
-	if err := devices.initDevmapper(doInit); err != nil {
-		return nil, err
-	}
-
-	return devices, nil
-}

+ 0 - 106
daemon/graphdriver/devmapper/devmapper_doc.go

@@ -1,106 +0,0 @@
-package devmapper // import "github.com/docker/docker/daemon/graphdriver/devmapper"
-
-// Definition of struct dm_task and sub structures (from lvm2)
-//
-// struct dm_ioctl {
-// 	/*
-// 	 * The version number is made up of three parts:
-// 	 * major - no backward or forward compatibility,
-// 	 * minor - only backwards compatible,
-// 	 * patch - both backwards and forwards compatible.
-// 	 *
-// 	 * All clients of the ioctl interface should fill in the
-// 	 * version number of the interface that they were
-// 	 * compiled with.
-// 	 *
-// 	 * All recognized ioctl commands (ie. those that don't
-// 	 * return -ENOTTY) fill out this field, even if the
-// 	 * command failed.
-// 	 */
-// 	uint32_t version[3];	/* in/out */
-// 	uint32_t data_size;	/* total size of data passed in
-// 				 * including this struct */
-
-// 	uint32_t data_start;	/* offset to start of data
-// 				 * relative to start of this struct */
-
-// 	uint32_t target_count;	/* in/out */
-// 	int32_t open_count;	/* out */
-// 	uint32_t flags;		/* in/out */
-
-// 	/*
-// 	 * event_nr holds either the event number (input and output) or the
-// 	 * udev cookie value (input only).
-// 	 * The DM_DEV_WAIT ioctl takes an event number as input.
-// 	 * The DM_SUSPEND, DM_DEV_REMOVE and DM_DEV_RENAME ioctls
-// 	 * use the field as a cookie to return in the DM_COOKIE
-// 	 * variable with the uevents they issue.
-// 	 * For output, the ioctls return the event number, not the cookie.
-// 	 */
-// 	uint32_t event_nr;      	/* in/out */
-// 	uint32_t padding;
-
-// 	uint64_t dev;		/* in/out */
-
-// 	char name[DM_NAME_LEN];	/* device name */
-// 	char uuid[DM_UUID_LEN];	/* unique identifier for
-// 				 * the block device */
-// 	char data[7];		/* padding or data */
-// };
-
-// struct target {
-// 	uint64_t start;
-// 	uint64_t length;
-// 	char *type;
-// 	char *params;
-
-// 	struct target *next;
-// };
-
-// typedef enum {
-// 	DM_ADD_NODE_ON_RESUME, /* add /dev/mapper node with dmsetup resume */
-// 	DM_ADD_NODE_ON_CREATE  /* add /dev/mapper node with dmsetup create */
-// } dm_add_node_t;
-
-// struct dm_task {
-// 	int type;
-// 	char *dev_name;
-// 	char *mangled_dev_name;
-
-// 	struct target *head, *tail;
-
-// 	int read_only;
-// 	uint32_t event_nr;
-// 	int major;
-// 	int minor;
-// 	int allow_default_major_fallback;
-// 	uid_t uid;
-// 	gid_t gid;
-// 	mode_t mode;
-// 	uint32_t read_ahead;
-// 	uint32_t read_ahead_flags;
-// 	union {
-// 		struct dm_ioctl *v4;
-// 	} dmi;
-// 	char *newname;
-// 	char *message;
-// 	char *geometry;
-// 	uint64_t sector;
-// 	int no_flush;
-// 	int no_open_count;
-// 	int skip_lockfs;
-// 	int query_inactive_table;
-// 	int suppress_identical_reload;
-// 	dm_add_node_t add_node;
-// 	uint64_t existing_table_size;
-// 	int cookie_set;
-// 	int new_uuid;
-// 	int secure_data;
-// 	int retry_remove;
-// 	int enable_checks;
-// 	int expected_errno;
-
-// 	char *uuid;
-// 	char *mangled_uuid;
-// };
-//

+ 0 - 208
daemon/graphdriver/devmapper/devmapper_test.go

@@ -1,208 +0,0 @@
-//go:build linux
-// +build linux
-
-package devmapper // import "github.com/docker/docker/daemon/graphdriver/devmapper"
-
-import (
-	"fmt"
-	"os"
-	"os/exec"
-	"syscall"
-	"testing"
-	"time"
-
-	"github.com/docker/docker/daemon/graphdriver"
-	"github.com/docker/docker/daemon/graphdriver/graphtest"
-	"github.com/docker/docker/pkg/idtools"
-	"github.com/docker/docker/pkg/parsers/kernel"
-	"golang.org/x/sys/unix"
-)
-
-func init() {
-	// Reduce the size of the base fs and loopback for the tests
-	defaultDataLoopbackSize = 300 * 1024 * 1024
-	defaultMetaDataLoopbackSize = 200 * 1024 * 1024
-	defaultBaseFsSize = 300 * 1024 * 1024
-	defaultUdevSyncOverride = true
-	if err := initLoopbacks(); err != nil {
-		panic(err)
-	}
-}
-
-// initLoopbacks ensures that the loopback devices are properly created within
-// the system running the device mapper tests.
-func initLoopbacks() error {
-	statT, err := getBaseLoopStats()
-	if err != nil {
-		return err
-	}
-	// create at least 128 loopback files, since a few first ones
-	// might be already in use by the host OS
-	for i := 0; i < 128; i++ {
-		loopPath := fmt.Sprintf("/dev/loop%d", i)
-		// only create new loopback files if they don't exist
-		if _, err := os.Stat(loopPath); err != nil {
-			if mkerr := syscall.Mknod(loopPath,
-				uint32(statT.Mode|syscall.S_IFBLK), int((7<<8)|(i&0xff)|((i&0xfff00)<<12))); mkerr != nil { //nolint: unconvert
-				return mkerr
-			}
-			os.Chown(loopPath, int(statT.Uid), int(statT.Gid))
-		}
-	}
-	return nil
-}
-
-// getBaseLoopStats inspects /dev/loop0 to collect uid,gid, and mode for the
-// loop0 device on the system.  If it does not exist we assume 0,0,0660 for the
-// stat data
-func getBaseLoopStats() (*syscall.Stat_t, error) {
-	loop0, err := os.Stat("/dev/loop0")
-	if err != nil {
-		if os.IsNotExist(err) {
-			return &syscall.Stat_t{
-				Uid:  0,
-				Gid:  0,
-				Mode: 0660,
-			}, nil
-		}
-		return nil, err
-	}
-	return loop0.Sys().(*syscall.Stat_t), nil
-}
-
-// This avoids creating a new driver for each test if all tests are run
-// Make sure to put new tests between TestDevmapperSetup and TestDevmapperTeardown
-func TestDevmapperSetup(t *testing.T) {
-	graphtest.GetDriver(t, "devicemapper")
-}
-
-func TestDevmapperCreateEmpty(t *testing.T) {
-	graphtest.DriverTestCreateEmpty(t, "devicemapper")
-}
-
-func TestDevmapperCreateBase(t *testing.T) {
-	graphtest.DriverTestCreateBase(t, "devicemapper")
-}
-
-func TestDevmapperCreateSnap(t *testing.T) {
-	graphtest.DriverTestCreateSnap(t, "devicemapper")
-}
-
-func TestDevmapperTeardown(t *testing.T) {
-	graphtest.PutDriver(t)
-}
-
-func TestDevmapperReduceLoopBackSize(t *testing.T) {
-	tenMB := int64(10 * 1024 * 1024)
-	testChangeLoopBackSize(t, -tenMB, defaultDataLoopbackSize, defaultMetaDataLoopbackSize)
-}
-
-func TestDevmapperIncreaseLoopBackSize(t *testing.T) {
-	tenMB := int64(10 * 1024 * 1024)
-	testChangeLoopBackSize(t, tenMB, defaultDataLoopbackSize+tenMB, defaultMetaDataLoopbackSize+tenMB)
-}
-
-func testChangeLoopBackSize(t *testing.T, delta, expectDataSize, expectMetaDataSize int64) {
-	driver := graphtest.GetDriver(t, "devicemapper").(*graphtest.Driver).Driver.(*graphdriver.NaiveDiffDriver).ProtoDriver.(*Driver)
-	defer graphtest.PutDriver(t)
-	// make sure data or metadata loopback size are the default size
-	if s := driver.DeviceSet.Status(); s.Data.Total != uint64(defaultDataLoopbackSize) || s.Metadata.Total != uint64(defaultMetaDataLoopbackSize) {
-		t.Fatal("data or metadata loop back size is incorrect")
-	}
-	if err := driver.Cleanup(); err != nil {
-		t.Fatal(err)
-	}
-	// Reload
-	d, err := Init(driver.home, []string{
-		fmt.Sprintf("dm.loopdatasize=%d", defaultDataLoopbackSize+delta),
-		fmt.Sprintf("dm.loopmetadatasize=%d", defaultMetaDataLoopbackSize+delta),
-	}, idtools.IdentityMapping{})
-	if err != nil {
-		t.Fatalf("error creating devicemapper driver: %v", err)
-	}
-	driver = d.(*graphdriver.NaiveDiffDriver).ProtoDriver.(*Driver)
-	if s := driver.DeviceSet.Status(); s.Data.Total != uint64(expectDataSize) || s.Metadata.Total != uint64(expectMetaDataSize) {
-		t.Fatal("data or metadata loop back size is incorrect")
-	}
-	if err := driver.Cleanup(); err != nil {
-		t.Fatal(err)
-	}
-}
-
-// Make sure devices.Lock() has been release upon return from cleanupDeletedDevices() function
-func TestDevmapperLockReleasedDeviceDeletion(t *testing.T) {
-	driver := graphtest.GetDriver(t, "devicemapper").(*graphtest.Driver).Driver.(*graphdriver.NaiveDiffDriver).ProtoDriver.(*Driver)
-	defer graphtest.PutDriver(t)
-
-	// Call cleanupDeletedDevices() and after the call take and release
-	// DeviceSet Lock. If lock has not been released, this will hang.
-	driver.DeviceSet.cleanupDeletedDevices()
-
-	doneChan := make(chan bool, 1)
-
-	go func() {
-		driver.DeviceSet.Lock()
-		defer driver.DeviceSet.Unlock()
-		doneChan <- true
-	}()
-
-	select {
-	case <-time.After(time.Second * 5):
-		// Timer expired. That means lock was not released upon
-		// function return and we are deadlocked. Release lock
-		// here so that cleanup could succeed and fail the test.
-		driver.DeviceSet.Unlock()
-		t.Fatal("Could not acquire devices lock after call to cleanupDeletedDevices()")
-	case <-doneChan:
-	}
-}
-
-// Ensure that mounts aren't leakedriver. It's non-trivial for us to test the full
-// reproducer of #34573 in a unit test, but we can at least make sure that a
-// simple command run in a new namespace doesn't break things horribly.
-func TestDevmapperMountLeaks(t *testing.T) {
-	if !kernel.CheckKernelVersion(3, 18, 0) {
-		t.Skipf("kernel version <3.18.0 and so is missing torvalds/linux@8ed936b5671bfb33d89bc60bdcc7cf0470ba52fe.")
-	}
-
-	driver := graphtest.GetDriver(t, "devicemapper", "dm.use_deferred_removal=false", "dm.use_deferred_deletion=false").(*graphtest.Driver).Driver.(*graphdriver.NaiveDiffDriver).ProtoDriver.(*Driver)
-	defer graphtest.PutDriver(t)
-
-	// We need to create a new (dummy) device.
-	if err := driver.Create("some-layer", "", nil); err != nil {
-		t.Fatalf("setting up some-layer: %v", err)
-	}
-
-	// Mount the device.
-	_, err := driver.Get("some-layer", "")
-	if err != nil {
-		t.Fatalf("mounting some-layer: %v", err)
-	}
-
-	// Create a new subprocess which will inherit our mountpoint, then
-	// intentionally leak it and stick around. We can't do this entirely within
-	// Go because forking and namespaces in Go are really not handled well at
-	// all.
-	cmd := exec.Cmd{
-		Path: "/bin/sh",
-		Args: []string{
-			"/bin/sh", "-c",
-			"mount --make-rprivate / && sleep 1000s",
-		},
-		SysProcAttr: &syscall.SysProcAttr{
-			Unshareflags: syscall.CLONE_NEWNS,
-		},
-	}
-	if err := cmd.Start(); err != nil {
-		t.Fatalf("starting sub-command: %v", err)
-	}
-	defer func() {
-		unix.Kill(cmd.Process.Pid, unix.SIGKILL)
-		cmd.Wait()
-	}()
-
-	// Now try to "drop" the device.
-	if err := driver.Put("some-layer"); err != nil {
-		t.Fatalf("unmounting some-layer: %v", err)
-	}
-}

+ 0 - 244
daemon/graphdriver/devmapper/driver.go

@@ -1,244 +0,0 @@
-//go:build linux
-// +build linux
-
-package devmapper // import "github.com/docker/docker/daemon/graphdriver/devmapper"
-
-import (
-	"fmt"
-	"os"
-	"path"
-	"strconv"
-
-	"github.com/docker/docker/daemon/graphdriver"
-	"github.com/docker/docker/pkg/devicemapper"
-	"github.com/docker/docker/pkg/idtools"
-	units "github.com/docker/go-units"
-	"github.com/moby/locker"
-	"github.com/moby/sys/mount"
-	"github.com/sirupsen/logrus"
-	"golang.org/x/sys/unix"
-)
-
-func init() {
-	graphdriver.Register("devicemapper", Init)
-}
-
-// Driver contains the device set mounted and the home directory
-type Driver struct {
-	*DeviceSet
-	home   string
-	ctr    *graphdriver.RefCounter
-	locker *locker.Locker
-}
-
-// Init creates a driver with the given home and the set of options.
-func Init(home string, options []string, idMap idtools.IdentityMapping) (graphdriver.Driver, error) {
-	deviceSet, err := NewDeviceSet(home, true, options, idMap)
-	if err != nil {
-		return nil, err
-	}
-
-	d := &Driver{
-		DeviceSet: deviceSet,
-		home:      home,
-		ctr:       graphdriver.NewRefCounter(graphdriver.NewDefaultChecker()),
-		locker:    locker.New(),
-	}
-
-	return graphdriver.NewNaiveDiffDriver(d, d.idMap), nil
-}
-
-func (d *Driver) String() string {
-	return "devicemapper"
-}
-
-// Status returns the status about the driver in a printable format.
-// Information returned contains Pool Name, Data File, Metadata file, disk usage by
-// the data and metadata, etc.
-func (d *Driver) Status() [][2]string {
-	s := d.DeviceSet.Status()
-
-	status := [][2]string{
-		{"Pool Name", s.PoolName},
-		{"Pool Blocksize", units.HumanSize(float64(s.SectorSize))},
-		{"Base Device Size", units.HumanSize(float64(s.BaseDeviceSize))},
-		{"Backing Filesystem", s.BaseDeviceFS},
-		{"Udev Sync Supported", fmt.Sprintf("%v", s.UdevSyncSupported)},
-	}
-
-	if len(s.DataFile) > 0 {
-		status = append(status, [2]string{"Data file", s.DataFile})
-	}
-	if len(s.MetadataFile) > 0 {
-		status = append(status, [2]string{"Metadata file", s.MetadataFile})
-	}
-	if len(s.DataLoopback) > 0 {
-		status = append(status, [2]string{"Data loop file", s.DataLoopback})
-	}
-	if len(s.MetadataLoopback) > 0 {
-		status = append(status, [2]string{"Metadata loop file", s.MetadataLoopback})
-	}
-
-	status = append(status, [][2]string{
-		{"Data Space Used", units.HumanSize(float64(s.Data.Used))},
-		{"Data Space Total", units.HumanSize(float64(s.Data.Total))},
-		{"Data Space Available", units.HumanSize(float64(s.Data.Available))},
-		{"Metadata Space Used", units.HumanSize(float64(s.Metadata.Used))},
-		{"Metadata Space Total", units.HumanSize(float64(s.Metadata.Total))},
-		{"Metadata Space Available", units.HumanSize(float64(s.Metadata.Available))},
-		{"Thin Pool Minimum Free Space", units.HumanSize(float64(s.MinFreeSpace))},
-		{"Deferred Removal Enabled", fmt.Sprintf("%v", s.DeferredRemoveEnabled)},
-		{"Deferred Deletion Enabled", fmt.Sprintf("%v", s.DeferredDeleteEnabled)},
-		{"Deferred Deleted Device Count", fmt.Sprintf("%v", s.DeferredDeletedDeviceCount)},
-	}...)
-
-	if vStr, err := devicemapper.GetLibraryVersion(); err == nil {
-		status = append(status, [2]string{"Library Version", vStr})
-	}
-	return status
-}
-
-// GetMetadata returns a map of information about the device.
-func (d *Driver) GetMetadata(id string) (map[string]string, error) {
-	m, err := d.DeviceSet.exportDeviceMetadata(id)
-
-	if err != nil {
-		return nil, err
-	}
-
-	metadata := make(map[string]string)
-	metadata["DeviceId"] = strconv.Itoa(m.deviceID)
-	metadata["DeviceSize"] = strconv.FormatUint(m.deviceSize, 10)
-	metadata["DeviceName"] = m.deviceName
-	return metadata, nil
-}
-
-// Cleanup unmounts a device.
-func (d *Driver) Cleanup() error {
-	err := d.DeviceSet.Shutdown(d.home)
-	umountErr := mount.RecursiveUnmount(d.home)
-
-	// in case we have two errors, prefer the one from Shutdown()
-	if err != nil {
-		return err
-	}
-
-	return umountErr
-}
-
-// CreateReadWrite creates a layer that is writable for use as a container
-// file system.
-func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error {
-	return d.Create(id, parent, opts)
-}
-
-// Create adds a device with a given id and the parent.
-func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
-	var storageOpt map[string]string
-	if opts != nil {
-		storageOpt = opts.StorageOpt
-	}
-	return d.DeviceSet.AddDevice(id, parent, storageOpt)
-}
-
-// Remove removes a device with a given id, unmounts the filesystem, and removes the mount point.
-func (d *Driver) Remove(id string) error {
-	d.locker.Lock(id)
-	defer d.locker.Unlock(id)
-	if !d.DeviceSet.HasDevice(id) {
-		// Consider removing a non-existing device a no-op
-		// This is useful to be able to progress on container removal
-		// if the underlying device has gone away due to earlier errors
-		return nil
-	}
-
-	// This assumes the device has been properly Get/Put:ed and thus is unmounted
-	if err := d.DeviceSet.DeleteDevice(id, false); err != nil {
-		return fmt.Errorf("failed to remove device %s: %v", id, err)
-	}
-
-	// Most probably the mount point is already removed on Put()
-	// (see DeviceSet.UnmountDevice()), but just in case it was not
-	// let's try to remove it here as well, ignoring errors as
-	// an older kernel can return EBUSY if e.g. the mount was leaked
-	// to other mount namespaces. A failure to remove the container's
-	// mount point is not important and should not be treated
-	// as a failure to remove the container.
-	mp := path.Join(d.home, "mnt", id)
-	err := unix.Rmdir(mp)
-	if err != nil && !os.IsNotExist(err) {
-		logrus.WithField("storage-driver", "devicemapper").Warnf("unable to remove mount point %q: %s", mp, err)
-	}
-
-	return nil
-}
-
-// Get mounts a device with given id into the root filesystem
-func (d *Driver) Get(id, mountLabel string) (string, error) {
-	d.locker.Lock(id)
-	defer d.locker.Unlock(id)
-	mp := path.Join(d.home, "mnt", id)
-	rootFs := path.Join(mp, "rootfs")
-	if count := d.ctr.Increment(mp); count > 1 {
-		return rootFs, nil
-	}
-
-	root := d.idMap.RootPair()
-
-	// Create the target directories if they don't exist
-	if err := idtools.MkdirAllAndChown(path.Join(d.home, "mnt"), 0755, root); err != nil {
-		d.ctr.Decrement(mp)
-		return "", err
-	}
-	if err := idtools.MkdirAndChown(mp, 0755, root); err != nil && !os.IsExist(err) {
-		d.ctr.Decrement(mp)
-		return "", err
-	}
-
-	// Mount the device
-	if err := d.DeviceSet.MountDevice(id, mp, mountLabel); err != nil {
-		d.ctr.Decrement(mp)
-		return "", err
-	}
-
-	if err := idtools.MkdirAllAndChown(rootFs, 0755, root); err != nil {
-		d.ctr.Decrement(mp)
-		d.DeviceSet.UnmountDevice(id, mp)
-		return "", err
-	}
-
-	idFile := path.Join(mp, "id")
-	if _, err := os.Stat(idFile); err != nil && os.IsNotExist(err) {
-		// Create an "id" file with the container/image id in it to help reconstruct this in case
-		// of later problems
-		if err := os.WriteFile(idFile, []byte(id), 0600); err != nil {
-			d.ctr.Decrement(mp)
-			d.DeviceSet.UnmountDevice(id, mp)
-			return "", err
-		}
-	}
-
-	return rootFs, nil
-}
-
-// Put unmounts a device and removes it.
-func (d *Driver) Put(id string) error {
-	d.locker.Lock(id)
-	defer d.locker.Unlock(id)
-	mp := path.Join(d.home, "mnt", id)
-	if count := d.ctr.Decrement(mp); count > 0 {
-		return nil
-	}
-
-	err := d.DeviceSet.UnmountDevice(id, mp)
-	if err != nil {
-		logrus.WithField("storage-driver", "devicemapper").Errorf("Error unmounting device %s: %v", id, err)
-	}
-
-	return err
-}
-
-// Exists checks to see if the device exists.
-func (d *Driver) Exists(id string) bool {
-	return d.DeviceSet.HasDevice(id)
-}

+ 0 - 67
daemon/graphdriver/devmapper/mount.go

@@ -1,67 +0,0 @@
-//go:build linux
-// +build linux
-
-package devmapper // import "github.com/docker/docker/daemon/graphdriver/devmapper"
-
-import (
-	"bytes"
-	"fmt"
-	"os"
-)
-
-type probeData struct {
-	fsName string
-	magic  string
-	offset uint64
-}
-
-// ProbeFsType returns the filesystem name for the given device id.
-func ProbeFsType(device string) (string, error) {
-	probes := []probeData{
-		{"btrfs", "_BHRfS_M", 0x10040},
-		{"ext4", "\123\357", 0x438},
-		{"xfs", "XFSB", 0},
-	}
-
-	maxLen := uint64(0)
-	for _, p := range probes {
-		l := p.offset + uint64(len(p.magic))
-		if l > maxLen {
-			maxLen = l
-		}
-	}
-
-	file, err := os.Open(device)
-	if err != nil {
-		return "", err
-	}
-	defer file.Close()
-
-	buffer := make([]byte, maxLen)
-	l, err := file.Read(buffer)
-	if err != nil {
-		return "", err
-	}
-
-	if uint64(l) != maxLen {
-		return "", fmt.Errorf("devmapper: unable to detect filesystem type of %s, short read", device)
-	}
-
-	for _, p := range probes {
-		if bytes.Equal([]byte(p.magic), buffer[p.offset:p.offset+uint64(len(p.magic))]) {
-			return p.fsName, nil
-		}
-	}
-
-	return "", fmt.Errorf("devmapper: Unknown filesystem type on %s", device)
-}
-
-func joinMountOptions(a, b string) string {
-	if a == "" {
-		return b
-	}
-	if b == "" {
-		return a
-	}
-	return a + "," + b
-}

+ 1 - 5
daemon/graphdriver/driver.go

@@ -316,18 +316,14 @@ func isEmptyDir(name string) bool {
 
 
 // isDeprecated checks if a storage-driver is marked "deprecated"
 // isDeprecated checks if a storage-driver is marked "deprecated"
 func isDeprecated(name string) bool {
 func isDeprecated(name string) bool {
-	switch name {
 	// NOTE: when deprecating a driver, update daemon.fillDriverInfo() accordingly
 	// NOTE: when deprecating a driver, update daemon.fillDriverInfo() accordingly
-	case "devicemapper":
-		return true
-	}
 	return false
 	return false
 }
 }
 
 
 // checkRemoved checks if a storage-driver has been deprecated (and removed)
 // checkRemoved checks if a storage-driver has been deprecated (and removed)
 func checkRemoved(name string) error {
 func checkRemoved(name string) error {
 	switch name {
 	switch name {
-	case "aufs", "overlay":
+	case "aufs", "devicemapper", "overlay":
 		return NotSupportedError(fmt.Sprintf("[graphdriver] ERROR: the %s storage-driver has been deprecated and removed; visit https://docs.docker.com/go/storage-driver/ for more information", name))
 		return NotSupportedError(fmt.Sprintf("[graphdriver] ERROR: the %s storage-driver has been deprecated and removed; visit https://docs.docker.com/go/storage-driver/ for more information", name))
 	}
 	}
 	return nil
 	return nil

+ 1 - 1
daemon/graphdriver/driver_linux.go

@@ -50,7 +50,7 @@ const (
 
 
 var (
 var (
 	// List of drivers that should be used in an order
 	// List of drivers that should be used in an order
-	priority = "overlay2,fuse-overlayfs,btrfs,zfs,devicemapper,vfs"
+	priority = "overlay2,fuse-overlayfs,btrfs,zfs,vfs"
 
 
 	// FsNames maps filesystem id to name of the filesystem.
 	// FsNames maps filesystem id to name of the filesystem.
 	FsNames = map[FsMagic]string{
 	FsNames = map[FsMagic]string{

+ 0 - 9
daemon/graphdriver/register/register_devicemapper.go

@@ -1,9 +0,0 @@
-//go:build !exclude_graphdriver_devicemapper && !static_build && linux
-// +build !exclude_graphdriver_devicemapper,!static_build,linux
-
-package register // import "github.com/docker/docker/daemon/graphdriver/register"
-
-import (
-	// register the devmapper graphdriver
-	_ "github.com/docker/docker/daemon/graphdriver/devmapper"
-)

+ 1 - 1
daemon/info.go

@@ -128,7 +128,7 @@ WARNING: The %s storage-driver is deprecated, and will be removed in a future re
          Refer to the documentation for more information: https://docs.docker.com/go/storage-driver/`
          Refer to the documentation for more information: https://docs.docker.com/go/storage-driver/`
 
 
 	switch v.Driver {
 	switch v.Driver {
-	case "devicemapper", "overlay":
+	case "overlay":
 		v.Warnings = append(v.Warnings, fmt.Sprintf(warnMsg, v.Driver))
 		v.Warnings = append(v.Warnings, fmt.Sprintf(warnMsg, v.Driver))
 	}
 	}
 
 

+ 1 - 1
docs/api/v1.18.md

@@ -377,7 +377,7 @@ Return low-level information on the container `id`
 			"WorkingDir": ""
 			"WorkingDir": ""
 		},
 		},
 		"Created": "2015-01-06T15:47:31.485331387Z",
 		"Created": "2015-01-06T15:47:31.485331387Z",
-		"Driver": "devicemapper",
+		"Driver": "overlay2",
 		"ExecDriver": "native-0.2",
 		"ExecDriver": "native-0.2",
 		"ExecIDs": null,
 		"ExecIDs": null,
 		"HostConfig": {
 		"HostConfig": {

+ 1 - 1
docs/api/v1.19.md

@@ -387,7 +387,7 @@ Return low-level information on the container `id`
 			"WorkingDir": ""
 			"WorkingDir": ""
 		},
 		},
 		"Created": "2015-01-06T15:47:31.485331387Z",
 		"Created": "2015-01-06T15:47:31.485331387Z",
-		"Driver": "devicemapper",
+		"Driver": "overlay2",
 		"ExecDriver": "native-0.2",
 		"ExecDriver": "native-0.2",
 		"ExecIDs": null,
 		"ExecIDs": null,
 		"HostConfig": {
 		"HostConfig": {

+ 1 - 1
docs/api/v1.20.md

@@ -390,7 +390,7 @@ Return low-level information on the container `id`
 			"WorkingDir": ""
 			"WorkingDir": ""
 		},
 		},
 		"Created": "2015-01-06T15:47:31.485331387Z",
 		"Created": "2015-01-06T15:47:31.485331387Z",
-		"Driver": "devicemapper",
+		"Driver": "overlay2",
 		"ExecDriver": "native-0.2",
 		"ExecDriver": "native-0.2",
 		"ExecIDs": null,
 		"ExecIDs": null,
 		"HostConfig": {
 		"HostConfig": {

+ 1 - 1
docs/api/v1.21.md

@@ -412,7 +412,7 @@ Return low-level information on the container `id`
 			"StopSignal": "SIGTERM"
 			"StopSignal": "SIGTERM"
 		},
 		},
 		"Created": "2015-01-06T15:47:31.485331387Z",
 		"Created": "2015-01-06T15:47:31.485331387Z",
-		"Driver": "devicemapper",
+		"Driver": "overlay2",
 		"ExecDriver": "native-0.2",
 		"ExecDriver": "native-0.2",
 		"ExecIDs": null,
 		"ExecIDs": null,
 		"HostConfig": {
 		"HostConfig": {

+ 1 - 1
docs/api/v1.22.md

@@ -529,7 +529,7 @@ Return low-level information on the container `id`
 			"StopSignal": "SIGTERM"
 			"StopSignal": "SIGTERM"
 		},
 		},
 		"Created": "2015-01-06T15:47:31.485331387Z",
 		"Created": "2015-01-06T15:47:31.485331387Z",
-		"Driver": "devicemapper",
+		"Driver": "overlay2",
 		"ExecIDs": null,
 		"ExecIDs": null,
 		"HostConfig": {
 		"HostConfig": {
 			"Binds": null,
 			"Binds": null,

+ 1 - 1
docs/api/v1.23.md

@@ -555,7 +555,7 @@ Return low-level information on the container `id`
 			"StopSignal": "SIGTERM"
 			"StopSignal": "SIGTERM"
 		},
 		},
 		"Created": "2015-01-06T15:47:31.485331387Z",
 		"Created": "2015-01-06T15:47:31.485331387Z",
-		"Driver": "devicemapper",
+		"Driver": "overlay2",
 		"ExecIDs": null,
 		"ExecIDs": null,
 		"HostConfig": {
 		"HostConfig": {
 			"Binds": null,
 			"Binds": null,

+ 1 - 1
docs/api/v1.24.md

@@ -597,7 +597,7 @@ Return low-level information on the container `id`
 			"StopSignal": "SIGTERM"
 			"StopSignal": "SIGTERM"
 		},
 		},
 		"Created": "2015-01-06T15:47:31.485331387Z",
 		"Created": "2015-01-06T15:47:31.485331387Z",
-		"Driver": "devicemapper",
+		"Driver": "overlay2",
 		"ExecIDs": null,
 		"ExecIDs": null,
 		"HostConfig": {
 		"HostConfig": {
 			"Binds": null,
 			"Binds": null,

+ 1 - 1
docs/api/v1.25.yaml

@@ -2995,7 +2995,7 @@ paths:
                 StopSignal: "SIGTERM"
                 StopSignal: "SIGTERM"
                 StopTimeout: 10
                 StopTimeout: 10
               Created: "2015-01-06T15:47:31.485331387Z"
               Created: "2015-01-06T15:47:31.485331387Z"
-              Driver: "devicemapper"
+              Driver: "overlay2"
               HostConfig:
               HostConfig:
                 MaximumIOps: 0
                 MaximumIOps: 0
                 MaximumIOBps: 0
                 MaximumIOBps: 0

+ 1 - 1
docs/api/v1.26.yaml

@@ -3000,7 +3000,7 @@ paths:
                 StopSignal: "SIGTERM"
                 StopSignal: "SIGTERM"
                 StopTimeout: 10
                 StopTimeout: 10
               Created: "2015-01-06T15:47:31.485331387Z"
               Created: "2015-01-06T15:47:31.485331387Z"
-              Driver: "devicemapper"
+              Driver: "overlay2"
               HostConfig:
               HostConfig:
                 MaximumIOps: 0
                 MaximumIOps: 0
                 MaximumIOBps: 0
                 MaximumIOBps: 0

+ 1 - 1
docs/api/v1.27.yaml

@@ -3060,7 +3060,7 @@ paths:
                 StopSignal: "SIGTERM"
                 StopSignal: "SIGTERM"
                 StopTimeout: 10
                 StopTimeout: 10
               Created: "2015-01-06T15:47:31.485331387Z"
               Created: "2015-01-06T15:47:31.485331387Z"
-              Driver: "devicemapper"
+              Driver: "overlay2"
               HostConfig:
               HostConfig:
                 MaximumIOps: 0
                 MaximumIOps: 0
                 MaximumIOBps: 0
                 MaximumIOBps: 0

+ 1 - 1
docs/api/v1.28.yaml

@@ -3150,7 +3150,7 @@ paths:
                 StopSignal: "SIGTERM"
                 StopSignal: "SIGTERM"
                 StopTimeout: 10
                 StopTimeout: 10
               Created: "2015-01-06T15:47:31.485331387Z"
               Created: "2015-01-06T15:47:31.485331387Z"
-              Driver: "devicemapper"
+              Driver: "overlay2"
               HostConfig:
               HostConfig:
                 MaximumIOps: 0
                 MaximumIOps: 0
                 MaximumIOBps: 0
                 MaximumIOBps: 0

+ 1 - 1
docs/api/v1.29.yaml

@@ -3184,7 +3184,7 @@ paths:
                 StopSignal: "SIGTERM"
                 StopSignal: "SIGTERM"
                 StopTimeout: 10
                 StopTimeout: 10
               Created: "2015-01-06T15:47:31.485331387Z"
               Created: "2015-01-06T15:47:31.485331387Z"
-              Driver: "devicemapper"
+              Driver: "overlay2"
               HostConfig:
               HostConfig:
                 MaximumIOps: 0
                 MaximumIOps: 0
                 MaximumIOBps: 0
                 MaximumIOBps: 0

+ 1 - 1
docs/api/v1.30.yaml

@@ -3410,7 +3410,7 @@ paths:
                 StopSignal: "SIGTERM"
                 StopSignal: "SIGTERM"
                 StopTimeout: 10
                 StopTimeout: 10
               Created: "2015-01-06T15:47:31.485331387Z"
               Created: "2015-01-06T15:47:31.485331387Z"
-              Driver: "devicemapper"
+              Driver: "overlay2"
               HostConfig:
               HostConfig:
                 MaximumIOps: 0
                 MaximumIOps: 0
                 MaximumIOBps: 0
                 MaximumIOBps: 0

+ 1 - 1
docs/api/v1.31.yaml

@@ -3480,7 +3480,7 @@ paths:
                 StopSignal: "SIGTERM"
                 StopSignal: "SIGTERM"
                 StopTimeout: 10
                 StopTimeout: 10
               Created: "2015-01-06T15:47:31.485331387Z"
               Created: "2015-01-06T15:47:31.485331387Z"
-              Driver: "devicemapper"
+              Driver: "overlay2"
               HostConfig:
               HostConfig:
                 MaximumIOps: 0
                 MaximumIOps: 0
                 MaximumIOBps: 0
                 MaximumIOBps: 0

+ 1 - 1
docs/api/v1.32.yaml

@@ -4722,7 +4722,7 @@ paths:
                 StopSignal: "SIGTERM"
                 StopSignal: "SIGTERM"
                 StopTimeout: 10
                 StopTimeout: 10
               Created: "2015-01-06T15:47:31.485331387Z"
               Created: "2015-01-06T15:47:31.485331387Z"
-              Driver: "devicemapper"
+              Driver: "overlay2"
               HostConfig:
               HostConfig:
                 MaximumIOps: 0
                 MaximumIOps: 0
                 MaximumIOBps: 0
                 MaximumIOBps: 0

+ 1 - 1
docs/api/v1.33.yaml

@@ -4727,7 +4727,7 @@ paths:
                 StopSignal: "SIGTERM"
                 StopSignal: "SIGTERM"
                 StopTimeout: 10
                 StopTimeout: 10
               Created: "2015-01-06T15:47:31.485331387Z"
               Created: "2015-01-06T15:47:31.485331387Z"
-              Driver: "devicemapper"
+              Driver: "overlay2"
               HostConfig:
               HostConfig:
                 MaximumIOps: 0
                 MaximumIOps: 0
                 MaximumIOBps: 0
                 MaximumIOBps: 0

+ 1 - 1
docs/api/v1.34.yaml

@@ -4756,7 +4756,7 @@ paths:
                 StopSignal: "SIGTERM"
                 StopSignal: "SIGTERM"
                 StopTimeout: 10
                 StopTimeout: 10
               Created: "2015-01-06T15:47:31.485331387Z"
               Created: "2015-01-06T15:47:31.485331387Z"
-              Driver: "devicemapper"
+              Driver: "overlay2"
               HostConfig:
               HostConfig:
                 MaximumIOps: 0
                 MaximumIOps: 0
                 MaximumIOBps: 0
                 MaximumIOBps: 0

+ 1 - 1
docs/api/v1.35.yaml

@@ -4738,7 +4738,7 @@ paths:
                 StopSignal: "SIGTERM"
                 StopSignal: "SIGTERM"
                 StopTimeout: 10
                 StopTimeout: 10
               Created: "2015-01-06T15:47:31.485331387Z"
               Created: "2015-01-06T15:47:31.485331387Z"
-              Driver: "devicemapper"
+              Driver: "overlay2"
               HostConfig:
               HostConfig:
                 MaximumIOps: 0
                 MaximumIOps: 0
                 MaximumIOBps: 0
                 MaximumIOBps: 0

+ 1 - 1
docs/api/v1.36.yaml

@@ -4754,7 +4754,7 @@ paths:
                 StopSignal: "SIGTERM"
                 StopSignal: "SIGTERM"
                 StopTimeout: 10
                 StopTimeout: 10
               Created: "2015-01-06T15:47:31.485331387Z"
               Created: "2015-01-06T15:47:31.485331387Z"
-              Driver: "devicemapper"
+              Driver: "overlay2"
               HostConfig:
               HostConfig:
                 MaximumIOps: 0
                 MaximumIOps: 0
                 MaximumIOBps: 0
                 MaximumIOBps: 0

+ 1 - 1
docs/api/v1.37.yaml

@@ -4774,7 +4774,7 @@ paths:
                 StopSignal: "SIGTERM"
                 StopSignal: "SIGTERM"
                 StopTimeout: 10
                 StopTimeout: 10
               Created: "2015-01-06T15:47:31.485331387Z"
               Created: "2015-01-06T15:47:31.485331387Z"
-              Driver: "devicemapper"
+              Driver: "overlay2"
               HostConfig:
               HostConfig:
                 MaximumIOps: 0
                 MaximumIOps: 0
                 MaximumIOBps: 0
                 MaximumIOBps: 0

+ 1 - 1
docs/api/v1.38.yaml

@@ -4832,7 +4832,7 @@ paths:
                 StopSignal: "SIGTERM"
                 StopSignal: "SIGTERM"
                 StopTimeout: 10
                 StopTimeout: 10
               Created: "2015-01-06T15:47:31.485331387Z"
               Created: "2015-01-06T15:47:31.485331387Z"
-              Driver: "devicemapper"
+              Driver: "overlay2"
               ExecIDs:
               ExecIDs:
                 - "b35395de42bc8abd327f9dd65d913b9ba28c74d2f0734eeeae84fa1c616a0fca"
                 - "b35395de42bc8abd327f9dd65d913b9ba28c74d2f0734eeeae84fa1c616a0fca"
                 - "3fc1232e5cd20c8de182ed81178503dc6437f4e7ef12b52cc5e8de020652f1c4"
                 - "3fc1232e5cd20c8de182ed81178503dc6437f4e7ef12b52cc5e8de020652f1c4"

+ 1 - 1
docs/api/v1.39.yaml

@@ -5824,7 +5824,7 @@ paths:
                 StopSignal: "SIGTERM"
                 StopSignal: "SIGTERM"
                 StopTimeout: 10
                 StopTimeout: 10
               Created: "2015-01-06T15:47:31.485331387Z"
               Created: "2015-01-06T15:47:31.485331387Z"
-              Driver: "devicemapper"
+              Driver: "overlay2"
               ExecIDs:
               ExecIDs:
                 - "b35395de42bc8abd327f9dd65d913b9ba28c74d2f0734eeeae84fa1c616a0fca"
                 - "b35395de42bc8abd327f9dd65d913b9ba28c74d2f0734eeeae84fa1c616a0fca"
                 - "3fc1232e5cd20c8de182ed81178503dc6437f4e7ef12b52cc5e8de020652f1c4"
                 - "3fc1232e5cd20c8de182ed81178503dc6437f4e7ef12b52cc5e8de020652f1c4"

+ 1 - 1
docs/api/v1.40.yaml

@@ -6125,7 +6125,7 @@ paths:
                 StopSignal: "SIGTERM"
                 StopSignal: "SIGTERM"
                 StopTimeout: 10
                 StopTimeout: 10
               Created: "2015-01-06T15:47:31.485331387Z"
               Created: "2015-01-06T15:47:31.485331387Z"
-              Driver: "devicemapper"
+              Driver: "overlay2"
               ExecIDs:
               ExecIDs:
                 - "b35395de42bc8abd327f9dd65d913b9ba28c74d2f0734eeeae84fa1c616a0fca"
                 - "b35395de42bc8abd327f9dd65d913b9ba28c74d2f0734eeeae84fa1c616a0fca"
                 - "3fc1232e5cd20c8de182ed81178503dc6437f4e7ef12b52cc5e8de020652f1c4"
                 - "3fc1232e5cd20c8de182ed81178503dc6437f4e7ef12b52cc5e8de020652f1c4"

+ 1 - 1
docs/api/v1.41.yaml

@@ -6317,7 +6317,7 @@ paths:
                 StopSignal: "SIGTERM"
                 StopSignal: "SIGTERM"
                 StopTimeout: 10
                 StopTimeout: 10
               Created: "2015-01-06T15:47:31.485331387Z"
               Created: "2015-01-06T15:47:31.485331387Z"
-              Driver: "devicemapper"
+              Driver: "overlay2"
               ExecIDs:
               ExecIDs:
                 - "b35395de42bc8abd327f9dd65d913b9ba28c74d2f0734eeeae84fa1c616a0fca"
                 - "b35395de42bc8abd327f9dd65d913b9ba28c74d2f0734eeeae84fa1c616a0fca"
                 - "3fc1232e5cd20c8de182ed81178503dc6437f4e7ef12b52cc5e8de020652f1c4"
                 - "3fc1232e5cd20c8de182ed81178503dc6437f4e7ef12b52cc5e8de020652f1c4"

+ 1 - 1
docs/contributing/set-up-dev-env.md

@@ -130,7 +130,7 @@ can take over 15 minutes to complete.
    ```none
    ```none
    Successfully built 3d872560918e
    Successfully built 3d872560918e
    Successfully tagged docker-dev:dry-run-test
    Successfully tagged docker-dev:dry-run-test
-   docker run --rm -i --privileged -e BUILDFLAGS -e KEEPBUNDLE -e DOCKER_BUILD_GOGC -e DOCKER_BUILD_PKGS -e DOCKER_CLIENTONLY -e DOCKER_DEBUG -e DOCKER_EXPERIMENTAL -e DOCKER_GITCOMMIT -e DOCKER_GRAPHDRIVER=devicemapper -e DOCKER_REMAP_ROOT -e DOCKER_STORAGE_OPTS -e DOCKER_USERLANDPROXY -e TESTDIRS -e TESTFLAGS -e TIMEOUT -v "home/ubuntu/repos/docker/bundles:/go/src/github.com/docker/docker/bundles" -t "docker-dev:dry-run-test" bash
+   docker run --rm -i --privileged -e BUILDFLAGS -e KEEPBUNDLE -e DOCKER_BUILD_GOGC -e DOCKER_BUILD_PKGS -e DOCKER_CLIENTONLY -e DOCKER_DEBUG -e DOCKER_EXPERIMENTAL -e DOCKER_GITCOMMIT -e DOCKER_GRAPHDRIVER=vfs -e DOCKER_REMAP_ROOT -e DOCKER_STORAGE_OPTS -e DOCKER_USERLANDPROXY -e TESTDIRS -e TESTFLAGS -e TIMEOUT -v "home/ubuntu/repos/docker/bundles:/go/src/github.com/docker/docker/bundles" -t "docker-dev:dry-run-test" bash
    #
    #
    ```
    ```
 
 

+ 0 - 24
integration-cli/docker_cli_create_test.go

@@ -63,30 +63,6 @@ func (s *DockerCLICreateSuite) TestCreateArgs(c *testing.T) {
 	}
 	}
 }
 }
 
 
-// Make sure we can grow the container's rootfs at creation time.
-func (s *DockerCLICreateSuite) TestCreateGrowRootfs(c *testing.T) {
-	// Windows and Devicemapper support growing the rootfs
-	if testEnv.OSType != "windows" {
-		testRequires(c, Devicemapper)
-	}
-	out, _ := dockerCmd(c, "create", "--storage-opt", "size=120G", "busybox")
-
-	cleanedContainerID := strings.TrimSpace(out)
-
-	inspectOut := inspectField(c, cleanedContainerID, "HostConfig.StorageOpt")
-	assert.Equal(c, inspectOut, "map[size:120G]")
-}
-
-// Make sure we cannot shrink the container's rootfs at creation time.
-func (s *DockerCLICreateSuite) TestCreateShrinkRootfs(c *testing.T) {
-	testRequires(c, Devicemapper)
-
-	// Ensure this fails because of the defaultBaseFsSize is 10G
-	out, _, err := dockerCmdWithError("create", "--storage-opt", "size=5G", "busybox")
-	assert.ErrorContains(c, err, "", out)
-	assert.Assert(c, strings.Contains(out, "Container size cannot be smaller than"))
-}
-
 // Make sure we can set hostconfig options too
 // Make sure we can set hostconfig options too
 func (s *DockerCLICreateSuite) TestCreateHostConfig(c *testing.T) {
 func (s *DockerCLICreateSuite) TestCreateHostConfig(c *testing.T) {
 	out, _ := dockerCmd(c, "create", "-P", "busybox", "echo")
 	out, _ := dockerCmd(c, "create", "-P", "busybox", "echo")

+ 0 - 72
integration-cli/docker_cli_daemon_test.go

@@ -34,7 +34,6 @@ import (
 	"github.com/docker/docker/libnetwork/iptables"
 	"github.com/docker/docker/libnetwork/iptables"
 	"github.com/docker/docker/opts"
 	"github.com/docker/docker/opts"
 	testdaemon "github.com/docker/docker/testutil/daemon"
 	testdaemon "github.com/docker/docker/testutil/daemon"
-	units "github.com/docker/go-units"
 	"github.com/moby/sys/mount"
 	"github.com/moby/sys/mount"
 	"golang.org/x/sys/unix"
 	"golang.org/x/sys/unix"
 	"gotest.tools/v3/assert"
 	"gotest.tools/v3/assert"
@@ -203,77 +202,6 @@ func (s *DockerDaemonSuite) TestDaemonStartIptablesFalse(c *testing.T) {
 	s.d.Start(c, "--iptables=false")
 	s.d.Start(c, "--iptables=false")
 }
 }
 
 
-// Make sure we cannot shrink base device at daemon restart.
-func (s *DockerDaemonSuite) TestDaemonRestartWithInvalidBasesize(c *testing.T) {
-	testRequires(c, Devicemapper)
-	s.d.Start(c)
-
-	oldBasesizeBytes := getBaseDeviceSize(c, s.d)
-	var newBasesizeBytes int64 = 1073741824 // 1GB in bytes
-
-	if newBasesizeBytes < oldBasesizeBytes {
-		err := s.d.RestartWithError("--storage-opt", fmt.Sprintf("dm.basesize=%d", newBasesizeBytes))
-		assert.Assert(c, err != nil, "daemon should not have started as new base device size is less than existing base device size: %v", err)
-		// 'err != nil' is expected behaviour, no new daemon started,
-		// so no need to stop daemon.
-		if err != nil {
-			return
-		}
-	}
-	s.d.Stop(c)
-}
-
-// Make sure we can grow base device at daemon restart.
-func (s *DockerDaemonSuite) TestDaemonRestartWithIncreasedBasesize(c *testing.T) {
-	testRequires(c, Devicemapper)
-	s.d.Start(c)
-
-	oldBasesizeBytes := getBaseDeviceSize(c, s.d)
-
-	var newBasesizeBytes int64 = 53687091200 // 50GB in bytes
-
-	if newBasesizeBytes < oldBasesizeBytes {
-		c.Skipf("New base device size (%v) must be greater than (%s)", units.HumanSize(float64(newBasesizeBytes)), units.HumanSize(float64(oldBasesizeBytes)))
-	}
-
-	err := s.d.RestartWithError("--storage-opt", fmt.Sprintf("dm.basesize=%d", newBasesizeBytes))
-	assert.Assert(c, err == nil, "we should have been able to start the daemon with increased base device size: %v", err)
-
-	basesizeAfterRestart := getBaseDeviceSize(c, s.d)
-	newBasesize, err := convertBasesize(newBasesizeBytes)
-	assert.Assert(c, err == nil, "Error in converting base device size: %v", err)
-	assert.Equal(c, newBasesize, basesizeAfterRestart, "Basesize passed is not equal to Basesize set")
-	s.d.Stop(c)
-}
-
-func getBaseDeviceSize(c *testing.T, d *daemon.Daemon) int64 {
-	info := d.Info(c)
-	for _, statusLine := range info.DriverStatus {
-		key, value := statusLine[0], statusLine[1]
-		if key == "Base Device Size" {
-			return parseDeviceSize(c, value)
-		}
-	}
-	c.Fatal("failed to parse Base Device Size from info")
-	return int64(0)
-}
-
-func parseDeviceSize(c *testing.T, raw string) int64 {
-	size, err := units.RAMInBytes(strings.TrimSpace(raw))
-	assert.NilError(c, err)
-	return size
-}
-
-func convertBasesize(basesizeBytes int64) (int64, error) {
-	basesize := units.HumanSize(float64(basesizeBytes))
-	basesize = strings.Trim(basesize, " ")[:len(basesize)-3]
-	basesizeFloat, err := strconv.ParseFloat(strings.Trim(basesize, " "), 64)
-	if err != nil {
-		return 0, err
-	}
-	return int64(basesizeFloat) * 1024 * 1024 * 1024, nil
-}
-
 // Issue #8444: If docker0 bridge is modified (intentionally or unintentionally) and
 // Issue #8444: If docker0 bridge is modified (intentionally or unintentionally) and
 // no longer has an IP associated, we should gracefully handle that case and associate
 // no longer has an IP associated, we should gracefully handle that case and associate
 // an IP with it rather than fail daemon start
 // an IP with it rather than fail daemon start

+ 0 - 49
integration-cli/docker_cli_inspect_test.go

@@ -27,12 +27,6 @@ func (s *DockerCLIInspectSuite) OnTimeout(c *testing.T) {
 	s.ds.OnTimeout(c)
 	s.ds.OnTimeout(c)
 }
 }
 
 
-func checkValidGraphDriver(c *testing.T, name string) {
-	if name != "devicemapper" && name != "overlay" && name != "vfs" && name != "zfs" && name != "btrfs" && name != "aufs" {
-		c.Fatalf("%v is not a valid graph driver name", name)
-	}
-}
-
 func (s *DockerCLIInspectSuite) TestInspectImage(c *testing.T) {
 func (s *DockerCLIInspectSuite) TestInspectImage(c *testing.T) {
 	testRequires(c, DaemonIsLinux)
 	testRequires(c, DaemonIsLinux)
 	imageTest := "emptyfs"
 	imageTest := "emptyfs"
@@ -177,49 +171,6 @@ func (s *DockerCLIInspectSuite) TestInspectContainerFilterInt(c *testing.T) {
 	assert.Equal(c, inspectResult, true)
 	assert.Equal(c, inspectResult, true)
 }
 }
 
 
-func (s *DockerCLIInspectSuite) TestInspectImageGraphDriver(c *testing.T) {
-	testRequires(c, DaemonIsLinux, Devicemapper)
-	imageTest := "emptyfs"
-	name := inspectField(c, imageTest, "GraphDriver.Name")
-
-	checkValidGraphDriver(c, name)
-
-	deviceID := inspectField(c, imageTest, "GraphDriver.Data.DeviceId")
-
-	_, err := strconv.Atoi(deviceID)
-	assert.Assert(c, err == nil, "failed to inspect DeviceId of the image: %s, %v", deviceID, err)
-
-	deviceSize := inspectField(c, imageTest, "GraphDriver.Data.DeviceSize")
-
-	_, err = strconv.ParseUint(deviceSize, 10, 64)
-	assert.Assert(c, err == nil, "failed to inspect DeviceSize of the image: %s, %v", deviceSize, err)
-}
-
-func (s *DockerCLIInspectSuite) TestInspectContainerGraphDriver(c *testing.T) {
-	testRequires(c, DaemonIsLinux, Devicemapper)
-
-	out, _ := dockerCmd(c, "run", "-d", "busybox", "true")
-	out = strings.TrimSpace(out)
-
-	name := inspectField(c, out, "GraphDriver.Name")
-
-	checkValidGraphDriver(c, name)
-
-	imageDeviceID := inspectField(c, "busybox", "GraphDriver.Data.DeviceId")
-
-	deviceID := inspectField(c, out, "GraphDriver.Data.DeviceId")
-
-	assert.Assert(c, imageDeviceID != deviceID)
-
-	_, err := strconv.Atoi(deviceID)
-	assert.Assert(c, err == nil, "failed to inspect DeviceId of the image: %s, %v", deviceID, err)
-
-	deviceSize := inspectField(c, out, "GraphDriver.Data.DeviceSize")
-
-	_, err = strconv.ParseUint(deviceSize, 10, 64)
-	assert.Assert(c, err == nil, "failed to inspect DeviceSize of the image: %s, %v", deviceSize, err)
-}
-
 func (s *DockerCLIInspectSuite) TestInspectBindMountPoint(c *testing.T) {
 func (s *DockerCLIInspectSuite) TestInspectBindMountPoint(c *testing.T) {
 	modifier := ",z"
 	modifier := ",z"
 	prefix, slash := getPrefixAndSlashFromDaemonPlatform()
 	prefix, slash := getPrefixAndSlashFromDaemonPlatform()

+ 0 - 4
integration-cli/requirements_test.go

@@ -100,10 +100,6 @@ func Apparmor() bool {
 	return err == nil && len(buf) > 1 && buf[0] == 'Y'
 	return err == nil && len(buf) > 1 && buf[0] == 'Y'
 }
 }
 
 
-func Devicemapper() bool {
-	return strings.HasPrefix(testEnv.DaemonInfo.Driver, "devicemapper")
-}
-
 // containerdSnapshotterEnabled checks if the daemon in the test-environment is
 // containerdSnapshotterEnabled checks if the daemon in the test-environment is
 // configured with containerd-snapshotters enabled.
 // configured with containerd-snapshotters enabled.
 func containerdSnapshotterEnabled() bool {
 func containerdSnapshotterEnabled() bool {

+ 0 - 34
integration/container/stop_linux_test.go

@@ -2,19 +2,14 @@ package container // import "github.com/docker/docker/integration/container"
 
 
 import (
 import (
 	"context"
 	"context"
-	"fmt"
 	"strconv"
 	"strconv"
-	"strings"
 	"testing"
 	"testing"
 	"time"
 	"time"
 
 
-	"github.com/docker/docker/api/types"
 	containertypes "github.com/docker/docker/api/types/container"
 	containertypes "github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/integration/internal/container"
 	"github.com/docker/docker/integration/internal/container"
 	"gotest.tools/v3/assert"
 	"gotest.tools/v3/assert"
-	"gotest.tools/v3/icmd"
 	"gotest.tools/v3/poll"
 	"gotest.tools/v3/poll"
-	"gotest.tools/v3/skip"
 )
 )
 
 
 // TestStopContainerWithTimeout checks that ContainerStop with
 // TestStopContainerWithTimeout checks that ContainerStop with
@@ -69,32 +64,3 @@ func TestStopContainerWithTimeout(t *testing.T) {
 		})
 		})
 	}
 	}
 }
 }
-
-func TestDeleteDevicemapper(t *testing.T) {
-	skip.If(t, testEnv.DaemonInfo.Driver != "devicemapper")
-	skip.If(t, testEnv.IsRemoteDaemon)
-
-	defer setupTest(t)()
-	client := testEnv.APIClient()
-	ctx := context.Background()
-
-	id := container.Run(ctx, t, client, container.WithName("foo-"+t.Name()), container.WithCmd("echo"))
-
-	poll.WaitOn(t, container.IsStopped(ctx, client, id), poll.WithDelay(100*time.Millisecond))
-
-	inspect, err := client.ContainerInspect(ctx, id)
-	assert.NilError(t, err)
-
-	deviceID := inspect.GraphDriver.Data["DeviceId"]
-
-	// Find pool name from device name
-	deviceName := inspect.GraphDriver.Data["DeviceName"]
-	devicePrefix := deviceName[:strings.LastIndex(deviceName, "-")]
-	devicePool := fmt.Sprintf("/dev/mapper/%s-pool", devicePrefix)
-
-	result := icmd.RunCommand("dmsetup", "message", devicePool, "0", fmt.Sprintf("delete %s", deviceID))
-	result.Assert(t, icmd.Success)
-
-	err = client.ContainerRemove(ctx, id, types.ContainerRemoveOptions{})
-	assert.NilError(t, err)
-}

+ 0 - 811
pkg/devicemapper/devmapper.go

@@ -1,811 +0,0 @@
-//go:build linux && cgo
-// +build linux,cgo
-
-package devicemapper // import "github.com/docker/docker/pkg/devicemapper"
-
-import (
-	"errors"
-	"fmt"
-	"os"
-	"runtime"
-	"unsafe"
-
-	"github.com/sirupsen/logrus"
-	"golang.org/x/sys/unix"
-)
-
-// Same as DM_DEVICE_* enum values from libdevmapper.h
-//
-//nolint:unused
-const (
-	deviceCreate TaskType = iota
-	deviceReload
-	deviceRemove
-	deviceRemoveAll
-	deviceSuspend
-	deviceResume
-	deviceInfo
-	deviceDeps
-	deviceRename
-	deviceVersion
-	deviceStatus
-	deviceTable
-	deviceWaitevent
-	deviceList
-	deviceClear
-	deviceMknodes
-	deviceListVersions
-	deviceTargetMsg
-	deviceSetGeometry
-)
-
-const (
-	addNodeOnResume AddNodeType = iota
-	addNodeOnCreate
-)
-
-// List of errors returned when using devicemapper.
-var (
-	ErrTaskRun              = errors.New("dm_task_run failed")
-	ErrTaskSetName          = errors.New("dm_task_set_name failed")
-	ErrTaskSetMessage       = errors.New("dm_task_set_message failed")
-	ErrTaskSetAddNode       = errors.New("dm_task_set_add_node failed")
-	ErrTaskAddTarget        = errors.New("dm_task_add_target failed")
-	ErrTaskSetSector        = errors.New("dm_task_set_sector failed")
-	ErrTaskGetDeps          = errors.New("dm_task_get_deps failed")
-	ErrTaskGetInfo          = errors.New("dm_task_get_info failed")
-	ErrTaskGetDriverVersion = errors.New("dm_task_get_driver_version failed")
-	ErrTaskDeferredRemove   = errors.New("dm_task_deferred_remove failed")
-	ErrTaskSetCookie        = errors.New("dm_task_set_cookie failed")
-	ErrNilCookie            = errors.New("cookie ptr can't be nil")
-	ErrGetBlockSize         = errors.New("Can't get block size")
-	ErrUdevWait             = errors.New("wait on udev cookie failed")
-	ErrSetDevDir            = errors.New("dm_set_dev_dir failed")
-	ErrGetLibraryVersion    = errors.New("dm_get_library_version failed")
-	ErrInvalidAddNode       = errors.New("Invalid AddNode type")
-	ErrBusy                 = errors.New("Device is Busy")
-	ErrDeviceIDExists       = errors.New("Device Id Exists")
-	ErrEnxio                = errors.New("No such device or address")
-)
-
-var (
-	dmSawBusy    bool
-	dmSawExist   bool
-	dmSawEnxio   bool // No Such Device or Address
-	dmSawEnoData bool // No data available
-)
-
-type (
-	// Task represents a devicemapper task (like lvcreate, etc.) ; a task is needed for each ioctl
-	// command to execute.
-	Task struct {
-		unmanaged *cdmTask
-	}
-	// Deps represents dependents (layer) of a device.
-	Deps struct {
-		Count  uint32
-		Filler uint32
-		Device []uint64
-	}
-	// Info represents information about a device.
-	Info struct {
-		Exists         int
-		Suspended      int
-		LiveTable      int
-		InactiveTable  int
-		OpenCount      int32
-		EventNr        uint32
-		Major          uint32
-		Minor          uint32
-		ReadOnly       int
-		TargetCount    int32
-		DeferredRemove int
-	}
-	// TaskType represents a type of task
-	TaskType int
-	// AddNodeType represents a type of node to be added
-	AddNodeType int
-)
-
-// DeviceIDExists returns whether error conveys the information about device Id already
-// exist or not. This will be true if device creation or snap creation
-// operation fails if device or snap device already exists in pool.
-// Current implementation is little crude as it scans the error string
-// for exact pattern match. Replacing it with more robust implementation
-// is desirable.
-func DeviceIDExists(err error) bool {
-	return fmt.Sprint(err) == fmt.Sprint(ErrDeviceIDExists)
-}
-
-func (t *Task) destroy() {
-	if t != nil {
-		DmTaskDestroy(t.unmanaged)
-		runtime.SetFinalizer(t, nil)
-	}
-}
-
-// TaskCreateNamed is a convenience function for TaskCreate when a name
-// will be set on the task as well
-func TaskCreateNamed(t TaskType, name string) (*Task, error) {
-	task := TaskCreate(t)
-	if task == nil {
-		return nil, fmt.Errorf("devicemapper: Can't create task of type %d", int(t))
-	}
-	if err := task.setName(name); err != nil {
-		return nil, fmt.Errorf("devicemapper: Can't set task name %s", name)
-	}
-	return task, nil
-}
-
-// TaskCreate initializes a devicemapper task of tasktype
-func TaskCreate(tasktype TaskType) *Task {
-	Ctask := DmTaskCreate(int(tasktype))
-	if Ctask == nil {
-		return nil
-	}
-	task := &Task{unmanaged: Ctask}
-	runtime.SetFinalizer(task, (*Task).destroy)
-	return task
-}
-
-func (t *Task) run() error {
-	if res := DmTaskRun(t.unmanaged); res != 1 {
-		return ErrTaskRun
-	}
-	runtime.KeepAlive(t)
-	return nil
-}
-
-func (t *Task) setName(name string) error {
-	if res := DmTaskSetName(t.unmanaged, name); res != 1 {
-		return ErrTaskSetName
-	}
-	return nil
-}
-
-func (t *Task) setMessage(message string) error {
-	if res := DmTaskSetMessage(t.unmanaged, message); res != 1 {
-		return ErrTaskSetMessage
-	}
-	return nil
-}
-
-func (t *Task) setSector(sector uint64) error {
-	if res := DmTaskSetSector(t.unmanaged, sector); res != 1 {
-		return ErrTaskSetSector
-	}
-	return nil
-}
-
-func (t *Task) setCookie(cookie *uint, flags uint16) error {
-	if cookie == nil {
-		return ErrNilCookie
-	}
-	if res := DmTaskSetCookie(t.unmanaged, cookie, flags); res != 1 {
-		return ErrTaskSetCookie
-	}
-	return nil
-}
-
-func (t *Task) setAddNode(addNode AddNodeType) error {
-	if addNode != addNodeOnResume && addNode != addNodeOnCreate {
-		return ErrInvalidAddNode
-	}
-	if res := DmTaskSetAddNode(t.unmanaged, addNode); res != 1 {
-		return ErrTaskSetAddNode
-	}
-	return nil
-}
-
-func (t *Task) addTarget(start, size uint64, ttype, params string) error {
-	if res := DmTaskAddTarget(t.unmanaged, start, size,
-		ttype, params); res != 1 {
-		return ErrTaskAddTarget
-	}
-	return nil
-}
-
-func (t *Task) getDeps() (*Deps, error) {
-	var deps *Deps
-	if deps = DmTaskGetDeps(t.unmanaged); deps == nil {
-		return nil, ErrTaskGetDeps
-	}
-	return deps, nil
-}
-
-func (t *Task) getInfo() (*Info, error) {
-	info := &Info{}
-	if res := DmTaskGetInfo(t.unmanaged, info); res != 1 {
-		return nil, ErrTaskGetInfo
-	}
-	return info, nil
-}
-
-func (t *Task) getInfoWithDeferred() (*Info, error) {
-	info := &Info{}
-	if res := DmTaskGetInfoWithDeferred(t.unmanaged, info); res != 1 {
-		return nil, ErrTaskGetInfo
-	}
-	return info, nil
-}
-
-func (t *Task) getDriverVersion() (string, error) {
-	res := DmTaskGetDriverVersion(t.unmanaged)
-	if res == "" {
-		return "", ErrTaskGetDriverVersion
-	}
-	return res, nil
-}
-
-func (t *Task) getNextTarget(next unsafe.Pointer) (nextPtr unsafe.Pointer, start uint64, length uint64, targetType string, params string) {
-	return DmGetNextTarget(t.unmanaged, next, &start, &length, &targetType, &params), start, length, targetType, params
-}
-
-// UdevWait waits for any processes that are waiting for udev to complete the specified cookie.
-func UdevWait(cookie *uint) error {
-	if res := DmUdevWait(*cookie); res != 1 {
-		logrus.Debugf("devicemapper: Failed to wait on udev cookie %d, %d", *cookie, res)
-		return ErrUdevWait
-	}
-	return nil
-}
-
-// SetDevDir sets the dev folder for the device mapper library (usually /dev).
-func SetDevDir(dir string) error {
-	if res := DmSetDevDir(dir); res != 1 {
-		logrus.Debug("devicemapper: Error dm_set_dev_dir")
-		return ErrSetDevDir
-	}
-	return nil
-}
-
-// GetLibraryVersion returns the device mapper library version.
-func GetLibraryVersion() (string, error) {
-	var version string
-	if res := DmGetLibraryVersion(&version); res != 1 {
-		return "", ErrGetLibraryVersion
-	}
-	return version, nil
-}
-
-// UdevSyncSupported returns whether device-mapper is able to sync with udev
-//
-// This is essential otherwise race conditions can arise where both udev and
-// device-mapper attempt to create and destroy devices.
-func UdevSyncSupported() bool {
-	return DmUdevGetSyncSupport() != 0
-}
-
-// UdevSetSyncSupport allows setting whether the udev sync should be enabled.
-// The return bool indicates the state of whether the sync is enabled.
-func UdevSetSyncSupport(enable bool) bool {
-	if enable {
-		DmUdevSetSyncSupport(1)
-	} else {
-		DmUdevSetSyncSupport(0)
-	}
-
-	return UdevSyncSupported()
-}
-
-// CookieSupported returns whether the version of device-mapper supports the
-// use of cookie's in the tasks.
-// This is largely a lower level call that other functions use.
-func CookieSupported() bool {
-	return DmCookieSupported() != 0
-}
-
-// RemoveDevice is a useful helper for cleaning up a device.
-func RemoveDevice(name string) error {
-	task, err := TaskCreateNamed(deviceRemove, name)
-	if task == nil {
-		return err
-	}
-
-	cookie := new(uint)
-	if err := task.setCookie(cookie, 0); err != nil {
-		return fmt.Errorf("devicemapper: Can not set cookie: %s", err)
-	}
-	defer UdevWait(cookie)
-
-	dmSawBusy = false // reset before the task is run
-	dmSawEnxio = false
-	if err = task.run(); err != nil {
-		if dmSawBusy {
-			return ErrBusy
-		}
-		if dmSawEnxio {
-			return ErrEnxio
-		}
-		return fmt.Errorf("devicemapper: Error running RemoveDevice %s", err)
-	}
-
-	return nil
-}
-
-// RemoveDeviceDeferred is a useful helper for cleaning up a device, but deferred.
-func RemoveDeviceDeferred(name string) error {
-	logrus.Debugf("devicemapper: RemoveDeviceDeferred START(%s)", name)
-	defer logrus.Debugf("devicemapper: RemoveDeviceDeferred END(%s)", name)
-	task, err := TaskCreateNamed(deviceRemove, name)
-	if task == nil {
-		return err
-	}
-
-	if err := DmTaskDeferredRemove(task.unmanaged); err != 1 {
-		return ErrTaskDeferredRemove
-	}
-
-	// set a task cookie and disable library fallback, or else libdevmapper will
-	// disable udev dm rules and delete the symlink under /dev/mapper by itself,
-	// even if the removal is deferred by the kernel.
-	cookie := new(uint)
-	flags := uint16(DmUdevDisableLibraryFallback)
-	if err := task.setCookie(cookie, flags); err != nil {
-		return fmt.Errorf("devicemapper: Can not set cookie: %s", err)
-	}
-
-	// libdevmapper and udev relies on System V semaphore for synchronization,
-	// semaphores created in `task.setCookie` will be cleaned up in `UdevWait`.
-	// So these two function call must come in pairs, otherwise semaphores will
-	// be leaked, and the  limit of number of semaphores defined in `/proc/sys/kernel/sem`
-	// will be reached, which will eventually make all following calls to 'task.SetCookie'
-	// fail.
-	// this call will not wait for the deferred removal's final executing, since no
-	// udev event will be generated, and the semaphore's value will not be incremented
-	// by udev, what UdevWait is just cleaning up the semaphore.
-	defer UdevWait(cookie)
-
-	dmSawEnxio = false
-	if err = task.run(); err != nil {
-		if dmSawEnxio {
-			return ErrEnxio
-		}
-		return fmt.Errorf("devicemapper: Error running RemoveDeviceDeferred %s", err)
-	}
-
-	return nil
-}
-
-// CancelDeferredRemove cancels a deferred remove for a device.
-func CancelDeferredRemove(deviceName string) error {
-	task, err := TaskCreateNamed(deviceTargetMsg, deviceName)
-	if task == nil {
-		return err
-	}
-
-	if err := task.setSector(0); err != nil {
-		return fmt.Errorf("devicemapper: Can't set sector %s", err)
-	}
-
-	if err := task.setMessage("@cancel_deferred_remove"); err != nil {
-		return fmt.Errorf("devicemapper: Can't set message %s", err)
-	}
-
-	dmSawBusy = false
-	dmSawEnxio = false
-	if err := task.run(); err != nil {
-		// A device might be being deleted already
-		if dmSawBusy {
-			return ErrBusy
-		} else if dmSawEnxio {
-			return ErrEnxio
-		}
-		return fmt.Errorf("devicemapper: Error running CancelDeferredRemove %s", err)
-	}
-	return nil
-}
-
-// GetBlockDeviceSize returns the size of a block device identified by the specified file.
-func GetBlockDeviceSize(file *os.File) (uint64, error) {
-	size, err := ioctlBlkGetSize64(file.Fd())
-	if err != nil {
-		logrus.Errorf("devicemapper: Error getblockdevicesize: %s", err)
-		return 0, ErrGetBlockSize
-	}
-	return uint64(size), nil
-}
-
-// BlockDeviceDiscard runs discard for the given path.
-// This is used as a workaround for the kernel not discarding block so
-// on the thin pool when we remove a thinp device, so we do it
-// manually
-func BlockDeviceDiscard(path string) error {
-	file, err := os.OpenFile(path, os.O_RDWR, 0)
-	if err != nil {
-		return err
-	}
-	defer file.Close()
-
-	size, err := GetBlockDeviceSize(file)
-	if err != nil {
-		return err
-	}
-
-	if err := ioctlBlkDiscard(file.Fd(), 0, size); err != nil {
-		return err
-	}
-
-	// Without this sometimes the remove of the device that happens after
-	// discard fails with EBUSY.
-	unix.Sync()
-
-	return nil
-}
-
-// CreatePool is the programmatic example of "dmsetup create".
-// It creates a device with the specified poolName, data and metadata file and block size.
-func CreatePool(poolName string, dataFile, metadataFile *os.File, poolBlockSize uint32) error {
-	task, err := TaskCreateNamed(deviceCreate, poolName)
-	if task == nil {
-		return err
-	}
-
-	size, err := GetBlockDeviceSize(dataFile)
-	if err != nil {
-		return fmt.Errorf("devicemapper: Can't get data size %s", err)
-	}
-
-	params := fmt.Sprintf("%s %s %d 32768 1 skip_block_zeroing", metadataFile.Name(), dataFile.Name(), poolBlockSize)
-	if err := task.addTarget(0, size/512, "thin-pool", params); err != nil {
-		return fmt.Errorf("devicemapper: Can't add target %s", err)
-	}
-
-	cookie := new(uint)
-	flags := uint16(DmUdevDisableSubsystemRulesFlag | DmUdevDisableDiskRulesFlag | DmUdevDisableOtherRulesFlag)
-	if err := task.setCookie(cookie, flags); err != nil {
-		return fmt.Errorf("devicemapper: Can't set cookie %s", err)
-	}
-	defer UdevWait(cookie)
-
-	if err := task.run(); err != nil {
-		return fmt.Errorf("devicemapper: Error running deviceCreate (CreatePool) %s", err)
-	}
-
-	return nil
-}
-
-// ReloadPool is the programmatic example of "dmsetup reload".
-// It reloads the table with the specified poolName, data and metadata file and block size.
-func ReloadPool(poolName string, dataFile, metadataFile *os.File, poolBlockSize uint32) error {
-	task, err := TaskCreateNamed(deviceReload, poolName)
-	if task == nil {
-		return err
-	}
-
-	size, err := GetBlockDeviceSize(dataFile)
-	if err != nil {
-		return fmt.Errorf("devicemapper: Can't get data size %s", err)
-	}
-
-	params := fmt.Sprintf("%s %s %d 32768 1 skip_block_zeroing", metadataFile.Name(), dataFile.Name(), poolBlockSize)
-	if err := task.addTarget(0, size/512, "thin-pool", params); err != nil {
-		return fmt.Errorf("devicemapper: Can't add target %s", err)
-	}
-
-	if err := task.run(); err != nil {
-		return fmt.Errorf("devicemapper: Error running ReloadPool %s", err)
-	}
-
-	return nil
-}
-
-// GetDeps is the programmatic example of "dmsetup deps".
-// It outputs a list of devices referenced by the live table for the specified device.
-func GetDeps(name string) (*Deps, error) {
-	task, err := TaskCreateNamed(deviceDeps, name)
-	if task == nil {
-		return nil, err
-	}
-	if err := task.run(); err != nil {
-		return nil, err
-	}
-	return task.getDeps()
-}
-
-// GetInfo is the programmatic example of "dmsetup info".
-// It outputs some brief information about the device.
-func GetInfo(name string) (*Info, error) {
-	task, err := TaskCreateNamed(deviceInfo, name)
-	if task == nil {
-		return nil, err
-	}
-	if err := task.run(); err != nil {
-		return nil, err
-	}
-	return task.getInfo()
-}
-
-// GetInfoWithDeferred is the programmatic example of "dmsetup info", but deferred.
-// It outputs some brief information about the device.
-func GetInfoWithDeferred(name string) (*Info, error) {
-	task, err := TaskCreateNamed(deviceInfo, name)
-	if task == nil {
-		return nil, err
-	}
-	if err := task.run(); err != nil {
-		return nil, err
-	}
-	return task.getInfoWithDeferred()
-}
-
-// GetDriverVersion is the programmatic example of "dmsetup version".
-// It outputs version information of the driver.
-func GetDriverVersion() (string, error) {
-	task := TaskCreate(deviceVersion)
-	if task == nil {
-		return "", fmt.Errorf("devicemapper: Can't create deviceVersion task")
-	}
-	if err := task.run(); err != nil {
-		return "", err
-	}
-	return task.getDriverVersion()
-}
-
-// GetStatus is the programmatic example of "dmsetup status".
-// It outputs status information for the specified device name.
-func GetStatus(name string) (uint64, uint64, string, string, error) {
-	task, err := TaskCreateNamed(deviceStatus, name)
-	if task == nil {
-		logrus.Debugf("devicemapper: GetStatus() Error TaskCreateNamed: %s", err)
-		return 0, 0, "", "", err
-	}
-	if err := task.run(); err != nil {
-		logrus.Debugf("devicemapper: GetStatus() Error Run: %s", err)
-		return 0, 0, "", "", err
-	}
-
-	devinfo, err := task.getInfo()
-	if err != nil {
-		logrus.Debugf("devicemapper: GetStatus() Error GetInfo: %s", err)
-		return 0, 0, "", "", err
-	}
-	if devinfo.Exists == 0 {
-		logrus.Debugf("devicemapper: GetStatus() Non existing device %s", name)
-		return 0, 0, "", "", fmt.Errorf("devicemapper: Non existing device %s", name)
-	}
-
-	_, start, length, targetType, params := task.getNextTarget(unsafe.Pointer(nil))
-	return start, length, targetType, params, nil
-}
-
-// GetTable is the programmatic example for "dmsetup table".
-// It outputs the current table for the specified device name.
-func GetTable(name string) (uint64, uint64, string, string, error) {
-	task, err := TaskCreateNamed(deviceTable, name)
-	if task == nil {
-		logrus.Debugf("devicemapper: GetTable() Error TaskCreateNamed: %s", err)
-		return 0, 0, "", "", err
-	}
-	if err := task.run(); err != nil {
-		logrus.Debugf("devicemapper: GetTable() Error Run: %s", err)
-		return 0, 0, "", "", err
-	}
-
-	devinfo, err := task.getInfo()
-	if err != nil {
-		logrus.Debugf("devicemapper: GetTable() Error GetInfo: %s", err)
-		return 0, 0, "", "", err
-	}
-	if devinfo.Exists == 0 {
-		logrus.Debugf("devicemapper: GetTable() Non existing device %s", name)
-		return 0, 0, "", "", fmt.Errorf("devicemapper: Non existing device %s", name)
-	}
-
-	_, start, length, targetType, params := task.getNextTarget(unsafe.Pointer(nil))
-	return start, length, targetType, params, nil
-}
-
-// SetTransactionID sets a transaction id for the specified device name.
-func SetTransactionID(poolName string, oldID uint64, newID uint64) error {
-	task, err := TaskCreateNamed(deviceTargetMsg, poolName)
-	if task == nil {
-		return err
-	}
-
-	if err := task.setSector(0); err != nil {
-		return fmt.Errorf("devicemapper: Can't set sector %s", err)
-	}
-
-	if err := task.setMessage(fmt.Sprintf("set_transaction_id %d %d", oldID, newID)); err != nil {
-		return fmt.Errorf("devicemapper: Can't set message %s", err)
-	}
-
-	if err := task.run(); err != nil {
-		return fmt.Errorf("devicemapper: Error running SetTransactionID %s", err)
-	}
-	return nil
-}
-
-// SuspendDevice is the programmatic example of "dmsetup suspend".
-// It suspends the specified device.
-func SuspendDevice(name string) error {
-	task, err := TaskCreateNamed(deviceSuspend, name)
-	if task == nil {
-		return err
-	}
-	if err := task.run(); err != nil {
-		return fmt.Errorf("devicemapper: Error running deviceSuspend %s", err)
-	}
-	return nil
-}
-
-// ResumeDevice is the programmatic example of "dmsetup resume".
-// It un-suspends the specified device.
-func ResumeDevice(name string) error {
-	task, err := TaskCreateNamed(deviceResume, name)
-	if task == nil {
-		return err
-	}
-
-	cookie := new(uint)
-	if err := task.setCookie(cookie, 0); err != nil {
-		return fmt.Errorf("devicemapper: Can't set cookie %s", err)
-	}
-	defer UdevWait(cookie)
-
-	if err := task.run(); err != nil {
-		return fmt.Errorf("devicemapper: Error running deviceResume %s", err)
-	}
-
-	return nil
-}
-
-// CreateDevice creates a device with the specified poolName with the specified device id.
-func CreateDevice(poolName string, deviceID int) error {
-	logrus.Debugf("devicemapper: CreateDevice(poolName=%v, deviceID=%v)", poolName, deviceID)
-	task, err := TaskCreateNamed(deviceTargetMsg, poolName)
-	if task == nil {
-		return err
-	}
-
-	if err := task.setSector(0); err != nil {
-		return fmt.Errorf("devicemapper: Can't set sector %s", err)
-	}
-
-	if err := task.setMessage(fmt.Sprintf("create_thin %d", deviceID)); err != nil {
-		return fmt.Errorf("devicemapper: Can't set message %s", err)
-	}
-
-	dmSawExist = false // reset before the task is run
-	if err := task.run(); err != nil {
-		// Caller wants to know about ErrDeviceIDExists so that it can try with a different device id.
-		if dmSawExist {
-			return ErrDeviceIDExists
-		}
-
-		return fmt.Errorf("devicemapper: Error running CreateDevice %s", err)
-	}
-	return nil
-}
-
-// DeleteDevice deletes a device with the specified poolName with the specified device id.
-func DeleteDevice(poolName string, deviceID int) error {
-	task, err := TaskCreateNamed(deviceTargetMsg, poolName)
-	if task == nil {
-		return err
-	}
-
-	if err := task.setSector(0); err != nil {
-		return fmt.Errorf("devicemapper: Can't set sector %s", err)
-	}
-
-	if err := task.setMessage(fmt.Sprintf("delete %d", deviceID)); err != nil {
-		return fmt.Errorf("devicemapper: Can't set message %s", err)
-	}
-
-	dmSawBusy = false
-	dmSawEnoData = false
-	if err := task.run(); err != nil {
-		if dmSawBusy {
-			return ErrBusy
-		}
-		if dmSawEnoData {
-			logrus.Debugf("devicemapper: Device(id: %d) from pool(%s) does not exist", deviceID, poolName)
-			return nil
-		}
-		return fmt.Errorf("devicemapper: Error running DeleteDevice %s", err)
-	}
-	return nil
-}
-
-// ActivateDevice activates the device identified by the specified
-// poolName, name and deviceID with the specified size.
-func ActivateDevice(poolName string, name string, deviceID int, size uint64) error {
-	return activateDevice(poolName, name, deviceID, size, "")
-}
-
-// ActivateDeviceWithExternal activates the device identified by the specified
-// poolName, name and deviceID with the specified size.
-func ActivateDeviceWithExternal(poolName string, name string, deviceID int, size uint64, external string) error {
-	return activateDevice(poolName, name, deviceID, size, external)
-}
-
-func activateDevice(poolName string, name string, deviceID int, size uint64, external string) error {
-	task, err := TaskCreateNamed(deviceCreate, name)
-	if task == nil {
-		return err
-	}
-
-	var params string
-	if len(external) > 0 {
-		params = fmt.Sprintf("%s %d %s", poolName, deviceID, external)
-	} else {
-		params = fmt.Sprintf("%s %d", poolName, deviceID)
-	}
-	if err := task.addTarget(0, size/512, "thin", params); err != nil {
-		return fmt.Errorf("devicemapper: Can't add target %s", err)
-	}
-	if err := task.setAddNode(addNodeOnCreate); err != nil {
-		return fmt.Errorf("devicemapper: Can't add node %s", err)
-	}
-
-	cookie := new(uint)
-	if err := task.setCookie(cookie, 0); err != nil {
-		return fmt.Errorf("devicemapper: Can't set cookie %s", err)
-	}
-
-	defer UdevWait(cookie)
-
-	if err := task.run(); err != nil {
-		return fmt.Errorf("devicemapper: Error running deviceCreate (ActivateDevice) %s", err)
-	}
-
-	return nil
-}
-
-// CreateSnapDeviceRaw creates a snapshot device. Caller needs to suspend and resume the origin device if it is active.
-func CreateSnapDeviceRaw(poolName string, deviceID int, baseDeviceID int) error {
-	task, err := TaskCreateNamed(deviceTargetMsg, poolName)
-	if task == nil {
-		return err
-	}
-
-	if err := task.setSector(0); err != nil {
-		return fmt.Errorf("devicemapper: Can't set sector %s", err)
-	}
-
-	if err := task.setMessage(fmt.Sprintf("create_snap %d %d", deviceID, baseDeviceID)); err != nil {
-		return fmt.Errorf("devicemapper: Can't set message %s", err)
-	}
-
-	dmSawExist = false // reset before the task is run
-	if err := task.run(); err != nil {
-		// Caller wants to know about ErrDeviceIDExists so that it can try with a different device id.
-		if dmSawExist {
-			return ErrDeviceIDExists
-		}
-		return fmt.Errorf("devicemapper: Error running deviceCreate (CreateSnapDeviceRaw) %s", err)
-	}
-
-	return nil
-}
-
-// CreateSnapDevice creates a snapshot based on the device identified by the baseName and baseDeviceId,
-func CreateSnapDevice(poolName string, deviceID int, baseName string, baseDeviceID int) error {
-	devinfo, _ := GetInfo(baseName)
-	doSuspend := devinfo != nil && devinfo.Exists != 0
-
-	if doSuspend {
-		if err := SuspendDevice(baseName); err != nil {
-			return err
-		}
-	}
-
-	if err := CreateSnapDeviceRaw(poolName, deviceID, baseDeviceID); err != nil {
-		if doSuspend {
-			if err2 := ResumeDevice(baseName); err2 != nil {
-				return fmt.Errorf("CreateSnapDeviceRaw Error: (%v): ResumeDevice Error: (%v)", err, err2)
-			}
-		}
-		return err
-	}
-
-	if doSuspend {
-		if err := ResumeDevice(baseName); err != nil {
-			return err
-		}
-	}
-
-	return nil
-}

+ 0 - 126
pkg/devicemapper/devmapper_log.go

@@ -1,126 +0,0 @@
-//go:build linux && cgo
-// +build linux,cgo
-
-package devicemapper // import "github.com/docker/docker/pkg/devicemapper"
-
-import "C"
-
-import (
-	"fmt"
-	"strings"
-
-	"github.com/sirupsen/logrus"
-)
-
-// DevmapperLogger defines methods required to register as a callback for
-// logging events received from devicemapper. Note that devicemapper will send
-// *all* logs regardless to callbacks (including debug logs) so it's
-// recommended to not spam the console with the outputs.
-type DevmapperLogger interface {
-	// DMLog is the logging callback containing all of the information from
-	// devicemapper. The interface is identical to the C libdm counterpart.
-	DMLog(level int, file string, line int, dmError int, message string)
-}
-
-// dmLogger is the current logger in use that is being forwarded our messages.
-var dmLogger DevmapperLogger
-
-// LogInit changes the logging callback called after processing libdm logs for
-// error message information. The default logger simply forwards all logs to
-// logrus. Calling LogInit(nil) disables the calling of callbacks.
-func LogInit(logger DevmapperLogger) {
-	dmLogger = logger
-}
-
-// Due to the way cgo works this has to be in a separate file, as devmapper.go has
-// definitions in the cgo block, which is incompatible with using "//export"
-
-// DevmapperLogCallback exports the devmapper log callback for cgo. Note that
-// because we are using callbacks, this function will be called for *every* log
-// in libdm (even debug ones because there's no way of setting the verbosity
-// level for an external logging callback).
-//
-//export DevmapperLogCallback
-func DevmapperLogCallback(level C.int, file *C.char, line, dmErrnoOrClass C.int, message *C.char) {
-	msg := C.GoString(message)
-
-	// Track what errno libdm saw, because the library only gives us 0 or 1.
-	if level < LogLevelDebug {
-		if strings.Contains(msg, "busy") {
-			dmSawBusy = true
-		}
-
-		if strings.Contains(msg, "File exists") {
-			dmSawExist = true
-		}
-
-		if strings.Contains(msg, "No such device or address") {
-			dmSawEnxio = true
-		}
-		if strings.Contains(msg, "No data available") {
-			dmSawEnoData = true
-		}
-	}
-
-	if dmLogger != nil {
-		dmLogger.DMLog(int(level), C.GoString(file), int(line), int(dmErrnoOrClass), msg)
-	}
-}
-
-// DefaultLogger is the default logger used by pkg/devicemapper. It forwards
-// all logs that are of higher or equal priority to the given level to the
-// corresponding logrus level.
-type DefaultLogger struct {
-	// Level corresponds to the highest libdm level that will be forwarded to
-	// logrus. In order to change this, register a new DefaultLogger.
-	Level int
-}
-
-// DMLog is the logging callback containing all of the information from
-// devicemapper. The interface is identical to the C libdm counterpart.
-func (l DefaultLogger) DMLog(level int, file string, line, dmError int, message string) {
-	if level <= l.Level {
-		// Forward the log to the correct logrus level, if allowed by dmLogLevel.
-		logMsg := fmt.Sprintf("libdevmapper(%d): %s:%d (%d) %s", level, file, line, dmError, message)
-		switch level {
-		case LogLevelFatal, LogLevelErr:
-			logrus.Error(logMsg)
-		case LogLevelWarn:
-			logrus.Warn(logMsg)
-		case LogLevelNotice, LogLevelInfo:
-			logrus.Info(logMsg)
-		case LogLevelDebug:
-			logrus.Debug(logMsg)
-		default:
-			// Don't drop any "unknown" levels.
-			logrus.Info(logMsg)
-		}
-	}
-}
-
-// registerLogCallback registers our own logging callback function for libdm
-// (which is DevmapperLogCallback).
-//
-// Because libdm only gives us {0,1} error codes we need to parse the logs
-// produced by libdm (to set dmSawBusy and so on). Note that by registering a
-// callback using DevmapperLogCallback, libdm will no longer output logs to
-// stderr so we have to log everything ourselves. None of this handling is
-// optional because we depend on log callbacks to parse the logs, and if we
-// don't forward the log information we'll be in a lot of trouble when
-// debugging things.
-func registerLogCallback() {
-	LogWithErrnoInit()
-}
-
-func init() {
-	// Use the default logger by default. We only allow LogLevelFatal by
-	// default, because internally we mask a lot of libdm errors by retrying
-	// and similar tricks. Also, libdm is very chatty and we don't want to
-	// worry users for no reason.
-	dmLogger = DefaultLogger{
-		Level: LogLevelFatal,
-	}
-
-	// Register as early as possible so we don't miss anything.
-	registerLogCallback()
-}

+ 0 - 246
pkg/devicemapper/devmapper_wrapper.go

@@ -1,246 +0,0 @@
-//go:build linux && cgo
-// +build linux,cgo
-
-package devicemapper // import "github.com/docker/docker/pkg/devicemapper"
-
-/*
-#define _GNU_SOURCE
-#include <libdevmapper.h>
-#include <linux/fs.h>   // FIXME: present only for BLKGETSIZE64, maybe we can remove it?
-
-// FIXME: Can't we find a way to do the logging in pure Go?
-extern void DevmapperLogCallback(int level, char *file, int line, int dm_errno_or_class, char *str);
-
-static void	log_cb(int level, const char *file, int line, int dm_errno_or_class, const char *f, ...)
-{
-	char *buffer = NULL;
-	va_list ap;
-	int ret;
-
-	va_start(ap, f);
-	ret = vasprintf(&buffer, f, ap);
-	va_end(ap);
-	if (ret < 0) {
-		// memory allocation failed -- should never happen?
-		return;
-	}
-
-	DevmapperLogCallback(level, (char *)file, line, dm_errno_or_class, buffer);
-	free(buffer);
-}
-
-static void	log_with_errno_init()
-{
-	dm_log_with_errno_init(log_cb);
-}
-*/
-import "C"
-
-import (
-	"reflect"
-	"unsafe"
-)
-
-type (
-	cdmTask C.struct_dm_task
-)
-
-// IOCTL consts
-const (
-	BlkGetSize64 = C.BLKGETSIZE64
-	BlkDiscard   = C.BLKDISCARD
-)
-
-// Devicemapper cookie flags.
-const (
-	DmUdevDisableSubsystemRulesFlag = C.DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG
-	DmUdevDisableDiskRulesFlag      = C.DM_UDEV_DISABLE_DISK_RULES_FLAG
-	DmUdevDisableOtherRulesFlag     = C.DM_UDEV_DISABLE_OTHER_RULES_FLAG
-	DmUdevDisableLibraryFallback    = C.DM_UDEV_DISABLE_LIBRARY_FALLBACK
-)
-
-// DeviceMapper mapped functions.
-var (
-	DmGetLibraryVersion       = dmGetLibraryVersionFct
-	DmGetNextTarget           = dmGetNextTargetFct
-	DmSetDevDir               = dmSetDevDirFct
-	DmTaskAddTarget           = dmTaskAddTargetFct
-	DmTaskCreate              = dmTaskCreateFct
-	DmTaskDestroy             = dmTaskDestroyFct
-	DmTaskGetDeps             = dmTaskGetDepsFct
-	DmTaskGetInfo             = dmTaskGetInfoFct
-	DmTaskGetDriverVersion    = dmTaskGetDriverVersionFct
-	DmTaskRun                 = dmTaskRunFct
-	DmTaskSetAddNode          = dmTaskSetAddNodeFct
-	DmTaskSetCookie           = dmTaskSetCookieFct
-	DmTaskSetMessage          = dmTaskSetMessageFct
-	DmTaskSetName             = dmTaskSetNameFct
-	DmTaskSetSector           = dmTaskSetSectorFct
-	DmUdevWait                = dmUdevWaitFct
-	DmUdevSetSyncSupport      = dmUdevSetSyncSupportFct
-	DmUdevGetSyncSupport      = dmUdevGetSyncSupportFct
-	DmCookieSupported         = dmCookieSupportedFct
-	LogWithErrnoInit          = logWithErrnoInitFct
-	DmTaskDeferredRemove      = dmTaskDeferredRemoveFct
-	DmTaskGetInfoWithDeferred = dmTaskGetInfoWithDeferredFct
-)
-
-func free(p *C.char) {
-	C.free(unsafe.Pointer(p))
-}
-
-func dmTaskDestroyFct(task *cdmTask) {
-	C.dm_task_destroy((*C.struct_dm_task)(task))
-}
-
-func dmTaskCreateFct(taskType int) *cdmTask {
-	return (*cdmTask)(C.dm_task_create(C.int(taskType)))
-}
-
-func dmTaskRunFct(task *cdmTask) int {
-	ret, _ := C.dm_task_run((*C.struct_dm_task)(task))
-	return int(ret)
-}
-
-func dmTaskSetNameFct(task *cdmTask, name string) int {
-	Cname := C.CString(name)
-	defer free(Cname)
-
-	return int(C.dm_task_set_name((*C.struct_dm_task)(task), Cname))
-}
-
-func dmTaskSetMessageFct(task *cdmTask, message string) int {
-	Cmessage := C.CString(message)
-	defer free(Cmessage)
-
-	return int(C.dm_task_set_message((*C.struct_dm_task)(task), Cmessage))
-}
-
-func dmTaskSetSectorFct(task *cdmTask, sector uint64) int {
-	return int(C.dm_task_set_sector((*C.struct_dm_task)(task), C.uint64_t(sector)))
-}
-
-func dmTaskSetCookieFct(task *cdmTask, cookie *uint, flags uint16) int {
-	cCookie := C.uint32_t(*cookie)
-	defer func() {
-		*cookie = uint(cCookie)
-	}()
-	return int(C.dm_task_set_cookie((*C.struct_dm_task)(task), &cCookie, C.uint16_t(flags)))
-}
-
-func dmTaskSetAddNodeFct(task *cdmTask, addNode AddNodeType) int {
-	return int(C.dm_task_set_add_node((*C.struct_dm_task)(task), C.dm_add_node_t(addNode)))
-}
-
-func dmTaskAddTargetFct(task *cdmTask, start, size uint64, ttype, params string) int {
-	Cttype := C.CString(ttype)
-	defer free(Cttype)
-
-	Cparams := C.CString(params)
-	defer free(Cparams)
-
-	return int(C.dm_task_add_target((*C.struct_dm_task)(task), C.uint64_t(start), C.uint64_t(size), Cttype, Cparams))
-}
-
-func dmTaskGetDepsFct(task *cdmTask) *Deps {
-	Cdeps := C.dm_task_get_deps((*C.struct_dm_task)(task))
-	if Cdeps == nil {
-		return nil
-	}
-
-	// golang issue: https://github.com/golang/go/issues/11925
-	var devices []C.uint64_t
-	devicesHdr := (*reflect.SliceHeader)(unsafe.Pointer(&devices))
-	devicesHdr.Data = uintptr(unsafe.Pointer(uintptr(unsafe.Pointer(Cdeps)) + unsafe.Sizeof(*Cdeps)))
-	devicesHdr.Len = int(Cdeps.count)
-	devicesHdr.Cap = int(Cdeps.count)
-
-	deps := &Deps{
-		Count:  uint32(Cdeps.count),
-		Filler: uint32(Cdeps.filler),
-	}
-	for _, device := range devices {
-		deps.Device = append(deps.Device, uint64(device))
-	}
-	return deps
-}
-
-func dmTaskGetInfoFct(task *cdmTask, info *Info) int {
-	Cinfo := C.struct_dm_info{}
-	defer func() {
-		info.Exists = int(Cinfo.exists)
-		info.Suspended = int(Cinfo.suspended)
-		info.LiveTable = int(Cinfo.live_table)
-		info.InactiveTable = int(Cinfo.inactive_table)
-		info.OpenCount = int32(Cinfo.open_count)
-		info.EventNr = uint32(Cinfo.event_nr)
-		info.Major = uint32(Cinfo.major)
-		info.Minor = uint32(Cinfo.minor)
-		info.ReadOnly = int(Cinfo.read_only)
-		info.TargetCount = int32(Cinfo.target_count)
-	}()
-	return int(C.dm_task_get_info((*C.struct_dm_task)(task), &Cinfo))
-}
-
-func dmTaskGetDriverVersionFct(task *cdmTask) string {
-	buffer := C.malloc(128)
-	defer C.free(buffer)
-	res := C.dm_task_get_driver_version((*C.struct_dm_task)(task), (*C.char)(buffer), 128)
-	if res == 0 {
-		return ""
-	}
-	return C.GoString((*C.char)(buffer))
-}
-
-func dmGetNextTargetFct(task *cdmTask, next unsafe.Pointer, start, length *uint64, target, params *string) unsafe.Pointer {
-	var (
-		Cstart, Clength      C.uint64_t
-		CtargetType, Cparams *C.char
-	)
-	defer func() {
-		*start = uint64(Cstart)
-		*length = uint64(Clength)
-		*target = C.GoString(CtargetType)
-		*params = C.GoString(Cparams)
-	}()
-
-	//lint:ignore SA4000 false positive on (identical expressions on the left and right side of the '==' operator) (staticcheck)
-	nextp := C.dm_get_next_target((*C.struct_dm_task)(task), next, &Cstart, &Clength, &CtargetType, &Cparams)
-	return nextp
-}
-
-func dmUdevSetSyncSupportFct(syncWithUdev int) {
-	C.dm_udev_set_sync_support(C.int(syncWithUdev))
-}
-
-func dmUdevGetSyncSupportFct() int {
-	return int(C.dm_udev_get_sync_support())
-}
-
-func dmUdevWaitFct(cookie uint) int {
-	return int(C.dm_udev_wait(C.uint32_t(cookie)))
-}
-
-func dmCookieSupportedFct() int {
-	return int(C.dm_cookie_supported())
-}
-
-func logWithErrnoInitFct() {
-	C.log_with_errno_init()
-}
-
-func dmSetDevDirFct(dir string) int {
-	Cdir := C.CString(dir)
-	defer free(Cdir)
-
-	return int(C.dm_set_dev_dir(Cdir))
-}
-
-func dmGetLibraryVersionFct(version *string) int {
-	buffer := C.CString(string(make([]byte, 128)))
-	defer free(buffer)
-	defer func() {
-		*version = C.GoString(buffer)
-	}()
-	return int(C.dm_get_library_version(buffer, 128))
-}

+ 0 - 7
pkg/devicemapper/devmapper_wrapper_dynamic.go

@@ -1,7 +0,0 @@
-//go:build linux && cgo && !static_build
-// +build linux,cgo,!static_build
-
-package devicemapper // import "github.com/docker/docker/pkg/devicemapper"
-
-// #cgo pkg-config: devmapper
-import "C"

+ 0 - 35
pkg/devicemapper/devmapper_wrapper_dynamic_deferred_remove.go

@@ -1,35 +0,0 @@
-//go:build linux && cgo && !static_build && !libdm_dlsym_deferred_remove && !libdm_no_deferred_remove
-// +build linux,cgo,!static_build,!libdm_dlsym_deferred_remove,!libdm_no_deferred_remove
-
-package devicemapper // import "github.com/docker/docker/pkg/devicemapper"
-
-/*
-#include <libdevmapper.h>
-*/
-import "C"
-
-// LibraryDeferredRemovalSupport tells if the feature is supported by the
-// current Docker invocation.
-const LibraryDeferredRemovalSupport = true
-
-func dmTaskDeferredRemoveFct(task *cdmTask) int {
-	return int(C.dm_task_deferred_remove((*C.struct_dm_task)(task)))
-}
-
-func dmTaskGetInfoWithDeferredFct(task *cdmTask, info *Info) int {
-	Cinfo := C.struct_dm_info{}
-	defer func() {
-		info.Exists = int(Cinfo.exists)
-		info.Suspended = int(Cinfo.suspended)
-		info.LiveTable = int(Cinfo.live_table)
-		info.InactiveTable = int(Cinfo.inactive_table)
-		info.OpenCount = int32(Cinfo.open_count)
-		info.EventNr = uint32(Cinfo.event_nr)
-		info.Major = uint32(Cinfo.major)
-		info.Minor = uint32(Cinfo.minor)
-		info.ReadOnly = int(Cinfo.read_only)
-		info.TargetCount = int32(Cinfo.target_count)
-		info.DeferredRemove = int(Cinfo.deferred_remove)
-	}()
-	return int(C.dm_task_get_info((*C.struct_dm_task)(task), &Cinfo))
-}

+ 0 - 128
pkg/devicemapper/devmapper_wrapper_dynamic_dlsym_deferred_remove.go

@@ -1,128 +0,0 @@
-//go:build linux && cgo && !static_build && libdm_dlsym_deferred_remove && !libdm_no_deferred_remove
-// +build linux,cgo,!static_build,libdm_dlsym_deferred_remove,!libdm_no_deferred_remove
-
-package devicemapper
-
-/*
-#cgo LDFLAGS: -ldl
-#include <stdlib.h>
-#include <dlfcn.h>
-#include <libdevmapper.h>
-
-// Yes, I know this looks scary. In order to be able to fill our own internal
-// dm_info with deferred_remove we need to have a struct definition that is
-// correct (regardless of the version of libdm that was used to compile it). To
-// this end, we define struct_backport_dm_info. This code comes from lvm2, and
-// I have verified that the structure has only ever had elements *appended* to
-// it (since 2001).
-//
-// It is also important that this structure be _larger_ than the dm_info that
-// libdevmapper expected. Otherwise libdm might try to write to memory it
-// shouldn't (they don't have a "known size" API).
-struct backport_dm_info {
-	int exists;
-	int suspended;
-	int live_table;
-	int inactive_table;
-	int32_t open_count;
-	uint32_t event_nr;
-	uint32_t major;
-	uint32_t minor;
-	int read_only;
-
-	int32_t target_count;
-
-	int deferred_remove;
-	int internal_suspend;
-
-	// Padding, purely for our own safety. This is to avoid cases where libdm
-	// was updated underneath us and we call into dm_task_get_info() with too
-	// small of a buffer.
-	char _[512];
-};
-
-// We have to wrap this in CGo, because Go really doesn't like function pointers.
-int call_dm_task_deferred_remove(void *fn, struct dm_task *task)
-{
-	int (*_dm_task_deferred_remove)(struct dm_task *task) = fn;
-	return _dm_task_deferred_remove(task);
-}
-*/
-import "C"
-
-import (
-	"unsafe"
-
-	"github.com/sirupsen/logrus"
-)
-
-// dm_task_deferred_remove is not supported by all distributions, due to
-// out-dated versions of devicemapper. However, in the case where the
-// devicemapper library was updated without rebuilding Docker (which can happen
-// in some distributions) then we should attempt to dynamically load the
-// relevant object rather than try to link to it.
-
-// dmTaskDeferredRemoveFct is a "bound" version of dm_task_deferred_remove.
-// It is nil if dm_task_deferred_remove was not found in the libdevmapper that
-// is currently loaded.
-var dmTaskDeferredRemovePtr unsafe.Pointer
-
-// LibraryDeferredRemovalSupport tells if the feature is supported by the
-// current Docker invocation. This value is fixed during init.
-var LibraryDeferredRemovalSupport bool
-
-func init() {
-	// Clear any errors.
-	var err *C.char
-	C.dlerror()
-
-	// The symbol we want to fetch.
-	symName := C.CString("dm_task_deferred_remove")
-	defer C.free(unsafe.Pointer(symName))
-
-	// See if we can find dm_task_deferred_remove. Since we already are linked
-	// to libdevmapper, we can search our own address space (rather than trying
-	// to guess what libdevmapper is called). We use NULL here, as RTLD_DEFAULT
-	// is not available in CGO (even if you set _GNU_SOURCE for some reason).
-	// The semantics are identical on glibc.
-	sym := C.dlsym(nil, symName)
-	err = C.dlerror()
-	if err != nil {
-		logrus.Debugf("devmapper: could not load dm_task_deferred_remove: %s", C.GoString(err))
-		return
-	}
-
-	logrus.Debugf("devmapper: found dm_task_deferred_remove at %x", uintptr(sym))
-	dmTaskDeferredRemovePtr = sym
-	LibraryDeferredRemovalSupport = true
-}
-
-func dmTaskDeferredRemoveFct(task *cdmTask) int {
-	sym := dmTaskDeferredRemovePtr
-	if sym == nil || !LibraryDeferredRemovalSupport {
-		return -1
-	}
-	return int(C.call_dm_task_deferred_remove(sym, (*C.struct_dm_task)(task)))
-}
-
-func dmTaskGetInfoWithDeferredFct(task *cdmTask, info *Info) int {
-	if !LibraryDeferredRemovalSupport {
-		return -1
-	}
-
-	Cinfo := C.struct_backport_dm_info{}
-	defer func() {
-		info.Exists = int(Cinfo.exists)
-		info.Suspended = int(Cinfo.suspended)
-		info.LiveTable = int(Cinfo.live_table)
-		info.InactiveTable = int(Cinfo.inactive_table)
-		info.OpenCount = int32(Cinfo.open_count)
-		info.EventNr = uint32(Cinfo.event_nr)
-		info.Major = uint32(Cinfo.major)
-		info.Minor = uint32(Cinfo.minor)
-		info.ReadOnly = int(Cinfo.read_only)
-		info.TargetCount = int32(Cinfo.target_count)
-		info.DeferredRemove = int(Cinfo.deferred_remove)
-	}()
-	return int(C.dm_task_get_info((*C.struct_dm_task)(task), (*C.struct_dm_info)(unsafe.Pointer(&Cinfo))))
-}

+ 0 - 17
pkg/devicemapper/devmapper_wrapper_no_deferred_remove.go

@@ -1,17 +0,0 @@
-//go:build linux && cgo && !libdm_dlsym_deferred_remove && libdm_no_deferred_remove
-// +build linux,cgo,!libdm_dlsym_deferred_remove,libdm_no_deferred_remove
-
-package devicemapper // import "github.com/docker/docker/pkg/devicemapper"
-
-// LibraryDeferredRemovalSupport tells if the feature is supported by the
-// current Docker invocation.
-const LibraryDeferredRemovalSupport = false
-
-func dmTaskDeferredRemoveFct(task *cdmTask) int {
-	// Error. Nobody should be calling it.
-	return -1
-}
-
-func dmTaskGetInfoWithDeferredFct(task *cdmTask, info *Info) int {
-	return -1
-}

+ 0 - 29
pkg/devicemapper/ioctl.go

@@ -1,29 +0,0 @@
-//go:build linux && cgo
-// +build linux,cgo
-
-package devicemapper // import "github.com/docker/docker/pkg/devicemapper"
-
-import (
-	"unsafe"
-
-	"golang.org/x/sys/unix"
-)
-
-func ioctlBlkGetSize64(fd uintptr) (int64, error) {
-	var size int64
-	if _, _, err := unix.Syscall(unix.SYS_IOCTL, fd, BlkGetSize64, uintptr(unsafe.Pointer(&size))); err != 0 {
-		return 0, err
-	}
-	return size, nil
-}
-
-func ioctlBlkDiscard(fd uintptr, offset, length uint64) error {
-	var r [2]uint64
-	r[0] = offset
-	r[1] = length
-
-	if _, _, err := unix.Syscall(unix.SYS_IOCTL, fd, BlkDiscard, uintptr(unsafe.Pointer(&r[0]))); err != 0 {
-		return err
-	}
-	return nil
-}

+ 0 - 11
pkg/devicemapper/log.go

@@ -1,11 +0,0 @@
-package devicemapper // import "github.com/docker/docker/pkg/devicemapper"
-
-// definitions from lvm2 lib/log/log.h
-const (
-	LogLevelFatal  = 2 + iota // _LOG_FATAL
-	LogLevelErr               // _LOG_ERR
-	LogLevelWarn              // _LOG_WARN
-	LogLevelNotice            // _LOG_NOTICE
-	LogLevelInfo              // _LOG_INFO
-	LogLevelDebug             // _LOG_DEBUG
-)

+ 0 - 1
project/ISSUE-TRIAGE.md

@@ -71,7 +71,6 @@ have:
 | area/security/trust       |
 | area/security/trust       |
 | area/storage              |
 | area/storage              |
 | area/storage/btrfs        |
 | area/storage/btrfs        |
-| area/storage/devicemapper |
 | area/storage/overlay      |
 | area/storage/overlay      |
 | area/storage/zfs          |
 | area/storage/zfs          |
 | area/swarm                |
 | area/swarm                |

+ 3 - 3
project/PACKAGERS.md

@@ -89,14 +89,14 @@ To disable btrfs:
 export DOCKER_BUILDTAGS='exclude_graphdriver_btrfs'
 export DOCKER_BUILDTAGS='exclude_graphdriver_btrfs'
 ```
 ```
 
 
-To disable devicemapper:
+To disable zfs:
 ```bash
 ```bash
-export DOCKER_BUILDTAGS='exclude_graphdriver_devicemapper'
+export DOCKER_BUILDTAGS='exclude_graphdriver_zfs'
 ```
 ```
 
 
 NOTE: if you need to set more than one build tag, space separate them:
 NOTE: if you need to set more than one build tag, space separate them:
 ```bash
 ```bash
-export DOCKER_BUILDTAGS='exclude_graphdriver_devicemapper exclude_graphdriver_btrfs'
+export DOCKER_BUILDTAGS='exclude_graphdriver_btrfs exclude_graphdriver_zfs'
 ```
 ```
 
 
 ## System Dependencies
 ## System Dependencies