Make devicemapper backend able to support multiple processes
| ... | ... |
@@ -11,7 +11,6 @@ import ( |
| 11 | 11 |
"path" |
| 12 | 12 |
"path/filepath" |
| 13 | 13 |
"strconv" |
| 14 |
- "strings" |
|
| 15 | 14 |
"sync" |
| 16 | 15 |
"syscall" |
| 17 | 16 |
"time" |
| ... | ... |
@@ -62,8 +61,7 @@ type DeviceSet struct {
|
| 62 | 62 |
devicePrefix string |
| 63 | 63 |
TransactionId uint64 |
| 64 | 64 |
NewTransactionId uint64 |
| 65 |
- nextFreeDevice int |
|
| 66 |
- sawBusy bool |
|
| 65 |
+ nextDeviceId int |
|
| 67 | 66 |
} |
| 68 | 67 |
|
| 69 | 68 |
type DiskUsage struct {
|
| ... | ... |
@@ -109,7 +107,19 @@ func (devices *DeviceSet) loopbackDir() string {
|
| 109 | 109 |
return path.Join(devices.root, "devicemapper") |
| 110 | 110 |
} |
| 111 | 111 |
|
| 112 |
-func (devices *DeviceSet) jsonFile() string {
|
|
| 112 |
+func (devices *DeviceSet) metadataDir() string {
|
|
| 113 |
+ return path.Join(devices.root, "metadata") |
|
| 114 |
+} |
|
| 115 |
+ |
|
| 116 |
+func (devices *DeviceSet) metadataFile(info *DevInfo) string {
|
|
| 117 |
+ file := info.Hash |
|
| 118 |
+ if file == "" {
|
|
| 119 |
+ file = "base" |
|
| 120 |
+ } |
|
| 121 |
+ return path.Join(devices.metadataDir(), file) |
|
| 122 |
+} |
|
| 123 |
+ |
|
| 124 |
+func (devices *DeviceSet) oldMetadataFile() string {
|
|
| 113 | 125 |
return path.Join(devices.loopbackDir(), "json") |
| 114 | 126 |
} |
| 115 | 127 |
|
| ... | ... |
@@ -159,26 +169,24 @@ func (devices *DeviceSet) ensureImage(name string, size int64) (string, error) {
|
| 159 | 159 |
return filename, nil |
| 160 | 160 |
} |
| 161 | 161 |
|
| 162 |
-func (devices *DeviceSet) allocateDeviceId() int {
|
|
| 163 |
- // TODO: Add smarter reuse of deleted devices |
|
| 164 |
- id := devices.nextFreeDevice |
|
| 165 |
- devices.nextFreeDevice = devices.nextFreeDevice + 1 |
|
| 166 |
- return id |
|
| 167 |
-} |
|
| 168 |
- |
|
| 169 | 162 |
func (devices *DeviceSet) allocateTransactionId() uint64 {
|
| 170 | 163 |
devices.NewTransactionId = devices.NewTransactionId + 1 |
| 171 | 164 |
return devices.NewTransactionId |
| 172 | 165 |
} |
| 173 | 166 |
|
| 174 |
-func (devices *DeviceSet) saveMetadata() error {
|
|
| 175 |
- devices.devicesLock.Lock() |
|
| 176 |
- jsonData, err := json.Marshal(devices.MetaData) |
|
| 177 |
- devices.devicesLock.Unlock() |
|
| 167 |
+func (devices *DeviceSet) removeMetadata(info *DevInfo) error {
|
|
| 168 |
+ if err := osRemoveAll(devices.metadataFile(info)); err != nil {
|
|
| 169 |
+ return fmt.Errorf("Error removing metadata file %s: %s", devices.metadataFile(info), err)
|
|
| 170 |
+ } |
|
| 171 |
+ return nil |
|
| 172 |
+} |
|
| 173 |
+ |
|
| 174 |
+func (devices *DeviceSet) saveMetadata(info *DevInfo) error {
|
|
| 175 |
+ jsonData, err := json.Marshal(info) |
|
| 178 | 176 |
if err != nil {
|
| 179 | 177 |
return fmt.Errorf("Error encoding metadata to json: %s", err)
|
| 180 | 178 |
} |
| 181 |
- tmpFile, err := ioutil.TempFile(filepath.Dir(devices.jsonFile()), ".json") |
|
| 179 |
+ tmpFile, err := ioutil.TempFile(devices.metadataDir(), ".tmp") |
|
| 182 | 180 |
if err != nil {
|
| 183 | 181 |
return fmt.Errorf("Error creating metadata file: %s", err)
|
| 184 | 182 |
} |
| ... | ... |
@@ -196,7 +204,7 @@ func (devices *DeviceSet) saveMetadata() error {
|
| 196 | 196 |
if err := tmpFile.Close(); err != nil {
|
| 197 | 197 |
return fmt.Errorf("Error closing metadata file %s: %s", tmpFile.Name(), err)
|
| 198 | 198 |
} |
| 199 |
- if err := osRename(tmpFile.Name(), devices.jsonFile()); err != nil {
|
|
| 199 |
+ if err := osRename(tmpFile.Name(), devices.metadataFile(info)); err != nil {
|
|
| 200 | 200 |
return fmt.Errorf("Error committing metadata file %s: %s", tmpFile.Name(), err)
|
| 201 | 201 |
} |
| 202 | 202 |
|
| ... | ... |
@@ -214,7 +222,12 @@ func (devices *DeviceSet) lookupDevice(hash string) (*DevInfo, error) {
|
| 214 | 214 |
defer devices.devicesLock.Unlock() |
| 215 | 215 |
info := devices.Devices[hash] |
| 216 | 216 |
if info == nil {
|
| 217 |
- return nil, fmt.Errorf("Unknown device %s", hash)
|
|
| 217 |
+ info = devices.loadMetadata(hash) |
|
| 218 |
+ if info == nil {
|
|
| 219 |
+ return nil, fmt.Errorf("Unknown device %s", hash)
|
|
| 220 |
+ } |
|
| 221 |
+ |
|
| 222 |
+ devices.Devices[hash] = info |
|
| 218 | 223 |
} |
| 219 | 224 |
return info, nil |
| 220 | 225 |
} |
| ... | ... |
@@ -234,7 +247,7 @@ func (devices *DeviceSet) registerDevice(id int, hash string, size uint64) (*Dev |
| 234 | 234 |
devices.Devices[hash] = info |
| 235 | 235 |
devices.devicesLock.Unlock() |
| 236 | 236 |
|
| 237 |
- if err := devices.saveMetadata(); err != nil {
|
|
| 237 |
+ if err := devices.saveMetadata(info); err != nil {
|
|
| 238 | 238 |
// Try to remove unused device |
| 239 | 239 |
devices.devicesLock.Lock() |
| 240 | 240 |
delete(devices.Devices, hash) |
| ... | ... |
@@ -269,9 +282,7 @@ func (devices *DeviceSet) createFilesystem(info *DevInfo) error {
|
| 269 | 269 |
return nil |
| 270 | 270 |
} |
| 271 | 271 |
|
| 272 |
-func (devices *DeviceSet) loadMetaData() error {
|
|
| 273 |
- utils.Debugf("loadMetadata()")
|
|
| 274 |
- defer utils.Debugf("loadMetadata END")
|
|
| 272 |
+func (devices *DeviceSet) initMetaData() error {
|
|
| 275 | 273 |
_, _, _, params, err := getStatus(devices.getPoolName()) |
| 276 | 274 |
if err != nil {
|
| 277 | 275 |
utils.Debugf("\n--->Err: %s\n", err)
|
| ... | ... |
@@ -284,39 +295,64 @@ func (devices *DeviceSet) loadMetaData() error {
|
| 284 | 284 |
} |
| 285 | 285 |
devices.NewTransactionId = devices.TransactionId |
| 286 | 286 |
|
| 287 |
- jsonData, err := ioutil.ReadFile(devices.jsonFile()) |
|
| 287 |
+ // Migrate old metadatafile |
|
| 288 |
+ |
|
| 289 |
+ jsonData, err := ioutil.ReadFile(devices.oldMetadataFile()) |
|
| 288 | 290 |
if err != nil && !osIsNotExist(err) {
|
| 289 | 291 |
utils.Debugf("\n--->Err: %s\n", err)
|
| 290 | 292 |
return err |
| 291 | 293 |
} |
| 292 | 294 |
|
| 293 |
- devices.MetaData.Devices = make(map[string]*DevInfo) |
|
| 294 | 295 |
if jsonData != nil {
|
| 295 |
- if err := json.Unmarshal(jsonData, &devices.MetaData); err != nil {
|
|
| 296 |
+ m := MetaData{Devices: make(map[string]*DevInfo)}
|
|
| 297 |
+ |
|
| 298 |
+ if err := json.Unmarshal(jsonData, &m); err != nil {
|
|
| 296 | 299 |
utils.Debugf("\n--->Err: %s\n", err)
|
| 297 | 300 |
return err |
| 298 | 301 |
} |
| 299 |
- } |
|
| 300 | 302 |
|
| 301 |
- for hash, d := range devices.Devices {
|
|
| 302 |
- d.Hash = hash |
|
| 303 |
- d.devices = devices |
|
| 303 |
+ for hash, info := range m.Devices {
|
|
| 304 |
+ info.Hash = hash |
|
| 304 | 305 |
|
| 305 |
- if d.DeviceId >= devices.nextFreeDevice {
|
|
| 306 |
- devices.nextFreeDevice = d.DeviceId + 1 |
|
| 306 |
+ // If the transaction id is larger than the actual one we lost the device due to some crash |
|
| 307 |
+ if info.TransactionId <= devices.TransactionId {
|
|
| 308 |
+ devices.saveMetadata(info) |
|
| 309 |
+ } |
|
| 307 | 310 |
} |
| 308 |
- |
|
| 309 |
- // If the transaction id is larger than the actual one we lost the device due to some crash |
|
| 310 |
- if d.TransactionId > devices.TransactionId {
|
|
| 311 |
- utils.Debugf("Removing lost device %s with id %d", hash, d.TransactionId)
|
|
| 312 |
- delete(devices.Devices, hash) |
|
| 311 |
+ if err := osRename(devices.oldMetadataFile(), devices.oldMetadataFile()+".migrated"); err != nil {
|
|
| 312 |
+ return err |
|
| 313 | 313 |
} |
| 314 |
+ |
|
| 314 | 315 |
} |
| 316 |
+ |
|
| 315 | 317 |
return nil |
| 316 | 318 |
} |
| 317 | 319 |
|
| 320 |
+func (devices *DeviceSet) loadMetadata(hash string) *DevInfo {
|
|
| 321 |
+ info := &DevInfo{Hash: hash, devices: devices}
|
|
| 322 |
+ |
|
| 323 |
+ jsonData, err := ioutil.ReadFile(devices.metadataFile(info)) |
|
| 324 |
+ if err != nil {
|
|
| 325 |
+ return nil |
|
| 326 |
+ } |
|
| 327 |
+ |
|
| 328 |
+ if err := json.Unmarshal(jsonData, &info); err != nil {
|
|
| 329 |
+ return nil |
|
| 330 |
+ } |
|
| 331 |
+ |
|
| 332 |
+ fmt.Printf("Loaded metadata %v\n", info)
|
|
| 333 |
+ |
|
| 334 |
+ // If the transaction id is larger than the actual one we lost the device due to some crash |
|
| 335 |
+ if info.TransactionId > devices.TransactionId {
|
|
| 336 |
+ return nil |
|
| 337 |
+ } |
|
| 338 |
+ |
|
| 339 |
+ return info |
|
| 340 |
+} |
|
| 341 |
+ |
|
| 318 | 342 |
func (devices *DeviceSet) setupBaseImage() error {
|
| 319 | 343 |
oldInfo, _ := devices.lookupDevice("")
|
| 344 |
+ utils.Debugf("oldInfo: %p", oldInfo)
|
|
| 320 | 345 |
if oldInfo != nil && oldInfo.Initialized {
|
| 321 | 346 |
return nil |
| 322 | 347 |
} |
| ... | ... |
@@ -331,14 +367,17 @@ func (devices *DeviceSet) setupBaseImage() error {
|
| 331 | 331 |
|
| 332 | 332 |
utils.Debugf("Initializing base device-manager snapshot")
|
| 333 | 333 |
|
| 334 |
- id := devices.allocateDeviceId() |
|
| 334 |
+ id := devices.nextDeviceId |
|
| 335 | 335 |
|
| 336 | 336 |
// Create initial device |
| 337 |
- if err := createDevice(devices.getPoolDevName(), id); err != nil {
|
|
| 337 |
+ if err := createDevice(devices.getPoolDevName(), &id); err != nil {
|
|
| 338 | 338 |
utils.Debugf("\n--->Err: %s\n", err)
|
| 339 | 339 |
return err |
| 340 | 340 |
} |
| 341 | 341 |
|
| 342 |
+ // Ids are 24bit, so wrap around |
|
| 343 |
+ devices.nextDeviceId = (id + 1) & 0xffffff |
|
| 344 |
+ |
|
| 342 | 345 |
utils.Debugf("Registering base device (id %v) with FS size %v", id, DefaultBaseFsSize)
|
| 343 | 346 |
info, err := devices.registerDevice(id, "", DefaultBaseFsSize) |
| 344 | 347 |
if err != nil {
|
| ... | ... |
@@ -360,7 +399,7 @@ func (devices *DeviceSet) setupBaseImage() error {
|
| 360 | 360 |
} |
| 361 | 361 |
|
| 362 | 362 |
info.Initialized = true |
| 363 |
- if err = devices.saveMetadata(); err != nil {
|
|
| 363 |
+ if err = devices.saveMetadata(info); err != nil {
|
|
| 364 | 364 |
info.Initialized = false |
| 365 | 365 |
utils.Debugf("\n--->Err: %s\n", err)
|
| 366 | 366 |
return err |
| ... | ... |
@@ -388,10 +427,6 @@ func (devices *DeviceSet) log(level int, file string, line int, dmError int, mes |
| 388 | 388 |
return // Ignore _LOG_DEBUG |
| 389 | 389 |
} |
| 390 | 390 |
|
| 391 |
- if strings.Contains(message, "busy") {
|
|
| 392 |
- devices.sawBusy = true |
|
| 393 |
- } |
|
| 394 |
- |
|
| 395 | 391 |
utils.Debugf("libdevmapper(%d): %s:%d (%d) %s", level, file, line, dmError, message)
|
| 396 | 392 |
} |
| 397 | 393 |
|
| ... | ... |
@@ -472,29 +507,7 @@ func (devices *DeviceSet) ResizePool(size int64) error {
|
| 472 | 472 |
func (devices *DeviceSet) initDevmapper(doInit bool) error {
|
| 473 | 473 |
logInit(devices) |
| 474 | 474 |
|
| 475 |
- // Make sure the sparse images exist in <root>/devicemapper/data and |
|
| 476 |
- // <root>/devicemapper/metadata |
|
| 477 |
- |
|
| 478 |
- hasData := devices.hasImage("data")
|
|
| 479 |
- hasMetadata := devices.hasImage("metadata")
|
|
| 480 |
- |
|
| 481 |
- if !doInit && !hasData {
|
|
| 482 |
- return errors.New("Loopback data file not found")
|
|
| 483 |
- } |
|
| 484 |
- |
|
| 485 |
- if !doInit && !hasMetadata {
|
|
| 486 |
- return errors.New("Loopback metadata file not found")
|
|
| 487 |
- } |
|
| 488 |
- |
|
| 489 |
- createdLoopback := !hasData || !hasMetadata |
|
| 490 |
- data, err := devices.ensureImage("data", DefaultDataLoopbackSize)
|
|
| 491 |
- if err != nil {
|
|
| 492 |
- utils.Debugf("Error device ensureImage (data): %s\n", err)
|
|
| 493 |
- return err |
|
| 494 |
- } |
|
| 495 |
- metadata, err := devices.ensureImage("metadata", DefaultMetaDataLoopbackSize)
|
|
| 496 |
- if err != nil {
|
|
| 497 |
- utils.Debugf("Error device ensureImage (metadata): %s\n", err)
|
|
| 475 |
+ if err := osMkdirAll(devices.metadataDir(), 0700); err != nil && !osIsExist(err) {
|
|
| 498 | 476 |
return err |
| 499 | 477 |
} |
| 500 | 478 |
|
| ... | ... |
@@ -527,10 +540,38 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
|
| 527 | 527 |
// so we add this badhack to make sure it closes itself |
| 528 | 528 |
setCloseOnExec("/dev/mapper/control")
|
| 529 | 529 |
|
| 530 |
+ // Make sure the sparse images exist in <root>/devicemapper/data and |
|
| 531 |
+ // <root>/devicemapper/metadata |
|
| 532 |
+ |
|
| 533 |
+ createdLoopback := false |
|
| 534 |
+ |
|
| 530 | 535 |
// If the pool doesn't exist, create it |
| 531 | 536 |
if info.Exists == 0 {
|
| 532 | 537 |
utils.Debugf("Pool doesn't exist. Creating it.")
|
| 533 | 538 |
|
| 539 |
+ hasData := devices.hasImage("data")
|
|
| 540 |
+ hasMetadata := devices.hasImage("metadata")
|
|
| 541 |
+ |
|
| 542 |
+ if !doInit && !hasData {
|
|
| 543 |
+ return errors.New("Loopback data file not found")
|
|
| 544 |
+ } |
|
| 545 |
+ |
|
| 546 |
+ if !doInit && !hasMetadata {
|
|
| 547 |
+ return errors.New("Loopback metadata file not found")
|
|
| 548 |
+ } |
|
| 549 |
+ |
|
| 550 |
+ createdLoopback = !hasData || !hasMetadata |
|
| 551 |
+ data, err := devices.ensureImage("data", DefaultDataLoopbackSize)
|
|
| 552 |
+ if err != nil {
|
|
| 553 |
+ utils.Debugf("Error device ensureImage (data): %s\n", err)
|
|
| 554 |
+ return err |
|
| 555 |
+ } |
|
| 556 |
+ metadata, err := devices.ensureImage("metadata", DefaultMetaDataLoopbackSize)
|
|
| 557 |
+ if err != nil {
|
|
| 558 |
+ utils.Debugf("Error device ensureImage (metadata): %s\n", err)
|
|
| 559 |
+ return err |
|
| 560 |
+ } |
|
| 561 |
+ |
|
| 534 | 562 |
dataFile, err := attachLoopDevice(data) |
| 535 | 563 |
if err != nil {
|
| 536 | 564 |
utils.Debugf("\n--->Err: %s\n", err)
|
| ... | ... |
@@ -552,9 +593,9 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
|
| 552 | 552 |
} |
| 553 | 553 |
|
| 554 | 554 |
// If we didn't just create the data or metadata image, we need to |
| 555 |
- // load the metadata from the existing file. |
|
| 555 |
+ // load the transaction id and migrate old metadata |
|
| 556 | 556 |
if !createdLoopback {
|
| 557 |
- if err = devices.loadMetaData(); err != nil {
|
|
| 557 |
+ if err = devices.initMetaData(); err != nil {
|
|
| 558 | 558 |
utils.Debugf("\n--->Err: %s\n", err)
|
| 559 | 559 |
return err |
| 560 | 560 |
} |
| ... | ... |
@@ -587,13 +628,16 @@ func (devices *DeviceSet) AddDevice(hash, baseHash string) error {
|
| 587 | 587 |
return fmt.Errorf("device %s already exists", hash)
|
| 588 | 588 |
} |
| 589 | 589 |
|
| 590 |
- deviceId := devices.allocateDeviceId() |
|
| 590 |
+ deviceId := devices.nextDeviceId |
|
| 591 | 591 |
|
| 592 |
- if err := devices.createSnapDevice(devices.getPoolDevName(), deviceId, baseInfo.Name(), baseInfo.DeviceId); err != nil {
|
|
| 592 |
+ if err := createSnapDevice(devices.getPoolDevName(), &deviceId, baseInfo.Name(), baseInfo.DeviceId); err != nil {
|
|
| 593 | 593 |
utils.Debugf("Error creating snap device: %s\n", err)
|
| 594 | 594 |
return err |
| 595 | 595 |
} |
| 596 | 596 |
|
| 597 |
+ // Ids are 24bit, so wrap around |
|
| 598 |
+ devices.nextDeviceId = (deviceId + 1) & 0xffffff |
|
| 599 |
+ |
|
| 597 | 600 |
if _, err := devices.registerDevice(deviceId, hash, baseInfo.Size); err != nil {
|
| 598 | 601 |
deleteDevice(devices.getPoolDevName(), deviceId) |
| 599 | 602 |
utils.Debugf("Error registering device: %s\n", err)
|
| ... | ... |
@@ -620,14 +664,6 @@ func (devices *DeviceSet) deleteDevice(info *DevInfo) error {
|
| 620 | 620 |
} |
| 621 | 621 |
} |
| 622 | 622 |
|
| 623 |
- if info.Initialized {
|
|
| 624 |
- info.Initialized = false |
|
| 625 |
- if err := devices.saveMetadata(); err != nil {
|
|
| 626 |
- utils.Debugf("Error saving meta data: %s\n", err)
|
|
| 627 |
- return err |
|
| 628 |
- } |
|
| 629 |
- } |
|
| 630 |
- |
|
| 631 | 623 |
if err := deleteDevice(devices.getPoolDevName(), info.DeviceId); err != nil {
|
| 632 | 624 |
utils.Debugf("Error deleting device: %s\n", err)
|
| 633 | 625 |
return err |
| ... | ... |
@@ -638,11 +674,11 @@ func (devices *DeviceSet) deleteDevice(info *DevInfo) error {
|
| 638 | 638 |
delete(devices.Devices, info.Hash) |
| 639 | 639 |
devices.devicesLock.Unlock() |
| 640 | 640 |
|
| 641 |
- if err := devices.saveMetadata(); err != nil {
|
|
| 641 |
+ if err := devices.removeMetadata(info); err != nil {
|
|
| 642 | 642 |
devices.devicesLock.Lock() |
| 643 | 643 |
devices.Devices[info.Hash] = info |
| 644 | 644 |
devices.devicesLock.Unlock() |
| 645 |
- utils.Debugf("Error saving meta data: %s\n", err)
|
|
| 645 |
+ utils.Debugf("Error removing meta data: %s\n", err)
|
|
| 646 | 646 |
return err |
| 647 | 647 |
} |
| 648 | 648 |
|
| ... | ... |
@@ -711,12 +747,11 @@ func (devices *DeviceSet) removeDeviceAndWait(devname string) error {
|
| 711 | 711 |
var err error |
| 712 | 712 |
|
| 713 | 713 |
for i := 0; i < 1000; i++ {
|
| 714 |
- devices.sawBusy = false |
|
| 715 | 714 |
err = removeDevice(devname) |
| 716 | 715 |
if err == nil {
|
| 717 | 716 |
break |
| 718 | 717 |
} |
| 719 |
- if !devices.sawBusy {
|
|
| 718 |
+ if err != ErrBusy {
|
|
| 720 | 719 |
return err |
| 721 | 720 |
} |
| 722 | 721 |
|
| ... | ... |
@@ -886,7 +921,7 @@ func (devices *DeviceSet) MountDevice(hash, path, mountLabel string) error {
|
| 886 | 886 |
info.mountCount = 1 |
| 887 | 887 |
info.mountPath = path |
| 888 | 888 |
|
| 889 |
- return devices.setInitialized(info) |
|
| 889 |
+ return nil |
|
| 890 | 890 |
} |
| 891 | 891 |
|
| 892 | 892 |
func (devices *DeviceSet) UnmountDevice(hash string) error {
|
| ... | ... |
@@ -937,14 +972,6 @@ func (devices *DeviceSet) HasDevice(hash string) bool {
|
| 937 | 937 |
return info != nil |
| 938 | 938 |
} |
| 939 | 939 |
|
| 940 |
-func (devices *DeviceSet) HasInitializedDevice(hash string) bool {
|
|
| 941 |
- devices.Lock() |
|
| 942 |
- defer devices.Unlock() |
|
| 943 |
- |
|
| 944 |
- info, _ := devices.lookupDevice(hash) |
|
| 945 |
- return info != nil && info.Initialized |
|
| 946 |
-} |
|
| 947 |
- |
|
| 948 | 940 |
func (devices *DeviceSet) HasActivatedDevice(hash string) bool {
|
| 949 | 941 |
info, _ := devices.lookupDevice(hash) |
| 950 | 942 |
if info == nil {
|
| ... | ... |
@@ -961,17 +988,6 @@ func (devices *DeviceSet) HasActivatedDevice(hash string) bool {
|
| 961 | 961 |
return devinfo != nil && devinfo.Exists != 0 |
| 962 | 962 |
} |
| 963 | 963 |
|
| 964 |
-func (devices *DeviceSet) setInitialized(info *DevInfo) error {
|
|
| 965 |
- info.Initialized = true |
|
| 966 |
- if err := devices.saveMetadata(); err != nil {
|
|
| 967 |
- info.Initialized = false |
|
| 968 |
- utils.Debugf("\n--->Err: %s\n", err)
|
|
| 969 |
- return err |
|
| 970 |
- } |
|
| 971 |
- |
|
| 972 |
- return nil |
|
| 973 |
-} |
|
| 974 |
- |
|
| 975 | 964 |
func (devices *DeviceSet) List() []string {
|
| 976 | 965 |
devices.Lock() |
| 977 | 966 |
defer devices.Unlock() |
| ... | ... |
@@ -62,6 +62,10 @@ var ( |
| 62 | 62 |
ErrInvalidAddNode = errors.New("Invalide AddNoce type")
|
| 63 | 63 |
ErrGetLoopbackBackingFile = errors.New("Unable to get loopback backing file")
|
| 64 | 64 |
ErrLoopbackSetCapacity = errors.New("Unable set loopback capacity")
|
| 65 |
+ ErrBusy = errors.New("Device is Busy")
|
|
| 66 |
+ |
|
| 67 |
+ dmSawBusy bool |
|
| 68 |
+ dmSawExist bool |
|
| 65 | 69 |
) |
| 66 | 70 |
|
| 67 | 71 |
type ( |
| ... | ... |
@@ -464,23 +468,33 @@ func resumeDevice(name string) error {
|
| 464 | 464 |
return nil |
| 465 | 465 |
} |
| 466 | 466 |
|
| 467 |
-func createDevice(poolName string, deviceId int) error {
|
|
| 468 |
- utils.Debugf("[devmapper] createDevice(poolName=%v, deviceId=%v)", poolName, deviceId)
|
|
| 469 |
- task, err := createTask(DeviceTargetMsg, poolName) |
|
| 470 |
- if task == nil {
|
|
| 471 |
- return err |
|
| 472 |
- } |
|
| 467 |
+func createDevice(poolName string, deviceId *int) error {
|
|
| 468 |
+ utils.Debugf("[devmapper] createDevice(poolName=%v, deviceId=%v)", poolName, *deviceId)
|
|
| 473 | 469 |
|
| 474 |
- if err := task.SetSector(0); err != nil {
|
|
| 475 |
- return fmt.Errorf("Can't set sector")
|
|
| 476 |
- } |
|
| 470 |
+ for {
|
|
| 471 |
+ task, err := createTask(DeviceTargetMsg, poolName) |
|
| 472 |
+ if task == nil {
|
|
| 473 |
+ return err |
|
| 474 |
+ } |
|
| 477 | 475 |
|
| 478 |
- if err := task.SetMessage(fmt.Sprintf("create_thin %d", deviceId)); err != nil {
|
|
| 479 |
- return fmt.Errorf("Can't set message")
|
|
| 480 |
- } |
|
| 476 |
+ if err := task.SetSector(0); err != nil {
|
|
| 477 |
+ return fmt.Errorf("Can't set sector")
|
|
| 478 |
+ } |
|
| 481 | 479 |
|
| 482 |
- if err := task.Run(); err != nil {
|
|
| 483 |
- return fmt.Errorf("Error running createDevice")
|
|
| 480 |
+ if err := task.SetMessage(fmt.Sprintf("create_thin %d", *deviceId)); err != nil {
|
|
| 481 |
+ return fmt.Errorf("Can't set message")
|
|
| 482 |
+ } |
|
| 483 |
+ |
|
| 484 |
+ dmSawExist = false |
|
| 485 |
+ if err := task.Run(); err != nil {
|
|
| 486 |
+ if dmSawExist {
|
|
| 487 |
+ // Already exists, try next id |
|
| 488 |
+ *deviceId++ |
|
| 489 |
+ continue |
|
| 490 |
+ } |
|
| 491 |
+ return fmt.Errorf("Error running createDevice")
|
|
| 492 |
+ } |
|
| 493 |
+ break |
|
| 484 | 494 |
} |
| 485 | 495 |
return nil |
| 486 | 496 |
} |
| ... | ... |
@@ -512,7 +526,11 @@ func removeDevice(name string) error {
|
| 512 | 512 |
if task == nil {
|
| 513 | 513 |
return err |
| 514 | 514 |
} |
| 515 |
+ dmSawBusy = false |
|
| 515 | 516 |
if err = task.Run(); err != nil {
|
| 517 |
+ if dmSawBusy {
|
|
| 518 |
+ return ErrBusy |
|
| 519 |
+ } |
|
| 516 | 520 |
return fmt.Errorf("Error running removeDevice")
|
| 517 | 521 |
} |
| 518 | 522 |
return nil |
| ... | ... |
@@ -546,7 +564,7 @@ func activateDevice(poolName string, name string, deviceId int, size uint64) err |
| 546 | 546 |
return nil |
| 547 | 547 |
} |
| 548 | 548 |
|
| 549 |
-func (devices *DeviceSet) createSnapDevice(poolName string, deviceId int, baseName string, baseDeviceId int) error {
|
|
| 549 |
+func createSnapDevice(poolName string, deviceId *int, baseName string, baseDeviceId int) error {
|
|
| 550 | 550 |
devinfo, _ := getInfo(baseName) |
| 551 | 551 |
doSuspend := devinfo != nil && devinfo.Exists != 0 |
| 552 | 552 |
|
| ... | ... |
@@ -556,33 +574,44 @@ func (devices *DeviceSet) createSnapDevice(poolName string, deviceId int, baseNa |
| 556 | 556 |
} |
| 557 | 557 |
} |
| 558 | 558 |
|
| 559 |
- task, err := createTask(DeviceTargetMsg, poolName) |
|
| 560 |
- if task == nil {
|
|
| 561 |
- if doSuspend {
|
|
| 562 |
- resumeDevice(baseName) |
|
| 559 |
+ for {
|
|
| 560 |
+ task, err := createTask(DeviceTargetMsg, poolName) |
|
| 561 |
+ if task == nil {
|
|
| 562 |
+ if doSuspend {
|
|
| 563 |
+ resumeDevice(baseName) |
|
| 564 |
+ } |
|
| 565 |
+ return err |
|
| 563 | 566 |
} |
| 564 |
- return err |
|
| 565 |
- } |
|
| 566 | 567 |
|
| 567 |
- if err := task.SetSector(0); err != nil {
|
|
| 568 |
- if doSuspend {
|
|
| 569 |
- resumeDevice(baseName) |
|
| 568 |
+ if err := task.SetSector(0); err != nil {
|
|
| 569 |
+ if doSuspend {
|
|
| 570 |
+ resumeDevice(baseName) |
|
| 571 |
+ } |
|
| 572 |
+ return fmt.Errorf("Can't set sector")
|
|
| 570 | 573 |
} |
| 571 |
- return fmt.Errorf("Can't set sector")
|
|
| 572 |
- } |
|
| 573 | 574 |
|
| 574 |
- if err := task.SetMessage(fmt.Sprintf("create_snap %d %d", deviceId, baseDeviceId)); err != nil {
|
|
| 575 |
- if doSuspend {
|
|
| 576 |
- resumeDevice(baseName) |
|
| 575 |
+ if err := task.SetMessage(fmt.Sprintf("create_snap %d %d", *deviceId, baseDeviceId)); err != nil {
|
|
| 576 |
+ if doSuspend {
|
|
| 577 |
+ resumeDevice(baseName) |
|
| 578 |
+ } |
|
| 579 |
+ return fmt.Errorf("Can't set message")
|
|
| 577 | 580 |
} |
| 578 |
- return fmt.Errorf("Can't set message")
|
|
| 579 |
- } |
|
| 580 | 581 |
|
| 581 |
- if err := task.Run(); err != nil {
|
|
| 582 |
- if doSuspend {
|
|
| 583 |
- resumeDevice(baseName) |
|
| 582 |
+ dmSawExist = false |
|
| 583 |
+ if err := task.Run(); err != nil {
|
|
| 584 |
+ if dmSawExist {
|
|
| 585 |
+ // Already exists, try next id |
|
| 586 |
+ *deviceId++ |
|
| 587 |
+ continue |
|
| 588 |
+ } |
|
| 589 |
+ |
|
| 590 |
+ if doSuspend {
|
|
| 591 |
+ resumeDevice(baseName) |
|
| 592 |
+ } |
|
| 593 |
+ return fmt.Errorf("Error running DeviceCreate (createSnapDevice)")
|
|
| 584 | 594 |
} |
| 585 |
- return fmt.Errorf("Error running DeviceCreate (createSnapDevice)")
|
|
| 595 |
+ |
|
| 596 |
+ break |
|
| 586 | 597 |
} |
| 587 | 598 |
|
| 588 | 599 |
if doSuspend {
|
| ... | ... |
@@ -4,12 +4,27 @@ package devmapper |
| 4 | 4 |
|
| 5 | 5 |
import "C" |
| 6 | 6 |
|
| 7 |
+import ( |
|
| 8 |
+ "strings" |
|
| 9 |
+) |
|
| 10 |
+ |
|
| 7 | 11 |
// Due to the way cgo works this has to be in a separate file, as devmapper.go has |
| 8 | 12 |
// definitions in the cgo block, which is incompatible with using "//export" |
| 9 | 13 |
|
| 10 | 14 |
//export DevmapperLogCallback |
| 11 | 15 |
func DevmapperLogCallback(level C.int, file *C.char, line C.int, dm_errno_or_class C.int, message *C.char) {
|
| 16 |
+ msg := C.GoString(message) |
|
| 17 |
+ if level < 7 {
|
|
| 18 |
+ if strings.Contains(msg, "busy") {
|
|
| 19 |
+ dmSawBusy = true |
|
| 20 |
+ } |
|
| 21 |
+ |
|
| 22 |
+ if strings.Contains(msg, "File exists") {
|
|
| 23 |
+ dmSawExist = true |
|
| 24 |
+ } |
|
| 25 |
+ } |
|
| 26 |
+ |
|
| 12 | 27 |
if dmLogger != nil {
|
| 13 |
- dmLogger.log(int(level), C.GoString(file), int(line), int(dm_errno_or_class), C.GoString(message)) |
|
| 28 |
+ dmLogger.log(int(level), C.GoString(file), int(line), int(dm_errno_or_class), msg) |
|
| 14 | 29 |
} |
| 15 | 30 |
} |
| ... | ... |
@@ -825,10 +825,6 @@ func TestGetReturnsValidDevice(t *testing.T) {
|
| 825 | 825 |
if !d.HasActivatedDevice("1") {
|
| 826 | 826 |
t.Fatalf("Expected id 1 to be activated")
|
| 827 | 827 |
} |
| 828 |
- |
|
| 829 |
- if !d.HasInitializedDevice("1") {
|
|
| 830 |
- t.Fatalf("Expected id 1 to be initialized")
|
|
| 831 |
- } |
|
| 832 | 828 |
} |
| 833 | 829 |
|
| 834 | 830 |
func TestDriverGetSize(t *testing.T) {
|