# HG changeset patch # User kfraser@localhost.localdomain # Date 1180016489 -3600 # Node ID 3ef4a4d8213061fe14d905e89594c99d0b9cb605 # Parent 6a4af9502b4da269388a60416a7cca0ecadb3bb3 xend: Fix for removing devices at save/destroy domain. The function XendDomainInfo:_releaseDevices() is called during the save/destroy phase of a domain. It made some attempt to clean up the devices, but wasn't complete, leaving dangling devices in the xenstore. Not a big problem with normal use of Xen, but a buildup over a large number of save/destroy instances, it would make the xenstore database grow quite large, which in turn meant swap-thrashing in Dom0. This patch makes use of the destroyDevices() function in XendDomainInfo. This function needed some re-writing to make it work correctly - I think it had some old code (not sure how old, as xm annotate says that it's changeset 12071, but that, I think, is when it was split out from XendDomain.py, rather than when it was created). I have tested this over a few hundred save/restore cycles [two domains constantly saved/restored with a short sleep to let them process some work] combined with a loop of "xenstore-ls|wc". The output of the latter is pretty much constant (it obviously varies a bit depending on when in the save/restore cycle it hits). Previously, it would increase by some 10 lines or so per save/restore cycle. Signed-off-by: Mats Petersson Index: xen-3.1-testing/tools/python/xen/xend/XendDomainInfo.py =================================================================== --- xen-3.1-testing.orig/tools/python/xen/xend/XendDomainInfo.py +++ xen-3.1-testing/tools/python/xen/xend/XendDomainInfo.py @@ -544,20 +544,30 @@ class XendDomainInfo: self.getDeviceController(devclass).waitForDevices() def destroyDevice(self, deviceClass, devid, force = False): + found = True # Assume devid is an integer. try: devid = int(devid) except ValueError: # devid is not a number, let's search for it in xenstore. devicePath = '%s/device/%s' % (self.dompath, deviceClass) + found = False for entry in xstransact.List(devicePath): + log.debug("Attempting to find devid at %s/%s", devicePath, entry) backend = xstransact.Read('%s/%s' % (devicePath, entry), "backend") - devName = xstransact.Read(backend, "dev") - if devName == devid: - # We found the integer matching our devid, use it instead - devid = entry - break - + if backend != None: + devName = '%s/%s' % (deviceClass, entry) + log.debug("devName=%s", devName) + if devName == devid: + # We found the integer matching our devid, use it instead + devid = int(entry) + found = True + break + + if not found: + log.debug("Could not find the device %s", devid) + return None + log.debug("devid = %s", devid) return self.getDeviceController(deviceClass).destroyDevice(devid, force) def getDeviceSxprs(self, deviceClass): @@ -1330,20 +1340,19 @@ class XendDomainInfo: self.image.destroy(suspend) return - while True: - t = xstransact("%s/device" % self.dompath) - for devclass in XendDevices.valid_devices(): - for dev in t.list(devclass): - try: - t.remove(dev) - except: - # Log and swallow any exceptions in removal -- - # there's nothing more we can do. - log.exception( - "Device release failed: %s; %s; %s", - self.info['name_label'], devclass, dev) - if t.commit(): - break + t = xstransact("%s/device" % self.dompath) + for devclass in XendDevices.valid_devices(): + for dev in t.list(devclass): + try: + log.debug("Removing %s", dev); + self.destroyDevice(devclass, dev, False); + except: + # Log and swallow any exceptions in removal -- + # there's nothing more we can do. + log.exception("Device release failed: %s; %s; %s", + self.info['name_label'], devclass, dev) + + def getDeviceController(self, name): """Get the device controller for this domain, and if it