@@ -576,6 +576,20 @@ def in_sync_with_xenapi_record(self, x):
576576 return False
577577 return True
578578
579+ def _list_vdi_snapshots (self , vdi_uuid ):
580+ """List UUIDs of all direct snapshots of a VDI"""
581+ try :
582+ vdi_ref = self .session .xenapi .VDI .get_by_uuid (vdi_uuid )
583+ record = self .session .xenapi .VDI .get_record (vdi_ref )
584+ return [
585+ self .session .xenapi .VDI .get_uuid (ref )
586+ for ref in record .get ("snapshots" , [])
587+ if self .session .xenapi .VDI .get_uuid (ref )
588+ ]
589+ except Exception as error :
590+ util .SMlog ("Error listing snapshots for VDI %s : %s" % (vdi_ref , error ))
591+ return []
592+
579593 def configure_blocktracking (self , sr_uuid , vdi_uuid , enable ):
580594 """Function for configuring blocktracking"""
581595 import blktap2
@@ -616,29 +630,50 @@ def configure_blocktracking(self, sr_uuid, vdi_uuid, enable):
616630 self ._delete_cbt_log ()
617631 raise xs_errors .XenError ('CBTActivateFailed' ,
618632 opterr = str (error ))
633+
619634 else :
620- from lock import Lock
621- lock = Lock ("cbtlog" , str (vdi_uuid ))
622- lock .acquire ()
623- try :
624- # Find parent of leaf metadata file, if any,
625- # and nullify its successor
626- logpath = self ._get_cbt_logpath (self .uuid )
627- parent = self ._cbt_op (self .uuid ,
628- cbtutil .get_cbt_parent , logpath )
629- self ._delete_cbt_log ()
630- parent_path = self ._get_cbt_logpath (parent )
631- if self ._cbt_log_exists (parent_path ):
632- self ._cbt_op (parent , cbtutil .set_cbt_child ,
633- parent_path , uuid .UUID (int = 0 ))
634- except Exception as error :
635- raise xs_errors .XenError ('CBTDeactivateFailed' , str (error ))
636- finally :
637- lock .release ()
638- lock .cleanup ("cbtlog" , str (vdi_uuid ))
635+ self ._disable_cbt (vdi_uuid )
636+
639637 finally :
640638 blktap2 .VDI .tap_unpause (self .session , sr_uuid , vdi_uuid )
641639
640+ def _disable_cbt (self , vdi_uuid , visited = None ):
641+ # Prevent infite loop
642+ if visited is None :
643+ visited = set ()
644+ if vdi_uuid in visited :
645+ return
646+ visited .add (vdi_uuid )
647+
648+ from lock import Lock
649+ lock = Lock ("cbtlog" , str (vdi_uuid ))
650+ lock .acquire ()
651+ try :
652+ self .uuid = vdi_uuid
653+ vdi_ref = self .session .xenapi .VDI .get_by_uuid (self .uuid )
654+ vdi_record = self .session .xenapi .VDI .get_record (vdi_ref )
655+ logpath = self ._get_cbt_logpath (self .uuid )
656+ if self ._cbt_log_exists (logpath ):
657+ parent = self ._cbt_op (self .uuid , cbtutil .get_cbt_parent , logpath )
658+ self ._delete_cbt_log ()
659+ # Find parent of leaf metadata file, if any,
660+ # and nullify its successor
661+ parent_path = self ._get_cbt_logpath (parent )
662+ if self ._cbt_log_exists (parent_path ):
663+ self ._cbt_op (parent , cbtutil .set_cbt_child , parent_path , uuid .UUID (int = 0 ))
664+ self .session .xenapi .VDI .set_cbt_enabled (vdi_ref , False )
665+ for snapshot_ref in self ._list_vdi_snapshots (self .uuid ):
666+ snap_ref = self .session .xenapi .VDI .get_by_uuid (snapshot_ref )
667+ snapshot_uuid = self .session .xenapi .VDI .get_uuid (snap_ref )
668+ self ._disable_cbt (snapshot_uuid , visited )
669+
670+ except Exception as error :
671+ util .SMlog (f"Error disabling CBT for VDI { self .uuid } : { error } " )
672+ raise xs_errors .XenError ('CBTDeactivateFailed' , str (error ))
673+ finally :
674+ lock .release ()
675+ lock .cleanup ("cbtlog" , str (vdi_uuid ))
676+
642677 def data_destroy (self , sr_uuid , vdi_uuid ):
643678 """Delete the data associated with a CBT enabled snapshot
644679
0 commit comments