Browse code

devmapper: Simplify thin pool device id allocation

Instead of globally keeping track of the free device ids we just
start from 0 each run and handle EEXIST error and try the next one.

This way we don't need any global state for the device ids, which
means we can read device metadata lazily. This is important for
multi-process use of the backend.

Docker-DCO-1.1-Signed-off-by: Alexander Larsson <alexl@redhat.com> (github: alexlarsson)

Alexander Larsson authored on 2014/04/25 05:36:45
Showing 3 changed files
... ...
@@ -60,7 +60,7 @@ type DeviceSet struct {
60 60
 	devicePrefix     string
61 61
 	TransactionId    uint64
62 62
 	NewTransactionId uint64
63
-	nextFreeDevice   int
63
+	nextDeviceId     int
64 64
 }
65 65
 
66 66
 type DiskUsage struct {
... ...
@@ -156,13 +156,6 @@ func (devices *DeviceSet) ensureImage(name string, size int64) (string, error) {
156 156
 	return filename, nil
157 157
 }
158 158
 
159
-func (devices *DeviceSet) allocateDeviceId() int {
160
-	// TODO: Add smarter reuse of deleted devices
161
-	id := devices.nextFreeDevice
162
-	devices.nextFreeDevice = devices.nextFreeDevice + 1
163
-	return id
164
-}
165
-
166 159
 func (devices *DeviceSet) allocateTransactionId() uint64 {
167 160
 	devices.NewTransactionId = devices.NewTransactionId + 1
168 161
 	return devices.NewTransactionId
... ...
@@ -299,10 +292,6 @@ func (devices *DeviceSet) loadMetaData() error {
299 299
 		d.Hash = hash
300 300
 		d.devices = devices
301 301
 
302
-		if d.DeviceId >= devices.nextFreeDevice {
303
-			devices.nextFreeDevice = d.DeviceId + 1
304
-		}
305
-
306 302
 		// If the transaction id is larger than the actual one we lost the device due to some crash
307 303
 		if d.TransactionId > devices.TransactionId {
308 304
 			utils.Debugf("Removing lost device %s with id %d", hash, d.TransactionId)
... ...
@@ -328,14 +317,17 @@ func (devices *DeviceSet) setupBaseImage() error {
328 328
 
329 329
 	utils.Debugf("Initializing base device-manager snapshot")
330 330
 
331
-	id := devices.allocateDeviceId()
331
+	id := devices.nextDeviceId
332 332
 
333 333
 	// Create initial device
334
-	if err := createDevice(devices.getPoolDevName(), id); err != nil {
334
+	if err := createDevice(devices.getPoolDevName(), &id); err != nil {
335 335
 		utils.Debugf("\n--->Err: %s\n", err)
336 336
 		return err
337 337
 	}
338 338
 
339
+	// Ids are 24bit, so wrap around
340
+	devices.nextDeviceId = (id + 1) & 0xffffff
341
+
339 342
 	utils.Debugf("Registering base device (id %v) with FS size %v", id, DefaultBaseFsSize)
340 343
 	info, err := devices.registerDevice(id, "", DefaultBaseFsSize)
341 344
 	if err != nil {
... ...
@@ -580,13 +572,16 @@ func (devices *DeviceSet) AddDevice(hash, baseHash string) error {
580 580
 		return fmt.Errorf("device %s already exists", hash)
581 581
 	}
582 582
 
583
-	deviceId := devices.allocateDeviceId()
583
+	deviceId := devices.nextDeviceId
584 584
 
585
-	if err := createSnapDevice(devices.getPoolDevName(), deviceId, baseInfo.Name(), baseInfo.DeviceId); err != nil {
585
+	if err := createSnapDevice(devices.getPoolDevName(), &deviceId, baseInfo.Name(), baseInfo.DeviceId); err != nil {
586 586
 		utils.Debugf("Error creating snap device: %s\n", err)
587 587
 		return err
588 588
 	}
589 589
 
590
+	// Ids are 24bit, so wrap around
591
+	devices.nextDeviceId = (deviceId + 1) & 0xffffff
592
+
590 593
 	if _, err := devices.registerDevice(deviceId, hash, baseInfo.Size); err != nil {
591 594
 		deleteDevice(devices.getPoolDevName(), deviceId)
592 595
 		utils.Debugf("Error registering device: %s\n", err)
... ...
@@ -64,7 +64,8 @@ var (
64 64
 	ErrLoopbackSetCapacity    = errors.New("Unable set loopback capacity")
65 65
 	ErrBusy                   = errors.New("Device is Busy")
66 66
 
67
-	dmSawBusy bool
67
+	dmSawBusy  bool
68
+	dmSawExist bool
68 69
 )
69 70
 
70 71
 type (
... ...
@@ -467,23 +468,33 @@ func resumeDevice(name string) error {
467 467
 	return nil
468 468
 }
469 469
 
470
-func createDevice(poolName string, deviceId int) error {
471
-	utils.Debugf("[devmapper] createDevice(poolName=%v, deviceId=%v)", poolName, deviceId)
472
-	task, err := createTask(DeviceTargetMsg, poolName)
473
-	if task == nil {
474
-		return err
475
-	}
470
+func createDevice(poolName string, deviceId *int) error {
471
+	utils.Debugf("[devmapper] createDevice(poolName=%v, deviceId=%v)", poolName, *deviceId)
476 472
 
477
-	if err := task.SetSector(0); err != nil {
478
-		return fmt.Errorf("Can't set sector")
479
-	}
473
+	for {
474
+		task, err := createTask(DeviceTargetMsg, poolName)
475
+		if task == nil {
476
+			return err
477
+		}
480 478
 
481
-	if err := task.SetMessage(fmt.Sprintf("create_thin %d", deviceId)); err != nil {
482
-		return fmt.Errorf("Can't set message")
483
-	}
479
+		if err := task.SetSector(0); err != nil {
480
+			return fmt.Errorf("Can't set sector")
481
+		}
484 482
 
485
-	if err := task.Run(); err != nil {
486
-		return fmt.Errorf("Error running createDevice")
483
+		if err := task.SetMessage(fmt.Sprintf("create_thin %d", *deviceId)); err != nil {
484
+			return fmt.Errorf("Can't set message")
485
+		}
486
+
487
+		dmSawExist = false
488
+		if err := task.Run(); err != nil {
489
+			if dmSawExist {
490
+				// Already exists, try next id
491
+				*deviceId++
492
+				continue
493
+			}
494
+			return fmt.Errorf("Error running createDevice")
495
+		}
496
+		break
487 497
 	}
488 498
 	return nil
489 499
 }
... ...
@@ -553,7 +564,7 @@ func activateDevice(poolName string, name string, deviceId int, size uint64) err
553 553
 	return nil
554 554
 }
555 555
 
556
-func createSnapDevice(poolName string, deviceId int, baseName string, baseDeviceId int) error {
556
+func createSnapDevice(poolName string, deviceId *int, baseName string, baseDeviceId int) error {
557 557
 	devinfo, _ := getInfo(baseName)
558 558
 	doSuspend := devinfo != nil && devinfo.Exists != 0
559 559
 
... ...
@@ -563,33 +574,44 @@ func createSnapDevice(poolName string, deviceId int, baseName string, baseDevice
563 563
 		}
564 564
 	}
565 565
 
566
-	task, err := createTask(DeviceTargetMsg, poolName)
567
-	if task == nil {
568
-		if doSuspend {
569
-			resumeDevice(baseName)
566
+	for {
567
+		task, err := createTask(DeviceTargetMsg, poolName)
568
+		if task == nil {
569
+			if doSuspend {
570
+				resumeDevice(baseName)
571
+			}
572
+			return err
570 573
 		}
571
-		return err
572
-	}
573 574
 
574
-	if err := task.SetSector(0); err != nil {
575
-		if doSuspend {
576
-			resumeDevice(baseName)
575
+		if err := task.SetSector(0); err != nil {
576
+			if doSuspend {
577
+				resumeDevice(baseName)
578
+			}
579
+			return fmt.Errorf("Can't set sector")
577 580
 		}
578
-		return fmt.Errorf("Can't set sector")
579
-	}
580 581
 
581
-	if err := task.SetMessage(fmt.Sprintf("create_snap %d %d", deviceId, baseDeviceId)); err != nil {
582
-		if doSuspend {
583
-			resumeDevice(baseName)
582
+		if err := task.SetMessage(fmt.Sprintf("create_snap %d %d", *deviceId, baseDeviceId)); err != nil {
583
+			if doSuspend {
584
+				resumeDevice(baseName)
585
+			}
586
+			return fmt.Errorf("Can't set message")
584 587
 		}
585
-		return fmt.Errorf("Can't set message")
586
-	}
587 588
 
588
-	if err := task.Run(); err != nil {
589
-		if doSuspend {
590
-			resumeDevice(baseName)
589
+		dmSawExist = false
590
+		if err := task.Run(); err != nil {
591
+			if dmSawExist {
592
+				// Already exists, try next id
593
+				*deviceId++
594
+				continue
595
+			}
596
+
597
+			if doSuspend {
598
+				resumeDevice(baseName)
599
+			}
600
+			return fmt.Errorf("Error running DeviceCreate (createSnapDevice)")
591 601
 		}
592
-		return fmt.Errorf("Error running DeviceCreate (createSnapDevice)")
602
+
603
+		break
593 604
 	}
594 605
 
595 606
 	if doSuspend {
... ...
@@ -18,6 +18,10 @@ func DevmapperLogCallback(level C.int, file *C.char, line C.int, dm_errno_or_cla
18 18
 		if strings.Contains(msg, "busy") {
19 19
 			dmSawBusy = true
20 20
 		}
21
+
22
+		if strings.Contains(msg, "File exists") {
23
+			dmSawExist = true
24
+		}
21 25
 	}
22 26
 
23 27
 	if dmLogger != nil {