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)
This commit is contained in:
Alexander Larsson 2014-03-28 15:36:55 +01:00
parent 807bc2cd04
commit a226168a8b
2 changed files with 97 additions and 29 deletions

View file

@ -95,3 +95,33 @@ Here is the list of supported options:
Example use: Example use:
``docker -d --storage-opt dm.mountopt=nodiscard`` ``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``

View file

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