|
@@ -1081,6 +1081,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)
|
|
@@ -1225,6 +1345,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 {
|