mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
libxl: carve out memory specific functions from libxl.c
libxl.c has grown to an uncomfortable size. Carve out the memory related functions to libxl_mem.c. Signed-off-by: Juergen Gross <jgross@suse.com> Reviewed-by: Wei Liu <wei.liu2@citrix.com> Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
This commit is contained in:
1 parent
a99642bfee
commit
c8cbddd8d6
3 files changed
+602
-578
No files matched your search
@@ -137,7 +137,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
|
||||
libxl_qmp.o libxl_event.o libxl_fork.o \
|
||||
libxl_dom_suspend.o libxl_dom_save.o libxl_usb.o \
|
||||
libxl_vtpm.o libxl_nic.o libxl_disk.o libxl_console.o \
|
||||
libxl_cpupool.o libxl_sched.o \
|
||||
libxl_cpupool.o libxl_mem.o libxl_sched.o \
|
||||
$(LIBXL_OBJS-y)
|
||||
LIBXL_OBJS += libxl_genid.o
|
||||
LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "libxl_osdeps.h"
|
||||
|
||||
#include "libxl_internal.h"
|
||||
#include "libxl_arch.h"
|
||||
|
||||
#define PAGE_TO_MEMKB(pages) ((pages) * 4)
|
||||
|
||||
@@ -1952,582 +1951,6 @@ out:
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/*
|
||||
* Set the maximum memory size of the domain in the hypervisor. There is no
|
||||
* change of the current memory size involved. The specified memory size can
|
||||
* even be above the configured maxmem size of the domain, but the related
|
||||
* Xenstore entry memory/static-max isn't modified!
|
||||
*/
|
||||
int libxl_domain_setmaxmem(libxl_ctx *ctx, uint32_t domid, uint64_t max_memkb)
|
||||
{
|
||||
GC_INIT(ctx);
|
||||
char *mem, *endptr;
|
||||
uint64_t memorykb, size;
|
||||
char *dompath = libxl__xs_get_dompath(gc, domid);
|
||||
int rc = 1;
|
||||
libxl__domain_userdata_lock *lock = NULL;
|
||||
libxl_domain_config d_config;
|
||||
|
||||
libxl_domain_config_init(&d_config);
|
||||
|
||||
CTX_LOCK;
|
||||
|
||||
lock = libxl__lock_domain_userdata(gc, domid);
|
||||
if (!lock) {
|
||||
rc = ERROR_LOCK_FAIL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mem = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/memory/target", dompath));
|
||||
if (!mem) {
|
||||
LOGED(ERROR, domid, "Cannot get memory info from %s/memory/target",
|
||||
dompath);
|
||||
goto out;
|
||||
}
|
||||
memorykb = strtoull(mem, &endptr, 10);
|
||||
if (*endptr != '\0') {
|
||||
LOGED(ERROR, domid, "Invalid memory %s from %s/memory/target\n",
|
||||
mem, dompath);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (max_memkb < memorykb) {
|
||||
LOGED(ERROR, domid,
|
||||
"memory_static_max must be greater than or or equal to memory_dynamic_max");
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = libxl__get_domain_configuration(gc, domid, &d_config);
|
||||
if (rc < 0) {
|
||||
LOGE(ERROR, "unable to retrieve domain configuration");
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = libxl__arch_extra_memory(gc, &d_config.b_info, &size);
|
||||
if (rc < 0) {
|
||||
LOGE(ERROR, "Couldn't get arch extra constant memory size");
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = xc_domain_setmaxmem(ctx->xch, domid, max_memkb + size);
|
||||
if (rc != 0) {
|
||||
LOGED(ERROR, domid,
|
||||
"xc_domain_setmaxmem domid=%d memkb=%"PRIu64" failed ""rc=%d\n",
|
||||
domid, max_memkb + size, rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
out:
|
||||
libxl_domain_config_dispose(&d_config);
|
||||
if (lock) libxl__unlock_domain_userdata(lock);
|
||||
CTX_UNLOCK;
|
||||
GC_FREE;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int libxl__fill_dom0_memory_info(libxl__gc *gc, uint64_t *target_memkb,
|
||||
uint64_t *max_memkb)
|
||||
{
|
||||
int rc;
|
||||
libxl_dominfo info;
|
||||
libxl_physinfo physinfo;
|
||||
char *target = NULL, *staticmax = NULL, *endptr = NULL;
|
||||
char *target_path = "/local/domain/0/memory/target";
|
||||
char *max_path = "/local/domain/0/memory/static-max";
|
||||
xs_transaction_t t;
|
||||
libxl_ctx *ctx = libxl__gc_owner(gc);
|
||||
|
||||
libxl_dominfo_init(&info);
|
||||
|
||||
retry_transaction:
|
||||
t = xs_transaction_start(ctx->xsh);
|
||||
|
||||
target = libxl__xs_read(gc, t, target_path);
|
||||
staticmax = libxl__xs_read(gc, t, max_path);
|
||||
if (target && staticmax) {
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (target) {
|
||||
*target_memkb = strtoull(target, &endptr, 10);
|
||||
if (*endptr != '\0') {
|
||||
LOGED(ERROR, 0, "Invalid memory target %s from %s\n", target,
|
||||
target_path);
|
||||
rc = ERROR_FAIL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (staticmax) {
|
||||
*max_memkb = strtoull(staticmax, &endptr, 10);
|
||||
if (*endptr != '\0') {
|
||||
LOGED(ERROR, 0, "Invalid memory static-max %s from %s\n",
|
||||
staticmax,
|
||||
max_path);
|
||||
rc = ERROR_FAIL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
libxl_dominfo_dispose(&info);
|
||||
libxl_dominfo_init(&info);
|
||||
rc = libxl_domain_info(ctx, &info, 0);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
rc = libxl_get_physinfo(ctx, &physinfo);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
if (target == NULL) {
|
||||
libxl__xs_printf(gc, t, target_path, "%"PRIu64, info.current_memkb);
|
||||
*target_memkb = info.current_memkb;
|
||||
}
|
||||
if (staticmax == NULL) {
|
||||
libxl__xs_printf(gc, t, max_path, "%"PRIu64, info.max_memkb);
|
||||
*max_memkb = info.max_memkb;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
if (!xs_transaction_end(ctx->xsh, t, 0)) {
|
||||
if (errno == EAGAIN)
|
||||
goto retry_transaction;
|
||||
else
|
||||
rc = ERROR_FAIL;
|
||||
}
|
||||
|
||||
libxl_dominfo_dispose(&info);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int libxl_set_memory_target(libxl_ctx *ctx, uint32_t domid,
|
||||
int64_t target_memkb, int relative, int enforce)
|
||||
{
|
||||
GC_INIT(ctx);
|
||||
int rc, r, lrc, abort_transaction = 0;
|
||||
uint64_t memorykb, size;
|
||||
uint64_t videoram = 0;
|
||||
uint64_t current_target_memkb = 0, new_target_memkb = 0;
|
||||
uint64_t current_max_memkb = 0;
|
||||
char *memmax, *endptr, *videoram_s = NULL, *target = NULL;
|
||||
char *dompath = libxl__xs_get_dompath(gc, domid);
|
||||
xc_domaininfo_t info;
|
||||
libxl_dominfo ptr;
|
||||
char *uuid;
|
||||
xs_transaction_t t;
|
||||
libxl__domain_userdata_lock *lock;
|
||||
libxl_domain_config d_config;
|
||||
|
||||
libxl_domain_config_init(&d_config);
|
||||
|
||||
CTX_LOCK;
|
||||
|
||||
lock = libxl__lock_domain_userdata(gc, domid);
|
||||
if (!lock) {
|
||||
rc = ERROR_LOCK_FAIL;
|
||||
goto out_no_transaction;
|
||||
}
|
||||
|
||||
rc = libxl__get_domain_configuration(gc, domid, &d_config);
|
||||
if (rc < 0) {
|
||||
LOGE(ERROR, "unable to retrieve domain configuration");
|
||||
goto out_no_transaction;
|
||||
}
|
||||
|
||||
rc = libxl__arch_extra_memory(gc, &d_config.b_info, &size);
|
||||
if (rc < 0) {
|
||||
LOGE(ERROR, "Couldn't get arch extra constant memory size");
|
||||
goto out_no_transaction;
|
||||
}
|
||||
|
||||
retry_transaction:
|
||||
t = xs_transaction_start(ctx->xsh);
|
||||
|
||||
target = libxl__xs_read(gc, t, GCSPRINTF("%s/memory/target", dompath));
|
||||
if (!target && !domid) {
|
||||
if (!xs_transaction_end(ctx->xsh, t, 1)) {
|
||||
rc = ERROR_FAIL;
|
||||
goto out_no_transaction;
|
||||
}
|
||||
lrc = libxl__fill_dom0_memory_info(gc, ¤t_target_memkb,
|
||||
¤t_max_memkb);
|
||||
if (lrc < 0) { rc = ERROR_FAIL; goto out_no_transaction; }
|
||||
goto retry_transaction;
|
||||
} else if (!target) {
|
||||
LOGED(ERROR, domid, "Cannot get target memory info from %s/memory/target",
|
||||
dompath);
|
||||
abort_transaction = 1;
|
||||
rc = ERROR_FAIL;
|
||||
goto out;
|
||||
} else {
|
||||
current_target_memkb = strtoull(target, &endptr, 10);
|
||||
if (*endptr != '\0') {
|
||||
LOGED(ERROR, domid, "Invalid memory target %s from %s/memory/target\n",
|
||||
target, dompath);
|
||||
abort_transaction = 1;
|
||||
rc = ERROR_FAIL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
memmax = libxl__xs_read(gc, t, GCSPRINTF("%s/memory/static-max", dompath));
|
||||
if (!memmax) {
|
||||
LOGED(ERROR, domid, "Cannot get memory info from %s/memory/static-max",
|
||||
dompath);
|
||||
abort_transaction = 1;
|
||||
rc = ERROR_FAIL;
|
||||
goto out;
|
||||
}
|
||||
memorykb = strtoull(memmax, &endptr, 10);
|
||||
if (*endptr != '\0') {
|
||||
LOGED(ERROR, domid, "Invalid max memory %s from %s/memory/static-max\n",
|
||||
memmax, dompath);
|
||||
abort_transaction = 1;
|
||||
rc = ERROR_FAIL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
videoram_s = libxl__xs_read(gc, t, GCSPRINTF("%s/memory/videoram",
|
||||
dompath));
|
||||
videoram = videoram_s ? atoi(videoram_s) : 0;
|
||||
|
||||
if (relative) {
|
||||
if (target_memkb < 0 && llabs(target_memkb) > current_target_memkb)
|
||||
new_target_memkb = 0;
|
||||
else
|
||||
new_target_memkb = current_target_memkb + target_memkb;
|
||||
} else
|
||||
new_target_memkb = target_memkb - videoram;
|
||||
if (new_target_memkb > memorykb) {
|
||||
LOGD(ERROR, domid,
|
||||
"memory_dynamic_max must be less than or equal to"
|
||||
" memory_static_max\n");
|
||||
abort_transaction = 1;
|
||||
rc = ERROR_INVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!domid && new_target_memkb < LIBXL_MIN_DOM0_MEM) {
|
||||
LOGD(ERROR, domid,
|
||||
"New target %"PRIu64" for dom0 is below the minimum threshold",
|
||||
new_target_memkb);
|
||||
abort_transaction = 1;
|
||||
rc = ERROR_INVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (enforce) {
|
||||
memorykb = new_target_memkb + videoram;
|
||||
r = xc_domain_setmaxmem(ctx->xch, domid, memorykb + size);
|
||||
if (r != 0) {
|
||||
LOGED(ERROR, domid,
|
||||
"xc_domain_setmaxmem memkb=%"PRIu64" failed ""rc=%d\n",
|
||||
memorykb + size,
|
||||
r);
|
||||
abort_transaction = 1;
|
||||
rc = ERROR_FAIL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
r = xc_domain_set_pod_target(ctx->xch, domid,
|
||||
(new_target_memkb + size) / 4, NULL, NULL, NULL);
|
||||
if (r != 0) {
|
||||
LOGED(ERROR, domid,
|
||||
"xc_domain_set_pod_target memkb=%"PRIu64" failed rc=%d\n",
|
||||
(new_target_memkb + size) / 4,
|
||||
r);
|
||||
abort_transaction = 1;
|
||||
rc = ERROR_FAIL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
libxl__xs_printf(gc, t, GCSPRINTF("%s/memory/target", dompath),
|
||||
"%"PRIu64, new_target_memkb);
|
||||
|
||||
r = xc_domain_getinfolist(ctx->xch, domid, 1, &info);
|
||||
if (r != 1 || info.domain != domid) {
|
||||
abort_transaction = 1;
|
||||
rc = ERROR_FAIL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
libxl_dominfo_init(&ptr);
|
||||
libxl__xcinfo2xlinfo(ctx, &info, &ptr);
|
||||
uuid = libxl__uuid2string(gc, ptr.uuid);
|
||||
libxl__xs_printf(gc, t, GCSPRINTF("/vm/%s/memory", uuid),
|
||||
"%"PRIu64, new_target_memkb / 1024);
|
||||
libxl_dominfo_dispose(&ptr);
|
||||
|
||||
rc = 0;
|
||||
out:
|
||||
if (!xs_transaction_end(ctx->xsh, t, abort_transaction)
|
||||
&& !abort_transaction)
|
||||
if (errno == EAGAIN)
|
||||
goto retry_transaction;
|
||||
|
||||
out_no_transaction:
|
||||
libxl_domain_config_dispose(&d_config);
|
||||
if (lock) libxl__unlock_domain_userdata(lock);
|
||||
CTX_UNLOCK;
|
||||
GC_FREE;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* out_target_memkb and out_max_memkb can be NULL */
|
||||
int libxl__get_memory_target(libxl__gc *gc, uint32_t domid,
|
||||
uint64_t *out_target_memkb,
|
||||
uint64_t *out_max_memkb)
|
||||
{
|
||||
int rc;
|
||||
char *target = NULL, *static_max = NULL, *endptr = NULL;
|
||||
char *dompath = libxl__xs_get_dompath(gc, domid);
|
||||
uint64_t target_memkb, max_memkb;
|
||||
|
||||
target = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/memory/target",
|
||||
dompath));
|
||||
static_max = libxl__xs_read(gc, XBT_NULL,
|
||||
GCSPRINTF("%s/memory/static-max", dompath));
|
||||
|
||||
rc = ERROR_FAIL;
|
||||
if ((!target || !static_max) && !domid) {
|
||||
rc = libxl__fill_dom0_memory_info(gc, &target_memkb,
|
||||
&max_memkb);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
} else if (!target) {
|
||||
LOGED(ERROR, domid, "Cannot get target memory info from %s/memory/target",
|
||||
dompath);
|
||||
goto out;
|
||||
} else if (!static_max) {
|
||||
LOGED(ERROR, domid,
|
||||
"Cannot get target memory info from %s/memory/static-max",
|
||||
dompath);
|
||||
goto out;
|
||||
} else {
|
||||
target_memkb = strtoull(target, &endptr, 10);
|
||||
if (*endptr != '\0') {
|
||||
LOGED(ERROR, domid, "Invalid memory target %s from %s/memory/target\n",
|
||||
target, dompath);
|
||||
goto out;
|
||||
}
|
||||
max_memkb = strtoull(static_max, &endptr, 10);
|
||||
if (*endptr != '\0') {
|
||||
LOGED(ERROR, domid,
|
||||
"Invalid memory target %s from %s/memory/static-max\n",
|
||||
static_max,
|
||||
dompath);
|
||||
goto out;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (out_target_memkb)
|
||||
*out_target_memkb = target_memkb;
|
||||
|
||||
if (out_max_memkb)
|
||||
*out_max_memkb = max_memkb;
|
||||
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int libxl__memkb_64to32(libxl_ctx *ctx, int rc,
|
||||
uint64_t val64, uint32_t *ptr32)
|
||||
{
|
||||
GC_INIT(ctx);
|
||||
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
*ptr32 = val64;
|
||||
if (*ptr32 == val64)
|
||||
goto out;
|
||||
|
||||
LOGE(ERROR, "memory size %"PRIu64" too large for 32 bit value\n", val64);
|
||||
rc = ERROR_FAIL;
|
||||
|
||||
out:
|
||||
GC_FREE;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int libxl_get_memory_target(libxl_ctx *ctx, uint32_t domid,
|
||||
uint64_t *out_target)
|
||||
{
|
||||
GC_INIT(ctx);
|
||||
int rc;
|
||||
|
||||
rc = libxl__get_memory_target(gc, domid, out_target, NULL);
|
||||
|
||||
GC_FREE;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int libxl_get_memory_target_0x040700(
|
||||
libxl_ctx *ctx, uint32_t domid, uint32_t *out_target)
|
||||
{
|
||||
uint64_t my_out_target;
|
||||
int rc;
|
||||
|
||||
rc = libxl_get_memory_target(ctx, domid, &my_out_target);
|
||||
return libxl__memkb_64to32(ctx, rc, my_out_target, out_target);
|
||||
}
|
||||
|
||||
int libxl_domain_need_memory(libxl_ctx *ctx,
|
||||
const libxl_domain_build_info *b_info_in,
|
||||
uint64_t *need_memkb)
|
||||
{
|
||||
GC_INIT(ctx);
|
||||
libxl_domain_build_info b_info[1];
|
||||
int rc;
|
||||
|
||||
libxl_domain_build_info_init(b_info);
|
||||
libxl_domain_build_info_copy(ctx, b_info, b_info_in);
|
||||
|
||||
rc = libxl__domain_build_info_setdefault(gc, b_info);
|
||||
if (rc) goto out;
|
||||
|
||||
*need_memkb = b_info->target_memkb;
|
||||
switch (b_info->type) {
|
||||
case LIBXL_DOMAIN_TYPE_HVM:
|
||||
*need_memkb += b_info->shadow_memkb + LIBXL_HVM_EXTRA_MEMORY;
|
||||
if (libxl_defbool_val(b_info->device_model_stubdomain))
|
||||
*need_memkb += 32 * 1024;
|
||||
break;
|
||||
case LIBXL_DOMAIN_TYPE_PV:
|
||||
*need_memkb += b_info->shadow_memkb + LIBXL_PV_EXTRA_MEMORY;
|
||||
break;
|
||||
default:
|
||||
rc = ERROR_INVAL;
|
||||
goto out;
|
||||
}
|
||||
if (*need_memkb % (2 * 1024))
|
||||
*need_memkb += (2 * 1024) - (*need_memkb % (2 * 1024));
|
||||
rc = 0;
|
||||
out:
|
||||
GC_FREE;
|
||||
libxl_domain_build_info_dispose(b_info);
|
||||
return rc;
|
||||
|
||||
}
|
||||
|
||||
int libxl_domain_need_memory_0x040700(libxl_ctx *ctx,
|
||||
const libxl_domain_build_info *b_info_in,
|
||||
uint32_t *need_memkb)
|
||||
{
|
||||
uint64_t my_need_memkb;
|
||||
int rc;
|
||||
|
||||
rc = libxl_domain_need_memory(ctx, b_info_in, &my_need_memkb);
|
||||
return libxl__memkb_64to32(ctx, rc, my_need_memkb, need_memkb);
|
||||
}
|
||||
|
||||
int libxl_get_free_memory(libxl_ctx *ctx, uint64_t *memkb)
|
||||
{
|
||||
int rc = 0;
|
||||
libxl_physinfo info;
|
||||
GC_INIT(ctx);
|
||||
|
||||
rc = libxl_get_physinfo(ctx, &info);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
*memkb = (info.free_pages + info.scrub_pages) * 4;
|
||||
|
||||
out:
|
||||
GC_FREE;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int libxl_get_free_memory_0x040700(libxl_ctx *ctx, uint32_t *memkb)
|
||||
{
|
||||
uint64_t my_memkb;
|
||||
int rc;
|
||||
|
||||
rc = libxl_get_free_memory(ctx, &my_memkb);
|
||||
return libxl__memkb_64to32(ctx, rc, my_memkb, memkb);
|
||||
}
|
||||
|
||||
int libxl_wait_for_free_memory(libxl_ctx *ctx, uint32_t domid,
|
||||
uint64_t memory_kb, int wait_secs)
|
||||
{
|
||||
int rc = 0;
|
||||
libxl_physinfo info;
|
||||
GC_INIT(ctx);
|
||||
|
||||
while (wait_secs > 0) {
|
||||
rc = libxl_get_physinfo(ctx, &info);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
if (info.free_pages * 4 >= memory_kb) {
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
wait_secs--;
|
||||
sleep(1);
|
||||
}
|
||||
rc = ERROR_NOMEM;
|
||||
|
||||
out:
|
||||
GC_FREE;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int libxl_wait_for_memory_target(libxl_ctx *ctx, uint32_t domid, int wait_secs)
|
||||
{
|
||||
int rc = 0;
|
||||
uint64_t target_memkb = 0;
|
||||
uint64_t current_memkb, prev_memkb;
|
||||
libxl_dominfo info;
|
||||
|
||||
rc = libxl_get_memory_target(ctx, domid, &target_memkb);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
libxl_dominfo_init(&info);
|
||||
prev_memkb = UINT64_MAX;
|
||||
|
||||
do {
|
||||
sleep(2);
|
||||
|
||||
libxl_dominfo_dispose(&info);
|
||||
libxl_dominfo_init(&info);
|
||||
rc = libxl_domain_info(ctx, &info, domid);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
current_memkb = info.current_memkb + info.outstanding_memkb;
|
||||
|
||||
if (current_memkb > prev_memkb)
|
||||
{
|
||||
rc = ERROR_FAIL;
|
||||
goto out;
|
||||
}
|
||||
else if (current_memkb == prev_memkb)
|
||||
wait_secs -= 2;
|
||||
/* if current_memkb < prev_memkb loop for free as progress has
|
||||
* been made */
|
||||
|
||||
prev_memkb = current_memkb;
|
||||
} while (wait_secs > 0 && current_memkb > target_memkb);
|
||||
|
||||
if (current_memkb <= target_memkb)
|
||||
rc = 0;
|
||||
else
|
||||
rc = ERROR_FAIL;
|
||||
|
||||
out:
|
||||
libxl_dominfo_dispose(&info);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int libxl_get_physinfo(libxl_ctx *ctx, libxl_physinfo *physinfo)
|
||||
{
|
||||
xc_physinfo_t xcphysinfo = { 0 };
|
||||
|
||||
@@ -0,0 +1,601 @@
|
||||
/*
|
||||
* Copyright 2009-2017 Citrix Ltd and other contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation; version 2.1 only. with the special
|
||||
* exception on linking described in file LICENSE.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "libxl_osdeps.h"
|
||||
|
||||
#include "libxl_internal.h"
|
||||
#include "libxl_arch.h"
|
||||
|
||||
/*
|
||||
* Set the maximum memory size of the domain in the hypervisor. There is no
|
||||
* change of the current memory size involved. The specified memory size can
|
||||
* even be above the configured maxmem size of the domain, but the related
|
||||
* Xenstore entry memory/static-max isn't modified!
|
||||
*/
|
||||
int libxl_domain_setmaxmem(libxl_ctx *ctx, uint32_t domid, uint64_t max_memkb)
|
||||
{
|
||||
GC_INIT(ctx);
|
||||
char *mem, *endptr;
|
||||
uint64_t memorykb, size;
|
||||
char *dompath = libxl__xs_get_dompath(gc, domid);
|
||||
int rc = 1;
|
||||
libxl__domain_userdata_lock *lock = NULL;
|
||||
libxl_domain_config d_config;
|
||||
|
||||
libxl_domain_config_init(&d_config);
|
||||
|
||||
CTX_LOCK;
|
||||
|
||||
lock = libxl__lock_domain_userdata(gc, domid);
|
||||
if (!lock) {
|
||||
rc = ERROR_LOCK_FAIL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mem = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/memory/target", dompath));
|
||||
if (!mem) {
|
||||
LOGED(ERROR, domid, "Cannot get memory info from %s/memory/target",
|
||||
dompath);
|
||||
goto out;
|
||||
}
|
||||
memorykb = strtoull(mem, &endptr, 10);
|
||||
if (*endptr != '\0') {
|
||||
LOGED(ERROR, domid, "Invalid memory %s from %s/memory/target\n",
|
||||
mem, dompath);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (max_memkb < memorykb) {
|
||||
LOGED(ERROR, domid,
|
||||
"memory_static_max must be greater than or or equal to memory_dynamic_max");
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = libxl__get_domain_configuration(gc, domid, &d_config);
|
||||
if (rc < 0) {
|
||||
LOGE(ERROR, "unable to retrieve domain configuration");
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = libxl__arch_extra_memory(gc, &d_config.b_info, &size);
|
||||
if (rc < 0) {
|
||||
LOGE(ERROR, "Couldn't get arch extra constant memory size");
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = xc_domain_setmaxmem(ctx->xch, domid, max_memkb + size);
|
||||
if (rc != 0) {
|
||||
LOGED(ERROR, domid,
|
||||
"xc_domain_setmaxmem domid=%d memkb=%"PRIu64" failed ""rc=%d\n",
|
||||
domid, max_memkb + size, rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
out:
|
||||
libxl_domain_config_dispose(&d_config);
|
||||
if (lock) libxl__unlock_domain_userdata(lock);
|
||||
CTX_UNLOCK;
|
||||
GC_FREE;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int libxl__fill_dom0_memory_info(libxl__gc *gc, uint64_t *target_memkb,
|
||||
uint64_t *max_memkb)
|
||||
{
|
||||
int rc;
|
||||
libxl_dominfo info;
|
||||
libxl_physinfo physinfo;
|
||||
char *target = NULL, *staticmax = NULL, *endptr = NULL;
|
||||
char *target_path = "/local/domain/0/memory/target";
|
||||
char *max_path = "/local/domain/0/memory/static-max";
|
||||
xs_transaction_t t;
|
||||
libxl_ctx *ctx = libxl__gc_owner(gc);
|
||||
|
||||
libxl_dominfo_init(&info);
|
||||
|
||||
retry_transaction:
|
||||
t = xs_transaction_start(ctx->xsh);
|
||||
|
||||
target = libxl__xs_read(gc, t, target_path);
|
||||
staticmax = libxl__xs_read(gc, t, max_path);
|
||||
if (target && staticmax) {
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (target) {
|
||||
*target_memkb = strtoull(target, &endptr, 10);
|
||||
if (*endptr != '\0') {
|
||||
LOGED(ERROR, 0, "Invalid memory target %s from %s\n", target,
|
||||
target_path);
|
||||
rc = ERROR_FAIL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (staticmax) {
|
||||
*max_memkb = strtoull(staticmax, &endptr, 10);
|
||||
if (*endptr != '\0') {
|
||||
LOGED(ERROR, 0, "Invalid memory static-max %s from %s\n",
|
||||
staticmax,
|
||||
max_path);
|
||||
rc = ERROR_FAIL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
libxl_dominfo_dispose(&info);
|
||||
libxl_dominfo_init(&info);
|
||||
rc = libxl_domain_info(ctx, &info, 0);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
rc = libxl_get_physinfo(ctx, &physinfo);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
if (target == NULL) {
|
||||
libxl__xs_printf(gc, t, target_path, "%"PRIu64, info.current_memkb);
|
||||
*target_memkb = info.current_memkb;
|
||||
}
|
||||
if (staticmax == NULL) {
|
||||
libxl__xs_printf(gc, t, max_path, "%"PRIu64, info.max_memkb);
|
||||
*max_memkb = info.max_memkb;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
if (!xs_transaction_end(ctx->xsh, t, 0)) {
|
||||
if (errno == EAGAIN)
|
||||
goto retry_transaction;
|
||||
else
|
||||
rc = ERROR_FAIL;
|
||||
}
|
||||
|
||||
libxl_dominfo_dispose(&info);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int libxl_set_memory_target(libxl_ctx *ctx, uint32_t domid,
|
||||
int64_t target_memkb, int relative, int enforce)
|
||||
{
|
||||
GC_INIT(ctx);
|
||||
int rc, r, lrc, abort_transaction = 0;
|
||||
uint64_t memorykb, size;
|
||||
uint64_t videoram = 0;
|
||||
uint64_t current_target_memkb = 0, new_target_memkb = 0;
|
||||
uint64_t current_max_memkb = 0;
|
||||
char *memmax, *endptr, *videoram_s = NULL, *target = NULL;
|
||||
char *dompath = libxl__xs_get_dompath(gc, domid);
|
||||
xc_domaininfo_t info;
|
||||
libxl_dominfo ptr;
|
||||
char *uuid;
|
||||
xs_transaction_t t;
|
||||
libxl__domain_userdata_lock *lock;
|
||||
libxl_domain_config d_config;
|
||||
|
||||
libxl_domain_config_init(&d_config);
|
||||
|
||||
CTX_LOCK;
|
||||
|
||||
lock = libxl__lock_domain_userdata(gc, domid);
|
||||
if (!lock) {
|
||||
rc = ERROR_LOCK_FAIL;
|
||||
goto out_no_transaction;
|
||||
}
|
||||
|
||||
rc = libxl__get_domain_configuration(gc, domid, &d_config);
|
||||
if (rc < 0) {
|
||||
LOGE(ERROR, "unable to retrieve domain configuration");
|
||||
goto out_no_transaction;
|
||||
}
|
||||
|
||||
rc = libxl__arch_extra_memory(gc, &d_config.b_info, &size);
|
||||
if (rc < 0) {
|
||||
LOGE(ERROR, "Couldn't get arch extra constant memory size");
|
||||
goto out_no_transaction;
|
||||
}
|
||||
|
||||
retry_transaction:
|
||||
t = xs_transaction_start(ctx->xsh);
|
||||
|
||||
target = libxl__xs_read(gc, t, GCSPRINTF("%s/memory/target", dompath));
|
||||
if (!target && !domid) {
|
||||
if (!xs_transaction_end(ctx->xsh, t, 1)) {
|
||||
rc = ERROR_FAIL;
|
||||
goto out_no_transaction;
|
||||
}
|
||||
lrc = libxl__fill_dom0_memory_info(gc, ¤t_target_memkb,
|
||||
¤t_max_memkb);
|
||||
if (lrc < 0) { rc = ERROR_FAIL; goto out_no_transaction; }
|
||||
goto retry_transaction;
|
||||
} else if (!target) {
|
||||
LOGED(ERROR, domid, "Cannot get target memory info from %s/memory/target",
|
||||
dompath);
|
||||
abort_transaction = 1;
|
||||
rc = ERROR_FAIL;
|
||||
goto out;
|
||||
} else {
|
||||
current_target_memkb = strtoull(target, &endptr, 10);
|
||||
if (*endptr != '\0') {
|
||||
LOGED(ERROR, domid, "Invalid memory target %s from %s/memory/target\n",
|
||||
target, dompath);
|
||||
abort_transaction = 1;
|
||||
rc = ERROR_FAIL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
memmax = libxl__xs_read(gc, t, GCSPRINTF("%s/memory/static-max", dompath));
|
||||
if (!memmax) {
|
||||
LOGED(ERROR, domid, "Cannot get memory info from %s/memory/static-max",
|
||||
dompath);
|
||||
abort_transaction = 1;
|
||||
rc = ERROR_FAIL;
|
||||
goto out;
|
||||
}
|
||||
memorykb = strtoull(memmax, &endptr, 10);
|
||||
if (*endptr != '\0') {
|
||||
LOGED(ERROR, domid, "Invalid max memory %s from %s/memory/static-max\n",
|
||||
memmax, dompath);
|
||||
abort_transaction = 1;
|
||||
rc = ERROR_FAIL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
videoram_s = libxl__xs_read(gc, t, GCSPRINTF("%s/memory/videoram",
|
||||
dompath));
|
||||
videoram = videoram_s ? atoi(videoram_s) : 0;
|
||||
|
||||
if (relative) {
|
||||
if (target_memkb < 0 && llabs(target_memkb) > current_target_memkb)
|
||||
new_target_memkb = 0;
|
||||
else
|
||||
new_target_memkb = current_target_memkb + target_memkb;
|
||||
} else
|
||||
new_target_memkb = target_memkb - videoram;
|
||||
if (new_target_memkb > memorykb) {
|
||||
LOGD(ERROR, domid,
|
||||
"memory_dynamic_max must be less than or equal to"
|
||||
" memory_static_max\n");
|
||||
abort_transaction = 1;
|
||||
rc = ERROR_INVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!domid && new_target_memkb < LIBXL_MIN_DOM0_MEM) {
|
||||
LOGD(ERROR, domid,
|
||||
"New target %"PRIu64" for dom0 is below the minimum threshold",
|
||||
new_target_memkb);
|
||||
abort_transaction = 1;
|
||||
rc = ERROR_INVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (enforce) {
|
||||
memorykb = new_target_memkb + videoram;
|
||||
r = xc_domain_setmaxmem(ctx->xch, domid, memorykb + size);
|
||||
if (r != 0) {
|
||||
LOGED(ERROR, domid,
|
||||
"xc_domain_setmaxmem memkb=%"PRIu64" failed ""rc=%d\n",
|
||||
memorykb + size,
|
||||
r);
|
||||
abort_transaction = 1;
|
||||
rc = ERROR_FAIL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
r = xc_domain_set_pod_target(ctx->xch, domid,
|
||||
(new_target_memkb + size) / 4, NULL, NULL, NULL);
|
||||
if (r != 0) {
|
||||
LOGED(ERROR, domid,
|
||||
"xc_domain_set_pod_target memkb=%"PRIu64" failed rc=%d\n",
|
||||
(new_target_memkb + size) / 4,
|
||||
r);
|
||||
abort_transaction = 1;
|
||||
rc = ERROR_FAIL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
libxl__xs_printf(gc, t, GCSPRINTF("%s/memory/target", dompath),
|
||||
"%"PRIu64, new_target_memkb);
|
||||
|
||||
r = xc_domain_getinfolist(ctx->xch, domid, 1, &info);
|
||||
if (r != 1 || info.domain != domid) {
|
||||
abort_transaction = 1;
|
||||
rc = ERROR_FAIL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
libxl_dominfo_init(&ptr);
|
||||
libxl__xcinfo2xlinfo(ctx, &info, &ptr);
|
||||
uuid = libxl__uuid2string(gc, ptr.uuid);
|
||||
libxl__xs_printf(gc, t, GCSPRINTF("/vm/%s/memory", uuid),
|
||||
"%"PRIu64, new_target_memkb / 1024);
|
||||
libxl_dominfo_dispose(&ptr);
|
||||
|
||||
rc = 0;
|
||||
out:
|
||||
if (!xs_transaction_end(ctx->xsh, t, abort_transaction)
|
||||
&& !abort_transaction)
|
||||
if (errno == EAGAIN)
|
||||
goto retry_transaction;
|
||||
|
||||
out_no_transaction:
|
||||
libxl_domain_config_dispose(&d_config);
|
||||
if (lock) libxl__unlock_domain_userdata(lock);
|
||||
CTX_UNLOCK;
|
||||
GC_FREE;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* out_target_memkb and out_max_memkb can be NULL */
|
||||
int libxl__get_memory_target(libxl__gc *gc, uint32_t domid,
|
||||
uint64_t *out_target_memkb,
|
||||
uint64_t *out_max_memkb)
|
||||
{
|
||||
int rc;
|
||||
char *target = NULL, *static_max = NULL, *endptr = NULL;
|
||||
char *dompath = libxl__xs_get_dompath(gc, domid);
|
||||
uint64_t target_memkb, max_memkb;
|
||||
|
||||
target = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/memory/target",
|
||||
dompath));
|
||||
static_max = libxl__xs_read(gc, XBT_NULL,
|
||||
GCSPRINTF("%s/memory/static-max", dompath));
|
||||
|
||||
rc = ERROR_FAIL;
|
||||
if ((!target || !static_max) && !domid) {
|
||||
rc = libxl__fill_dom0_memory_info(gc, &target_memkb,
|
||||
&max_memkb);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
} else if (!target) {
|
||||
LOGED(ERROR, domid, "Cannot get target memory info from %s/memory/target",
|
||||
dompath);
|
||||
goto out;
|
||||
} else if (!static_max) {
|
||||
LOGED(ERROR, domid,
|
||||
"Cannot get target memory info from %s/memory/static-max",
|
||||
dompath);
|
||||
goto out;
|
||||
} else {
|
||||
target_memkb = strtoull(target, &endptr, 10);
|
||||
if (*endptr != '\0') {
|
||||
LOGED(ERROR, domid, "Invalid memory target %s from %s/memory/target\n",
|
||||
target, dompath);
|
||||
goto out;
|
||||
}
|
||||
max_memkb = strtoull(static_max, &endptr, 10);
|
||||
if (*endptr != '\0') {
|
||||
LOGED(ERROR, domid,
|
||||
"Invalid memory target %s from %s/memory/static-max\n",
|
||||
static_max,
|
||||
dompath);
|
||||
goto out;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (out_target_memkb)
|
||||
*out_target_memkb = target_memkb;
|
||||
|
||||
if (out_max_memkb)
|
||||
*out_max_memkb = max_memkb;
|
||||
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int libxl__memkb_64to32(libxl_ctx *ctx, int rc,
|
||||
uint64_t val64, uint32_t *ptr32)
|
||||
{
|
||||
GC_INIT(ctx);
|
||||
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
*ptr32 = val64;
|
||||
if (*ptr32 == val64)
|
||||
goto out;
|
||||
|
||||
LOGE(ERROR, "memory size %"PRIu64" too large for 32 bit value\n", val64);
|
||||
rc = ERROR_FAIL;
|
||||
|
||||
out:
|
||||
GC_FREE;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int libxl_get_memory_target(libxl_ctx *ctx, uint32_t domid,
|
||||
uint64_t *out_target)
|
||||
{
|
||||
GC_INIT(ctx);
|
||||
int rc;
|
||||
|
||||
rc = libxl__get_memory_target(gc, domid, out_target, NULL);
|
||||
|
||||
GC_FREE;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int libxl_get_memory_target_0x040700(
|
||||
libxl_ctx *ctx, uint32_t domid, uint32_t *out_target)
|
||||
{
|
||||
uint64_t my_out_target;
|
||||
int rc;
|
||||
|
||||
rc = libxl_get_memory_target(ctx, domid, &my_out_target);
|
||||
return libxl__memkb_64to32(ctx, rc, my_out_target, out_target);
|
||||
}
|
||||
|
||||
int libxl_domain_need_memory(libxl_ctx *ctx,
|
||||
const libxl_domain_build_info *b_info_in,
|
||||
uint64_t *need_memkb)
|
||||
{
|
||||
GC_INIT(ctx);
|
||||
libxl_domain_build_info b_info[1];
|
||||
int rc;
|
||||
|
||||
libxl_domain_build_info_init(b_info);
|
||||
libxl_domain_build_info_copy(ctx, b_info, b_info_in);
|
||||
|
||||
rc = libxl__domain_build_info_setdefault(gc, b_info);
|
||||
if (rc) goto out;
|
||||
|
||||
*need_memkb = b_info->target_memkb;
|
||||
switch (b_info->type) {
|
||||
case LIBXL_DOMAIN_TYPE_HVM:
|
||||
*need_memkb += b_info->shadow_memkb + LIBXL_HVM_EXTRA_MEMORY;
|
||||
if (libxl_defbool_val(b_info->device_model_stubdomain))
|
||||
*need_memkb += 32 * 1024;
|
||||
break;
|
||||
case LIBXL_DOMAIN_TYPE_PV:
|
||||
*need_memkb += b_info->shadow_memkb + LIBXL_PV_EXTRA_MEMORY;
|
||||
break;
|
||||
default:
|
||||
rc = ERROR_INVAL;
|
||||
goto out;
|
||||
}
|
||||
if (*need_memkb % (2 * 1024))
|
||||
*need_memkb += (2 * 1024) - (*need_memkb % (2 * 1024));
|
||||
rc = 0;
|
||||
out:
|
||||
GC_FREE;
|
||||
libxl_domain_build_info_dispose(b_info);
|
||||
return rc;
|
||||
|
||||
}
|
||||
|
||||
int libxl_domain_need_memory_0x040700(libxl_ctx *ctx,
|
||||
const libxl_domain_build_info *b_info_in,
|
||||
uint32_t *need_memkb)
|
||||
{
|
||||
uint64_t my_need_memkb;
|
||||
int rc;
|
||||
|
||||
rc = libxl_domain_need_memory(ctx, b_info_in, &my_need_memkb);
|
||||
return libxl__memkb_64to32(ctx, rc, my_need_memkb, need_memkb);
|
||||
}
|
||||
|
||||
int libxl_get_free_memory(libxl_ctx *ctx, uint64_t *memkb)
|
||||
{
|
||||
int rc = 0;
|
||||
libxl_physinfo info;
|
||||
GC_INIT(ctx);
|
||||
|
||||
rc = libxl_get_physinfo(ctx, &info);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
*memkb = (info.free_pages + info.scrub_pages) * 4;
|
||||
|
||||
out:
|
||||
GC_FREE;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int libxl_get_free_memory_0x040700(libxl_ctx *ctx, uint32_t *memkb)
|
||||
{
|
||||
uint64_t my_memkb;
|
||||
int rc;
|
||||
|
||||
rc = libxl_get_free_memory(ctx, &my_memkb);
|
||||
return libxl__memkb_64to32(ctx, rc, my_memkb, memkb);
|
||||
}
|
||||
|
||||
int libxl_wait_for_free_memory(libxl_ctx *ctx, uint32_t domid,
|
||||
uint64_t memory_kb, int wait_secs)
|
||||
{
|
||||
int rc = 0;
|
||||
libxl_physinfo info;
|
||||
GC_INIT(ctx);
|
||||
|
||||
while (wait_secs > 0) {
|
||||
rc = libxl_get_physinfo(ctx, &info);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
if (info.free_pages * 4 >= memory_kb) {
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
wait_secs--;
|
||||
sleep(1);
|
||||
}
|
||||
rc = ERROR_NOMEM;
|
||||
|
||||
out:
|
||||
GC_FREE;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int libxl_wait_for_memory_target(libxl_ctx *ctx, uint32_t domid, int wait_secs)
|
||||
{
|
||||
int rc = 0;
|
||||
uint64_t target_memkb = 0;
|
||||
uint64_t current_memkb, prev_memkb;
|
||||
libxl_dominfo info;
|
||||
|
||||
rc = libxl_get_memory_target(ctx, domid, &target_memkb);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
libxl_dominfo_init(&info);
|
||||
prev_memkb = UINT64_MAX;
|
||||
|
||||
do {
|
||||
sleep(2);
|
||||
|
||||
libxl_dominfo_dispose(&info);
|
||||
libxl_dominfo_init(&info);
|
||||
rc = libxl_domain_info(ctx, &info, domid);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
current_memkb = info.current_memkb + info.outstanding_memkb;
|
||||
|
||||
if (current_memkb > prev_memkb)
|
||||
{
|
||||
rc = ERROR_FAIL;
|
||||
goto out;
|
||||
}
|
||||
else if (current_memkb == prev_memkb)
|
||||
wait_secs -= 2;
|
||||
/* if current_memkb < prev_memkb loop for free as progress has
|
||||
* been made */
|
||||
|
||||
prev_memkb = current_memkb;
|
||||
} while (wait_secs > 0 && current_memkb > target_memkb);
|
||||
|
||||
if (current_memkb <= target_memkb)
|
||||
rc = 0;
|
||||
else
|
||||
rc = ERROR_FAIL;
|
||||
|
||||
out:
|
||||
libxl_dominfo_dispose(&info);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||