Skip to content

Commit 0cbc76e

Browse files
committed
Fix relinking for online coalesce
Add a condition to not add the relinking key to the leafs of the chain used for online coalesce. Tapdisk will have done the rebase itself and the scan before doing the relink would drop the VDIs from the children list and the tag would never be removed. It would then block the vdi_activate that check if relink is happening before continuing. Signed-off-by: Damien Thenot <damien.thenot@vates.tech>
1 parent f778854 commit 0cbc76e

File tree

2 files changed

+62
-14
lines changed

2 files changed

+62
-14
lines changed

drivers/cleanup.py

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,7 +1092,18 @@ def _reload(self):
10921092
raise
10931093
self.refresh()
10941094

1095-
def _tagChildrenForRelink(self):
1095+
def _needRelink(self, list_not_to_relink):
1096+
"""
1097+
If we coalesce up the chain, we shouldn't need to do the relink at all, we only need to do the relink on the children if their direct parent was the one we were coalescing
1098+
"""
1099+
if not list_not_to_relink:
1100+
return True
1101+
if self.uuid in list_not_to_relink:
1102+
return False
1103+
else:
1104+
return True
1105+
1106+
def _tagChildrenForRelink(self, list_not_to_relink=None):
10961107
if len(self.children) == 0:
10971108
retries = 0
10981109
try:
@@ -1102,13 +1113,17 @@ def _tagChildrenForRelink(self):
11021113
Util.log("VDI %s is activating, wait to relink" %
11031114
self.uuid)
11041115
else:
1105-
self.setConfig(VDI.DB_VDI_RELINKING, "True")
1106-
1107-
if self.getConfig(VDI.DB_VDI_ACTIVATING):
1108-
self.delConfig(VDI.DB_VDI_RELINKING)
1109-
Util.log("VDI %s started activating while tagging" %
1110-
self.uuid)
1116+
if self._needRelink(list_not_to_relink):
1117+
self.setConfig(VDI.DB_VDI_RELINKING, "True")
1118+
1119+
if self.getConfig(VDI.DB_VDI_ACTIVATING):
1120+
self.delConfig(VDI.DB_VDI_RELINKING)
1121+
Util.log("VDI %s started activating while tagging" %
1122+
self.uuid)
1123+
else:
1124+
return
11111125
else:
1126+
Util.log(f"Not adding relinking tag to VDI {self.uuid}")
11121127
return
11131128
time.sleep(2)
11141129

@@ -1118,7 +1133,7 @@ def _tagChildrenForRelink(self):
11181133
raise
11191134

11201135
for child in self.children:
1121-
child._tagChildrenForRelink()
1136+
child._tagChildrenForRelink(list_not_to_relink)
11221137

11231138
def _loadInfoParent(self):
11241139
ret = self.cowutil.getParent(self.path, LvmCowUtil.extractUuid)
@@ -1138,6 +1153,15 @@ def _setParent(self, parent) -> None:
11381153
Util.log("Failed to update %s with vhd-parent field %s" % \
11391154
(self.uuid, self.parentUuid))
11401155

1156+
def _update_vhd_parent(self, real_parent_uuid):
1157+
try:
1158+
self.setConfig(self.DB_VDI_PARENT, real_parent_uuid)
1159+
Util.log("Updated the vhd-parent field for child %s with real parent %s following a online coalesce" % \
1160+
(self.uuid, real_parent_uuid))
1161+
except:
1162+
Util.log("Failed to update %s with vhd-parent field %s" % \
1163+
(self.uuid, real_parent_uuid))
1164+
11411165
def isHidden(self) -> bool:
11421166
if self._hidden is None:
11431167
self._loadInfoHidden()
@@ -2495,6 +2519,7 @@ def _delete_running_file(self, vdi: VDI):
24952519
os.unlink(self._gc_running_file(vdi))
24962520

24972521
def _coalesce(self, vdi: VDI):
2522+
list_not_to_relink = None
24982523
if self.journaler.get(vdi.JRN_RELINK, vdi.uuid):
24992524
# this means we had done the actual coalescing already and just
25002525
# need to finish relinking and/or refreshing the children
@@ -2514,19 +2539,26 @@ def _coalesce(self, vdi: VDI):
25142539
host_refs = self._hasLeavesAttachedOn(vdi)
25152540
#TODO: this check of multiple host_refs should be done earlier in `is_coalesceable` to avoid stopping this late every time
25162541
if len(host_refs) > 1:
2517-
util.SMlog("Not coalesceable, chain activated more than once")
2542+
Util.log("Not coalesceable, chain activated more than once")
25182543
raise Exception("Not coalesceable, chain activated more than once") #TODO: Use correct error
25192544

25202545
try:
25212546
if host_refs and vdi.cowutil.isCoalesceableOnRemote():
25222547
#Leaf opened on another host, we need to call online coalesce
2523-
util.SMlog("Remote coalesce for {}".format(vdi.path))
2548+
Util.log("Remote coalesce for {}".format(vdi.path))
25242549
vdi._doCoalesceOnHost(list(host_refs)[0])
2550+
# If we use a host OpaqueRef to do a online coalesce, this vdi will not need to be relinked since it was done by tapdisk
2551+
# If we coalesce up the chain, we shouldn't need to do the relink at all, we only need to do the relink on the children if their direct parent was the one we were coalescing
2552+
for child in vdi.children:
2553+
real_parent_uuid = child.extractUuid(child.getParent())
2554+
if real_parent_uuid == vdi.parent.uuid:
2555+
child._update_vhd_parent(real_parent_uuid) # We update the sm-config:vhd-parent value for this VDI since it has already been relinked
2556+
list_not_to_relink = [leaf.uuid for leaf in child.getAllLeaves()]
25252557
else:
2526-
util.SMlog("Offline coalesce for {}".format(vdi.path))
2558+
Util.log("Offline coalesce for {}".format(vdi.path))
25272559
vdi._doCoalesce()
25282560
except Exception as e:
2529-
util.SMlog("EXCEPTION while coalescing: {}".format(e))
2561+
Util.log("EXCEPTION while coalescing: {}".format(e))
25302562
self._delete_running_file(vdi)
25312563
raise
25322564

@@ -2543,9 +2575,9 @@ def _coalesce(self, vdi: VDI):
25432575

25442576
self.lock()
25452577
try:
2546-
vdi.parent._tagChildrenForRelink()
2578+
vdi.parent._tagChildrenForRelink(list_not_to_relink)
25472579
self.scan()
2548-
vdi._relinkSkip() #TODO: We could check if the parent is already the right one before doing the relink, or we could do the relink a second time, it doesn't seem to cause issues
2580+
vdi._relinkSkip()
25492581
finally:
25502582
self.unlock()
25512583
# Reload the children to leave things consistent

drivers/util.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,22 @@ def get_hosts_attached_on(session, vdi_uuids):
768768
host_refs[key[len('host_'):]] = True
769769
return host_refs.keys()
770770

771+
def get_hosts_attached_on_with_vdi_uuid(session, vdi_uuids):
772+
"""
773+
Return a dict of {vdi_uuid: host OpaqueRef}
774+
"""
775+
host_refs = {}
776+
for vdi_uuid in vdi_uuids:
777+
try:
778+
vdi_ref = session.xenapi.VDI.get_by_uuid(vdi_uuid)
779+
except XenAPI.Failure:
780+
SMlog("VDI %s not in db, ignoring" % vdi_uuid)
781+
continue
782+
sm_config = session.xenapi.VDI.get_sm_config(vdi_ref)
783+
for key in [x for x in sm_config.keys() if x.startswith('host_')]:
784+
host_refs[vdi_uuid] = key[len('host_'):]
785+
return host_refs
786+
771787
def get_this_host_address(session):
772788
host_uuid = get_this_host()
773789
host_ref = session.xenapi.host.get_by_uuid(host_uuid)

0 commit comments

Comments
 (0)