Bladeren bron

devmapper: Add options for specifying block devices

This adds dm.datadev and dm.metadatadev options that you can use with
--storage-opt to set to specific devices to use for the thin
provisioning pool.

Docker-DCO-1.1-Signed-off-by: Alexander Larsson <alexl@redhat.com> (github: alexlarsson)
Alexander Larsson 11 jaren geleden
bovenliggende
commit
a226168a8b
2 gewijzigde bestanden met toevoegingen van 97 en 29 verwijderingen
  1. 30 0
      daemon/graphdriver/devmapper/README.md
  2. 67 29
      daemon/graphdriver/devmapper/deviceset.go

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

@@ -95,3 +95,33 @@ Here is the list of supported options:
     Example use:
 
     ``docker -d --storage-opt dm.mountopt=nodiscard``
+
+ *  `dm.datadev`
+
+    Specifies a custom blockdevice to use for data for the thin pool.
+
+    If using a block device for device mapper storage, ideally both
+    datadev and metadatadev should be specified to completely avoid
+    using the loopback device.
+
+    Example use:
+
+    ``docker -d --storage-opt dm.datadev=/dev/sdb1 --storage-opt dm.metadatadev=/dev/sdc1``
+
+ *  `dm.metadatadev`
+
+    Specifies a custom blockdevice to use for metadata for the thin
+    pool.
+
+    For best performance the metadata should be on a different spindle
+    than the data, or even better on an SSD.
+
+    If setting up a new metadata pool it is required to be valid. This
+    can be achieved by zeroing the first 4k to indicate empty
+    metadata, like this:
+
+    ``dd if=/dev/zero of=$metadata_dev bs=4096 count=1```
+
+    Example use:
+
+    ``docker -d --storage-opt dm.datadev=/dev/sdb1 --storage-opt dm.metadatadev=/dev/sdc1``

+ 67 - 29
daemon/graphdriver/devmapper/deviceset.go

@@ -75,6 +75,8 @@ type DeviceSet struct {
 	filesystem           string
 	mountOptions         string
 	mkfsArgs             []string
+	dataDevice           string
+	metadataDevice       string
 }
 
 type DiskUsage struct {
@@ -581,42 +583,74 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
 	if info.Exists == 0 {
 		utils.Debugf("Pool doesn't exist. Creating it.")
 
-		hasData := devices.hasImage("data")
-		hasMetadata := devices.hasImage("metadata")
+		var (
+			dataFile     *os.File
+			metadataFile *os.File
+		)
 
-		if !doInit && !hasData {
-			return errors.New("Loopback data file not found")
-		}
+		if devices.dataDevice == "" {
+			// Make sure the sparse images exist in <root>/devicemapper/data
 
-		if !doInit && !hasMetadata {
-			return errors.New("Loopback metadata file not found")
-		}
+			hasData := devices.hasImage("data")
 
-		createdLoopback = !hasData || !hasMetadata
-		data, err := devices.ensureImage("data", devices.dataLoopbackSize)
-		if err != nil {
-			utils.Debugf("Error device ensureImage (data): %s\n", err)
-			return err
-		}
-		metadata, err := devices.ensureImage("metadata", devices.metaDataLoopbackSize)
-		if err != nil {
-			utils.Debugf("Error device ensureImage (metadata): %s\n", err)
-			return err
-		}
+			if !doInit && !hasData {
+				return errors.New("Loopback data file not found")
+			}
 
-		dataFile, err := attachLoopDevice(data)
-		if err != nil {
-			utils.Debugf("\n--->Err: %s\n", err)
-			return err
+			if !hasData {
+				createdLoopback = true
+			}
+
+			data, err := devices.ensureImage("data", devices.dataLoopbackSize)
+			if err != nil {
+				utils.Debugf("Error device ensureImage (data): %s\n", err)
+				return err
+			}
+
+			dataFile, err = attachLoopDevice(data)
+			if err != nil {
+				utils.Debugf("\n--->Err: %s\n", err)
+				return err
+			}
+			defer dataFile.Close()
+		} else {
+			dataFile, err = os.OpenFile(devices.dataDevice, os.O_RDWR, 0600)
+			if err != nil {
+				return err
+			}
 		}
-		defer dataFile.Close()
 
-		metadataFile, err := attachLoopDevice(metadata)
-		if err != nil {
-			utils.Debugf("\n--->Err: %s\n", err)
-			return err
+		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 {
+				utils.Debugf("Error device ensureImage (metadata): %s\n", err)
+				return err
+			}
+
+			metadataFile, err = attachLoopDevice(metadata)
+			if err != nil {
+				utils.Debugf("\n--->Err: %s\n", err)
+				return err
+			}
+			defer metadataFile.Close()
+		} else {
+			metadataFile, err = os.OpenFile(devices.metadataDevice, os.O_RDWR, 0600)
+			if err != nil {
+				return err
+			}
 		}
-		defer metadataFile.Close()
 
 		if err := createPool(devices.getPoolName(), dataFile, metadataFile); err != nil {
 			utils.Debugf("\n--->Err: %s\n", err)
@@ -1176,6 +1210,10 @@ func NewDeviceSet(root string, doInit bool, options []string) (*DeviceSet, error
 			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
 		default:
 			return nil, fmt.Errorf("Unknown option %s\n", key)
 		}