static int sched_credit2_domain_set(libxl__gc *gc, uint32_t domid, const libxl_domain_sched_params *scinfo) { struct xen_domctl_sched_credit2 sdom; int rc; rc = xc_sched_credit2_domain_get(CTX->xch, domid, &sdom); if (rc != 0) { LOGED(ERROR, domid, "Getting domain sched credit2"); return ERROR_FAIL; } if (scinfo->weight != LIBXL_DOMAIN_SCHED_PARAM_WEIGHT_DEFAULT) { if (scinfo->weight < 1 || scinfo->weight > 65535) { LOGD(ERROR, domid, "Cpu weight out of range, " "valid values are within range from 1 to 65535"); return ERROR_INVAL; } sdom.weight = scinfo->weight; } rc = xc_sched_credit2_domain_set(CTX->xch, domid, &sdom); if ( rc < 0 ) { LOGED(ERROR, domid, "Setting domain sched credit2"); return ERROR_FAIL; } return 0; }
static int sched_rtds_domain_set(libxl__gc *gc, uint32_t domid, const libxl_domain_sched_params *scinfo) { struct xen_domctl_sched_rtds sdom; int rc; rc = xc_sched_rtds_domain_get(CTX->xch, domid, &sdom); if (rc != 0) { LOGED(ERROR, domid, "Getting domain sched rtds"); return ERROR_FAIL; } if (scinfo->period != LIBXL_DOMAIN_SCHED_PARAM_PERIOD_DEFAULT) sdom.period = scinfo->period; if (scinfo->budget != LIBXL_DOMAIN_SCHED_PARAM_BUDGET_DEFAULT) sdom.budget = scinfo->budget; if (sched_rtds_validate_params(gc, sdom.period, sdom.budget)) return ERROR_INVAL; rc = xc_sched_rtds_domain_set(CTX->xch, domid, &sdom); if (rc < 0) { LOGED(ERROR, domid, "Setting domain sched rtds"); return ERROR_FAIL; } return 0; }
/* 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; }
/* Set the RTDS scheduling parameters of vcpu(s) */ static int sched_rtds_vcpu_set(libxl__gc *gc, uint32_t domid, const libxl_vcpu_sched_params *scinfo) { int r, rc; int i; uint16_t max_vcpuid; xc_dominfo_t info; struct xen_domctl_schedparam_vcpu *vcpus; r = xc_domain_getinfo(CTX->xch, domid, 1, &info); if (r < 0) { LOGED(ERROR, domid, "Getting domain info"); rc = ERROR_FAIL; goto out; } max_vcpuid = info.max_vcpu_id; if (scinfo->num_vcpus <= 0) { rc = ERROR_INVAL; goto out; } for (i = 0; i < scinfo->num_vcpus; i++) { if (scinfo->vcpus[i].vcpuid < 0 || scinfo->vcpus[i].vcpuid > max_vcpuid) { LOGD(ERROR, domid, "Invalid VCPU %d: valid range is [0, %d]", scinfo->vcpus[i].vcpuid, max_vcpuid); rc = ERROR_INVAL; goto out; } rc = sched_rtds_validate_params(gc, scinfo->vcpus[i].period, scinfo->vcpus[i].budget); if (rc) { rc = ERROR_INVAL; goto out; } } GCNEW_ARRAY(vcpus, scinfo->num_vcpus); for (i = 0; i < scinfo->num_vcpus; i++) { vcpus[i].vcpuid = scinfo->vcpus[i].vcpuid; vcpus[i].u.rtds.period = scinfo->vcpus[i].period; vcpus[i].u.rtds.budget = scinfo->vcpus[i].budget; } r = xc_sched_rtds_vcpu_set(CTX->xch, domid, vcpus, scinfo->num_vcpus); if (r != 0) { LOGED(ERROR, domid, "Setting vcpu sched rtds"); rc = ERROR_FAIL; goto out; } rc = 0; out: return rc; }
/* Get the RTDS scheduling parameters of vcpu(s) */ static int sched_rtds_vcpu_get(libxl__gc *gc, uint32_t domid, libxl_vcpu_sched_params *scinfo) { uint32_t num_vcpus; int i, r, rc; xc_dominfo_t info; struct xen_domctl_schedparam_vcpu *vcpus; r = xc_domain_getinfo(CTX->xch, domid, 1, &info); if (r < 0) { LOGED(ERROR, domid, "Getting domain info"); rc = ERROR_FAIL; goto out; } if (scinfo->num_vcpus <= 0) { rc = ERROR_INVAL; goto out; } else { num_vcpus = scinfo->num_vcpus; GCNEW_ARRAY(vcpus, num_vcpus); for (i = 0; i < num_vcpus; i++) { if (scinfo->vcpus[i].vcpuid < 0 || scinfo->vcpus[i].vcpuid > info.max_vcpu_id) { LOGD(ERROR, domid, "VCPU index is out of range, " "valid values are within range from 0 to %d", info.max_vcpu_id); rc = ERROR_INVAL; goto out; } vcpus[i].vcpuid = scinfo->vcpus[i].vcpuid; } } r = xc_sched_rtds_vcpu_get(CTX->xch, domid, vcpus, num_vcpus); if (r != 0) { LOGED(ERROR, domid, "Getting vcpu sched rtds"); rc = ERROR_FAIL; goto out; } scinfo->sched = LIBXL_SCHEDULER_RTDS; for (i = 0; i < num_vcpus; i++) { scinfo->vcpus[i].period = vcpus[i].u.rtds.period; scinfo->vcpus[i].budget = vcpus[i].u.rtds.budget; scinfo->vcpus[i].vcpuid = vcpus[i].vcpuid; } rc = 0; out: return rc; }
static int sched_credit_domain_set(libxl__gc *gc, uint32_t domid, const libxl_domain_sched_params *scinfo) { struct xen_domctl_sched_credit sdom; xc_domaininfo_t domaininfo; int rc; rc = xc_domain_getinfolist(CTX->xch, domid, 1, &domaininfo); if (rc < 0) { LOGED(ERROR, domid, "Getting domain info list"); return ERROR_FAIL; } if (rc != 1 || domaininfo.domain != domid) return ERROR_INVAL; rc = xc_sched_credit_domain_get(CTX->xch, domid, &sdom); if (rc != 0) { LOGED(ERROR, domid, "Getting domain sched credit"); return ERROR_FAIL; } if (scinfo->weight != LIBXL_DOMAIN_SCHED_PARAM_WEIGHT_DEFAULT) { if (scinfo->weight < 1 || scinfo->weight > 65535) { LOGD(ERROR, domid, "Cpu weight out of range, " "valid values are within range from 1 to 65535"); return ERROR_INVAL; } sdom.weight = scinfo->weight; } if (scinfo->cap != LIBXL_DOMAIN_SCHED_PARAM_CAP_DEFAULT) { if (scinfo->cap < 0 || scinfo->cap > (domaininfo.max_vcpu_id + 1) * 100) { LOGD(ERROR, domid, "Cpu cap out of range, " "valid range is from 0 to %d for specified number of vcpus", ((domaininfo.max_vcpu_id + 1) * 100)); return ERROR_INVAL; } sdom.cap = scinfo->cap; } rc = xc_sched_credit_domain_set(CTX->xch, domid, &sdom); if ( rc < 0 ) { LOGED(ERROR, domid, "Setting domain sched credit"); return ERROR_FAIL; } return 0; }
int libxl__set_domain_configuration(libxl__gc *gc, uint32_t domid, libxl_domain_config *d_config) { char *d_config_json; int rc; d_config_json = libxl_domain_config_to_json(CTX, d_config); if (!d_config_json) { LOGED(ERROR, domid, "failed to convert domain configuration to JSON"); rc = ERROR_FAIL; goto out; } rc = libxl__userdata_store(gc, domid, "libxl-json", (const uint8_t *)d_config_json, strlen(d_config_json) + 1 /* include '\0' */); if (rc) { LOGEVD(ERROR, rc, domid, "failed to store domain configuration"); rc = ERROR_FAIL; goto out; } out: free(d_config_json); return rc; }
/* Set the RTDS scheduling parameters of all vcpus of a domain */ static int sched_rtds_vcpu_set_all(libxl__gc *gc, uint32_t domid, const libxl_vcpu_sched_params *scinfo) { int r, rc; int i; uint16_t max_vcpuid; xc_dominfo_t info; struct xen_domctl_schedparam_vcpu *vcpus; uint32_t num_vcpus; r = xc_domain_getinfo(CTX->xch, domid, 1, &info); if (r < 0) { LOGED(ERROR, domid, "Getting domain info"); rc = ERROR_FAIL; goto out; } max_vcpuid = info.max_vcpu_id; if (scinfo->num_vcpus != 1) { rc = ERROR_INVAL; goto out; } if (sched_rtds_validate_params(gc, scinfo->vcpus[0].period, scinfo->vcpus[0].budget)) { rc = ERROR_INVAL; goto out; } num_vcpus = max_vcpuid + 1; GCNEW_ARRAY(vcpus, num_vcpus); for (i = 0; i < num_vcpus; i++) { vcpus[i].vcpuid = i; vcpus[i].u.rtds.period = scinfo->vcpus[0].period; vcpus[i].u.rtds.budget = scinfo->vcpus[0].budget; } r = xc_sched_rtds_vcpu_set(CTX->xch, domid, vcpus, num_vcpus); if (r != 0) { LOGED(ERROR, domid, "Setting vcpu sched rtds"); rc = ERROR_FAIL; goto out; } rc = 0; out: return rc; }
/* Get the RTDS scheduling parameters of all vcpus of a domain */ static int sched_rtds_vcpu_get_all(libxl__gc *gc, uint32_t domid, libxl_vcpu_sched_params *scinfo) { uint32_t num_vcpus; int i, r, rc; xc_dominfo_t info; struct xen_domctl_schedparam_vcpu *vcpus; r = xc_domain_getinfo(CTX->xch, domid, 1, &info); if (r < 0) { LOGED(ERROR, domid, "Getting domain info"); rc = ERROR_FAIL; goto out; } if (scinfo->num_vcpus > 0) { rc = ERROR_INVAL; goto out; } else { num_vcpus = info.max_vcpu_id + 1; GCNEW_ARRAY(vcpus, num_vcpus); for (i = 0; i < num_vcpus; i++) vcpus[i].vcpuid = i; } r = xc_sched_rtds_vcpu_get(CTX->xch, domid, vcpus, num_vcpus); if (r != 0) { LOGED(ERROR, domid, "Getting vcpu sched rtds"); rc = ERROR_FAIL; goto out; } scinfo->sched = LIBXL_SCHEDULER_RTDS; scinfo->num_vcpus = num_vcpus; scinfo->vcpus = libxl__calloc(NOGC, num_vcpus, sizeof(libxl_sched_params)); for (i = 0; i < num_vcpus; i++) { scinfo->vcpus[i].period = vcpus[i].u.rtds.period; scinfo->vcpus[i].budget = vcpus[i].u.rtds.budget; scinfo->vcpus[i].vcpuid = vcpus[i].vcpuid; } rc = 0; out: return rc; }
int libxl_domain_get_nodeaffinity(libxl_ctx *ctx, uint32_t domid, libxl_bitmap *nodemap) { GC_INIT(ctx); if (xc_domain_node_getaffinity(ctx->xch, domid, nodemap->map)) { LOGED(ERROR, domid, "Getting node affinity"); GC_FREE; return ERROR_FAIL; } GC_FREE; return 0; }
static int sched_credit2_domain_get(libxl__gc *gc, uint32_t domid, libxl_domain_sched_params *scinfo) { struct xen_domctl_sched_credit2 sdom; int rc; rc = xc_sched_credit2_domain_get(CTX->xch, domid, &sdom); if (rc != 0) { LOGED(ERROR, domid, "Getting domain sched credit2"); return ERROR_FAIL; } libxl_domain_sched_params_init(scinfo); scinfo->sched = LIBXL_SCHEDULER_CREDIT2; scinfo->weight = sdom.weight; return 0; }
static int sched_rtds_domain_get(libxl__gc *gc, uint32_t domid, libxl_domain_sched_params *scinfo) { struct xen_domctl_sched_rtds sdom; int rc; rc = xc_sched_rtds_domain_get(CTX->xch, domid, &sdom); if (rc != 0) { LOGED(ERROR, domid, "Getting domain sched rtds"); return ERROR_FAIL; } libxl_domain_sched_params_init(scinfo); scinfo->sched = LIBXL_SCHEDULER_RTDS; scinfo->period = sdom.period; scinfo->budget = sdom.budget; return 0; }
int libxl__arch_domain_create(libxl__gc *gc, libxl_domain_config *d_config, uint32_t domid) { int ret = 0; int tsc_mode; uint32_t rtc_timeoffset; libxl_ctx *ctx = libxl__gc_owner(gc); if (d_config->b_info.type == LIBXL_DOMAIN_TYPE_PV) xc_domain_set_memmap_limit(ctx->xch, domid, (d_config->b_info.max_memkb + d_config->b_info.u.pv.slack_memkb)); switch (d_config->b_info.tsc_mode) { case LIBXL_TSC_MODE_DEFAULT: tsc_mode = 0; break; case LIBXL_TSC_MODE_ALWAYS_EMULATE: tsc_mode = 1; break; case LIBXL_TSC_MODE_NATIVE: tsc_mode = 2; break; case LIBXL_TSC_MODE_NATIVE_PARAVIRT: tsc_mode = 3; break; default: abort(); } xc_domain_set_tsc_info(ctx->xch, domid, tsc_mode, 0, 0, 0); if (libxl_defbool_val(d_config->b_info.disable_migrate)) xc_domain_disable_migrate(ctx->xch, domid); rtc_timeoffset = d_config->b_info.rtc_timeoffset; if (libxl_defbool_val(d_config->b_info.localtime)) { time_t t; struct tm *tm, result; t = time(NULL); tm = localtime_r(&t, &result); if (!tm) { LOGED(ERROR, domid, "Failed to call localtime_r"); ret = ERROR_FAIL; goto out; } rtc_timeoffset += tm->tm_gmtoff; } if (rtc_timeoffset) xc_domain_set_time_offset(ctx->xch, domid, rtc_timeoffset); if (d_config->b_info.type == LIBXL_DOMAIN_TYPE_HVM) { unsigned long shadow = DIV_ROUNDUP(d_config->b_info.shadow_memkb, 1024); xc_shadow_control(ctx->xch, domid, XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION, NULL, 0, &shadow, 0, NULL); } if (d_config->c_info.type == LIBXL_DOMAIN_TYPE_PV && libxl_defbool_val(d_config->b_info.u.pv.e820_host)) { ret = libxl__e820_alloc(gc, domid, d_config); if (ret) { LOGED(ERROR, domid, "Failed while collecting E820 with: %d (errno:%d)\n", ret, errno); } } out: return ret; }
int libxl__domain_rename(libxl__gc *gc, uint32_t domid, const char *old_name, const char *new_name, xs_transaction_t trans) { libxl_ctx *ctx = libxl__gc_owner(gc); char *dom_path = 0; const char *name_path; char *got_old_name; unsigned int got_old_len; xs_transaction_t our_trans = 0; uint32_t stub_dm_domid; const char *stub_dm_old_name = NULL, *stub_dm_new_name = NULL; int rc; libxl_dominfo info; char *uuid; const char *vm_name_path; libxl_dominfo_init(&info); dom_path = libxl__xs_get_dompath(gc, domid); if (!dom_path) goto x_nomem; name_path= GCSPRINTF("%s/name", dom_path); if (!name_path) goto x_nomem; stub_dm_domid = libxl_get_stubdom_id(CTX, domid); if (stub_dm_domid) { stub_dm_old_name = libxl__stub_dm_name(gc, old_name); stub_dm_new_name = libxl__stub_dm_name(gc, new_name); } retry_transaction: if (!trans) { trans = our_trans = xs_transaction_start(ctx->xsh); if (!our_trans) { LOGEVD(ERROR, errno, domid, "Create xs transaction for domain (re)name"); goto x_fail; } } if (!new_name) { LOGD(ERROR, domid, "New domain name not specified"); rc = ERROR_INVAL; goto x_rc; } if (new_name[0]) { /* nonempty names must be unique */ uint32_t domid_e; rc = libxl_name_to_domid(ctx, new_name, &domid_e); if (rc == ERROR_INVAL) { /* no such domain, good */ } else if (rc != 0) { LOGD(ERROR, domid, "Unexpected error checking for existing domain"); goto x_rc; } else if (domid_e == domid) { /* domain already has this name, ok (but we do still * need the rest of the code as we may need to check * old_name, for example). */ } else { LOGD(ERROR, domid, "Domain with name \"%s\" already exists.", new_name); rc = ERROR_INVAL; goto x_rc; } } if (old_name) { got_old_name = xs_read(ctx->xsh, trans, name_path, &got_old_len); if (!got_old_name) { LOGEVD(ERROR, errno, domid, "Check old name for domain allegedly named `%s'", old_name); goto x_fail; } if (strcmp(old_name, got_old_name)) { LOGD(ERROR, domid, "Allegedly named `%s' is actually named `%s' - racing ?", old_name, got_old_name); free(got_old_name); goto x_fail; } free(got_old_name); } if (!xs_write(ctx->xsh, trans, name_path, new_name, strlen(new_name))) { LOGD(ERROR, domid, "Failed to write new name `%s'" " for domain previously named `%s'", new_name, old_name); goto x_fail; } /* update /vm/<uuid>/name */ rc = libxl_domain_info(ctx, &info, domid); if (rc) goto x_rc; uuid = GCSPRINTF(LIBXL_UUID_FMT, LIBXL_UUID_BYTES(info.uuid)); vm_name_path = GCSPRINTF("/vm/%s/name", uuid); if (libxl__xs_write_checked(gc, trans, vm_name_path, new_name)) goto x_fail; if (stub_dm_domid) { rc = libxl__domain_rename(gc, stub_dm_domid, stub_dm_old_name, stub_dm_new_name, trans); if (rc) { LOGED(ERROR, domid, "Unable to rename stub-domain"); goto x_rc; } } if (our_trans) { if (!xs_transaction_end(ctx->xsh, our_trans, 0)) { trans = our_trans = 0; if (errno != EAGAIN) { LOGD(ERROR, domid, "Failed to commit new name `%s'" " for domain previously named `%s'", new_name, old_name); goto x_fail; } LOGD(DEBUG, domid, "Need to retry rename transaction" " for domain (name_path=\"%s\", new_name=\"%s\")", name_path, new_name); goto retry_transaction; } our_trans = 0; } rc = 0; x_rc: if (our_trans) xs_transaction_end(ctx->xsh, our_trans, 1); libxl_dominfo_dispose(&info); return rc; x_fail: rc = ERROR_FAIL; goto x_rc; x_nomem: rc = ERROR_NOMEM; goto x_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; }
static int libxl__set_vcpuaffinity(libxl_ctx *ctx, uint32_t domid, uint32_t vcpuid, const libxl_bitmap *cpumap_hard, const libxl_bitmap *cpumap_soft, unsigned flags) { GC_INIT(ctx); libxl_bitmap hard, soft; int rc; libxl_bitmap_init(&hard); libxl_bitmap_init(&soft); if (!cpumap_hard && !cpumap_soft && !flags) { rc = ERROR_INVAL; goto out; } /* * Xen wants writable hard and/or soft cpumaps, to put back in them * the effective hard and/or soft affinity that will be used. */ if (cpumap_hard) { rc = libxl_cpu_bitmap_alloc(ctx, &hard, 0); if (rc) goto out; libxl__bitmap_copy_best_effort(gc, &hard, cpumap_hard); flags |= XEN_VCPUAFFINITY_HARD; } if (cpumap_soft) { rc = libxl_cpu_bitmap_alloc(ctx, &soft, 0); if (rc) goto out; libxl__bitmap_copy_best_effort(gc, &soft, cpumap_soft); flags |= XEN_VCPUAFFINITY_SOFT; } if (xc_vcpu_setaffinity(ctx->xch, domid, vcpuid, cpumap_hard ? hard.map : NULL, cpumap_soft ? soft.map : NULL, flags)) { LOGED(ERROR, domid, "Setting vcpu affinity"); rc = ERROR_FAIL; goto out; } /* * Let's check the results. Hard affinity will never be empty, but it * is possible that Xen will use something different from what we asked * for various reasons. If that's the case, report it. */ if (cpumap_hard && !libxl_bitmap_equal(cpumap_hard, &hard, 0)) LOGD(DEBUG, domid, "New hard affinity for vcpu %d has unreachable cpus", vcpuid); /* * Soft affinity can both be different from what asked and empty. Check * for (and report) both. */ if (cpumap_soft) { if (!libxl_bitmap_equal(cpumap_soft, &soft, 0)) LOGD(DEBUG, domid, "New soft affinity for vcpu %d has unreachable cpus", vcpuid); if (libxl_bitmap_is_empty(&soft)) LOGD(WARN, domid, "All cpus in soft affinity of vcpu %d are unreachable." " Only hard affinity will be considered for scheduling", vcpuid); } rc = 0; out: libxl_bitmap_dispose(&hard); libxl_bitmap_dispose(&soft); GC_FREE; return rc; }
/* * 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; }
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; }
/* Portability note: this lock utilises flock(2) so a proper implementation of * flock(2) is required. */ libxl__domain_userdata_lock *libxl__lock_domain_userdata(libxl__gc *gc, uint32_t domid) { libxl__domain_userdata_lock *lock = NULL; const char *lockfile; int fd; struct stat stab, fstab; lockfile = libxl__userdata_path(gc, domid, "domain-userdata-lock", "l"); if (!lockfile) goto out; lock = libxl__zalloc(NOGC, sizeof(libxl__domain_userdata_lock)); lock->path = libxl__strdup(NOGC, lockfile); while (true) { libxl__carefd_begin(); fd = open(lockfile, O_RDWR|O_CREAT, 0666); if (fd < 0) LOGED(ERROR, domid, "cannot open lockfile %s, errno=%d", lockfile, errno); lock->carefd = libxl__carefd_opened(CTX, fd); if (fd < 0) goto out; /* Lock the file in exclusive mode, wait indefinitely to * acquire the lock */ while (flock(fd, LOCK_EX)) { switch (errno) { case EINTR: /* Signal received, retry */ continue; default: /* All other errno: EBADF, EINVAL, ENOLCK, EWOULDBLOCK */ LOGED(ERROR, domid, "unexpected error while trying to lock %s, fd=%d, errno=%d", lockfile, fd, errno); goto out; } } if (fstat(fd, &fstab)) { LOGED(ERROR, domid, "cannot fstat %s, fd=%d, errno=%d", lockfile, fd, errno); goto out; } if (stat(lockfile, &stab)) { if (errno != ENOENT) { LOGED(ERROR, domid, "cannot stat %s, errno=%d", lockfile, errno); goto out; } } else { if (stab.st_dev == fstab.st_dev && stab.st_ino == fstab.st_ino) break; } libxl__carefd_close(lock->carefd); } /* Check the domain is still there, if not we should release the * lock and clean up. */ if (libxl_domain_info(CTX, NULL, domid)) goto out; return lock; out: if (lock) libxl__unlock_domain_userdata(lock); return NULL; }