Exemplo n.º 1
0
    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 {}
Exemplo n.º 2
0
 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())
Exemplo n.º 3
0
    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 {}
Exemplo n.º 4
0
 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())
Exemplo n.º 5
0
 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
Exemplo n.º 7
0
 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
Exemplo n.º 8
0
 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')
Exemplo n.º 9
0
 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')
Exemplo n.º 10
0
    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
Exemplo n.º 11
0
    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
Exemplo n.º 12
0
    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
Exemplo n.º 13
0
    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
Exemplo n.º 14
0
    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")
Exemplo n.º 15
0
    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")
Exemplo n.º 16
0
 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())
Exemplo n.º 17
0
    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.
Exemplo n.º 18
0
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
Exemplo n.º 19
0
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
Exemplo n.º 20
0
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
Exemplo n.º 21
0
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
Exemplo n.º 22
0
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
Exemplo n.º 23
0
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
Exemplo n.º 24
0
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
Exemplo n.º 25
0
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