18
18
# blktap2: blktap/tapdisk management layer
19
19
#
20
20
21
- from sm_typing import Any , Callable , ClassVar , Dict , override
21
+ from sm_typing import Any , Callable , ClassVar , Dict , override , List
22
22
23
23
from abc import abstractmethod
24
24
@@ -1657,6 +1657,89 @@ def activate(self, sr_uuid, vdi_uuid, writable, caching_params):
1657
1657
time .sleep (1 )
1658
1658
raise util .SMException ("VDI %s locked" % vdi_uuid )
1659
1659
1660
+ def _get_host_ref (self ) -> str :
1661
+ """
1662
+ Give the host ref of the one responsible for Garbage Collection for a SR.
1663
+ Meaning this host for a local SR, the master for a shared SR.
1664
+ """
1665
+ sr = self .target .vdi .sr
1666
+ if sr .is_shared ():
1667
+ host_ref = util .get_master_ref (self ._session )
1668
+ else :
1669
+ host_ref = sr .host_ref
1670
+ return host_ref
1671
+
1672
+ def _get_chain (self , cowutil , extractUuid ) -> List [str ]:
1673
+ vdi_chain = []
1674
+ path = self .target .get_vdi_path ()
1675
+
1676
+ #TODO: Need to add handling of error for getParentNoCheck, e.g. corrupted VDI where we can't read parent
1677
+ vdi_chain .append (extractUuid (path ))
1678
+ parent = cowutil .getParentNoCheck (path )
1679
+ while parent :
1680
+ vdi_chain .append (extractUuid (parent ))
1681
+ parent = cowutil .getParentNoCheck (parent )
1682
+ vdi_chain .reverse ()
1683
+ return vdi_chain
1684
+
1685
+ def _check_journal_coalesce_chain (self , sr_uuid : str , vdi_uuid : str ) -> bool :
1686
+ vdi_type = self .target .get_vdi_type ()
1687
+ cowutil = getCowUtil (vdi_type )
1688
+ if not cowutil .isCoalesceableOnRemote (): #We only need to stop the coalesce in case of QCOW2
1689
+ return True
1690
+
1691
+ level = 0
1692
+ path = self .target .get_vdi_path ()
1693
+
1694
+ # Different extractUUID & journaler function for LVMSR and FileSR
1695
+ journaler = None
1696
+ extractUuid = None
1697
+ if path .startswith ("/dev/" ): #TODO: How to identify SR type easily, we could ask XAPI since we have the sruuid (and even ref)
1698
+ from lvmcowutil import LvmCowUtil
1699
+ import lvmcache
1700
+ import journaler
1701
+ vgName = "VG_XenStorage-{}" .format (sr_uuid )
1702
+ lvmCache = lvmcache .LVMCache (vgName )
1703
+ journaler = journaler .Journaler (lvmCache )
1704
+
1705
+ extractUuid = LvmCowUtil .extractUuid
1706
+ else :
1707
+ from FileSR import FileVDI
1708
+ import fjournaler
1709
+ journaler = fjournaler .Journaler (os .getcwd ())
1710
+ extractUuid = FileVDI .extractUuid
1711
+
1712
+ # Get the VDI chain
1713
+ vdi_chain = self ._get_chain (cowutil , extractUuid )
1714
+
1715
+ if len (vdi_chain ) == 1 :
1716
+ #We only have a leaf, do nothing
1717
+ util .SMlog ("VDI {} is only a leaf, continuing..." .format (vdi_uuid ))
1718
+ return True
1719
+
1720
+ # Log the chain of active VDI
1721
+ util .SMlog ("VDI chain:" )
1722
+ for vdi in vdi_chain :
1723
+ prefix = " " * level
1724
+ level += 1
1725
+ util .SMlog ("{}{}" .format (prefix , vdi ))
1726
+
1727
+ vdi_to_cancel = []
1728
+ for entry in journaler .getAll ("coalesce" ).keys ():
1729
+ if entry in vdi_chain :
1730
+ vdi_to_cancel .append (entry )
1731
+ util .SMlog ("Coalescing VDI {} in chain" .format (entry ))
1732
+
1733
+ # Get the host_ref from the host doing the GC work
1734
+ host_ref = self ._get_host_ref ()
1735
+ for vdi in vdi_to_cancel :
1736
+ args = {"sr_uuid" : sr_uuid , "vdi_uuid" : vdi }
1737
+ util .SMlog ("Calling cancel_coalesce_master with args: {}" .format (args ))
1738
+ self ._session .xenapi .host .call_plugin (\
1739
+ host_ref , PLUGIN_ON_SLAVE , "cancel_coalesce_master" , args )
1740
+
1741
+ return True
1742
+
1660
1743
@locking ("VDIUnavailable" )
1661
1744
def _activate_locked (self , sr_uuid , vdi_uuid , options ):
1662
1745
"""Wraps target.activate and adds a tapdisk"""
@@ -1666,8 +1749,6 @@ def _activate_locked(self, sr_uuid, vdi_uuid, options):
1666
1749
if self .tap_wanted ():
1667
1750
if not self ._add_tag (vdi_uuid , not options ["rdonly" ]):
1668
1751
return False
1669
- #TODO: Need to interrupt coalesce on master, the coalesce will check for host_OpaqueRef on the VDI before trying offline coalesce
1670
- #TODO: The coalesce could happen on another slave in onlinecoalesce, interrupt coalesce on another slave (online coalesce)?
1671
1752
refresh = True
1672
1753
1673
1754
try :
@@ -1692,6 +1773,9 @@ def _activate_locked(self, sr_uuid, vdi_uuid, options):
1692
1773
1693
1774
vdi_type = self .target .get_vdi_type ()
1694
1775
1776
+ self ._check_journal_coalesce_chain (sr_uuid , vdi_uuid )
1777
+ #TODO: handling error here
1778
+
1695
1779
# Take lvchange-p Lock before running
1696
1780
# tap-ctl open
1697
1781
# Needed to avoid race with lvchange -p which is
0 commit comments