Skip to content

Commit

Permalink
fix(LargeBlock): Connect the correct VG at reboot
Browse files Browse the repository at this point in the history
At reboot, the wrong disk will be identified by LVM as containing the
LogicalVolume of the EXTSR during scan.
This means that the SR can be connected through the 4K device instead of
the 512B loop device and fails silently until we try to do something on
the SR.
This commit add the ability to see if the LV is connected through the
correct device and correct it if needed while attaching the SR.

Signed-off-by: Damien Thenot <[email protected]>
  • Loading branch information
Nambrok committed Mar 15, 2024
1 parent 6317751 commit 3c86892
Showing 1 changed file with 31 additions and 0 deletions.
31 changes: 31 additions & 0 deletions drivers/LargeBlockSR.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import util
import xs_errors
import os
import re

CAPABILITIES = ["SR_PROBE", "SR_UPDATE", "SR_SUPPORTS_LOCAL_CACHING",
"VDI_CREATE", "VDI_DELETE", "VDI_ATTACH", "VDI_DETACH",
Expand Down Expand Up @@ -59,6 +60,8 @@ def load(self, sr_uuid):
def attach(self, sr_uuid):
if not self.is_deleting:
self.create_emulated_device()
if not self.is_vg_connection_correct(): # Check if we need to redo the connection by parsing `vgs -o vg_name,devices self.vgname`
self.redo_vg_connection() # Call redo VG connection to connect it correctly to the loop device instead of the real 4KiB block device
super(LargeBlockSR, self).attach(sr_uuid)

def detach(self, sr_uuid):
Expand Down Expand Up @@ -130,6 +133,34 @@ def get_loopdev_from_device(self, device):
return loopdev
return None

def is_vg_connection_correct(self):
output = util.pread2(["vgs", "--noheadings", "-o", "vg_name,devices", self.vgname]).split()
if self.vgname == output[0]:
output[1] = output[1].split("(")[0]
if re.match(r"(.*\.512)|(/dev/loop[0-9]+)", output[1]):
return True
else:
return False

def redo_vg_connection(self):
"""
In case of using a LargeBlockSR, the LVM scan at boot will find the LogicalVolume on the real block device.
And when the PBD is connecting, it will mount from the original device instead of the loop device since LVM prefers real devices it has seen first.
The PBD plug will succeed but then the SR will be accessed through the 4KiB device, returning to the erroneous behaviour on 4KiB device.
VM won't be able to run because vhd-util will fail to scan the VDI.
This function force the LogicalVolume to be mounted on top of our emulation layer by disabling the VolumeGroup and re-enabling while applying a filter.
"""

util.SMlog("Reconnecting VG {} to use emulated device".format(self.vgname))
try:
cmd = ["vgchange", "-an", self.vgname]
util.pread2(cmd)
cmd = ["vgchange", "-ay", self.vgname, "--config", "'devices{ global_filter = [ \"r|^/dev/nvme.*|\", \"a|/dev/loop.*|\" ] }"]
util.pread2(cmd)
except util.CommandException as e:
util.SMlog("Failed to reconnect the VolumeGroup {}, error: {}".format(self.vgname, e))


def get_emulated_device_path(self, dev):
return "{dev}.{bs}".format(dev=dev, bs=self.LOOP_SECTOR_SIZE)

Expand Down

0 comments on commit 3c86892

Please sign in to comment.