Merge pull request #14021 from rhvgoyal/detect-pool-loopback-devices

devicemapper: Check loop devices of existing pool
This commit is contained in:
Vincent Batts 2015-07-13 21:15:23 -04:00
Родитель 35b0223921 bebf534439
Коммит 5ca3e7c54c
2 изменённых файлов: 156 добавлений и 0 удалений

Просмотреть файл

@ -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 {