зеркало из https://github.com/microsoft/docker.git
Merge pull request #14021 from rhvgoyal/detect-pool-loopback-devices
devicemapper: Check loop devices of existing pool
This commit is contained in:
Коммит
5ca3e7c54c
|
@ -1089,6 +1089,126 @@ func determineDriverCapabilities(version string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Determine the major and minor number of loopback device
|
||||
func getDeviceMajorMinor(file *os.File) (uint64, uint64, error) {
|
||||
stat, err := file.Stat()
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
dev := stat.Sys().(*syscall.Stat_t).Rdev
|
||||
majorNum := major(dev)
|
||||
minorNum := minor(dev)
|
||||
|
||||
logrus.Debugf("[devmapper]: 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.Debugf("[devmapper]: Failed to open file %s", filename)
|
||||
return "", 0, 0, err
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
loopbackDevice := devicemapper.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.Debugf("[devmapper]: 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) initDevmapper(doInit bool) error {
|
||||
// give ourselves to libdm as a log handler
|
||||
devicemapper.LogInit(devices)
|
||||
|
@ -1233,6 +1353,17 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
|
|||
}
|
||||
}
|
||||
|
||||
// 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 info.Exists != 0 && devices.thinPoolDevice == "" {
|
||||
if err := devices.loadThinPoolLoopBackInfo(); err != nil {
|
||||
logrus.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 {
|
||||
|
|
|
@ -587,6 +587,31 @@ func GetStatus(name string) (uint64, uint64, string, string, error) {
|
|||
return start, length, targetType, params, nil
|
||||
}
|
||||
|
||||
func GetTable(name string) (uint64, uint64, string, string, error) {
|
||||
task, err := TaskCreateNamed(DeviceTable, name)
|
||||
if task == nil {
|
||||
logrus.Debugf("GetTable: Error TaskCreateNamed: %s", err)
|
||||
return 0, 0, "", "", err
|
||||
}
|
||||
if err := task.Run(); err != nil {
|
||||
logrus.Debugf("GetTable: Error Run: %s", err)
|
||||
return 0, 0, "", "", err
|
||||
}
|
||||
|
||||
devinfo, err := task.GetInfo()
|
||||
if err != nil {
|
||||
logrus.Debugf("GetTable: Error GetInfo: %s", err)
|
||||
return 0, 0, "", "", err
|
||||
}
|
||||
if devinfo.Exists == 0 {
|
||||
logrus.Debugf("GetTable: Non existing device %s", name)
|
||||
return 0, 0, "", "", fmt.Errorf("Non existing device %s", name)
|
||||
}
|
||||
|
||||
_, start, length, targetType, params := task.GetNextTarget(unsafe.Pointer(nil))
|
||||
return start, length, targetType, params, nil
|
||||
}
|
||||
|
||||
func SetTransactionId(poolName string, oldId uint64, newId uint64) error {
|
||||
task, err := TaskCreateNamed(DeviceTargetMsg, poolName)
|
||||
if task == nil {
|
||||
|
|
Загрузка…
Ссылка в новой задаче