Browse code

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

devicemapper: Check loop devices of existing pool

Vincent Batts authored on 2015/07/14 10:15:23
Showing 2 changed files
... ...
@@ -1089,6 +1089,126 @@ func determineDriverCapabilities(version string) error {
1089 1089
 	return nil
1090 1090
 }
1091 1091
 
1092
+// Determine the major and minor number of loopback device
1093
+func getDeviceMajorMinor(file *os.File) (uint64, uint64, error) {
1094
+	stat, err := file.Stat()
1095
+	if err != nil {
1096
+		return 0, 0, err
1097
+	}
1098
+
1099
+	dev := stat.Sys().(*syscall.Stat_t).Rdev
1100
+	majorNum := major(dev)
1101
+	minorNum := minor(dev)
1102
+
1103
+	logrus.Debugf("[devmapper]: Major:Minor for device: %s is:%v:%v", file.Name(), majorNum, minorNum)
1104
+	return majorNum, minorNum, nil
1105
+}
1106
+
1107
+// Given a file which is backing file of a loop back device, find the
1108
+// loopback device name and its major/minor number.
1109
+func getLoopFileDeviceMajMin(filename string) (string, uint64, uint64, error) {
1110
+	file, err := os.Open(filename)
1111
+	if err != nil {
1112
+		logrus.Debugf("[devmapper]: Failed to open file %s", filename)
1113
+		return "", 0, 0, err
1114
+	}
1115
+
1116
+	defer file.Close()
1117
+	loopbackDevice := devicemapper.FindLoopDeviceFor(file)
1118
+	if loopbackDevice == nil {
1119
+		return "", 0, 0, fmt.Errorf("[devmapper]: Unable to find loopback mount for: %s", filename)
1120
+	}
1121
+	defer loopbackDevice.Close()
1122
+
1123
+	Major, Minor, err := getDeviceMajorMinor(loopbackDevice)
1124
+	if err != nil {
1125
+		return "", 0, 0, err
1126
+	}
1127
+	return loopbackDevice.Name(), Major, Minor, nil
1128
+}
1129
+
1130
+// Get the major/minor numbers of thin pool data and metadata devices
1131
+func (devices *DeviceSet) getThinPoolDataMetaMajMin() (uint64, uint64, uint64, uint64, error) {
1132
+	var params, poolDataMajMin, poolMetadataMajMin string
1133
+
1134
+	_, _, _, params, err := devicemapper.GetTable(devices.getPoolName())
1135
+	if err != nil {
1136
+		return 0, 0, 0, 0, err
1137
+	}
1138
+
1139
+	if _, err = fmt.Sscanf(params, "%s %s", &poolMetadataMajMin, &poolDataMajMin); err != nil {
1140
+		return 0, 0, 0, 0, err
1141
+	}
1142
+
1143
+	logrus.Debugf("[devmapper]: poolDataMajMin=%s poolMetaMajMin=%s\n", poolDataMajMin, poolMetadataMajMin)
1144
+
1145
+	poolDataMajMinorSplit := strings.Split(poolDataMajMin, ":")
1146
+	poolDataMajor, err := strconv.ParseUint(poolDataMajMinorSplit[0], 10, 32)
1147
+	if err != nil {
1148
+		return 0, 0, 0, 0, err
1149
+	}
1150
+
1151
+	poolDataMinor, err := strconv.ParseUint(poolDataMajMinorSplit[1], 10, 32)
1152
+	if err != nil {
1153
+		return 0, 0, 0, 0, err
1154
+	}
1155
+
1156
+	poolMetadataMajMinorSplit := strings.Split(poolMetadataMajMin, ":")
1157
+	poolMetadataMajor, err := strconv.ParseUint(poolMetadataMajMinorSplit[0], 10, 32)
1158
+	if err != nil {
1159
+		return 0, 0, 0, 0, err
1160
+	}
1161
+
1162
+	poolMetadataMinor, err := strconv.ParseUint(poolMetadataMajMinorSplit[1], 10, 32)
1163
+	if err != nil {
1164
+		return 0, 0, 0, 0, err
1165
+	}
1166
+
1167
+	return poolDataMajor, poolDataMinor, poolMetadataMajor, poolMetadataMinor, nil
1168
+}
1169
+
1170
+func (devices *DeviceSet) loadThinPoolLoopBackInfo() error {
1171
+	poolDataMajor, poolDataMinor, poolMetadataMajor, poolMetadataMinor, err := devices.getThinPoolDataMetaMajMin()
1172
+	if err != nil {
1173
+		return err
1174
+	}
1175
+
1176
+	dirname := devices.loopbackDir()
1177
+
1178
+	// data device has not been passed in. So there should be a data file
1179
+	// which is being mounted as loop device.
1180
+	if devices.dataDevice == "" {
1181
+		datafilename := path.Join(dirname, "data")
1182
+		dataLoopDevice, dataMajor, dataMinor, err := getLoopFileDeviceMajMin(datafilename)
1183
+		if err != nil {
1184
+			return err
1185
+		}
1186
+
1187
+		// Compare the two
1188
+		if poolDataMajor == dataMajor && poolDataMinor == dataMinor {
1189
+			devices.dataDevice = dataLoopDevice
1190
+			devices.dataLoopFile = datafilename
1191
+		}
1192
+
1193
+	}
1194
+
1195
+	// metadata device has not been passed in. So there should be a
1196
+	// metadata file which is being mounted as loop device.
1197
+	if devices.metadataDevice == "" {
1198
+		metadatafilename := path.Join(dirname, "metadata")
1199
+		metadataLoopDevice, metadataMajor, metadataMinor, err := getLoopFileDeviceMajMin(metadatafilename)
1200
+		if err != nil {
1201
+			return err
1202
+		}
1203
+		if poolMetadataMajor == metadataMajor && poolMetadataMinor == metadataMinor {
1204
+			devices.metadataDevice = metadataLoopDevice
1205
+			devices.metadataLoopFile = metadatafilename
1206
+		}
1207
+	}
1208
+
1209
+	return nil
1210
+}
1211
+
1092 1212
 func (devices *DeviceSet) initDevmapper(doInit bool) error {
1093 1213
 	// give ourselves to libdm as a log handler
1094 1214
 	devicemapper.LogInit(devices)
... ...
@@ -1233,6 +1353,17 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
1233 1233
 		}
1234 1234
 	}
1235 1235
 
1236
+	// Pool already exists and caller did not pass us a pool. That means
1237
+	// we probably created pool earlier and could not remove it as some
1238
+	// containers were still using it. Detect some of the properties of
1239
+	// pool, like is it using loop devices.
1240
+	if info.Exists != 0 && devices.thinPoolDevice == "" {
1241
+		if err := devices.loadThinPoolLoopBackInfo(); err != nil {
1242
+			logrus.Debugf("Failed to load thin pool loopback device information:%v", err)
1243
+			return err
1244
+		}
1245
+	}
1246
+
1236 1247
 	// If we didn't just create the data or metadata image, we need to
1237 1248
 	// load the transaction id and migrate old metadata
1238 1249
 	if !createdLoopback {
... ...
@@ -587,6 +587,31 @@ func GetStatus(name string) (uint64, uint64, string, string, error) {
587 587
 	return start, length, targetType, params, nil
588 588
 }
589 589
 
590
+func GetTable(name string) (uint64, uint64, string, string, error) {
591
+	task, err := TaskCreateNamed(DeviceTable, name)
592
+	if task == nil {
593
+		logrus.Debugf("GetTable: Error TaskCreateNamed: %s", err)
594
+		return 0, 0, "", "", err
595
+	}
596
+	if err := task.Run(); err != nil {
597
+		logrus.Debugf("GetTable: Error Run: %s", err)
598
+		return 0, 0, "", "", err
599
+	}
600
+
601
+	devinfo, err := task.GetInfo()
602
+	if err != nil {
603
+		logrus.Debugf("GetTable: Error GetInfo: %s", err)
604
+		return 0, 0, "", "", err
605
+	}
606
+	if devinfo.Exists == 0 {
607
+		logrus.Debugf("GetTable: Non existing device %s", name)
608
+		return 0, 0, "", "", fmt.Errorf("Non existing device %s", name)
609
+	}
610
+
611
+	_, start, length, targetType, params := task.GetNextTarget(unsafe.Pointer(nil))
612
+	return start, length, targetType, params, nil
613
+}
614
+
590 615
 func SetTransactionId(poolName string, oldId uint64, newId uint64) error {
591 616
 	task, err := TaskCreateNamed(DeviceTargetMsg, poolName)
592 617
 	if task == nil {