Files
xen/tools/xl/xl_cpupool.c
Anthony PERARD fded24ea83 libxl: Make libxl_set_vcpuonline async
.. because it makes QMP calls which are going to be async.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
2019-09-20 10:41:01 +01:00

625 lines
17 KiB
C

/*
* 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 <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include <libxl.h>
#include <libxl_utils.h>
#include <libxlutil.h>
#include "xl.h"
#include "xl_utils.h"
#include "xl_parse.h"
int main_cpupoolcreate(int argc, char **argv)
{
const char *filename = NULL, *config_src=NULL;
const char *p;
char *extra_config = NULL;
int opt;
static struct option opts[] = {
{"defconfig", 1, 0, 'f'},
{"dryrun", 0, 0, 'n'},
COMMON_LONG_OPTS
};
int ret;
char *config_data = 0;
int config_len = 0;
XLU_Config *config;
const char *buf;
char *name = NULL;
uint32_t poolid;
libxl_scheduler sched = 0;
XLU_ConfigList *cpus;
XLU_ConfigList *nodes;
int n_cpus, n_nodes, i, n;
libxl_bitmap freemap;
libxl_bitmap cpumap;
libxl_uuid uuid;
libxl_cputopology *topology;
int rc = EXIT_FAILURE;
SWITCH_FOREACH_OPT(opt, "nf:", opts, "cpupool-create", 0) {
case 'f':
filename = optarg;
break;
case 'n':
dryrun_only = 1;
break;
}
libxl_bitmap_init(&freemap);
libxl_bitmap_init(&cpumap);
while (optind < argc) {
if ((p = strchr(argv[optind], '='))) {
string_realloc_append(&extra_config, "\n");
string_realloc_append(&extra_config, argv[optind]);
} else if (!filename) {
filename = argv[optind];
} else {
help("cpupool-create");
goto out;
}
optind++;
}
if (filename)
{
if (libxl_read_file_contents(ctx, filename, (void **)&config_data,
&config_len)) {
fprintf(stderr, "Failed to read config file: %s: %s\n",
filename, strerror(errno));
goto out;
}
config_src=filename;
}
else
config_src="command line";
if (extra_config && strlen(extra_config)) {
if (config_len > INT_MAX - (strlen(extra_config) + 2)) {
fprintf(stderr, "Failed to attach extra configuration\n");
goto out;
}
config_data = xrealloc(config_data,
config_len + strlen(extra_config) + 2);
if (!config_data) {
fprintf(stderr, "Failed to realloc config_data\n");
goto out;
}
config_data[config_len] = 0;
strcat(config_data, extra_config);
strcat(config_data, "\n");
config_len += strlen(extra_config) + 1;
}
config = xlu_cfg_init(stderr, config_src);
if (!config) {
fprintf(stderr, "Failed to allocate for configuration\n");
goto out;
}
ret = xlu_cfg_readdata(config, config_data, config_len);
if (ret) {
fprintf(stderr, "Failed to parse config file: %s\n", strerror(ret));
goto out_cfg;
}
if (!xlu_cfg_get_string (config, "name", &buf, 0))
name = strdup(buf);
else if (filename)
name = libxl_basename(filename);
else {
fprintf(stderr, "Missing cpupool name!\n");
goto out_cfg;
}
if (!libxl_name_to_cpupoolid(ctx, name, &poolid)) {
fprintf(stderr, "Pool name \"%s\" already exists\n", name);
goto out_cfg;
}
if (!xlu_cfg_get_string (config, "sched", &buf, 0)) {
if ((libxl_scheduler_from_string(buf, &sched)) < 0) {
fprintf(stderr, "Unknown scheduler\n");
goto out_cfg;
}
} else {
rc = libxl_get_scheduler(ctx);
if (rc < 0) {
fprintf(stderr, "get_scheduler sysctl failed.\n");
goto out_cfg;
}
sched = rc;
}
if (libxl_get_freecpus(ctx, &freemap)) {
fprintf(stderr, "libxl_get_freecpus failed\n");
goto out_cfg;
}
if (libxl_cpu_bitmap_alloc(ctx, &cpumap, 0)) {
fprintf(stderr, "Failed to allocate cpumap\n");
goto out_cfg;
}
if (!xlu_cfg_get_list(config, "nodes", &nodes, 0, 0)) {
int nr;
n_cpus = 0;
n_nodes = 0;
topology = libxl_get_cpu_topology(ctx, &nr);
if (topology == NULL) {
fprintf(stderr, "libxl_get_topologyinfo failed\n");
goto out_cfg;
}
while ((buf = xlu_cfg_get_listitem(nodes, n_nodes)) != NULL) {
n = atoi(buf);
for (i = 0; i < nr; i++) {
if ((topology[i].node == n) &&
libxl_bitmap_test(&freemap, i)) {
libxl_bitmap_set(&cpumap, i);
n_cpus++;
}
}
n_nodes++;
}
libxl_cputopology_list_free(topology, nr);
if (n_cpus == 0) {
fprintf(stderr, "no free cpu found\n");
goto out_cfg;
}
} else if (!xlu_cfg_get_list(config, "cpus", &cpus, 0, 1)) {
n_cpus = 0;
while ((buf = xlu_cfg_get_listitem(cpus, n_cpus)) != NULL) {
i = atoi(buf);
if ((i < 0) || !libxl_bitmap_test(&freemap, i)) {
fprintf(stderr, "cpu %d illegal or not free\n", i);
goto out_cfg;
}
libxl_bitmap_set(&cpumap, i);
n_cpus++;
}
} else if (!xlu_cfg_get_string(config, "cpus", &buf, 0)) {
if (parse_cpurange(buf, &cpumap))
goto out_cfg;
n_cpus = 0;
libxl_for_each_set_bit(i, cpumap) {
if (!libxl_bitmap_test(&freemap, i)) {
fprintf(stderr, "cpu %d illegal or not free\n", i);
goto out_cfg;
}
n_cpus++;
}
} else
n_cpus = 0;
libxl_uuid_generate(&uuid);
printf("Using config file \"%s\"\n", config_src);
printf("cpupool name: %s\n", name);
printf("scheduler: %s\n", libxl_scheduler_to_string(sched));
printf("number of cpus: %d\n", n_cpus);
if (!dryrun_only) {
poolid = LIBXL_CPUPOOL_POOLID_ANY;
if (libxl_cpupool_create(ctx, name, sched, cpumap, &uuid, &poolid)) {
fprintf(stderr, "error on creating cpupool\n");
goto out_cfg;
}
}
/* We made it! */
rc = EXIT_SUCCESS;
out_cfg:
xlu_cfg_destroy(config);
out:
libxl_bitmap_dispose(&freemap);
libxl_bitmap_dispose(&cpumap);
free(name);
free(config_data);
free(extra_config);
return rc;
}
int main_cpupoollist(int argc, char **argv)
{
int opt;
static struct option opts[] = {
{"cpus", 0, 0, 'c'},
COMMON_LONG_OPTS
};
int opt_cpus = 0;
const char *pool = NULL;
libxl_cpupoolinfo *poolinfo;
int n_pools, p, c, n;
uint32_t poolid;
char *name;
SWITCH_FOREACH_OPT(opt, "c", opts, "cpupool-list", 0) {
case 'c':
opt_cpus = 1;
break;
}
if (optind < argc) {
pool = argv[optind];
if (libxl_name_to_cpupoolid(ctx, pool, &poolid)) {
fprintf(stderr, "Pool \'%s\' does not exist\n", pool);
return EXIT_FAILURE;
}
}
poolinfo = libxl_list_cpupool(ctx, &n_pools);
if (!poolinfo) {
fprintf(stderr, "error getting cpupool info\n");
return EXIT_FAILURE;
}
printf("%-19s", "Name");
if (opt_cpus)
printf("CPU list\n");
else
printf("CPUs Sched Active Domain count\n");
for (p = 0; p < n_pools; p++) {
if (!pool || (poolinfo[p].poolid == poolid)) {
name = poolinfo[p].pool_name;
printf("%-19s", name);
n = 0;
libxl_for_each_bit(c, poolinfo[p].cpumap)
if (libxl_bitmap_test(&poolinfo[p].cpumap, c)) {
if (n && opt_cpus) printf(",");
if (opt_cpus) printf("%d", c);
n++;
}
if (!opt_cpus) {
printf("%3d %9s y %4d", n,
libxl_scheduler_to_string(poolinfo[p].sched),
poolinfo[p].n_dom);
}
printf("\n");
}
}
libxl_cpupoolinfo_list_free(poolinfo, n_pools);
return EXIT_SUCCESS;
}
int main_cpupooldestroy(int argc, char **argv)
{
int opt;
const char *pool;
uint32_t poolid;
SWITCH_FOREACH_OPT(opt, "", NULL, "cpupool-destroy", 1) {
/* No options */
}
pool = argv[optind];
if (libxl_cpupool_qualifier_to_cpupoolid(ctx, pool, &poolid, NULL) ||
!libxl_cpupoolid_is_valid(ctx, poolid)) {
fprintf(stderr, "unknown cpupool '%s'\n", pool);
return EXIT_FAILURE;
}
if (libxl_cpupool_destroy(ctx, poolid)) {
fprintf(stderr, "Can't destroy cpupool '%s'\n", pool);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
int main_cpupoolrename(int argc, char **argv)
{
int opt;
const char *pool;
const char *new_name;
uint32_t poolid;
SWITCH_FOREACH_OPT(opt, "", NULL, "cpupool-rename", 2) {
/* No options */
}
pool = argv[optind++];
if (libxl_cpupool_qualifier_to_cpupoolid(ctx, pool, &poolid, NULL) ||
!libxl_cpupoolid_is_valid(ctx, poolid)) {
fprintf(stderr, "unknown cpupool '%s'\n", pool);
return EXIT_FAILURE;
}
new_name = argv[optind];
if (libxl_cpupool_rename(ctx, new_name, poolid)) {
fprintf(stderr, "Can't rename cpupool '%s'\n", pool);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
int main_cpupoolcpuadd(int argc, char **argv)
{
int opt;
const char *pool;
uint32_t poolid;
libxl_bitmap cpumap;
int rc = EXIT_FAILURE;
SWITCH_FOREACH_OPT(opt, "", NULL, "cpupool-cpu-add", 2) {
/* No options */
}
libxl_bitmap_init(&cpumap);
if (libxl_cpu_bitmap_alloc(ctx, &cpumap, 0)) {
fprintf(stderr, "Unable to allocate cpumap");
return EXIT_FAILURE;
}
pool = argv[optind++];
if (parse_cpurange(argv[optind], &cpumap))
goto out;
if (libxl_cpupool_qualifier_to_cpupoolid(ctx, pool, &poolid, NULL) ||
!libxl_cpupoolid_is_valid(ctx, poolid)) {
fprintf(stderr, "unknown cpupool \'%s\'\n", pool);
goto out;
}
if (libxl_cpupool_cpuadd_cpumap(ctx, poolid, &cpumap))
fprintf(stderr, "some cpus may not have been added to %s\n", pool);
rc = EXIT_SUCCESS;
out:
libxl_bitmap_dispose(&cpumap);
return rc;
}
int main_cpupoolcpuremove(int argc, char **argv)
{
int opt;
const char *pool;
uint32_t poolid;
libxl_bitmap cpumap;
int rc = EXIT_FAILURE;
libxl_bitmap_init(&cpumap);
if (libxl_cpu_bitmap_alloc(ctx, &cpumap, 0)) {
fprintf(stderr, "Unable to allocate cpumap");
return EXIT_FAILURE;
}
SWITCH_FOREACH_OPT(opt, "", NULL, "cpupool-cpu-remove", 2) {
/* No options */
}
pool = argv[optind++];
if (parse_cpurange(argv[optind], &cpumap))
goto out;
if (libxl_cpupool_qualifier_to_cpupoolid(ctx, pool, &poolid, NULL) ||
!libxl_cpupoolid_is_valid(ctx, poolid)) {
fprintf(stderr, "unknown cpupool \'%s\'\n", pool);
goto out;
}
if (libxl_cpupool_cpuremove_cpumap(ctx, poolid, &cpumap)) {
fprintf(stderr, "Some cpus may have not or only partially been removed from '%s'.\n", pool);
fprintf(stderr, "If a cpu can't be added to another cpupool, add it to '%s' again and retry.\n", pool);
}
rc = EXIT_SUCCESS;
out:
libxl_bitmap_dispose(&cpumap);
return rc;
}
int main_cpupoolmigrate(int argc, char **argv)
{
int opt;
const char *pool;
uint32_t poolid;
const char *dom;
uint32_t domid;
SWITCH_FOREACH_OPT(opt, "", NULL, "cpupool-migrate", 2) {
/* No options */
}
dom = argv[optind++];
pool = argv[optind];
if (libxl_domain_qualifier_to_domid(ctx, dom, &domid) ||
!libxl_domid_to_name(ctx, domid)) {
fprintf(stderr, "unknown domain '%s'\n", dom);
return EXIT_FAILURE;
}
if (libxl_cpupool_qualifier_to_cpupoolid(ctx, pool, &poolid, NULL) ||
!libxl_cpupoolid_is_valid(ctx, poolid)) {
fprintf(stderr, "unknown cpupool '%s'\n", pool);
return EXIT_FAILURE;
}
if (libxl_cpupool_movedomain(ctx, poolid, domid))
return EXIT_FAILURE;
return EXIT_SUCCESS;
}
int main_cpupoolnumasplit(int argc, char **argv)
{
int rc;
int opt;
int p;
int c;
int n;
uint32_t poolid;
libxl_scheduler sched;
int n_pools;
int node;
int n_cpus;
char *name = NULL;
libxl_uuid uuid;
libxl_bitmap cpumap;
libxl_cpupoolinfo *poolinfo;
libxl_cputopology *topology;
libxl_dominfo info;
SWITCH_FOREACH_OPT(opt, "", NULL, "cpupool-numa-split", 0) {
/* No options */
}
libxl_dominfo_init(&info);
rc = EXIT_FAILURE;
libxl_bitmap_init(&cpumap);
poolinfo = libxl_list_cpupool(ctx, &n_pools);
if (!poolinfo) {
fprintf(stderr, "error getting cpupool info\n");
return EXIT_FAILURE;
}
poolid = poolinfo[0].poolid;
sched = poolinfo[0].sched;
libxl_cpupoolinfo_list_free(poolinfo, n_pools);
if (n_pools > 1) {
fprintf(stderr, "splitting not possible, already cpupools in use\n");
return EXIT_FAILURE;
}
topology = libxl_get_cpu_topology(ctx, &n_cpus);
if (topology == NULL) {
fprintf(stderr, "libxl_get_topologyinfo failed\n");
return EXIT_FAILURE;
}
if (libxl_cpu_bitmap_alloc(ctx, &cpumap, 0)) {
fprintf(stderr, "Failed to allocate cpumap\n");
goto out;
}
/* Reset Pool-0 to 1st node: first add cpus, then remove cpus to avoid
a cpupool without cpus in between */
node = topology[0].node;
if (libxl_cpupool_cpuadd_node(ctx, 0, node, &n)) {
fprintf(stderr, "error on adding cpu to Pool 0\n");
goto out;
}
xasprintf(&name, "Pool-node%d", node);
if (libxl_cpupool_rename(ctx, name, 0)) {
fprintf(stderr, "error on renaming Pool 0\n");
goto out;
}
n = 0;
for (c = 0; c < n_cpus; c++) {
if (topology[c].node == node) {
topology[c].node = LIBXL_CPUTOPOLOGY_INVALID_ENTRY;
libxl_bitmap_set(&cpumap, n);
n++;
}
}
if (libxl_domain_info(ctx, &info, 0)) {
fprintf(stderr, "error on getting info for Domain-0\n");
goto out;
}
if (info.vcpu_online > n && libxl_set_vcpuonline(ctx, 0, &cpumap, NULL)) {
fprintf(stderr, "error on removing vcpus for Domain-0\n");
goto out;
}
for (c = 0; c < 10; c++) {
/* We've called libxl_dominfo_init before the loop and will
* call libxl_dominfo_dispose after the loop when we're done
* with info.
*/
libxl_dominfo_dispose(&info);
libxl_dominfo_init(&info);
if (libxl_domain_info(ctx, &info, 0)) {
fprintf(stderr, "error on getting info for Domain-0\n");
goto out;
}
if (info.vcpu_online <= n) {
break;
}
sleep(1);
}
if (info.vcpu_online > n) {
fprintf(stderr, "failed to offline vcpus\n");
goto out;
}
libxl_bitmap_set_none(&cpumap);
for (c = 0; c < n_cpus; c++) {
if (topology[c].node == LIBXL_CPUTOPOLOGY_INVALID_ENTRY) {
continue;
}
node = topology[c].node;
if (libxl_cpupool_cpuremove_node(ctx, 0, node, &n)) {
fprintf(stderr, "error on removing cpu from Pool 0\n");
goto out;
}
free(name);
xasprintf(&name, "Pool-node%d", node);
libxl_uuid_generate(&uuid);
poolid = 0;
if (libxl_cpupool_create(ctx, name, sched, cpumap, &uuid, &poolid)) {
fprintf(stderr, "error on creating cpupool\n");
goto out;
}
if (libxl_cpupool_cpuadd_node(ctx, poolid, node, &n)) {
fprintf(stderr, "error on adding cpus to cpupool\n");
goto out;
}
for (p = c; p < n_cpus; p++) {
if (topology[p].node == node) {
topology[p].node = LIBXL_CPUTOPOLOGY_INVALID_ENTRY;
}
}
}
rc = EXIT_SUCCESS;
out:
libxl_cputopology_list_free(topology, n_cpus);
libxl_bitmap_dispose(&cpumap);
libxl_dominfo_dispose(&info);
free(name);
return rc;
}
/*
* Local variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/