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:
parent
807bc2cd04
commit
a226168a8b
2 changed files with 97 additions and 29 deletions
|
@ -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``
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue