devicemapper: Check loop devices of existing pool
| ... | ... |
@@ -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 {
|