From f1404bd99c445bec1748f837b006beb3f4135cfb Mon Sep 17 00:00:00 2001 From: Antoine Bartuccio Date: Fri, 24 Oct 2025 09:39:23 +0200 Subject: [PATCH 1/2] fix(linstor): typo on resize for linstor raw VDI fix resize typo for linstor on raw VDI refactor linstor resize code Signed-off-by: Antoine Bartuccio --- drivers/LinstorSR.py | 52 +++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/drivers/LinstorSR.py b/drivers/LinstorSR.py index 28ca15729..6b40c2597 100755 --- a/drivers/LinstorSR.py +++ b/drivers/LinstorSR.py @@ -14,7 +14,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from sm_typing import Optional, override +from sm_typing import Optional, override, Tuple from constants import CBTLOG_TAG @@ -1907,7 +1907,30 @@ def detach(self, sr_uuid, vdi_uuid) -> None: vdi_uuid = parent_vdi_uuid @override - def resize(self, sr_uuid, vdi_uuid, size) -> str: + def resize(self, sr_uuid: str, vdi_uuid: str, size: int) -> str: + def compute_vdi_sizes(vdi: LinstorVDI) -> Tuple[int, int]: + if vdi.vdi_type == vhdutil.VDI_TYPE_RAW: + return vdi.size, LinstorVolumeManager.round_up_volume_size(size) + + old_volume_size = vdi.utilisation + if vdi.sr._provisioning == 'thin': + # VDI is currently deflated, so keep it deflated. + return old_volume_size, old_volume_size + + return old_volume_size, LinstorVhdUtil.compute_volume_size(size, vdi.vdi_type) + + def resize_vdi(vdi: LinstorVDI, old_volume_size: int, new_volume_size) -> None: + if vdi.vdi_type == vhdutil.VDI_TYPE_RAW: + vdi._linstor.resize_volume(vdi.uuid, new_volume_size) + return + + if new_volume_size != old_volume_size: + vdi.sr._vhdutil.inflate( + vdi.sr._journaler, vdi.uuid, vdi.path, + new_volume_size, old_volume_size + ) + vdi.sr._vhdutil.set_size_virt_fast(vdi.path, size) + util.SMlog('LinstorVDI.resize for {}'.format(self.uuid)) if not self.sr.is_master(): raise xs_errors.XenError( @@ -1934,37 +1957,22 @@ def resize(self, sr_uuid, vdi_uuid, size) -> str: raise xs_errors.XenError('VDISize', opterr='shrinking not allowed') if size == self.size: - return VDI.VDI.get_params(self) + return VDI.VDI.get_params(self) # No change needed - if self.vdi_type == vhdutil.VDI_TYPE_RAW: - old_volume_size = self.size - new_volume_size = LinstorVolumeManager.round_up_volume_size(size) - else: - old_volume_size = self.utilisation - if self.sr._provisioning == 'thin': - # VDI is currently deflated, so keep it deflated. - new_volume_size = old_volume_size - else: - new_volume_size = LinstorVhdUtil.compute_volume_size(size, self.vdi_type) + old_volume_size, new_volume_size = compute_vdi_sizes(self) assert new_volume_size >= old_volume_size space_needed = new_volume_size - old_volume_size self.sr._ensure_space_available(space_needed) old_size = self.size - if self.vdi_type == vhdutil.VDI_TYPE_RAW: - self._linstor.resize(self.uuid, new_volume_size) - else: - if new_volume_size != old_volume_size: - self.sr._vhdutil.inflate( - self.sr._journaler, self.uuid, self.path, - new_volume_size, old_volume_size - ) - self.sr._vhdutil.set_size_virt_fast(self.path, size) + + resize_vdi(self, old_volume_size, new_volume_size) # Reload size attributes. self._load_this() + # Update metadata vdi_ref = self.sr.srcmd.params['vdi_ref'] self.session.xenapi.VDI.set_virtual_size(vdi_ref, str(self.size)) self.session.xenapi.VDI.set_physical_utilisation( From 545ac97d5169183bc3a5a5af3cf562a2163da34e Mon Sep 17 00:00:00 2001 From: Antoine Bartuccio Date: Mon, 27 Oct 2025 10:16:20 +0100 Subject: [PATCH 2/2] fix(linstor): ensure that drbd is synced up before resizing Avoid most common drbd sync errors during resize with a cleaner wait mechanism and friendly user error Signed-off-by: Antoine Bartuccio --- drivers/linstorvolumemanager.py | 44 ++++++++++++++++----------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/linstorvolumemanager.py b/drivers/linstorvolumemanager.py index eea5c3679..65826d228 100755 --- a/drivers/linstorvolumemanager.py +++ b/drivers/linstorvolumemanager.py @@ -841,31 +841,31 @@ def resize_volume(self, volume_uuid, new_size): self.ensure_volume_is_not_locked(volume_uuid) new_size = self.round_up_volume_size(new_size) // 1024 - retry_count = 30 - while True: - result = self._linstor.volume_dfn_modify( - rsc_name=volume_name, - volume_nr=0, - size=new_size - ) - - self._mark_resource_cache_as_dirty() - - error_str = self._get_error_str(result) - if not error_str: - break + # We can't resize anything until DRBD is up to date + # We wait here for 5min max and raise an easy to understand error for the user + # This is mostly an issue for thick provisioning, thin isn't affected + start_time = time.monotonic() + try: + self._linstor.resource_dfn_wait_synced(volume_name, wait_interval=1.0, timeout=60*5) + except linstor.LinstorTimeoutError: + raise linstor.LinstorTimeoutError( + f"Volume `{volume_uuid}` from SR `{self._group_name}` is busy and can't be resized right now. " + + "Please retry later." + ) + util.SMlog(f"DRBD is up to date, syncing took {time.monotonic() - start_time}s") + + result = self._linstor.volume_dfn_modify( + rsc_name=volume_name, + volume_nr=0, + size=new_size + ) - # After volume creation, DRBD volume can be unusable during many seconds. - # So we must retry the definition change if the device is not up to date. - # Often the case for thick provisioning. - if retry_count and error_str.find('non-UpToDate DRBD device') >= 0: - time.sleep(2) - retry_count -= 1 - continue + self._mark_resource_cache_as_dirty() + error_str = self._get_error_str(result) + if error_str: raise LinstorVolumeManagerError( - 'Could not resize volume `{}` from SR `{}`: {}' - .format(volume_uuid, self._group_name, error_str) + f"Could not resize volume `{volume_uuid}` from SR `{self._group_name}`: {error_str}" ) def get_volume_name(self, volume_uuid):