Browse code

devmapper: Keep track of used device Ids in a bitmap

Currently devicemapper backend does not keep track of used device Ids in
the pool. It tries a device Id and if that device Id exists in pool, it
tries with a different Id and keeps on doing this in a loop till it succeeds.

This worked fine so far but now we are moving to transaction based
device creation and deletion. We will keep deviceId information in
transaction which will be rolled back if docker crashed before transaction
was complete.

If we store a deviceId in transaction and later figure out it already
existed in pool and docker crashed, then we will rollback and remove
that existing device Id from pool (which we should not have).

That means, we should know free device Id in pool in advance before
we put that device Id in transaction.

Hence this patch creates a bitmap (one bit each for a deviceId), and
sets the bit if device Id is used otherwise resets it. This patch
is just preparing the ground right now. Actual usage will follow
in later patches.

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>

Vivek Goyal authored on 2014/12/04 03:06:43
Showing 1 changed files
... ...
@@ -30,7 +30,9 @@ var (
30 30
 	DefaultDataLoopbackSize     int64  = 100 * 1024 * 1024 * 1024
31 31
 	DefaultMetaDataLoopbackSize int64  = 2 * 1024 * 1024 * 1024
32 32
 	DefaultBaseFsSize           uint64 = 10 * 1024 * 1024 * 1024
33
-	DefaultThinpBlockSize       uint32 = 128 // 64K = 128 512b sectors
33
+	DefaultThinpBlockSize       uint32 = 128      // 64K = 128 512b sectors
34
+	MaxDeviceId                 int    = 0xffffff // 24 bit, pool limit
35
+	DeviceIdMapSz               int    = (MaxDeviceId + 1) / 8
34 36
 )
35 37
 
36 38
 const deviceSetMetaFile string = "deviceset-metadata"
... ...
@@ -75,6 +77,7 @@ type DeviceSet struct {
75 75
 	devicePrefix  string
76 76
 	TransactionId uint64 `json:"-"`
77 77
 	NextDeviceId  int    `json:"next_device_id"`
78
+	deviceIdMap   []byte
78 79
 
79 80
 	// Options
80 81
 	dataLoopbackSize     int64
... ...
@@ -261,6 +264,30 @@ func (devices *DeviceSet) saveMetadata(info *DevInfo) error {
261 261
 	return nil
262 262
 }
263 263
 
264
+func (devices *DeviceSet) markDeviceIdUsed(deviceId int) {
265
+	var mask byte
266
+	i := deviceId % 8
267
+	mask = 1 << uint(i)
268
+	devices.deviceIdMap[deviceId/8] = devices.deviceIdMap[deviceId/8] | mask
269
+}
270
+
271
+func (devices *DeviceSet) markDeviceIdFree(deviceId int) {
272
+	var mask byte
273
+	i := deviceId % 8
274
+	mask = ^(1 << uint(i))
275
+	devices.deviceIdMap[deviceId/8] = devices.deviceIdMap[deviceId/8] & mask
276
+}
277
+
278
+func (devices *DeviceSet) isDeviceIdFree(deviceId int) bool {
279
+	var mask byte
280
+	i := deviceId % 8
281
+	mask = (1 << uint(i))
282
+	if (devices.deviceIdMap[deviceId/8] & mask) != 0 {
283
+		return false
284
+	}
285
+	return true
286
+}
287
+
264 288
 func (devices *DeviceSet) lookupDevice(hash string) (*DevInfo, error) {
265 289
 	devices.devicesLock.Lock()
266 290
 	defer devices.devicesLock.Unlock()
... ...
@@ -407,7 +434,7 @@ func (devices *DeviceSet) initMetaData() error {
407 407
 
408 408
 func (devices *DeviceSet) incNextDeviceId() {
409 409
 	// Ids are 24bit, so wrap around
410
-	devices.NextDeviceId = (devices.NextDeviceId + 1) & 0xffffff
410
+	devices.NextDeviceId = (devices.NextDeviceId + 1) & MaxDeviceId
411 411
 }
412 412
 
413 413
 func (devices *DeviceSet) createDevice(deviceId *int) error {
... ...
@@ -1333,6 +1360,7 @@ func NewDeviceSet(root string, doInit bool, options []string) (*DeviceSet, error
1333 1333
 		filesystem:           "ext4",
1334 1334
 		doBlkDiscard:         true,
1335 1335
 		thinpBlockSize:       DefaultThinpBlockSize,
1336
+		deviceIdMap:          make([]byte, DeviceIdMapSz),
1336 1337
 	}
1337 1338
 
1338 1339
 	foundBlkDiscard := false