Skip to content

Commit 055b44a

Browse files
refactor: use VHD header to fetch block size
Signed-off-by: Mathieu Labourier <mathieu.labourier@vates.tech>
1 parent 6950a5e commit 055b44a

9 files changed

Lines changed: 117 additions & 35 deletions

File tree

libs/sm/VDI.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ def __init__(self, sr, uuid):
101101
self.description = ''
102102
self.vbds = []
103103
self.size = 0
104+
self._block_size = -1
104105
self.utilisation = 0
105106
self.vdi_type = ''
106107
self.has_child = 0
@@ -120,6 +121,13 @@ def __init__(self, sr, uuid):
120121

121122
self.load(uuid)
122123

124+
@property
125+
def block_size(self):
126+
if self._block_size < 0:
127+
self._block_size = vhdutil.getBlockSize(self.path) if self.vdi_type == vhdutil.VDI_TYPE_VHD \
128+
else vhdutil.DEFAULT_VHD_BLOCK_SIZE
129+
return self._block_size
130+
123131
@staticmethod
124132
def from_uuid(session, vdi_uuid):
125133

libs/sm/cleanup.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -535,12 +535,20 @@ def __init__(self, sr, uuid, raw):
535535
self.sizeVirt = -1
536536
self._sizeVHD = -1
537537
self._sizeAllocated = -1
538+
self._block_size = -1
538539
self._hidden = False
539540
self.parent = None
540541
self.children = []
541542
self._vdiRef = None
542543
self._clearRef()
543544

545+
@property
546+
def block_size(self):
547+
if self._block_size < 0:
548+
self._block_size = vhdutil.DEFAULT_VHD_BLOCK_SIZE if self.raw \
549+
else vhdutil.getBlockSize(self.path)
550+
return self._block_size
551+
544552
@staticmethod
545553
def extractUuid(path):
546554
raise NotImplementedError("Implement in sub class")
@@ -1078,14 +1086,16 @@ def _getCoalescedSizeData(self):
10781086
blocksParent = self.parent.getVHDBlocks()
10791087
numBlocks = Util.countBits(blocksChild, blocksParent)
10801088
Util.log("Num combined blocks = %d" % numBlocks)
1081-
sizeData = numBlocks * vhdutil.VHD_BLOCK_SIZE
1089+
sizeData = numBlocks * self.block_size
10821090
assert(sizeData <= self.sizeVirt)
10831091
return sizeData
10841092

10851093
def _calcExtraSpaceForCoalescing(self):
10861094
sizeData = self._getCoalescedSizeData()
1087-
sizeCoalesced = sizeData + vhdutil.calcOverheadBitmap(sizeData) + \
1088-
vhdutil.calcOverheadEmpty(self.sizeVirt)
1095+
sizeCoalesced = sizeData + vhdutil.calcOverheadBitmap(
1096+
sizeData,
1097+
self.block_size
1098+
) + vhdutil.calcOverheadEmpty(self.sizeVirt)
10891099
Util.log("Coalesced size = %s" % Util.num2str(sizeCoalesced))
10901100
return sizeCoalesced - self.parent.getSizeVHD()
10911101

@@ -1241,7 +1251,7 @@ def deflate(self):
12411251
self._sizeAllocated = -1
12421252

12431253
def inflateFully(self):
1244-
self.inflate(lvhdutil.calcSizeVHDLV(self.sizeVirt))
1254+
self.inflate(lvhdutil.calcSizeVHDLV(self.sizeVirt, self.block_size))
12451255

12461256
def inflateParentForCoalesce(self):
12471257
"""Inflate the parent only as much as needed for the purposes of
@@ -1467,7 +1477,10 @@ def _queryVHDBlocks(self):
14671477
def _calcExtraSpaceForCoalescing(self):
14681478
if self.parent.raw:
14691479
return 0 # raw parents are never deflated in the first place
1470-
sizeCoalesced = lvhdutil.calcSizeVHDLV(self._getCoalescedSizeData())
1480+
sizeCoalesced = lvhdutil.calcSizeVHDLV(
1481+
self._getCoalescedSizeData(),
1482+
self.block_size
1483+
)
14711484
Util.log("Coalesced size = %s" % Util.num2str(sizeCoalesced))
14721485
return sizeCoalesced - self.parent.sizeLV
14731486

@@ -2809,7 +2822,7 @@ def _finishCoalesceLeaf(self, parent):
28092822
parent.deflate()
28102823

28112824
def _calcExtraSpaceNeeded(self, child, parent):
2812-
return lvhdutil.calcSizeVHDLV(parent.sizeVirt) - parent.sizeLV
2825+
return lvhdutil.calcSizeVHDLV(parent.sizeVirt, parent.block_size) - parent.sizeLV
28132826

28142827
def _handleInterruptedCoalesceLeaf(self):
28152828
entries = self.journaler.getAll(VDI.JRN_LEAF)

libs/sm/drivers/FileSR.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,7 @@ def resize(self, sr_uuid, vdi_uuid, size):
656656
return VDI.VDI.get_params(self)
657657

658658
# We already checked it is a VDI_TYPE_VHD
659-
size = vhdutil.validate_and_round_vhd_size(int(size))
659+
size = vhdutil.validate_and_round_vhd_size(int(size), self.block_size)
660660

661661
jFile = JOURNAL_FILE_PREFIX + self.uuid
662662
try:

libs/sm/drivers/LVHDSR.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,10 @@ def scan(self, uuid):
721721
util.roundup(lvutil.LVM_SIZE_INCREMENT,
722722
vhdutil.calcOverheadEmpty(lvhdutil.MSIZE))
723723
else:
724-
utilisation = lvhdutil.calcSizeVHDLV(int(size))
724+
utilisation = lvhdutil.calcSizeVHDLV(
725+
int(size),
726+
vhdutil.getBlockSize(lvPath)
727+
)
725728

726729
vdi_ref = self.session.xenapi.VDI.db_introduce(
727730
vdi_uuid,
@@ -989,7 +992,10 @@ def _undoCloneOp(self, lvs, origUuid, baseUuid, clonUuid):
989992

990993
# inflate the parent to fully-allocated size
991994
if base.vdiType == vhdutil.VDI_TYPE_VHD:
992-
fullSize = lvhdutil.calcSizeVHDLV(vhdInfo.sizeVirt)
995+
fullSize = lvhdutil.calcSizeVHDLV(
996+
vhdInfo.sizeVirt,
997+
vhdutil.getBlockSize(basePath)
998+
)
993999
lvhdutil.inflate(self.journaler, self.uuid, baseUuid, fullSize)
9941000

9951001
# rename back
@@ -1178,7 +1184,7 @@ def _undoAllVHDJournals(self):
11781184
util.SMlog("Found VHD journal %s, reverting %s" % (uuid, vdi.path))
11791185
self.lvActivator.activate(uuid, vdi.lvname, False)
11801186
self.lvmCache.activateNoRefcount(jlvName)
1181-
fullSize = lvhdutil.calcSizeVHDLV(vdi.size)
1187+
fullSize = lvhdutil.calcSizeVHDLV(vdi.size, vdi.block_size)
11821188
lvhdutil.inflate(self.journaler, self.uuid, vdi.uuid, fullSize)
11831189
try:
11841190
jFile = os.path.join(self.path, jlvName)
@@ -1189,7 +1195,7 @@ def _undoAllVHDJournals(self):
11891195
util.SMlog("VHD revert failed but VHD ok: removing journal")
11901196
# Attempt to reclaim unused space
11911197
vhdInfo = vhdutil.getVHDInfo(vdi.path, lvhdutil.extractUuid, False)
1192-
NewSize = lvhdutil.calcSizeVHDLV(vhdInfo.sizeVirt)
1198+
NewSize = lvhdutil.calcSizeVHDLV(vhdInfo.sizeVirt, vdi.block_size)
11931199
if NewSize < fullSize:
11941200
lvhdutil.deflate(self.lvmCache, vdi.lvname, int(NewSize))
11951201
lvhdutil.lvRefreshOnAllSlaves(self.session, self.uuid,
@@ -1444,7 +1450,10 @@ def attach(self, sr_uuid, vdi_uuid):
14441450
needInflate = False
14451451
else:
14461452
self._loadThis()
1447-
if self.utilisation >= lvhdutil.calcSizeVHDLV(self.size):
1453+
if (
1454+
self.utilisation >=
1455+
lvhdutil.calcSizeVHDLV(self.size, self.block_size)
1456+
):
14481457
needInflate = False
14491458

14501459
if needInflate:
@@ -1464,7 +1473,7 @@ def detach(self, sr_uuid, vdi_uuid):
14641473
util.SMlog("LVHDVDI.detach for %s" % self.uuid)
14651474
self._loadThis()
14661475
already_deflated = (self.utilisation < \
1467-
lvhdutil.calcSizeVHDLV(self.size))
1476+
lvhdutil.calcSizeVHDLV(self.size, self.block_size))
14681477
needDeflate = True
14691478
if self.vdi_type == vhdutil.VDI_TYPE_RAW or already_deflated:
14701479
needDeflate = False
@@ -1505,7 +1514,7 @@ def resize(self, sr_uuid, vdi_uuid, size):
15051514
'(current size: %d, new size: %d)' % (self.size, size))
15061515
raise xs_errors.XenError('VDISize', opterr='shrinking not allowed')
15071516

1508-
size = vhdutil.validate_and_round_vhd_size(int(size))
1517+
size = vhdutil.validate_and_round_vhd_size(int(size), self.block_size)
15091518

15101519
if size == self.size:
15111520
return VDI.VDI.get_params(self)
@@ -1515,7 +1524,7 @@ def resize(self, sr_uuid, vdi_uuid, size):
15151524
lvSizeNew = util.roundup(lvutil.LVM_SIZE_INCREMENT, size)
15161525
else:
15171526
lvSizeOld = self.utilisation
1518-
lvSizeNew = lvhdutil.calcSizeVHDLV(size)
1527+
lvSizeNew = lvhdutil.calcSizeVHDLV(size, self.block_size)
15191528
if self.sr.provision == "thin":
15201529
# VDI is currently deflated, so keep it deflated
15211530
lvSizeNew = lvSizeOld
@@ -1681,7 +1690,7 @@ def _snapshot(self, snapType, cloneOp=False, cbtlog=None, cbt_consistency=None):
16811690
self.issnap = self.session.xenapi.VDI.get_is_a_snapshot( \
16821691
self.sr.srcmd.params['vdi_ref'])
16831692

1684-
fullpr = lvhdutil.calcSizeVHDLV(self.size)
1693+
fullpr = lvhdutil.calcSizeVHDLV(self.size, self.block_size)
16851694
thinpr = util.roundup(lvutil.LVM_SIZE_INCREMENT, \
16861695
vhdutil.calcOverheadEmpty(lvhdutil.MSIZE))
16871696
lvSizeOrig = thinpr

libs/sm/lvhdutil.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,11 @@ def calcSizeLV(sizeVHD):
9595
return util.roundup(LVM_SIZE_INCREMENT, sizeVHD)
9696

9797

98-
def calcSizeVHDLV(sizeVirt):
98+
def calcSizeVHDLV(sizeVirt, block_size=vhdutil.DEFAULT_VHD_BLOCK_SIZE):
9999
# all LVHD VDIs have the metadata area preallocated for the maximum
100100
# possible virtual size (for fast online VDI.resize)
101101
metaOverhead = vhdutil.calcOverheadEmpty(MSIZE)
102-
bitmapOverhead = vhdutil.calcOverheadBitmap(sizeVirt)
102+
bitmapOverhead = vhdutil.calcOverheadBitmap(sizeVirt, block_size)
103103
return calcSizeLV(sizeVirt + metaOverhead + bitmapOverhead)
104104

105105

@@ -208,7 +208,12 @@ def setSizeVirt(journaler, srUuid, vdiUuid, size, jFile):
208208
lvName = LV_PREFIX[vhdutil.VDI_TYPE_VHD] + vdiUuid
209209
vgName = VG_PREFIX + srUuid
210210
path = os.path.join(VG_LOCATION, vgName, lvName)
211-
inflate(journaler, srUuid, vdiUuid, calcSizeVHDLV(size))
211+
inflate(
212+
journaler,
213+
srUuid,
214+
vdiUuid,
215+
calcSizeVHDLV(size, vhdutil.getBlockSize(path))
216+
)
212217
vhdutil.setSizeVirt(path, size, jFile)
213218

214219

@@ -233,7 +238,8 @@ def attachThin(journaler, srUuid, vdiUuid):
233238
_tryAcquire(lock)
234239
lvmCache.refresh()
235240
vhdInfo = vhdutil.getVHDInfoLVM(lvName, extractUuid, vgName)
236-
newSize = calcSizeVHDLV(vhdInfo.sizeVirt)
241+
path = os.path.join(VG_LOCATION, vgName, lvName)
242+
newSize = calcSizeVHDLV(vhdInfo.sizeVirt, vhdutil.getBlockSize(path))
237243
currSizeLV = lvmCache.getSize(lvName)
238244
if newSize <= currSizeLV:
239245
return

libs/sm/vhdutil.py

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
MAX_CHAIN_SIZE = 30 # max VHD parent chain size
3131
VHD_UTIL = "/usr/bin/vhd-util"
3232
OPT_LOG_ERR = "--debug"
33-
VHD_BLOCK_SIZE = 2 * 1024 * 1024
33+
DEFAULT_VHD_BLOCK_SIZE = 2 * 1024 * 1024
3434
VHD_FOOTER_SIZE = 512
3535

3636
# lock to lock the entire SR for short ops
@@ -82,9 +82,9 @@ def calcOverheadEmpty(virtual_size):
8282
return overhead
8383

8484

85-
def calcOverheadBitmap(virtual_size):
86-
num_blocks = virtual_size // VHD_BLOCK_SIZE
87-
if virtual_size % VHD_BLOCK_SIZE:
85+
def calcOverheadBitmap(virtual_size, block_size=DEFAULT_VHD_BLOCK_SIZE):
86+
num_blocks = virtual_size // block_size
87+
if virtual_size % block_size:
8888
num_blocks += 1
8989
return num_blocks * 4096
9090

@@ -93,10 +93,18 @@ def ioretry(cmd, text=True):
9393
return util.ioretry(lambda: util.pread2(cmd, text=text),
9494
errlist=[errno.EIO, errno.EAGAIN])
9595

96+
def getBlockSize(path):
97+
cmd = [VHD_UTIL, "read", "-pn", path]
98+
ret = ioretry(cmd)
99+
for field in ret.split('\n'):
100+
field = field.lstrip()
101+
if not field.startswith("Block size"): continue
102+
return int(field.split(':')[1].lstrip().split()[0])
103+
raise util.SMException("Unable to find block size in VHD with path: {}".format(path))
104+
96105

97-
def convertAllocatedSizeToBytes(size):
98-
# Assume we have standard 2MB allocation blocks
99-
return size * 2 * 1024 * 1024
106+
def convertAllocatedSizeToBytes(size, block_size=DEFAULT_VHD_BLOCK_SIZE):
107+
return size * block_size
100108

101109

102110
def getVHDInfo(path, extractUuidFunction, includeParent=True):
@@ -120,7 +128,10 @@ def getVHDInfo(path, extractUuidFunction, includeParent=True):
120128
vhdInfo.parentUuid = extractUuidFunction(fields[nextIndex])
121129
nextIndex += 1
122130
vhdInfo.hidden = int(fields[nextIndex].replace("hidden: ", ""))
123-
vhdInfo.sizeAllocated = convertAllocatedSizeToBytes(int(fields[nextIndex+1]))
131+
vhdInfo.sizeAllocated = convertAllocatedSizeToBytes(
132+
int(fields[nextIndex+1]),
133+
getBlockSize(path)
134+
)
124135
vhdInfo.path = path
125136
return vhdInfo
126137

@@ -279,7 +290,7 @@ def setSizePhys(path, size, debug=True):
279290
def getAllocatedSize(path):
280291
cmd = [VHD_UTIL, "query", OPT_LOG_ERR, '-a', '-n', path]
281292
ret = ioretry(cmd)
282-
return convertAllocatedSizeToBytes(int(ret))
293+
return convertAllocatedSizeToBytes(int(ret), getBlockSize(path))
283294

284295
def killData(path):
285296
"zero out the disk (kill all data inside the VHD file)"
@@ -406,7 +417,7 @@ def repair(path):
406417
ioretry([VHD_UTIL, 'repair', '-n', path])
407418

408419

409-
def validate_and_round_vhd_size(size):
420+
def validate_and_round_vhd_size(size, block_size=DEFAULT_VHD_BLOCK_SIZE):
410421
""" Take the supplied vhd size, in bytes, and check it is positive and less
411422
that the maximum supported size, rounding up to the next block boundary
412423
"""
@@ -419,7 +430,7 @@ def validate_and_round_vhd_size(size):
419430
if size < MIN_VHD_SIZE:
420431
size = MIN_VHD_SIZE
421432

422-
size = util.roundup(VHD_BLOCK_SIZE, size)
433+
size = util.roundup(block_size, size)
423434

424435
return size
425436

tests/test_FileSR.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ def test_create_vdi_vhd(self, mock_vhdutil):
327327
vdi = FakeFileVDI(sr, vdi_uuid)
328328
vdi.vdi_type = vhdutil.VDI_TYPE_VHD
329329
mock_vhdutil.validate_and_round_vhd_size.side_effect = vhdutil.validate_and_round_vhd_size
330+
mock_vhdutil.DEFAULT_VHD_BLOCK_SIZE = vhdutil.DEFAULT_VHD_BLOCK_SIZE
330331

331332
# Act
332333
vdi.create(sr_uuid, vdi_uuid, 20 * 1024 * 1024)

tests/test_LVHDSR.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,9 +324,11 @@ def test_snapshotof_success(self,
324324
mock_get_vg_stats = self.stubout('sm.drivers.LVHDSR.lvutil._getVGstats', autospec=True)
325325
mock_scsi_get_size = self.stubout('sm.drivers.LVHDSR.scsiutil.getsize', autospec=True)
326326
mock_vhdutil_getAllVHDs = self.stubout('sm.drivers.LVHDSR.vhdutil.getAllVHDs', autospec=True)
327+
mock_vhdutil_getBlockSize = self.stubout('sm.drivers.LVHDSR.vhdutil.getBlockSize', autospec=True)
327328
mock_sr_util_pathexists = self.stubout('sm.drivers.LVHDSR.util.pathexists', autospec=True)
328329
mock_sr_util_gen_uuid = self.stubout('sm.drivers.LVHDSR.util.gen_uuid', autospec=True)
329330
mock_cleanup.SR.TMP_RENAME_PREFIX = cleanup.SR.TMP_RENAME_PREFIX
331+
mock_vhdutil_getBlockSize.return_value = vhdutil.DEFAULT_VHD_BLOCK_SIZE
330332

331333
device_size = 100 * 1024 * 1024
332334
device_free = 10 * 1024 * 1024
@@ -515,9 +517,13 @@ def setUp(self):
515517
self.mock_lvhdutil.LV_PREFIX = lvhdutil.LV_PREFIX
516518
vhdutil_patcher = mock.patch('sm.drivers.LVHDSR.vhdutil', autospec=True)
517519
self.mock_vhdutil = vhdutil_patcher.start()
520+
self.mock_vhdutil.getBlockSize.return_value = vhdutil.DEFAULT_VHD_BLOCK_SIZE
518521
self.mock_vhdutil.VDI_TYPE_VHD = vhdutil.VDI_TYPE_VHD
519522
self.mock_vhdutil.VDI_TYPE_RAW = vhdutil.VDI_TYPE_RAW
520523
self.mock_vhdutil.MAX_CHAIN_SIZE = vhdutil.MAX_CHAIN_SIZE
524+
vdi_vhdutil_patcher = mock.patch('sm.VDI.vhdutil', autospec=True)
525+
self.mock_vdi_vhdutil = vdi_vhdutil_patcher.start()
526+
self.mock_vdi_vhdutil.getBlockSize.return_value = vhdutil.DEFAULT_VHD_BLOCK_SIZE
521527
lvutil_patcher = mock.patch('sm.drivers.LVHDSR.lvutil', autospec=True)
522528
self.mock_lvutil = lvutil_patcher.start()
523529
vdi_util_patcher = mock.patch('sm.VDI.util', autospec=True)

0 commit comments

Comments
 (0)