Skip to content

Commit

Permalink
LVM COW in progress (to squash)
Browse files Browse the repository at this point in the history
  • Loading branch information
Wescoeur committed Jan 29, 2025
1 parent 5abfc7e commit 38b6b4e
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 28 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ install: build
ln -sf $$i"SR.py" $$i"SR"; \
done
rm $(SM_STAGING)$(SM_DEST)/SHMSR
cd $(SM_STAGING)$(SM_DEST) && rm -f LVMSR && ln -sf LVMSR.py LVHDSR
cd $(SM_STAGING)$(SM_DEST) && rm -f LVMSR && ln -sf LVMSR.py LVMSR
cd $(SM_STAGING)$(SM_DEST) && rm -f RawISCSISR && ln -sf RawISCSISR.py ISCSISR
cd $(SM_STAGING)$(SM_DEST) && rm -f LVMoISCSISR && ln -sf LVMoISCSISR.py LVMoISCSISR
cd $(SM_STAGING)$(SM_DEST) && rm -f LVMoHBASR && ln -sf LVMoHBASR.py LVMoHBASR
Expand Down
2 changes: 1 addition & 1 deletion drivers/FileSR.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def __init__(self, srcmd, sr_uuid):
# "super" sometimes failed due to circular imports
SR.SR.__init__(self, srcmd, sr_uuid)
self.image_info = {}
self.init_preferred_image_formats()
self._init_preferred_image_formats()
self._check_o_direct()

@override
Expand Down
53 changes: 35 additions & 18 deletions drivers/LVMSR.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
from refcounter import RefCounter
from ipc import IPCFlag
from constants import NS_PREFIX_LVM, VG_LOCATION, VG_PREFIX
from cowutil import getCowUtil
from cowutil import getCowUtil, getVdiTypeFromImageFormat
from lvmcowutil import LV_PREFIX, LvmCowUtil
from lvmanager import LVActivator
from vditype import VdiType
Expand Down Expand Up @@ -155,6 +155,10 @@ def handles(type) -> bool:
return type == "ext"
return type == LVMSR.DRIVER_TYPE

def __init__(self, srcmd, sr_uuid):
SR.SR.__init__(self, srcmd, sr_uuid)
self._init_preferred_image_formats()

@override
def load(self, sr_uuid) -> None:
self.ops_exclusive = OPS_EXCLUSIVE
Expand Down Expand Up @@ -594,7 +598,7 @@ def attach(self, uuid) -> None:
self.session, self.sr_ref,
scsiutil.devlist_to_serialstring(self.dconf['device'].split(',')))

# Test Legacy Mode Flag and update if VHD volumes exist
# Test Legacy Mode Flag and update if COW volumes exist
if self.isMaster and self.legacyMode:
vdiInfo = LvmCowUtil.getVDIInfo(self.lvmCache)
for uuid, info in vdiInfo.items():
Expand Down Expand Up @@ -735,7 +739,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[parent.find('-') + 1:]
size = cowutil.getSizeVirt(lvPath)
if self.provision == "thin":
utilisation = util.roundup(
Expand Down Expand Up @@ -1368,14 +1372,17 @@ 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"]

try:
self._setType(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')

if not self.vdi_type:
self._setType(getVdiTypeFromImageFormat(self.sr.preferred_image_formats[0]))

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 @@ -1514,7 +1521,7 @@ def attach(self, sr_uuid, vdi_uuid) -> str:

if needInflate:
try:
self._prepareThin(True)
self._prepareThin(True, self.vdi_type)
except:
util.logException("attach")
raise xs_errors.XenError('LVMProvisionAttach')
Expand All @@ -1530,7 +1537,7 @@ def detach(self, sr_uuid, vdi_uuid) -> None:
util.SMlog("LVMVDI.detach for %s" % self.uuid)
self._loadThis()
already_deflated = (self.utilisation < \
LvmCowUtil.calcVolumeSize(self.size))
self.lvmcowutil.calcVolumeSize(self.size))
needDeflate = True
if not VdiType.isCowImage(self.vdi_type) or already_deflated:
needDeflate = False
Expand All @@ -1545,7 +1552,7 @@ def detach(self, sr_uuid, vdi_uuid) -> None:

if needDeflate:
try:
self._prepareThin(False)
self._prepareThin(False, self.vdi_type)
except:
util.logException("_prepareThin")
raise xs_errors.XenError('VDIUnavailable', opterr='deflate')
Expand Down Expand Up @@ -1582,7 +1589,7 @@ def resize(self, sr_uuid, vdi_uuid, size) -> str:
lvSizeNew = util.roundup(lvutil.LVM_SIZE_INCREMENT, size)
else:
lvSizeOld = self.utilisation
lvSizeNew = LvmCowUtil.calcVolumeSize(size)
lvSizeNew = self.lvmcowutil.calcVolumeSize(size)
if self.sr.provision == "thin":
# VDI is currently deflated, so keep it deflated
lvSizeNew = lvSizeOld
Expand Down Expand Up @@ -1724,6 +1731,8 @@ def _snapshot(self, snapType, cloneOp=False, cbtlog=None, cbt_consistency=None):
if self.hidden:
raise xs_errors.XenError('VDISnapshot', opterr='hidden VDI')

snapVdiType = self.sr._get_snap_vdi_type(self.vdi_type, self.size)

self.sm_config = self.session.xenapi.VDI.get_sm_config( \
self.sr.srcmd.params['vdi_ref'])
if "type" in self.sm_config and self.sm_config['type'] == 'raw':
Expand Down Expand Up @@ -1815,11 +1824,11 @@ def _snapshot(self, snapType, cloneOp=False, cbtlog=None, cbt_consistency=None):
self.utilisation = lvSizeBase
util.fistpoint.activate("LVHDRT_clone_vdi_after_shrink_parent", self.sr.uuid)

snapVDI = self._createSnap(origUuid, lvSizeOrig, False)
snapVDI = self._createSnap(origUuid, snapVdiType, lvSizeOrig, False)
util.fistpoint.activate("LVHDRT_clone_vdi_after_first_snap", self.sr.uuid)
snapVDI2 = None
if snapType == VDI.SNAPSHOT_DOUBLE:
snapVDI2 = self._createSnap(clonUuid, lvSizeClon, True)
snapVDI2 = self._createSnap(clonUuid, snapVdiType, lvSizeClon, True)
# If we have CBT enabled on the VDI,
# set CBT status for the new snapshot disk
if cbtlog:
Expand Down Expand Up @@ -1867,9 +1876,10 @@ def _snapshot(self, snapType, cloneOp=False, cbtlog=None, cbt_consistency=None):

return self._finishSnapshot(snapVDI, snapVDI2, hostRefs, cloneOp, snapType)

def _createSnap(self, snapUuid, snapSizeLV, isNew):
def _createSnap(self, snapUuid, snapVdiType, snapSizeLV, isNew):
"""Snapshot self and return the snapshot VDI object"""
snapLV = LV_PREFIX[self.vdi_type] + snapUuid

snapLV = LV_PREFIX[snapVdiType] + 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)
Expand All @@ -1893,7 +1903,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"] = snapType
snapVDI.sm_config["vdi_type"] = snapVdiType
snapVDI.sm_config["vhd-parent"] = snapParent
snapVDI.lvname = snapLV
return snapVDI
Expand Down Expand Up @@ -2030,8 +2040,8 @@ def _finishSnapshot(self, snapVDI, snapVDI2, hostRefs, cloneOp=False, snapType=N
snap = snapVDI
return snap.get_params()

def _setType(self, vdiType) -> None:
self.vdi_type = vdiInfo.vdiType
def _setType(self, vdiType: str) -> None:
self.vdi_type = vdiType
self.cowutil = getCowUtil(self.vdi_type)
self.lvmcowutil = LvmCowUtil(self.cowutil)

Expand Down Expand Up @@ -2183,7 +2193,7 @@ def _markHidden(self):
self.cowutil.setHidden(self.path)
self.hidden = 1

def _prepareThin(self, attach):
def _prepareThin(self, attach, vdiType):
origUtilisation = self.sr.lvmCache.getSize(self.lvname)
if self.sr.isMaster:
# the master can prepare the VDI locally
Expand All @@ -2198,8 +2208,15 @@ def _prepareThin(self, attach):
pools = self.session.xenapi.pool.get_all()
master = self.session.xenapi.pool.get_master(pools[0])
rv = self.session.xenapi.host.call_plugin(
master, self.sr.THIN_PLUGIN, fn,
{"srUuid": self.sr.uuid, "vdiUuid": self.uuid})
master,
self.sr.THIN_PLUGIN,
fn,
{
"srUuid": self.sr.uuid,
"vdiUuid": self.uuid,
"vdiType": vdiType
}
)
util.SMlog("call-plugin returned: %s" % rv)
if not rv:
raise Exception('plugin %s failed' % self.sr.THIN_PLUGIN)
Expand Down
4 changes: 4 additions & 0 deletions drivers/LinstorSR.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,10 @@ class LinstorSR(SR.SR):
def handles(type) -> bool:
return type == LinstorSR.DRIVER_TYPE

def __init__(self, srcmd, sr_uuid):
SR.SR.__init__(self, srcmd, sr_uuid)
self._init_preferred_image_formats()

@override
def load(self, sr_uuid) -> None:
if not LINSTOR_AVAILABLE:
Expand Down
14 changes: 12 additions & 2 deletions drivers/SR.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
import os
import traceback

from cowutil import ImageFormat, parseImageFormats
from cowutil import ImageFormat, getCowUtilFromImageFormat, getVdiTypeFromImageFormat, parseImageFormats
from vditype import VdiType

MOUNT_BASE = '/var/run/sr-mount'
DEFAULT_TAP = "vhd,qcow2"
Expand Down Expand Up @@ -520,12 +521,21 @@ def check_dconf(self, key_list, raise_flag=True):

return missing_keys

def init_preferred_image_formats(self):
def _init_preferred_image_formats(self) -> None:
self.preferred_image_formats = parseImageFormats(
self.dconf and self.dconf.get('preferred-image-formats'),
DEFAULT_IMAGE_FORMATS
)

def _get_snap_vdi_type(self, vdi_type: str, size: int) -> str:
if VdiType.isCowImage(vdi_type):
return vdi_type
if vdi_type == VdiType.RAW:
for image_format in self.preferred_image_formats:
if getCowUtilFromImageFormat(image_format).canSnapshotRaw(size):
return getVdiTypeFromImageFormat(image_format)
raise xs_errors.XenError('VDISnapshot', opterr=f"cannot snap from `{vdi_type}`")

class ScanRecord:
def __init__(self, sr):
self.sr = sr
Expand Down
13 changes: 11 additions & 2 deletions drivers/cowutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,10 @@ def snapshot(
) -> None:
pass

@abstractmethod
def canSnapshotRaw(self, size: int) -> bool:
pass

@abstractmethod
def check(
self,
Expand Down Expand Up @@ -316,10 +320,15 @@ def getVdiTypeFromImageFormat(image_format: ImageFormat) -> str:

assert False, f"Unsupported image format: {IMAGE_FORMAT_TO_STR[image_format]}"

def getCowUtil(vdi_type: str) -> CowUtil:
# ------------------------------------------------------------------------------

def getCowUtilFromImageFormat(image_format: ImageFormat) -> CowUtil:
import vhdutil

if getImageFormatFromVdiType(vdi_type) in (ImageFormat.RAW, ImageFormat.VHD):
if image_format in (ImageFormat.RAW, ImageFormat.VHD):
return vhdutil.VhdUtil()

assert False, f"Unsupported VDI type: {vdi_type}"

def getCowUtil(vdi_type: str) -> CowUtil:
return getCowUtilFromImageFormat(getImageFormatFromVdiType(vdi_type))
10 changes: 6 additions & 4 deletions drivers/lvhd-thin
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,12 @@ def attach(session, args):
os.environ['LVM_SYSTEM_DIR'] = lvutil.MASTER_LVM_CONF
srUuid = args["srUuid"]
vdiUuid = args["vdiUuid"]
vgName = "%s%s" % (lvmcowutil.VG_PREFIX, srUuid)
vdiType = args["vdiType"]
vgName = "%s%s" % (VG_PREFIX, srUuid)
lvmCache = LVMCache(vgName)
journaler = Journaler(lvmCache)
try:
lvcowutil.attachThin(journaler, srUuid, vdiUuid, vdiType)
LvmCowUtil(getCowUtil(vdiType)).attachThin(journaler, srUuid, vdiUuid, vdiType)
return str(True)
except Exception as e:
util.logException("lvhd-thin:attach %s" % e)
Expand All @@ -50,10 +51,11 @@ def detach(session, args):
os.environ['LVM_SYSTEM_DIR'] = lvutil.MASTER_LVM_CONF
srUuid = args["srUuid"]
vdiUuid = args["vdiUuid"]
vgName = "%s%s" % (lvmcowutil.VG_PREFIX, srUuid)
vdiType = args["vdiType"]
vgName = "%s%s" % (VG_PREFIX, srUuid)
lvmCache = LVMCache(vgName)
try:
lvcowutil.detachThin(session, lvmCache, srUuid, vdiUuid, vdiType)
LvmCowUtil(getCowUtil(vdiType)).detachThin(session, lvmCache, srUuid, vdiUuid, vdiType)
return str(True)
except Exception as e:
util.logException("lvhd-thin:detach %s" % e)
Expand Down
4 changes: 4 additions & 0 deletions drivers/vhdutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,10 @@ def snapshot(
cmd.append("-e")
self._ioretry(cmd)

@override
def canSnapshotRaw(self, size: int) -> bool:
return size <= MAX_VHD_SIZE

@override
def check(
self,
Expand Down

0 comments on commit 38b6b4e

Please sign in to comment.