Skip to content

Commit

Permalink
lvm squash
Browse files Browse the repository at this point in the history
Signed-off-by: Ronan Abhamon <[email protected]>
  • Loading branch information
Wescoeur committed Jan 22, 2025
1 parent d0ad7fe commit 5f8eaba
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 60 deletions.
105 changes: 56 additions & 49 deletions drivers/LVMSR.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
from journaler import Journaler
from refcounter import RefCounter
from ipc import IPCFlag
from cowutil import getCowUtil
from lvmcowutil import LV_PREFIX, NS_PREFIX_LVM, VG_LOCATION, VG_PREFIX
from lvmanager import LVActivator
from vditype import VdiType
Expand Down Expand Up @@ -77,8 +78,11 @@
'configuration': CONFIGURATION
}

PARAM_VHD = "vhd"
PARAM_RAW = "raw"
CREATE_PARAM_TYPES = {
"raw": VdiType.RAW,
"vhd": VdiType.VHD,
"qcow2": VdiType.QCOW2
}

OPS_EXCLUSIVE = [
"sr_create", "sr_delete", "sr_attach", "sr_detach", "sr_scan",
Expand Down Expand Up @@ -729,8 +733,7 @@ def scan(self, uuid) -> None:
parent = cowutil.getParentNoCheck(lvPath)

if parent is not None:
sm_config['vhd-parent'] = parent[len( \
LV_PREFIX[VdiType.VHD]):]
sm_config['vhd-parent'] = parent[len(LV_PREFIX[VdiType.VHD]):]
size = cowutil.getSizeVirt(lvPath)
if self.provision == "thin":
utilisation = util.roundup(
Expand Down Expand Up @@ -1123,7 +1126,7 @@ def _completeCloneOp(self, vdis, origUuid, baseUuid, clonUuid):
base_vdi.utilisation = base.sizeLV
base_vdi.managed = False
base_vdi.sm_config = {
"vdi_type": VdiType.VHD,
"vdi_type": base.vdiType,
"vhd-parent": baseUuid}

if not self.legacyMode:
Expand Down Expand Up @@ -1154,14 +1157,14 @@ def _completeCloneOp(self, vdis, origUuid, baseUuid, clonUuid):
util.SMlog("*** INTERRUPTED CLONE OP: complete")

def _undoAllJournals(self):
"""Undo all VHD & SM interrupted journaled operations. This call must
"""Undo all COW image & SM interrupted journaled operations. This call must
be serialized with respect to all operations that create journals"""
# undoing interrupted inflates must be done first, since undoing VHD
# undoing interrupted inflates must be done first, since undoing COW images
# ops might require inflations
self.lock.acquire()
try:
self._undoAllInflateJournals()
self._undoAllVHDJournals()
self._undoAllCowJournals()
self._handleInterruptedCloneOps()
self._handleInterruptedCoalesceLeaf()
finally:
Expand Down Expand Up @@ -1195,33 +1198,37 @@ def _undoAllInflateJournals(self):
delattr(self, "vdiInfo")
delattr(self, "allVDIs")

def _undoAllVHDJournals(self):
"""check if there are VHD journals in existence and revert them"""
journals = lvhdutil.getAllVHDJournals(self.lvmCache)
def _undoAllCowJournals(self):
"""
Check if there are COW journals in existence and revert them.
"""
journals = LvmCowUtil.getAllResizeJournals(self.lvmCache)
if len(journals) == 0:
return
self._loadvdis()
# TODO
cowutil = None

for uuid, jlvName in journals:
vdi = self.vdis[uuid]
util.SMlog("Found VHD journal %s, reverting %s" % (uuid, vdi.path))
util.SMlog("Found COW journal %s, reverting %s" % (uuid, vdi.path))
cowutil = getCowUtil(vdi.vdi_type)
lvmcowutil = LvmCowUtil(cowutil)

self.lvActivator.activate(uuid, vdi.lvname, False)
self.lvmCache.activateNoRefcount(jlvName)
fullSize = lvmcowutil.calcVolumeSize(vdi.size)
lvmcowutil.inflate(self.journaler, self.uuid, vdi.uuid, fullSize)
lvmcowutil.inflate(self.journaler, self.uuid, vdi.uuid, vdi.vdi_type, fullSize)
try:
jFile = os.path.join(self.path, jlvName)
cowutil.revert(vdi.path, jFile)
except util.CommandException:
util.logException("VHD journal revert")
util.logException("COW journal revert")
cowutil.check(vdi.path)
util.SMlog("VHD revert failed but VHD ok: removing journal")
util.SMlog("COW image revert failed but COW image ok: removing journal")
# Attempt to reclaim unused space


vhdInfo = cowutil.getInfo(vdi.path, LvmCowUtil.extractUuid, False)
NewSize = lvmcowutil.calcVolumeSize(vhdInfo.sizeVirt)
imageInfo = cowutil.getInfo(vdi.path, LvmCowUtil.extractUuid, False)
NewSize = lvmcowutil.calcVolumeSize(imageInfo.sizeVirt)
if NewSize < fullSize:
lvmcowutil.deflate(self.lvmCache, vdi.lvname, int(NewSize))
LvmCowUtil.refreshVolumeOnAllSlaves(self.session, self.uuid, self.vgname, vdi.lvname, uuid)
Expand Down Expand Up @@ -1360,15 +1367,14 @@ def load(self, vdi_uuid) -> None:
if "vdi_sm_config" in self.sr.srcmd.params and \
"type" in self.sr.srcmd.params["vdi_sm_config"]:
type = self.sr.srcmd.params["vdi_sm_config"]["type"]
if type == PARAM_RAW:
self.vdi_type = VdiType.RAW
elif type == PARAM_VHD:
self.vdi_type = VdiType.VHD
if self.sr.cmd == 'vdi_create' and self.sr.legacyMode:
raise xs_errors.XenError('VDICreate', \
opterr='Cannot create VHD type disk in legacy mode')
else:

try:
self.vdi_type = CREATE_PARAM_TYPES[type]
except:
raise xs_errors.XenError('VDICreate', opterr='bad type')
if self.sr.legacyMode and self.sr.cmd == 'vdi_create' and VdiType.isCowImage(self.vdi_type):
raise xs_errors.XenError('VDICreate', opterr='Cannot create COW type disk in legacy mode')

self.lvname = "%s%s" % (LV_PREFIX[self.vdi_type], vdi_uuid)
self.path = os.path.join(self.sr.path, self.lvname)

Expand Down Expand Up @@ -1772,8 +1778,7 @@ def _snapshot(self, snapType, cloneOp=False, cbtlog=None, cbt_consistency=None):
size_req = lvSizeOrig + lvSizeClon + 2 * self.sr.journaler.LV_SIZE
lvSizeBase = self.size
if VdiType.isCowImage(self.vdi_type):
lvSizeBase = util.roundup(lvutil.LVM_SIZE_INCREMENT,
vhdutil.getSizePhys(self.path))
lvSizeBase = util.roundup(lvutil.LVM_SIZE_INCREMENT, self.cowutil.getSizePhys(self.path))
size_req -= (self.utilisation - lvSizeBase)
self.sr._ensureSpaceAvailable(size_req)

Expand Down Expand Up @@ -1865,16 +1870,16 @@ def _snapshot(self, snapType, cloneOp=False, cbtlog=None, cbt_consistency=None):

def _createSnap(self, snapUuid, snapSizeLV, isNew):
"""Snapshot self and return the snapshot VDI object"""
snapLV = LV_PREFIX[VdiType.VHD] + snapUuid
snapLV = LV_PREFIX[self.vdi_type] + snapUuid
snapPath = os.path.join(self.sr.path, snapLV)
self.sr.lvmCache.create(snapLV, int(snapSizeLV))
util.fistpoint.activate("LVHDRT_clone_vdi_after_lvcreate", self.sr.uuid)
if isNew:
RefCounter.set(snapUuid, 1, 0, NS_PREFIX_LVM + self.sr.uuid)
self.sr.lvActivator.add(snapUuid, snapLV, False)
parentRaw = (self.vdi_type == VdiType.RAW)
self._cowutil.snapshot(snapPath, self.path, parentRaw, cowutil.getPreallocationSizeVirt())
snapParent = self._cowutil.getParent(snapPath, LvmCowUtil.extractUuid)
self.cowutil.snapshot(snapPath, self.path, parentRaw, cowutil.getPreallocationSizeVirt())
snapParent = self.cowutil.getParent(snapPath, LvmCowUtil.extractUuid)

snapVDI = LVMVDI(self.sr, snapUuid)
snapVDI.read_only = False
Expand All @@ -1887,7 +1892,7 @@ def _createSnap(self, snapUuid, snapSizeLV, isNew):
"type", "vdi_type", "vhd-parent", "paused", "relinking", "activating"] and \
not key.startswith("host_"):
snapVDI.sm_config[key] = val
snapVDI.sm_config["vdi_type"] = VdiType.VHD
snapVDI.sm_config["vdi_type"] = snapType
snapVDI.sm_config["vhd-parent"] = snapParent
snapVDI.lvname = snapLV
return snapVDI
Expand Down Expand Up @@ -1919,7 +1924,7 @@ def _finishSnapshot(self, snapVDI, snapVDI2, hostRefs, cloneOp=False, snapType=N
# for leaf nodes). The normal refcount of the child is not
# transferred to to the base VDI because normal refcounts are
# incremented and decremented individually, and not based on the
# VHD chain (i.e., the child's normal refcount will be decremented
# image chain (i.e., the child's normal refcount will be decremented
# independently of its parent situation). Add 1 for this clone op.
# Note that we do not need to do protect the refcount operations
# below with per-VDI locking like we do in lvutil because at this
Expand Down Expand Up @@ -2018,7 +2023,7 @@ def _finishSnapshot(self, snapVDI, snapVDI2, hostRefs, cloneOp=False, snapType=N
if not basePresent:
# a single-snapshot of an empty VDI will be a noop, resulting
# in no new VDIs, so return the existing one. The GC wouldn't
# normally try to single-snapshot an empty VHD of course, but
# normally try to single-snapshot an empty image of course, but
# if an external snapshot operation manages to sneak in right
# before a snapshot-coalesce phase, we would get here
snap = snapVDI
Expand Down Expand Up @@ -2059,14 +2064,16 @@ def _initFromLVInfo(self, lvInfo):
if not VdiType.isCowImage(self.vdi_type):
self.loaded = True

def _initFromVHDInfo(self, vhdInfo):
self.size = vhdInfo.sizeVirt
self.parent = vhdInfo.parentUuid
self.hidden = vhdInfo.hidden
def _initFromImageInfo(self, imageInfo):
self.size = imageInfo.sizeVirt
self.parent = imageInfo.parentUuid
self.hidden = imageInfo.hidden
self.loaded = True

def _determineType(self):
"""Determine whether this is a raw or a VHD VDI"""
"""
Determine whether this is a RAW or a COW VDI.
"""
if "vdi_ref" in self.sr.srcmd.params:
vdi_ref = self.sr.srcmd.params["vdi_ref"]
sm_config = self.session.xenapi.VDI.get_sm_config(vdi_ref)
Expand Down Expand Up @@ -2107,8 +2114,10 @@ def _determineType(self):
return False

def _loadThis(self):
"""Load VDI info for this VDI and activate the LV if it's VHD. We
don't do it in VDI.load() because not all VDI operations need it."""
"""
Load VDI info for this VDI and activate the LV if it's COW. We
don't do it in VDI.load() because not all VDI operations need it.
"""
if self.loaded:
if VdiType.isCowImage(self.vdi_type):
self.sr.lvActivator.activate(self.uuid, self.lvname, False)
Expand All @@ -2123,11 +2132,10 @@ def _loadThis(self):
self._initFromLVInfo(lvs[self.uuid])
if VdiType.isCowImage(self.vdi_type):
self.sr.lvActivator.activate(self.uuid, self.lvname, False)
vhdInfo = self._cowutil.getInfo(self.path, LvmCowUtil.extractUuid, False)
if not vhdInfo:
raise xs_errors.XenError('VDIUnavailable', \
opterr='getVHDInfo failed')
self._initFromVHDInfo(vhdInfo)
imageInfo = self.cowutil.getInfo(self.path, LvmCowUtil.extractUuid, False)
if not imageInfo:
raise xs_errors.XenError('VDIUnavailable', opterr='getInfo failed')
self._initFromImageInfo(imageInfo)
self.loaded = True

def _chainSetActive(self, active, binary, persistent=False):
Expand All @@ -2139,8 +2147,7 @@ def _chainSetActive(self, active, binary, persistent=False):

vdiList = {self.uuid: self.lvname}
if VdiType.isCowImage(self.vdi_type):
vdiList = vhdutil.getParentChain(self.lvname,
LvmCowUtil.extractUuid, self.sr.vgname)
vdiList = self.cowutil.getParentChain(self.lvname, LvmCowUtil.extractUuid, self.sr.vgname)
for uuid, lvName in vdiList.items():
binaryParam = binary
if uuid != self.uuid:
Expand Down
8 changes: 4 additions & 4 deletions drivers/cleanup.py
Original file line number Diff line number Diff line change
Expand Up @@ -982,7 +982,7 @@ def _reloadChildren(self, vdiSkip):
child._reload()

def _reload(self):
"""Pause & unpause to cause blktap to reload the VHD metadata"""
"""Pause & unpause to cause blktap to reload the image metadata"""
for child in self.children:
child._reload()

Expand Down Expand Up @@ -1092,9 +1092,9 @@ def _queryVHDBlocks(self) -> bytes:
return self.cowutil.getBlockBitmap(self.path)

def _getCoalescedSizeData(self):
"""Get the data size of the resulting VHD if we coalesce self onto
parent. We calculate the actual size by using the VHD block allocation
information (as opposed to just adding up the two VHD sizes to get an
"""Get the data size of the resulting image if we coalesce self onto
parent. We calculate the actual size by using the image block allocation
information (as opposed to just adding up the two image sizes to get an
upper bound)"""
# make sure we don't use stale BAT info from vdi_rec since the child
# was writable all this time
Expand Down
6 changes: 4 additions & 2 deletions drivers/lcache.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import glob
from stat import * # S_ISBLK(), ...

from vditype import VdiType

SECTOR_SHIFT = 9


Expand All @@ -33,7 +35,7 @@ def __init__(self, tapdisk, stats):

@classmethod
def from_tapdisk(cls, tapdisk, stats):
# pick the last image. if it's a VHD, we got a parent
# pick the last image. if it's a COW, we got a parent
# cache. the leaf case is an aio node sitting on a
# parent-caching tapdev. always checking the complementary
# case, so we bail on unexpected chains.
Expand All @@ -47,7 +49,7 @@ def __assert(cond):
if not cond:
raise cls.NotACachingTapdisk(tapdisk, stats)

if _type == 'vhd':
if VdiType.isCowImage(_type):
# parent

return ParentCachingTap(tapdisk, stats)
Expand Down
11 changes: 6 additions & 5 deletions drivers/lvmcowutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,15 @@ def destroyResizeJournal(self, lvmCache: LVMCache, jName: str) -> None:
lvName = "%s_%s" % (self.JOURNAL_RESIZE_TAG, jName)
lvmCache.remove(lvName)

def getAllResizeJournals(self, lvmCache: LVMCache) -> List[Tuple[str, str]]:
@classmethod
def getAllResizeJournals(cls, lvmCache: LVMCache) -> List[Tuple[str, str]]:
"""
Get a list of all resize journals in VG vgName as (jName, sjFile) pairs.
"""
journals = []
lvList = lvmCache.getTagged(self.JOURNAL_RESIZE_TAG)
lvList = lvmCache.getTagged(cls.JOURNAL_RESIZE_TAG)
for lvName in lvList:
jName = lvName[len(self.JOURNAL_RESIZE_TAG) + 1:]
jName = lvName[len(cls.JOURNAL_RESIZE_TAG) + 1:]
journals.append((jName, lvName))
return journals

Expand Down Expand Up @@ -307,13 +308,13 @@ def getVDIInfo(cls, lvmCache: LVMCache) -> Dict[str, VDIInfo]:
if not scan_result.get(uuid):
lvmCache.refresh()
if lvmCache.checkLV(vdi.lvName):
util.SMlog("*** VHD info missing: %s" % uuid)
util.SMlog("*** COW image info missing: %s" % uuid)
vdis[uuid].scanError = True
else:
util.SMlog("LV disappeared since last scan: %s" % uuid)
del vdis[uuid]
elif scan_result[uuid].error:
util.SMlog("*** vhd-scan error: %s" % uuid)
util.SMlog("*** cow-scan error: %s" % uuid)
vdis[uuid].scanError = True
else:
vdis[uuid].sizeVirt = vdis[uuid].sizeVirt
Expand Down

0 comments on commit 5f8eaba

Please sign in to comment.