def get_runtime_properties(self): xendom = XendDomain.instance() dominfo = xendom.get_vm_by_uuid(self.VM) try: device_dict = {} for device_sxp in dominfo.getDeviceSxprs('vscsi'): target_dev = None for dev in device_sxp[1][0][1]: vdev = sxp.child_value(dev, 'v-dev') if vdev == self.virtual_HCTL: target_dev = dev break if target_dev is None: continue dev_dict = {} for info in target_dev[1:]: dev_dict[info[0]] = info[1] device_dict['dev'] = dev_dict for info in device_sxp[1][1:]: device_dict[info[0]] = info[1] return device_dict except Exception, exn: log.exception(exn) return {}
def pool_list(cls, names): sxprs = [] try: node = XendNode.instance() xd = XendDomain.instance() pools = cls.get_all_records() for (pool_uuid, pool_vals) in pools.items(): if pool_vals['name_label'] in names or len(names) == 0: # conv host_cpu refs to cpu number cpus = [ node.get_host_cpu_field(cpu_ref, 'number') for cpu_ref in pool_vals['host_CPUs'] ] cpus.sort() pool_vals['host_CPU_numbers'] = cpus # query VMs names. Take in account, that a VM # returned by get_all_records could be destroy, now vm_names = [ vm.getName() for vm in map( xd.get_vm_by_uuid, pool_vals['started_VMs']) if vm ] pool_vals['started_VM_names'] = vm_names pool_vals['auto_power_on'] = int( pool_vals['auto_power_on']) sxprs += [[pool_uuid] + map2sxp(pool_vals)] except XendAPIError, ex: raise VmError(ex.get_api_error())
def destroy(self): xendom = XendDomain.instance() dom = xendom.get_vm_by_uuid(self.get_VM()) if not dom: raise InvalidHandleError("VM", self.get_VM()) XendTask.log_progress(0, 100, \ dom.destroy_dscsi_HBA, \ self.get_uuid())
def destroy(self): xendom = XendDomain.instance() dom = xendom.get_vm_by_uuid(self.get_VM()) if not dom: raise InvalidHandleError("VM", self.get_VM()) XendTask.log_progress(0, 100, \ dom.destroy_dscsi, \ self.get_uuid())
def get_VIFs(self): result = [] vms = XendDomain.instance().get_all_vms() for vm in vms: vifs = vm.get_vifs() for vif in vifs: vif_cfg = vm.get_dev_xenapi_config('vif', vif) if vif_cfg.get('network') == self.get_uuid(): result.append(vif) return result
def pool_migrate(cls, domname, poolname): dom = XendDomain.instance() pool = cls.lookup_pool(poolname) if not pool: raise VmError('unknown pool %s' % poolname) dominfo = dom.domain_lookup_nr(domname) if not dominfo: raise VmError('unknown domain %s' % domname) domid = dominfo.getDomid() if domid is not None: if domid == 0: raise VmError('could not move Domain-0') try: cls.move_domain(pool.get_uuid(), domid) except Exception, ex: raise VmError('could not move domain')
def get_started_VMs(self): """ Query all VMs currently assigned to pool. @return: ref of all VMs assigned to pool; if pool is not active, an empty list will be returned @rtype: list of str """ if self.get_activated(): # search VMs related to this pool pool_id = self.query_pool_id() started_VMs = [ vm.get_uuid() for vm in XendDomain.instance().list('all') if vm.get_cpu_pool() == pool_id ] else: # pool not active, so it couldn't have any started VMs started_VMs = [] return started_VMs
def create(self, dscsi_struct): # Check if VM is valid xendom = XendDomain.instance() if not xendom.is_valid_vm(dscsi_struct['VM']): raise InvalidHandleError('VM', dscsi_struct['VM']) dom = xendom.get_vm_by_uuid(dscsi_struct['VM']) # Check if PSCSI is valid xennode = XendNode.instance() pscsi_uuid = xennode.get_pscsi_by_uuid(dscsi_struct['PSCSI']) if not pscsi_uuid: raise InvalidHandleError('PSCSI', dscsi_struct['PSCSI']) # Assign PSCSI to VM try: dscsi_ref = XendTask.log_progress(0, 100, \ dom.create_dscsi, \ dscsi_struct) except XendError, e: log.exception("Error in create_dscsi") raise
def create(self, dpci_struct): # Check if VM is valid xendom = XendDomain.instance() if not xendom.is_valid_vm(dpci_struct['VM']): raise InvalidHandleError('VM', dpci_struct['VM']) dom = xendom.get_vm_by_uuid(dpci_struct['VM']) # Check if PPCI is valid xennode = XendNode.instance() ppci_uuid = xennode.get_ppci_by_uuid(dpci_struct['PPCI']) if not ppci_uuid: raise InvalidHandleError('PPCI', dpci_struct['PPCI']) for existing_dpci in XendAPIStore.get_all('DPCI'): if ppci_uuid == existing_dpci.get_PPCI(): raise DirectPCIError("Device is in use") # Assign PPCI to VM try: dpci_ref = XendTask.log_progress(0, 100, dom.create_dpci, dpci_struct) except XendError, e: raise DirectPCIError("Failed to assign device")
def pool_list(cls, names): sxprs = [] try: node = XendNode.instance() xd = XendDomain.instance() pools = cls.get_all_records() for (pool_uuid, pool_vals) in pools.items(): if pool_vals['name_label'] in names or len(names) == 0: # conv host_cpu refs to cpu number cpus = [ node.get_host_cpu_field(cpu_ref, 'number') for cpu_ref in pool_vals['host_CPUs'] ] cpus.sort() pool_vals['host_CPU_numbers'] = cpus # query VMs names. Take in account, that a VM # returned by get_all_records could be destroy, now vm_names = [ vm.getName() for vm in map(xd.get_vm_by_uuid, pool_vals['started_VMs']) if vm ] pool_vals['started_VM_names'] = vm_names pool_vals['auto_power_on'] = int(pool_vals['auto_power_on']) sxprs += [[pool_uuid] + map2sxp(pool_vals)] except XendAPIError, ex: raise VmError(ex.get_api_error())
except Exception, exn: log.exception("Can't create directory '/var/lib/xen'") raise XendError("Can't create directory '/var/lib/xen'") write_exact(fd, SIGNATURE, "could not write guest state file: signature") sxprep = dominfo.sxpr() if node > -1: insert_after(sxprep,'vcpus',['node', str(node)]) for device_sxp in sxp.children(sxprep, 'device'): backend = sxp.child(device_sxp[1], 'backend') if backend == None: continue bkdominfo = XendDomain.instance().domain_lookup_nr(backend[1]) if bkdominfo == None: raise XendError("Could not find backend: %s" % backend[1]) if bkdominfo.getDomid() == XendDomain.DOM0_ID: # Skip for compatibility of checkpoint data format continue backend[1] = bkdominfo.getName() config = sxp.to_string(sxprep) #log.debug('xendcheckpoint config: %s' % config) domain_name = dominfo.getName() # Rename the domain temporarily, so that we don't get a name clash if this # domain is migrating (live or non-live) to the local host. Doing such a # thing is useful for debugging.
def free(need_mem, dominfo): """Balloon out memory from the privileged domain so that there is the specified required amount (in KiB) free. """ # We check whether there is enough free memory, and if not, instruct dom0 # to balloon out to free some up. Memory freed by a destroyed domain may # not appear in the free_memory field immediately, because it needs to be # scrubbed before it can be released to the free list, which is done # asynchronously by Xen; ballooning is asynchronous also. Such memory # does, however, need to be accounted for when calculating how much dom0 # needs to balloon. No matter where we expect the free memory to come # from, we need to wait for it to become available. # # We are not allowed to balloon below dom0_min_mem, or if dom0_ballooning # is False, we cannot balloon at all. Memory can still become available # through a rebooting domain, however. # # Eventually, we time out (presumably because there really isn't enough # free memory). # # We don't want to set the memory target (triggering a watch) when that # has already been done, but we do want to respond to changing memory # usage, so we recheck the required alloc each time around the loop, but # track the last used value so that we don't trigger too many watches. xoptions = XendOptions.instance() dom0 = XendDomain.instance().privilegedDomain() xc = xen.lowlevel.xc.xc() try: dom0_min_mem = xoptions.get_dom0_min_mem() * 1024 dom0_ballooning = xoptions.get_enable_dom0_ballooning() dom0_alloc = get_dom0_current_alloc() retries = 0 sleep_time = SLEEP_TIME_GROWTH new_alloc = 0 last_new_alloc = None last_free = None rlimit = RETRY_LIMIT # stop tmem from absorbing any more memory (must THAW when done!) xc.tmem_control(0,TMEMC_FREEZE,-1, 0, 0, "") # If unreasonable memory size is required, we give up waiting # for ballooning or scrubbing, as if had retried. physinfo = xc.physinfo() free_mem = physinfo['free_memory'] scrub_mem = physinfo['scrub_memory'] total_mem = physinfo['total_memory'] if dom0_ballooning: max_free_mem = total_mem - dom0_min_mem else: max_free_mem = total_mem - dom0_alloc if need_mem >= max_free_mem: retries = rlimit freeable_mem = free_mem + scrub_mem if freeable_mem < need_mem and need_mem < max_free_mem: # flush memory from tmem to scrub_mem and reobtain physinfo need_tmem_kb = need_mem - freeable_mem tmem_kb = xc.tmem_control(0,TMEMC_FLUSH,-1, need_tmem_kb, 0, "") log.debug("Balloon: tmem relinquished %d KiB of %d KiB requested.", tmem_kb, need_tmem_kb) physinfo = xc.physinfo() free_mem = physinfo['free_memory'] scrub_mem = physinfo['scrub_memory'] # Check whethercurrent machine is a numa system and the new # created hvm has all its vcpus in the same node, if all the # conditions above are fit. We will wait until all the pages # in scrub list are freed (if waiting time go beyond 20s, # we will stop waiting it.) if physinfo['nr_nodes'] > 1 and retries == 0: oldnode = -1 waitscrub = 1 vcpus = dominfo.info['cpus'][0] for vcpu in vcpus: nodenum = 0 for node in physinfo['node_to_cpu']: for cpu in node: if vcpu == cpu: if oldnode == -1: oldnode = nodenum elif oldnode != nodenum: waitscrub = 0 nodenum = nodenum + 1 if waitscrub == 1 and scrub_mem > 0: log.debug("wait for scrub %s", scrub_mem) while scrub_mem > 0 and retries < rlimit: time.sleep(sleep_time) physinfo = xc.physinfo() free_mem = physinfo['free_memory'] scrub_mem = physinfo['scrub_memory'] retries += 1 sleep_time += SLEEP_TIME_GROWTH log.debug("scrub for %d times", retries) retries = 0 sleep_time = SLEEP_TIME_GROWTH while retries < rlimit: physinfo = xc.physinfo() free_mem = physinfo['free_memory'] scrub_mem = physinfo['scrub_memory'] if free_mem >= need_mem: log.debug("Balloon: %d KiB free; need %d; done.", free_mem, need_mem) return if retries == 0: rlimit += ((need_mem - free_mem)/1024/1024) * RETRY_LIMIT_INCR log.debug("Balloon: %d KiB free; %d to scrub; need %d; retries: %d.", free_mem, scrub_mem, need_mem, rlimit) if dom0_ballooning: dom0_alloc = get_dom0_current_alloc() new_alloc = dom0_alloc - (need_mem - free_mem - scrub_mem) if free_mem + scrub_mem >= need_mem: if last_new_alloc == None: log.debug("Balloon: waiting on scrubbing") last_new_alloc = dom0_alloc else: if (new_alloc >= dom0_min_mem and new_alloc != last_new_alloc): new_alloc_mb = new_alloc / 1024 # Round down log.debug("Balloon: setting dom0 target to %d MiB.", new_alloc_mb) dom0.setMemoryTarget(new_alloc_mb) last_new_alloc = new_alloc # Continue to retry, waiting for ballooning or scrubbing. time.sleep(sleep_time) if retries < 2 * RETRY_LIMIT: sleep_time += SLEEP_TIME_GROWTH if last_free != None and last_free >= free_mem + scrub_mem: retries += 1 last_free = free_mem + scrub_mem # Not enough memory; diagnose the problem. if not dom0_ballooning: raise VmError(('Not enough free memory and enable-dom0-ballooning ' 'is False, so I cannot release any more. ' 'I need %d KiB but only have %d.') % (need_mem, free_mem)) elif new_alloc < dom0_min_mem: raise VmError( ('I need %d KiB, but dom0_min_mem is %d and shrinking to ' '%d KiB would leave only %d KiB free.') % (need_mem, dom0_min_mem, dom0_min_mem, free_mem + scrub_mem + dom0_alloc - dom0_min_mem)) else: dom0_start_alloc_mb = get_dom0_current_alloc() / 1024 dom0.setMemoryTarget(dom0_start_alloc_mb) raise VmError( ('Not enough memory is available, and dom0 cannot' ' be shrunk any further')) finally: # allow tmem to accept pages again xc.tmem_control(0,TMEMC_THAW,-1, 0, 0, "") del xc
def free(need_mem, dominfo): """Balloon out memory from the privileged domain so that there is the specified required amount (in KiB) free. """ # We check whether there is enough free memory, and if not, instruct dom0 # to balloon out to free some up. Memory freed by a destroyed domain may # not appear in the free_memory field immediately, because it needs to be # scrubbed before it can be released to the free list, which is done # asynchronously by Xen; ballooning is asynchronous also. Such memory # does, however, need to be accounted for when calculating how much dom0 # needs to balloon. No matter where we expect the free memory to come # from, we need to wait for it to become available. # # We are not allowed to balloon below dom0_min_mem, or if dom0_ballooning # is False, we cannot balloon at all. Memory can still become available # through a rebooting domain, however. # # Eventually, we time out (presumably because there really isn't enough # free memory). # # We don't want to set the memory target (triggering a watch) when that # has already been done, but we do want to respond to changing memory # usage, so we recheck the required alloc each time around the loop, but # track the last used value so that we don't trigger too many watches. xoptions = XendOptions.instance() dom0 = XendDomain.instance().privilegedDomain() xc = xen.lowlevel.xc.xc() memory_pool = MemoryPool.instance() try: dom0_min_mem = xoptions.get_dom0_min_mem() * 1024 dom0_ballooning = xoptions.get_enable_dom0_ballooning() guest_size = 0 hvm = dominfo.info.is_hvm() if memory_pool.is_enabled() and dominfo.domid: if not hvm : if need_mem <= 4 * 1024: guest_size = 32 else: guest_size = dominfo.image.getBitSize() if guest_size == 32: dom0_ballooning = 0 else: #no ballooning as memory pool enabled dom0_ballooning = xoptions.get_enable_dom0_ballooning() dom0_alloc = get_dom0_current_alloc() retries = 0 sleep_time = SLEEP_TIME_GROWTH new_alloc = 0 last_new_alloc = None last_free = None rlimit = RETRY_LIMIT mem_need_balloon = 0 left_memory_pool = 0 mem_target = 0 untouched_memory_pool = 0 real_need_mem = need_mem # stop tmem from absorbing any more memory (must THAW when done!) xc.tmem_control(0,TMEMC_FREEZE,-1, 0, 0, 0, "") # If unreasonable memory size is required, we give up waiting # for ballooning or scrubbing, as if had retried. physinfo = xc.physinfo() free_mem = physinfo['free_memory'] scrub_mem = physinfo['scrub_memory'] total_mem = physinfo['total_memory'] if memory_pool.is_enabled() and dominfo.domid: if guest_size != 32 or hvm: if need_mem > 4 * 1024: dominfo.alloc_mem = need_mem left_memory_pool = memory_pool.get_left_memory() if need_mem > left_memory_pool: dominfo.alloc_mem = 0 raise VmError(('Not enough free memory' ' so I cannot release any more. ' 'I need %d KiB but only have %d in the pool.') % (need_mem, memory_pool.get_left_memory())) else: untouched_memory_pool = memory_pool.get_untouched_memory() if (left_memory_pool - untouched_memory_pool) > need_mem: dom0_ballooning = 0 else: mem_need_balloon = need_mem - left_memory_pool + untouched_memory_pool need_mem = free_mem + scrub_mem + mem_need_balloon if dom0_ballooning: max_free_mem = total_mem - dom0_min_mem else: max_free_mem = total_mem - dom0_alloc if need_mem >= max_free_mem: retries = rlimit freeable_mem = free_mem + scrub_mem if freeable_mem < need_mem and need_mem < max_free_mem: # flush memory from tmem to scrub_mem and reobtain physinfo need_tmem_kb = need_mem - freeable_mem tmem_kb = xc.tmem_control(0,TMEMC_FLUSH,-1, need_tmem_kb, 0, 0, "") log.debug("Balloon: tmem relinquished %d KiB of %d KiB requested.", tmem_kb, need_tmem_kb) physinfo = xc.physinfo() free_mem = physinfo['free_memory'] scrub_mem = physinfo['scrub_memory'] while retries < rlimit: physinfo = xc.physinfo() free_mem = physinfo['free_memory'] scrub_mem = physinfo['scrub_memory'] if free_mem >= need_mem: if (guest_size != 32 or hvm) and dominfo.domid: memory_pool.decrease_untouched_memory(mem_need_balloon) memory_pool.decrease_memory(real_need_mem) else: log.debug("Balloon: %d KiB free; need %d; done.", free_mem, need_mem) return if retries == 0: rlimit += ((need_mem - free_mem)/1024/1024) * RETRY_LIMIT_INCR log.debug("Balloon: %d KiB free; %d to scrub; need %d; retries: %d.", free_mem, scrub_mem, need_mem, rlimit) if dom0_ballooning: dom0_alloc = get_dom0_current_alloc() new_alloc = dom0_alloc - (need_mem - free_mem - scrub_mem) if free_mem + scrub_mem >= need_mem: if last_new_alloc == None: log.debug("Balloon: waiting on scrubbing") last_new_alloc = dom0_alloc else: if (new_alloc >= dom0_min_mem and new_alloc != last_new_alloc): new_alloc_mb = new_alloc / 1024 # Round down log.debug("Balloon: setting dom0 target to %d MiB.", new_alloc_mb) dom0.setMemoryTarget(new_alloc_mb) last_new_alloc = new_alloc # Continue to retry, waiting for ballooning or scrubbing. time.sleep(sleep_time) if retries < 2 * RETRY_LIMIT: sleep_time += SLEEP_TIME_GROWTH if last_free != None and last_free >= free_mem + scrub_mem: retries += 1 last_free = free_mem + scrub_mem # Not enough memory; diagnose the problem. if not dom0_ballooning: dominfo.alloc_mem = 0 raise VmError(('Not enough free memory and enable-dom0-ballooning ' 'is False, so I cannot release any more. ' 'I need %d KiB but only have %d.') % (need_mem, free_mem)) elif new_alloc < dom0_min_mem: dominfo.alloc_mem = 0 raise VmError( ('I need %d KiB, but dom0_min_mem is %d and shrinking to ' '%d KiB would leave only %d KiB free.') % (need_mem, dom0_min_mem, dom0_min_mem, free_mem + scrub_mem + dom0_alloc - dom0_min_mem)) else: dom0_start_alloc_mb = get_dom0_current_alloc() / 1024 dom0.setMemoryTarget(dom0_start_alloc_mb) dominfo.alloc_mem = 0 raise VmError( ('Not enough memory is available, and dom0 cannot' ' be shrunk any further')) finally: # allow tmem to accept pages again xc.tmem_control(0,TMEMC_THAW,-1, 0, 0, 0, "") del xc
def free(need_mem): """Balloon out memory from the privileged domain so that there is the specified required amount (in KiB) free. """ # We check whether there is enough free memory, and if not, instruct dom0 # to balloon out to free some up. Memory freed by a destroyed domain may # not appear in the free_memory field immediately, because it needs to be # scrubbed before it can be released to the free list, which is done # asynchronously by Xen; ballooning is asynchronous also. Such memory # does, however, need to be accounted for when calculating how much dom0 # needs to balloon. No matter where we expect the free memory to come # from, we need to wait for it to become available. # # We are not allowed to balloon below dom0_min_mem, or if dom0_min_mem # is 0, we cannot balloon at all. Memory can still become available # through a rebooting domain, however. # # Eventually, we time out (presumably because there really isn't enough # free memory). # # We don't want to set the memory target (triggering a watch) when that # has already been done, but we do want to respond to changing memory # usage, so we recheck the required alloc each time around the loop, but # track the last used value so that we don't trigger too many watches. xoptions = XendOptions.instance() dom0 = XendDomain.instance().privilegedDomain() xc = xen.lowlevel.xc.xc() dom0_start_alloc_mb = get_dom0_current_alloc() / 1024 try: dom0_min_mem = xoptions.get_dom0_min_mem() * 1024 dom0_alloc = get_dom0_current_alloc() retries = 0 sleep_time = SLEEP_TIME_GROWTH new_alloc = 0 last_new_alloc = None last_free = None rlimit = RETRY_LIMIT # If unreasonable memory size is required, we give up waiting # for ballooning or scrubbing, as if had retried. physinfo = xc.physinfo() free_mem = physinfo['free_memory'] scrub_mem = physinfo['scrub_memory'] total_mem = physinfo['total_memory'] if dom0_min_mem > 0: max_free_mem = total_mem - dom0_min_mem else: max_free_mem = total_mem - dom0_alloc if need_mem >= max_free_mem: retries = rlimit while retries < rlimit: physinfo = xc.physinfo() free_mem = physinfo['free_memory'] scrub_mem = physinfo['scrub_memory'] if free_mem >= need_mem: log.debug("Balloon: %d KiB free; need %d; done.", free_mem, need_mem) return if retries == 0: rlimit += ( (need_mem - free_mem) / 1024 / 1024) * RETRY_LIMIT_INCR log.debug( "Balloon: %d KiB free; %d to scrub; need %d; retries: %d.", free_mem, scrub_mem, need_mem, rlimit) if dom0_min_mem > 0: dom0_alloc = get_dom0_current_alloc() new_alloc = dom0_alloc - (need_mem - free_mem - scrub_mem) if free_mem + scrub_mem >= need_mem: if last_new_alloc == None: log.debug("Balloon: waiting on scrubbing") last_new_alloc = dom0_alloc else: if (new_alloc >= dom0_min_mem and new_alloc != last_new_alloc): new_alloc_mb = new_alloc / 1024 # Round down log.debug("Balloon: setting dom0 target to %d MiB.", new_alloc_mb) dom0.setMemoryTarget(new_alloc_mb) last_new_alloc = new_alloc # Continue to retry, waiting for ballooning or scrubbing. time.sleep(sleep_time) if retries < 2 * RETRY_LIMIT: sleep_time += SLEEP_TIME_GROWTH if last_free != None and last_free >= free_mem + scrub_mem: retries += 1 last_free = free_mem + scrub_mem # Not enough memory; diagnose the problem. if dom0_min_mem == 0: raise VmError(('Not enough free memory and dom0_min_mem is 0, so ' 'I cannot release any more. I need %d KiB but ' 'only have %d.') % (need_mem, free_mem)) elif new_alloc < dom0_min_mem: raise VmError( ('I need %d KiB, but dom0_min_mem is %d and shrinking to ' '%d KiB would leave only %d KiB free.') % (need_mem, dom0_min_mem, dom0_min_mem, free_mem + scrub_mem + dom0_alloc - dom0_min_mem)) else: dom0.setMemoryTarget(dom0_start_alloc_mb) raise VmError(('Not enough memory is available, and dom0 cannot' ' be shrunk any further')) finally: del xc
def free(need_mem, dominfo): """Balloon out memory from the privileged domain so that there is the specified required amount (in KiB) free. """ # We check whether there is enough free memory, and if not, instruct dom0 # to balloon out to free some up. Memory freed by a destroyed domain may # not appear in the free_memory field immediately, because it needs to be # scrubbed before it can be released to the free list, which is done # asynchronously by Xen; ballooning is asynchronous also. Such memory # does, however, need to be accounted for when calculating how much dom0 # needs to balloon. No matter where we expect the free memory to come # from, we need to wait for it to become available. # # We are not allowed to balloon below dom0_min_mem, or if dom0_ballooning # is False, we cannot balloon at all. Memory can still become available # through a rebooting domain, however. # # Eventually, we time out (presumably because there really isn't enough # free memory). # # We don't want to set the memory target (triggering a watch) when that # has already been done, but we do want to respond to changing memory # usage, so we recheck the required alloc each time around the loop, but # track the last used value so that we don't trigger too many watches. xoptions = XendOptions.instance() dom0 = XendDomain.instance().privilegedDomain() xc = xen.lowlevel.xc.xc() memory_pool = MemoryPool.instance() try: dom0_min_mem = xoptions.get_dom0_min_mem() * 1024 dom0_ballooning = xoptions.get_enable_dom0_ballooning() guest_size = 0 hvm = dominfo.info.is_hvm() if memory_pool.is_enabled() and dominfo.domid: if not hvm: if need_mem <= 4 * 1024: guest_size = 32 else: guest_size = dominfo.image.getBitSize() if guest_size == 32: dom0_ballooning = 0 else: #no ballooning as memory pool enabled dom0_ballooning = xoptions.get_enable_dom0_ballooning() dom0_alloc = get_dom0_current_alloc() retries = 0 sleep_time = SLEEP_TIME_GROWTH new_alloc = 0 last_new_alloc = None last_free = None rlimit = RETRY_LIMIT mem_need_balloon = 0 left_memory_pool = 0 mem_target = 0 untouched_memory_pool = 0 real_need_mem = need_mem # stop tmem from absorbing any more memory (must THAW when done!) xc.tmem_control(0, TMEMC_FREEZE, -1, 0, 0, 0, "") # If unreasonable memory size is required, we give up waiting # for ballooning or scrubbing, as if had retried. physinfo = xc.physinfo() free_mem = physinfo['free_memory'] scrub_mem = physinfo['scrub_memory'] total_mem = physinfo['total_memory'] if memory_pool.is_enabled() and dominfo.domid: if guest_size != 32 or hvm: if need_mem > 4 * 1024: dominfo.alloc_mem = need_mem left_memory_pool = memory_pool.get_left_memory() if need_mem > left_memory_pool: dominfo.alloc_mem = 0 raise VmError( ('Not enough free memory' ' so I cannot release any more. ' 'I need %d KiB but only have %d in the pool.') % (need_mem, memory_pool.get_left_memory())) else: untouched_memory_pool = memory_pool.get_untouched_memory() if (left_memory_pool - untouched_memory_pool) > need_mem: dom0_ballooning = 0 else: mem_need_balloon = need_mem - left_memory_pool + untouched_memory_pool need_mem = free_mem + scrub_mem + mem_need_balloon if dom0_ballooning: max_free_mem = total_mem - dom0_min_mem else: max_free_mem = total_mem - dom0_alloc if need_mem >= max_free_mem: retries = rlimit freeable_mem = free_mem + scrub_mem if freeable_mem < need_mem and need_mem < max_free_mem: # flush memory from tmem to scrub_mem and reobtain physinfo need_tmem_kb = need_mem - freeable_mem tmem_kb = xc.tmem_control(0, TMEMC_FLUSH, -1, need_tmem_kb, 0, 0, "") log.debug("Balloon: tmem relinquished %d KiB of %d KiB requested.", tmem_kb, need_tmem_kb) physinfo = xc.physinfo() free_mem = physinfo['free_memory'] scrub_mem = physinfo['scrub_memory'] while retries < rlimit: physinfo = xc.physinfo() free_mem = physinfo['free_memory'] scrub_mem = physinfo['scrub_memory'] if free_mem >= need_mem: if (guest_size != 32 or hvm) and dominfo.domid: memory_pool.decrease_untouched_memory(mem_need_balloon) memory_pool.decrease_memory(real_need_mem) else: log.debug("Balloon: %d KiB free; need %d; done.", free_mem, need_mem) return if retries == 0: rlimit += ( (need_mem - free_mem) / 1024 / 1024) * RETRY_LIMIT_INCR log.debug( "Balloon: %d KiB free; %d to scrub; need %d; retries: %d.", free_mem, scrub_mem, need_mem, rlimit) if dom0_ballooning: dom0_alloc = get_dom0_current_alloc() new_alloc = dom0_alloc - (need_mem - free_mem - scrub_mem) if free_mem + scrub_mem >= need_mem: if last_new_alloc == None: log.debug("Balloon: waiting on scrubbing") last_new_alloc = dom0_alloc else: if (new_alloc >= dom0_min_mem and new_alloc != last_new_alloc): new_alloc_mb = new_alloc / 1024 # Round down log.debug("Balloon: setting dom0 target to %d MiB.", new_alloc_mb) dom0.setMemoryTarget(new_alloc_mb) last_new_alloc = new_alloc # Continue to retry, waiting for ballooning or scrubbing. time.sleep(sleep_time) if retries < 2 * RETRY_LIMIT: sleep_time += SLEEP_TIME_GROWTH if last_free != None and last_free >= free_mem + scrub_mem: retries += 1 last_free = free_mem + scrub_mem # Not enough memory; diagnose the problem. if not dom0_ballooning: dominfo.alloc_mem = 0 raise VmError( ('Not enough free memory and enable-dom0-ballooning ' 'is False, so I cannot release any more. ' 'I need %d KiB but only have %d.') % (need_mem, free_mem)) elif new_alloc < dom0_min_mem: dominfo.alloc_mem = 0 raise VmError( ('I need %d KiB, but dom0_min_mem is %d and shrinking to ' '%d KiB would leave only %d KiB free.') % (need_mem, dom0_min_mem, dom0_min_mem, free_mem + scrub_mem + dom0_alloc - dom0_min_mem)) else: dom0_start_alloc_mb = get_dom0_current_alloc() / 1024 dom0.setMemoryTarget(dom0_start_alloc_mb) dominfo.alloc_mem = 0 raise VmError(('Not enough memory is available, and dom0 cannot' ' be shrunk any further')) finally: # allow tmem to accept pages again xc.tmem_control(0, TMEMC_THAW, -1, 0, 0, 0, "") del xc
def free(need_mem, dominfo): """Balloon out memory from the privileged domain so that there is the specified required amount (in KiB) free. """ # We check whether there is enough free memory, and if not, instruct dom0 # to balloon out to free some up. Memory freed by a destroyed domain may # not appear in the free_memory field immediately, because it needs to be # scrubbed before it can be released to the free list, which is done # asynchronously by Xen; ballooning is asynchronous also. Such memory # does, however, need to be accounted for when calculating how much dom0 # needs to balloon. No matter where we expect the free memory to come # from, we need to wait for it to become available. # # We are not allowed to balloon below dom0_min_mem, or if dom0_ballooning # is False, we cannot balloon at all. Memory can still become available # through a rebooting domain, however. # # Eventually, we time out (presumably because there really isn't enough # free memory). # # We don't want to set the memory target (triggering a watch) when that # has already been done, but we do want to respond to changing memory # usage, so we recheck the required alloc each time around the loop, but # track the last used value so that we don't trigger too many watches. xoptions = XendOptions.instance() dom0 = XendDomain.instance().privilegedDomain() xc = xen.lowlevel.xc.xc() try: dom0_min_mem = xoptions.get_dom0_min_mem() * 1024 dom0_ballooning = xoptions.get_enable_dom0_ballooning() dom0_alloc = get_dom0_current_alloc() retries = 0 sleep_time = SLEEP_TIME_GROWTH new_alloc = 0 last_new_alloc = None last_free = None rlimit = RETRY_LIMIT # If unreasonable memory size is required, we give up waiting # for ballooning or scrubbing, as if had retried. physinfo = xc.physinfo() free_mem = physinfo["free_memory"] scrub_mem = physinfo["scrub_memory"] total_mem = physinfo["total_memory"] if dom0_ballooning: max_free_mem = total_mem - dom0_min_mem else: max_free_mem = total_mem - dom0_alloc if need_mem >= max_free_mem: retries = rlimit # Check whethercurrent machine is a numa system and the new # created hvm has all its vcpus in the same node, if all the # conditions above are fit. We will wait until all the pages # in scrub list are freed (if waiting time go beyond 20s, # we will stop waiting it.) if physinfo["nr_nodes"] > 1 and retries == 0: oldnode = -1 waitscrub = 1 vcpus = dominfo.info["cpus"][0] for vcpu in vcpus: nodenum = 0 for node in physinfo["node_to_cpu"]: for cpu in node: if vcpu == cpu: if oldnode == -1: oldnode = nodenum elif oldnode != nodenum: waitscrub = 0 nodenum = nodenum + 1 if waitscrub == 1 and scrub_mem > 0: log.debug("wait for scrub %s", scrub_mem) while scrub_mem > 0 and retries < rlimit: time.sleep(sleep_time) physinfo = xc.physinfo() free_mem = physinfo["free_memory"] scrub_mem = physinfo["scrub_memory"] retries += 1 sleep_time += SLEEP_TIME_GROWTH log.debug("scrub for %d times", retries) retries = 0 sleep_time = SLEEP_TIME_GROWTH while retries < rlimit: physinfo = xc.physinfo() free_mem = physinfo["free_memory"] scrub_mem = physinfo["scrub_memory"] if free_mem >= need_mem: log.debug("Balloon: %d KiB free; need %d; done.", free_mem, need_mem) return if retries == 0: rlimit += ((need_mem - free_mem) / 1024 / 1024) * RETRY_LIMIT_INCR log.debug( "Balloon: %d KiB free; %d to scrub; need %d; retries: %d.", free_mem, scrub_mem, need_mem, rlimit ) if dom0_ballooning: dom0_alloc = get_dom0_current_alloc() new_alloc = dom0_alloc - (need_mem - free_mem - scrub_mem) if free_mem + scrub_mem >= need_mem: if last_new_alloc == None: log.debug("Balloon: waiting on scrubbing") last_new_alloc = dom0_alloc else: if new_alloc >= dom0_min_mem and new_alloc != last_new_alloc: new_alloc_mb = new_alloc / 1024 # Round down log.debug("Balloon: setting dom0 target to %d MiB.", new_alloc_mb) dom0.setMemoryTarget(new_alloc_mb) last_new_alloc = new_alloc # Continue to retry, waiting for ballooning or scrubbing. time.sleep(sleep_time) if retries < 2 * RETRY_LIMIT: sleep_time += SLEEP_TIME_GROWTH if last_free != None and last_free >= free_mem + scrub_mem: retries += 1 last_free = free_mem + scrub_mem # Not enough memory; diagnose the problem. if not dom0_ballooning: raise VmError( ( "Not enough free memory and enable-dom0-ballooning " "is False, so I cannot release any more. " "I need %d KiB but only have %d." ) % (need_mem, free_mem) ) elif new_alloc < dom0_min_mem: raise VmError( ("I need %d KiB, but dom0_min_mem is %d and shrinking to " "%d KiB would leave only %d KiB free.") % (need_mem, dom0_min_mem, dom0_min_mem, free_mem + scrub_mem + dom0_alloc - dom0_min_mem) ) else: dom0_start_alloc_mb = get_dom0_current_alloc() / 1024 dom0.setMemoryTarget(dom0_start_alloc_mb) raise VmError(("Not enough memory is available, and dom0 cannot" " be shrunk any further")) finally: del xc
def free(required): """Balloon out memory from the privileged domain so that there is the specified required amount (in KiB) free. """ # We check whether there is enough free memory, and if not, instruct dom0 # to balloon out to free some up. Memory freed by a destroyed domain may # not appear in the free_memory field immediately, because it needs to be # scrubbed before it can be released to the free list, which is done # asynchronously by Xen; ballooning is asynchronous also. No matter where # we expect the free memory to come from, therefore, we need to wait for # it to become available. # # We are not allowed to balloon below dom0_min_mem, or if dom0_min_mem # is 0, we cannot balloon at all. Memory can still become available # through a rebooting domain, however. # # Eventually, we time out (presumably because there really isn't enough # free memory). # # We don't want to set the memory target (triggering a watch) when that # has already been done, but we do want to respond to changing memory # usage, so we recheck the required alloc each time around the loop, but # track the last used value so that we don't trigger too many watches. need_mem = (required + 1023) / 1024 + BALLOON_OUT_SLACK xroot = XendRoot.instance() xc = xen.lowlevel.xc.xc() try: dom0_min_mem = xroot.get_dom0_min_mem() retries = 0 sleep_time = SLEEP_TIME_GROWTH last_new_alloc = None while retries < RETRY_LIMIT: free_mem = xc.physinfo()['free_memory'] if free_mem >= need_mem: log.debug("Balloon: free %d; need %d; done.", free_mem, need_mem) return if retries == 0: log.debug("Balloon: free %d; need %d.", free_mem, need_mem) if dom0_min_mem > 0: dom0_alloc = get_dom0_current_alloc() new_alloc = dom0_alloc - (need_mem - free_mem) if (new_alloc >= dom0_min_mem and new_alloc != last_new_alloc): log.debug("Balloon: setting dom0 target to %d.", new_alloc) dom0 = XendDomain.instance().privilegedDomain() dom0.setMemoryTarget(new_alloc) last_new_alloc = new_alloc # Continue to retry, waiting for ballooning. time.sleep(sleep_time) retries += 1 sleep_time += SLEEP_TIME_GROWTH # Not enough memory; diagnose the problem. if dom0_min_mem == 0: raise VmError(('Not enough free memory and dom0_min_mem is 0, so ' 'I cannot release any more. I need %d MiB but ' 'only have %d.') % (need_mem, free_mem)) elif new_alloc < dom0_min_mem: raise VmError( ('I need %d MiB, but dom0_min_mem is %d and shrinking to ' '%d MiB would leave only %d MiB free.') % (need_mem, dom0_min_mem, dom0_min_mem, free_mem + dom0_alloc - dom0_min_mem)) else: raise VmError('The privileged domain did not balloon!') finally: del xc
def free(need_mem): """Balloon out memory from the privileged domain so that there is the specified required amount (in KiB) free. """ # We check whether there is enough free memory, and if not, instruct dom0 # to balloon out to free some up. Memory freed by a destroyed domain may # not appear in the free_memory field immediately, because it needs to be # scrubbed before it can be released to the free list, which is done # asynchronously by Xen; ballooning is asynchronous also. Such memory # does, however, need to be accounted for when calculating how much dom0 # needs to balloon. No matter where we expect the free memory to come # from, we need to wait for it to become available. # # We are not allowed to balloon below dom0_min_mem, or if dom0_min_mem # is 0, we cannot balloon at all. Memory can still become available # through a rebooting domain, however. # # Eventually, we time out (presumably because there really isn't enough # free memory). # # We don't want to set the memory target (triggering a watch) when that # has already been done, but we do want to respond to changing memory # usage, so we recheck the required alloc each time around the loop, but # track the last used value so that we don't trigger too many watches. xoptions = XendOptions.instance() dom0 = XendDomain.instance().privilegedDomain() xc = xen.lowlevel.xc.xc() dom0_start_alloc_mb = get_dom0_current_alloc() / 1024 try: dom0_min_mem = xoptions.get_dom0_min_mem() * 1024 dom0_alloc = get_dom0_current_alloc() retries = 0 sleep_time = SLEEP_TIME_GROWTH new_alloc = 0 last_new_alloc = None last_free = None rlimit = RETRY_LIMIT # If unreasonable memory size is required, we give up waiting # for ballooning or scrubbing, as if had retried. physinfo = xc.physinfo() free_mem = physinfo['free_memory'] scrub_mem = physinfo['scrub_memory'] total_mem = physinfo['total_memory'] if dom0_min_mem > 0: max_free_mem = total_mem - dom0_min_mem else: max_free_mem = total_mem - dom0_alloc if need_mem >= max_free_mem: retries = rlimit while retries < rlimit: physinfo = xc.physinfo() free_mem = physinfo['free_memory'] scrub_mem = physinfo['scrub_memory'] if free_mem >= need_mem: log.debug("Balloon: %d KiB free; need %d; done.", free_mem, need_mem) return if retries == 0: rlimit += ((need_mem - free_mem)/1024/1024) * RETRY_LIMIT_INCR log.debug("Balloon: %d KiB free; %d to scrub; need %d; retries: %d.", free_mem, scrub_mem, need_mem, rlimit) if dom0_min_mem > 0: dom0_alloc = get_dom0_current_alloc() new_alloc = dom0_alloc - (need_mem - free_mem - scrub_mem) if free_mem + scrub_mem >= need_mem: if last_new_alloc == None: log.debug("Balloon: waiting on scrubbing") last_new_alloc = dom0_alloc else: if (new_alloc >= dom0_min_mem and new_alloc != last_new_alloc): new_alloc_mb = new_alloc / 1024 # Round down log.debug("Balloon: setting dom0 target to %d MiB.", new_alloc_mb) dom0.setMemoryTarget(new_alloc_mb) last_new_alloc = new_alloc # Continue to retry, waiting for ballooning or scrubbing. time.sleep(sleep_time) if retries < 2 * RETRY_LIMIT: sleep_time += SLEEP_TIME_GROWTH if last_free != None and last_free >= free_mem + scrub_mem: retries += 1 last_free = free_mem + scrub_mem # Not enough memory; diagnose the problem. if dom0_min_mem == 0: raise VmError(('Not enough free memory and dom0_min_mem is 0, so ' 'I cannot release any more. I need %d KiB but ' 'only have %d.') % (need_mem, free_mem)) elif new_alloc < dom0_min_mem: raise VmError( ('I need %d KiB, but dom0_min_mem is %d and shrinking to ' '%d KiB would leave only %d KiB free.') % (need_mem, dom0_min_mem, dom0_min_mem, free_mem + scrub_mem + dom0_alloc - dom0_min_mem)) else: dom0.setMemoryTarget(dom0_start_alloc_mb) raise VmError( ('Not enough memory is available, and dom0 cannot' ' be shrunk any further')) finally: del xc