1 /*
2 * Copyright 2009-2017 Citrix Ltd and other contributors
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published
6 * by the Free Software Foundation; version 2.1 only. with the special
7 * exception on linking described in file LICENSE.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 */
14
15 #include "libxl_osdeps.h"
16
17 #include "libxl_internal.h"
18
libxl__set_vcpuaffinity(libxl_ctx * ctx,uint32_t domid,uint32_t vcpuid,const libxl_bitmap * cpumap_hard,const libxl_bitmap * cpumap_soft,unsigned flags)19 static int libxl__set_vcpuaffinity(libxl_ctx *ctx, uint32_t domid,
20 uint32_t vcpuid,
21 const libxl_bitmap *cpumap_hard,
22 const libxl_bitmap *cpumap_soft,
23 unsigned flags)
24 {
25 GC_INIT(ctx);
26 libxl_bitmap hard, soft;
27 int rc;
28
29 libxl_bitmap_init(&hard);
30 libxl_bitmap_init(&soft);
31
32 if (!cpumap_hard && !cpumap_soft && !flags) {
33 rc = ERROR_INVAL;
34 goto out;
35 }
36
37 /*
38 * Xen wants writable hard and/or soft cpumaps, to put back in them
39 * the effective hard and/or soft affinity that will be used.
40 */
41 if (cpumap_hard) {
42 rc = libxl_cpu_bitmap_alloc(ctx, &hard, 0);
43 if (rc)
44 goto out;
45
46 libxl__bitmap_copy_best_effort(gc, &hard, cpumap_hard);
47 flags |= XEN_VCPUAFFINITY_HARD;
48 }
49 if (cpumap_soft) {
50 rc = libxl_cpu_bitmap_alloc(ctx, &soft, 0);
51 if (rc)
52 goto out;
53
54 libxl__bitmap_copy_best_effort(gc, &soft, cpumap_soft);
55 flags |= XEN_VCPUAFFINITY_SOFT;
56 }
57
58 if (xc_vcpu_setaffinity(ctx->xch, domid, vcpuid,
59 cpumap_hard ? hard.map : NULL,
60 cpumap_soft ? soft.map : NULL,
61 flags)) {
62 LOGED(ERROR, domid, "Setting vcpu affinity");
63 rc = ERROR_FAIL;
64 goto out;
65 }
66
67 /*
68 * Let's check the results. Hard affinity will never be empty, but it
69 * is possible that Xen will use something different from what we asked
70 * for various reasons. If that's the case, report it.
71 */
72 if (cpumap_hard &&
73 !libxl_bitmap_equal(cpumap_hard, &hard, 0))
74 LOGD(DEBUG, domid, "New hard affinity for vcpu %d has unreachable cpus", vcpuid);
75 /*
76 * Soft affinity can both be different from what asked and empty. Check
77 * for (and report) both.
78 */
79 if (cpumap_soft) {
80 if (!libxl_bitmap_equal(cpumap_soft, &soft, 0))
81 LOGD(DEBUG, domid, "New soft affinity for vcpu %d has unreachable cpus",
82 vcpuid);
83 if (libxl_bitmap_is_empty(&soft))
84 LOGD(WARN, domid, "All cpus in soft affinity of vcpu %d are unreachable."
85 " Only hard affinity will be considered for scheduling",
86 vcpuid);
87 }
88
89 rc = 0;
90 out:
91 libxl_bitmap_dispose(&hard);
92 libxl_bitmap_dispose(&soft);
93 GC_FREE;
94 return rc;
95 }
96
libxl_set_vcpuaffinity(libxl_ctx * ctx,uint32_t domid,uint32_t vcpuid,const libxl_bitmap * cpumap_hard,const libxl_bitmap * cpumap_soft)97 int libxl_set_vcpuaffinity(libxl_ctx *ctx, uint32_t domid, uint32_t vcpuid,
98 const libxl_bitmap *cpumap_hard,
99 const libxl_bitmap *cpumap_soft)
100 {
101 return libxl__set_vcpuaffinity(ctx, domid, vcpuid, cpumap_hard,
102 cpumap_soft, 0);
103 }
104
libxl_set_vcpuaffinity_force(libxl_ctx * ctx,uint32_t domid,uint32_t vcpuid,const libxl_bitmap * cpumap_hard,const libxl_bitmap * cpumap_soft)105 int libxl_set_vcpuaffinity_force(libxl_ctx *ctx, uint32_t domid,
106 uint32_t vcpuid,
107 const libxl_bitmap *cpumap_hard,
108 const libxl_bitmap *cpumap_soft)
109 {
110 return libxl__set_vcpuaffinity(ctx, domid, vcpuid, cpumap_hard,
111 cpumap_soft, XEN_VCPUAFFINITY_FORCE);
112 }
113
libxl_set_vcpuaffinity_all(libxl_ctx * ctx,uint32_t domid,unsigned int max_vcpus,const libxl_bitmap * cpumap_hard,const libxl_bitmap * cpumap_soft)114 int libxl_set_vcpuaffinity_all(libxl_ctx *ctx, uint32_t domid,
115 unsigned int max_vcpus,
116 const libxl_bitmap *cpumap_hard,
117 const libxl_bitmap *cpumap_soft)
118 {
119 GC_INIT(ctx);
120 int i, rc = 0;
121
122 for (i = 0; i < max_vcpus; i++) {
123 if (libxl_set_vcpuaffinity(ctx, domid, i, cpumap_hard, cpumap_soft)) {
124 LOGD(WARN, domid, "Failed to set affinity for %d", i);
125 rc = ERROR_FAIL;
126 }
127 }
128
129 GC_FREE;
130 return rc;
131 }
132
libxl_domain_set_nodeaffinity(libxl_ctx * ctx,uint32_t domid,libxl_bitmap * nodemap)133 int libxl_domain_set_nodeaffinity(libxl_ctx *ctx, uint32_t domid,
134 libxl_bitmap *nodemap)
135 {
136 GC_INIT(ctx);
137 if (xc_domain_node_setaffinity(ctx->xch, domid, nodemap->map)) {
138 LOGED(ERROR, domid, "Setting node affinity");
139 GC_FREE;
140 return ERROR_FAIL;
141 }
142 GC_FREE;
143 return 0;
144 }
145
libxl_domain_get_nodeaffinity(libxl_ctx * ctx,uint32_t domid,libxl_bitmap * nodemap)146 int libxl_domain_get_nodeaffinity(libxl_ctx *ctx, uint32_t domid,
147 libxl_bitmap *nodemap)
148 {
149 GC_INIT(ctx);
150 if (xc_domain_node_getaffinity(ctx->xch, domid, nodemap->map)) {
151 LOGED(ERROR, domid, "Getting node affinity");
152 GC_FREE;
153 return ERROR_FAIL;
154 }
155 GC_FREE;
156 return 0;
157 }
158
libxl_get_scheduler(libxl_ctx * ctx)159 int libxl_get_scheduler(libxl_ctx *ctx)
160 {
161 int r, sched;
162
163 GC_INIT(ctx);
164 r = xc_sched_id(ctx->xch, &sched);
165 if (r != 0) {
166 LOGE(ERROR, "getting current scheduler id");
167 sched = ERROR_FAIL;
168 }
169 GC_FREE;
170 return sched;
171 }
172
sched_arinc653_domain_set(libxl__gc * gc,uint32_t domid,const libxl_domain_sched_params * scinfo)173 static int sched_arinc653_domain_set(libxl__gc *gc, uint32_t domid,
174 const libxl_domain_sched_params *scinfo)
175 {
176 /* Currently, the ARINC 653 scheduler does not take any domain-specific
177 configuration, so we simply return success. */
178 return 0;
179 }
180
sched_null_domain_set(libxl__gc * gc,uint32_t domid,const libxl_domain_sched_params * scinfo)181 static int sched_null_domain_set(libxl__gc *gc, uint32_t domid,
182 const libxl_domain_sched_params *scinfo)
183 {
184 /* There aren't any domain-specific parameters to be set. */
185 return 0;
186 }
187
sched_null_domain_get(libxl__gc * gc,uint32_t domid,libxl_domain_sched_params * scinfo)188 static int sched_null_domain_get(libxl__gc *gc, uint32_t domid,
189 libxl_domain_sched_params *scinfo)
190 {
191 /* There aren't any domain-specific parameters to return. */
192 return 0;
193 }
194
sched_credit_domain_get(libxl__gc * gc,uint32_t domid,libxl_domain_sched_params * scinfo)195 static int sched_credit_domain_get(libxl__gc *gc, uint32_t domid,
196 libxl_domain_sched_params *scinfo)
197 {
198 struct xen_domctl_sched_credit sdom;
199 int rc;
200
201 rc = xc_sched_credit_domain_get(CTX->xch, domid, &sdom);
202 if (rc != 0) {
203 LOGED(ERROR, domid, "Getting domain sched credit");
204 return ERROR_FAIL;
205 }
206
207 libxl_domain_sched_params_init(scinfo);
208 scinfo->sched = LIBXL_SCHEDULER_CREDIT;
209 scinfo->weight = sdom.weight;
210 scinfo->cap = sdom.cap;
211
212 return 0;
213 }
214
sched_credit_domain_set(libxl__gc * gc,uint32_t domid,const libxl_domain_sched_params * scinfo)215 static int sched_credit_domain_set(libxl__gc *gc, uint32_t domid,
216 const libxl_domain_sched_params *scinfo)
217 {
218 struct xen_domctl_sched_credit sdom;
219 xc_domaininfo_t domaininfo;
220 int rc;
221
222 rc = xc_domain_getinfolist(CTX->xch, domid, 1, &domaininfo);
223 if (rc < 0) {
224 LOGED(ERROR, domid, "Getting domain info list");
225 return ERROR_FAIL;
226 }
227 if (rc != 1 || domaininfo.domain != domid)
228 return ERROR_INVAL;
229
230 rc = xc_sched_credit_domain_get(CTX->xch, domid, &sdom);
231 if (rc != 0) {
232 LOGED(ERROR, domid, "Getting domain sched credit");
233 return ERROR_FAIL;
234 }
235
236 if (scinfo->weight != LIBXL_DOMAIN_SCHED_PARAM_WEIGHT_DEFAULT) {
237 if (scinfo->weight < 1 || scinfo->weight > 65535) {
238 LOGD(ERROR, domid, "Cpu weight out of range, "
239 "valid values are within range from 1 to 65535");
240 return ERROR_INVAL;
241 }
242 sdom.weight = scinfo->weight;
243 }
244
245 if (scinfo->cap != LIBXL_DOMAIN_SCHED_PARAM_CAP_DEFAULT) {
246 if (scinfo->cap < 0
247 || scinfo->cap > (domaininfo.max_vcpu_id + 1) * 100) {
248 LOGD(ERROR, domid, "Cpu cap out of range, "
249 "valid range is from 0 to %d for specified number of vcpus",
250 ((domaininfo.max_vcpu_id + 1) * 100));
251 return ERROR_INVAL;
252 }
253 sdom.cap = scinfo->cap;
254 }
255
256 rc = xc_sched_credit_domain_set(CTX->xch, domid, &sdom);
257 if ( rc < 0 ) {
258 LOGED(ERROR, domid, "Setting domain sched credit");
259 return ERROR_FAIL;
260 }
261
262 return 0;
263 }
264
sched_ratelimit_check(libxl__gc * gc,int ratelimit)265 static int sched_ratelimit_check(libxl__gc *gc, int ratelimit)
266 {
267 if (ratelimit != 0 &&
268 (ratelimit < XEN_SYSCTL_SCHED_RATELIMIT_MIN ||
269 ratelimit > XEN_SYSCTL_SCHED_RATELIMIT_MAX)) {
270 LOG(ERROR, "Ratelimit out of range, valid range is from %d to %d",
271 XEN_SYSCTL_SCHED_RATELIMIT_MIN, XEN_SYSCTL_SCHED_RATELIMIT_MAX);
272 return ERROR_INVAL;
273 }
274
275 return 0;
276 }
277
libxl_sched_credit_params_get(libxl_ctx * ctx,uint32_t poolid,libxl_sched_credit_params * scinfo)278 int libxl_sched_credit_params_get(libxl_ctx *ctx, uint32_t poolid,
279 libxl_sched_credit_params *scinfo)
280 {
281 struct xen_sysctl_credit_schedule sparam;
282 int r, rc;
283 GC_INIT(ctx);
284
285 r = xc_sched_credit_params_get(ctx->xch, poolid, &sparam);
286 if (r < 0) {
287 LOGE(ERROR, "getting Credit scheduler parameters");
288 rc = ERROR_FAIL;
289 goto out;
290 }
291
292 scinfo->tslice_ms = sparam.tslice_ms;
293 scinfo->ratelimit_us = sparam.ratelimit_us;
294 scinfo->vcpu_migr_delay_us = sparam.vcpu_migr_delay_us;
295
296 rc = 0;
297 out:
298 GC_FREE;
299 return rc;
300 }
301
libxl_sched_credit_params_set(libxl_ctx * ctx,uint32_t poolid,libxl_sched_credit_params * scinfo)302 int libxl_sched_credit_params_set(libxl_ctx *ctx, uint32_t poolid,
303 libxl_sched_credit_params *scinfo)
304 {
305 struct xen_sysctl_credit_schedule sparam;
306 int r, rc;
307 GC_INIT(ctx);
308
309 if (scinfo->tslice_ms < XEN_SYSCTL_CSCHED_TSLICE_MIN
310 || scinfo->tslice_ms > XEN_SYSCTL_CSCHED_TSLICE_MAX) {
311 LOG(ERROR, "Time slice out of range, valid range is from %d to %d",
312 XEN_SYSCTL_CSCHED_TSLICE_MIN, XEN_SYSCTL_CSCHED_TSLICE_MAX);
313 rc = ERROR_INVAL;
314 goto out;
315 }
316 rc = sched_ratelimit_check(gc, scinfo->ratelimit_us);
317 if (rc) {
318 goto out;
319 }
320 if (scinfo->ratelimit_us > scinfo->tslice_ms*1000) {
321 LOG(ERROR, "Ratelimit cannot be greater than timeslice");
322 rc = ERROR_INVAL;
323 goto out;
324 }
325 if (scinfo->vcpu_migr_delay_us > XEN_SYSCTL_CSCHED_MGR_DLY_MAX_US) {
326 LOG(ERROR, "vcpu migration delay should be >= 0 and <= %dus",
327 XEN_SYSCTL_CSCHED_MGR_DLY_MAX_US);
328 rc = ERROR_INVAL;
329 goto out;
330 }
331
332 sparam.tslice_ms = scinfo->tslice_ms;
333 sparam.ratelimit_us = scinfo->ratelimit_us;
334 sparam.vcpu_migr_delay_us = scinfo->vcpu_migr_delay_us;
335
336 r = xc_sched_credit_params_set(ctx->xch, poolid, &sparam);
337 if ( r < 0 ) {
338 LOGE(ERROR, "Setting Credit scheduler parameters");
339 rc = ERROR_FAIL;
340 goto out;
341 }
342
343 scinfo->tslice_ms = sparam.tslice_ms;
344 scinfo->ratelimit_us = sparam.ratelimit_us;
345 scinfo->vcpu_migr_delay_us = sparam.vcpu_migr_delay_us;
346
347 rc = 0;
348 out:
349 GC_FREE;
350 return rc;
351 }
352
libxl_sched_credit2_params_get(libxl_ctx * ctx,uint32_t poolid,libxl_sched_credit2_params * scinfo)353 int libxl_sched_credit2_params_get(libxl_ctx *ctx, uint32_t poolid,
354 libxl_sched_credit2_params *scinfo)
355 {
356 struct xen_sysctl_credit2_schedule sparam;
357 int r, rc;
358 GC_INIT(ctx);
359
360 r = xc_sched_credit2_params_get(ctx->xch, poolid, &sparam);
361 if (r < 0) {
362 LOGE(ERROR, "getting Credit2 scheduler parameters");
363 rc = ERROR_FAIL;
364 goto out;
365 }
366
367 scinfo->ratelimit_us = sparam.ratelimit_us;
368
369 rc = 0;
370 out:
371 GC_FREE;
372 return rc;
373 }
374
libxl_sched_credit2_params_set(libxl_ctx * ctx,uint32_t poolid,libxl_sched_credit2_params * scinfo)375 int libxl_sched_credit2_params_set(libxl_ctx *ctx, uint32_t poolid,
376 libxl_sched_credit2_params *scinfo)
377 {
378 struct xen_sysctl_credit2_schedule sparam;
379 int r, rc;
380 GC_INIT(ctx);
381
382 rc = sched_ratelimit_check(gc, scinfo->ratelimit_us);
383 if (rc) goto out;
384
385 sparam.ratelimit_us = scinfo->ratelimit_us;
386
387 r = xc_sched_credit2_params_set(ctx->xch, poolid, &sparam);
388 if (r < 0) {
389 LOGE(ERROR, "Setting Credit2 scheduler parameters");
390 rc = ERROR_FAIL;
391 goto out;
392 }
393
394 scinfo->ratelimit_us = sparam.ratelimit_us;
395
396 rc = 0;
397 out:
398 GC_FREE;
399 return rc;
400 }
401
sched_credit2_domain_get(libxl__gc * gc,uint32_t domid,libxl_domain_sched_params * scinfo)402 static int sched_credit2_domain_get(libxl__gc *gc, uint32_t domid,
403 libxl_domain_sched_params *scinfo)
404 {
405 struct xen_domctl_sched_credit2 sdom;
406 int rc;
407
408 rc = xc_sched_credit2_domain_get(CTX->xch, domid, &sdom);
409 if (rc != 0) {
410 LOGED(ERROR, domid, "Getting domain sched credit2");
411 return ERROR_FAIL;
412 }
413
414 libxl_domain_sched_params_init(scinfo);
415 scinfo->sched = LIBXL_SCHEDULER_CREDIT2;
416 scinfo->weight = sdom.weight;
417 scinfo->cap = sdom.cap;
418
419 return 0;
420 }
421
sched_credit2_domain_set(libxl__gc * gc,uint32_t domid,const libxl_domain_sched_params * scinfo)422 static int sched_credit2_domain_set(libxl__gc *gc, uint32_t domid,
423 const libxl_domain_sched_params *scinfo)
424 {
425 struct xen_domctl_sched_credit2 sdom;
426 xc_domaininfo_t info;
427 int rc;
428
429 rc = xc_domain_getinfolist(CTX->xch, domid, 1, &info);
430 if (rc < 0) {
431 LOGED(ERROR, domid, "Getting domain info");
432 return ERROR_FAIL;
433 }
434 if (rc != 1 || info.domain != domid)
435 return ERROR_INVAL;
436
437 rc = xc_sched_credit2_domain_get(CTX->xch, domid, &sdom);
438 if (rc != 0) {
439 LOGED(ERROR, domid, "Getting domain sched credit2");
440 return ERROR_FAIL;
441 }
442
443 if (scinfo->weight != LIBXL_DOMAIN_SCHED_PARAM_WEIGHT_DEFAULT) {
444 if (scinfo->weight < 1 || scinfo->weight > 65535) {
445 LOGD(ERROR, domid, "Cpu weight out of range, "
446 "valid values are within range from 1 to 65535");
447 return ERROR_INVAL;
448 }
449 sdom.weight = scinfo->weight;
450 }
451
452 if (scinfo->cap != LIBXL_DOMAIN_SCHED_PARAM_CAP_DEFAULT) {
453 if (scinfo->cap < 0
454 || scinfo->cap > (info.max_vcpu_id + 1) * 100) {
455 LOGD(ERROR, domid, "Cpu cap out of range, "
456 "valid range is from 0 to %d for specified number of vcpus",
457 ((info.max_vcpu_id + 1) * 100));
458 return ERROR_INVAL;
459 }
460 sdom.cap = scinfo->cap;
461 }
462
463 rc = xc_sched_credit2_domain_set(CTX->xch, domid, &sdom);
464 if ( rc < 0 ) {
465 LOGED(ERROR, domid, "Setting domain sched credit2");
466 return ERROR_FAIL;
467 }
468
469 return 0;
470 }
471
sched_rtds_validate_params(libxl__gc * gc,int period,int budget)472 static int sched_rtds_validate_params(libxl__gc *gc, int period, int budget)
473 {
474 int rc;
475
476 if (period < 1) {
477 LOG(ERROR, "Invalid VCPU period of %d (it should be >= 1)", period);
478 rc = ERROR_INVAL;
479 goto out;
480 }
481
482 if (budget < 1) {
483 LOG(ERROR, "Invalid VCPU budget of %d (it should be >= 1)", budget);
484 rc = ERROR_INVAL;
485 goto out;
486 }
487
488 if (budget > period) {
489 LOG(ERROR, "VCPU budget must be smaller than or equal to period, "
490 "but %d > %d", budget, period);
491 rc = ERROR_INVAL;
492 goto out;
493 }
494 rc = 0;
495 out:
496 return rc;
497 }
498
499 /* Get the RTDS scheduling parameters of vcpu(s) */
sched_rtds_vcpu_get(libxl__gc * gc,uint32_t domid,libxl_vcpu_sched_params * scinfo)500 static int sched_rtds_vcpu_get(libxl__gc *gc, uint32_t domid,
501 libxl_vcpu_sched_params *scinfo)
502 {
503 uint32_t num_vcpus;
504 int i, r, rc;
505 xc_dominfo_t info;
506 struct xen_domctl_schedparam_vcpu *vcpus;
507
508 r = xc_domain_getinfo(CTX->xch, domid, 1, &info);
509 if (r < 0) {
510 LOGED(ERROR, domid, "Getting domain info");
511 rc = ERROR_FAIL;
512 goto out;
513 }
514
515 if (scinfo->num_vcpus <= 0) {
516 rc = ERROR_INVAL;
517 goto out;
518 } else {
519 num_vcpus = scinfo->num_vcpus;
520 GCNEW_ARRAY(vcpus, num_vcpus);
521 for (i = 0; i < num_vcpus; i++) {
522 if (scinfo->vcpus[i].vcpuid < 0 ||
523 scinfo->vcpus[i].vcpuid > info.max_vcpu_id) {
524 LOGD(ERROR, domid, "VCPU index is out of range, "
525 "valid values are within range from 0 to %d",
526 info.max_vcpu_id);
527 rc = ERROR_INVAL;
528 goto out;
529 }
530 vcpus[i].vcpuid = scinfo->vcpus[i].vcpuid;
531 }
532 }
533
534 r = xc_sched_rtds_vcpu_get(CTX->xch, domid, vcpus, num_vcpus);
535 if (r != 0) {
536 LOGED(ERROR, domid, "Getting vcpu sched rtds");
537 rc = ERROR_FAIL;
538 goto out;
539 }
540 scinfo->sched = LIBXL_SCHEDULER_RTDS;
541 for (i = 0; i < num_vcpus; i++) {
542 scinfo->vcpus[i].period = vcpus[i].u.rtds.period;
543 scinfo->vcpus[i].budget = vcpus[i].u.rtds.budget;
544 scinfo->vcpus[i].extratime =
545 !!(vcpus[i].u.rtds.flags & XEN_DOMCTL_SCHEDRT_extra);
546 scinfo->vcpus[i].vcpuid = vcpus[i].vcpuid;
547 }
548 rc = 0;
549 out:
550 return rc;
551 }
552
553 /* Get the RTDS scheduling parameters of all vcpus of a domain */
sched_rtds_vcpu_get_all(libxl__gc * gc,uint32_t domid,libxl_vcpu_sched_params * scinfo)554 static int sched_rtds_vcpu_get_all(libxl__gc *gc, uint32_t domid,
555 libxl_vcpu_sched_params *scinfo)
556 {
557 uint32_t num_vcpus;
558 int i, r, rc;
559 xc_dominfo_t info;
560 struct xen_domctl_schedparam_vcpu *vcpus;
561
562 r = xc_domain_getinfo(CTX->xch, domid, 1, &info);
563 if (r < 0) {
564 LOGED(ERROR, domid, "Getting domain info");
565 rc = ERROR_FAIL;
566 goto out;
567 }
568
569 if (scinfo->num_vcpus > 0) {
570 rc = ERROR_INVAL;
571 goto out;
572 } else {
573 num_vcpus = info.max_vcpu_id + 1;
574 GCNEW_ARRAY(vcpus, num_vcpus);
575 for (i = 0; i < num_vcpus; i++)
576 vcpus[i].vcpuid = i;
577 }
578
579 r = xc_sched_rtds_vcpu_get(CTX->xch, domid, vcpus, num_vcpus);
580 if (r != 0) {
581 LOGED(ERROR, domid, "Getting vcpu sched rtds");
582 rc = ERROR_FAIL;
583 goto out;
584 }
585 scinfo->sched = LIBXL_SCHEDULER_RTDS;
586 scinfo->num_vcpus = num_vcpus;
587 scinfo->vcpus = libxl__calloc(NOGC, num_vcpus,
588 sizeof(libxl_sched_params));
589
590 for (i = 0; i < num_vcpus; i++) {
591 scinfo->vcpus[i].period = vcpus[i].u.rtds.period;
592 scinfo->vcpus[i].budget = vcpus[i].u.rtds.budget;
593 scinfo->vcpus[i].extratime =
594 !!(vcpus[i].u.rtds.flags & XEN_DOMCTL_SCHEDRT_extra);
595 scinfo->vcpus[i].vcpuid = vcpus[i].vcpuid;
596 }
597 rc = 0;
598 out:
599 return rc;
600 }
601
602 /* Set the RTDS scheduling parameters of vcpu(s) */
sched_rtds_vcpu_set(libxl__gc * gc,uint32_t domid,const libxl_vcpu_sched_params * scinfo)603 static int sched_rtds_vcpu_set(libxl__gc *gc, uint32_t domid,
604 const libxl_vcpu_sched_params *scinfo)
605 {
606 int r, rc;
607 int i;
608 uint16_t max_vcpuid;
609 xc_dominfo_t info;
610 struct xen_domctl_schedparam_vcpu *vcpus;
611
612 r = xc_domain_getinfo(CTX->xch, domid, 1, &info);
613 if (r < 0) {
614 LOGED(ERROR, domid, "Getting domain info");
615 rc = ERROR_FAIL;
616 goto out;
617 }
618 max_vcpuid = info.max_vcpu_id;
619
620 if (scinfo->num_vcpus <= 0) {
621 rc = ERROR_INVAL;
622 goto out;
623 }
624 for (i = 0; i < scinfo->num_vcpus; i++) {
625 if (scinfo->vcpus[i].vcpuid < 0 ||
626 scinfo->vcpus[i].vcpuid > max_vcpuid) {
627 LOGD(ERROR, domid, "Invalid VCPU %d: valid range is [0, %d]",
628 scinfo->vcpus[i].vcpuid, max_vcpuid);
629 rc = ERROR_INVAL;
630 goto out;
631 }
632 rc = sched_rtds_validate_params(gc, scinfo->vcpus[i].period,
633 scinfo->vcpus[i].budget);
634 if (rc) {
635 rc = ERROR_INVAL;
636 goto out;
637 }
638 }
639 GCNEW_ARRAY(vcpus, scinfo->num_vcpus);
640 for (i = 0; i < scinfo->num_vcpus; i++) {
641 vcpus[i].vcpuid = scinfo->vcpus[i].vcpuid;
642 vcpus[i].u.rtds.period = scinfo->vcpus[i].period;
643 vcpus[i].u.rtds.budget = scinfo->vcpus[i].budget;
644 if (scinfo->vcpus[i].extratime)
645 vcpus[i].u.rtds.flags |= XEN_DOMCTL_SCHEDRT_extra;
646 else
647 vcpus[i].u.rtds.flags &= ~XEN_DOMCTL_SCHEDRT_extra;
648 }
649
650 r = xc_sched_rtds_vcpu_set(CTX->xch, domid,
651 vcpus, scinfo->num_vcpus);
652 if (r != 0) {
653 LOGED(ERROR, domid, "Setting vcpu sched rtds");
654 rc = ERROR_FAIL;
655 goto out;
656 }
657 rc = 0;
658 out:
659 return rc;
660 }
661
662 /* Set the RTDS scheduling parameters of all vcpus of a domain */
sched_rtds_vcpu_set_all(libxl__gc * gc,uint32_t domid,const libxl_vcpu_sched_params * scinfo)663 static int sched_rtds_vcpu_set_all(libxl__gc *gc, uint32_t domid,
664 const libxl_vcpu_sched_params *scinfo)
665 {
666 int r, rc;
667 int i;
668 uint16_t max_vcpuid;
669 xc_dominfo_t info;
670 struct xen_domctl_schedparam_vcpu *vcpus;
671 uint32_t num_vcpus;
672
673 r = xc_domain_getinfo(CTX->xch, domid, 1, &info);
674 if (r < 0) {
675 LOGED(ERROR, domid, "Getting domain info");
676 rc = ERROR_FAIL;
677 goto out;
678 }
679 max_vcpuid = info.max_vcpu_id;
680
681 if (scinfo->num_vcpus != 1) {
682 rc = ERROR_INVAL;
683 goto out;
684 }
685 if (sched_rtds_validate_params(gc, scinfo->vcpus[0].period,
686 scinfo->vcpus[0].budget)) {
687 rc = ERROR_INVAL;
688 goto out;
689 }
690 num_vcpus = max_vcpuid + 1;
691 GCNEW_ARRAY(vcpus, num_vcpus);
692 for (i = 0; i < num_vcpus; i++) {
693 vcpus[i].vcpuid = i;
694 vcpus[i].u.rtds.period = scinfo->vcpus[0].period;
695 vcpus[i].u.rtds.budget = scinfo->vcpus[0].budget;
696 if (scinfo->vcpus[0].extratime)
697 vcpus[i].u.rtds.flags |= XEN_DOMCTL_SCHEDRT_extra;
698 else
699 vcpus[i].u.rtds.flags &= ~XEN_DOMCTL_SCHEDRT_extra;
700 }
701
702 r = xc_sched_rtds_vcpu_set(CTX->xch, domid,
703 vcpus, num_vcpus);
704 if (r != 0) {
705 LOGED(ERROR, domid, "Setting vcpu sched rtds");
706 rc = ERROR_FAIL;
707 goto out;
708 }
709 rc = 0;
710 out:
711 return rc;
712 }
713
sched_rtds_domain_get(libxl__gc * gc,uint32_t domid,libxl_domain_sched_params * scinfo)714 static int sched_rtds_domain_get(libxl__gc *gc, uint32_t domid,
715 libxl_domain_sched_params *scinfo)
716 {
717 struct xen_domctl_sched_rtds sdom;
718 int rc;
719
720 rc = xc_sched_rtds_domain_get(CTX->xch, domid, &sdom);
721 if (rc != 0) {
722 LOGED(ERROR, domid, "Getting domain sched rtds");
723 return ERROR_FAIL;
724 }
725
726 libxl_domain_sched_params_init(scinfo);
727
728 scinfo->sched = LIBXL_SCHEDULER_RTDS;
729 scinfo->period = sdom.period;
730 scinfo->budget = sdom.budget;
731
732 return 0;
733 }
734
sched_rtds_domain_set(libxl__gc * gc,uint32_t domid,const libxl_domain_sched_params * scinfo)735 static int sched_rtds_domain_set(libxl__gc *gc, uint32_t domid,
736 const libxl_domain_sched_params *scinfo)
737 {
738 struct xen_domctl_sched_rtds sdom;
739 int rc;
740
741 rc = xc_sched_rtds_domain_get(CTX->xch, domid, &sdom);
742 if (rc != 0) {
743 LOGED(ERROR, domid, "Getting domain sched rtds");
744 return ERROR_FAIL;
745 }
746 if (scinfo->period != LIBXL_DOMAIN_SCHED_PARAM_PERIOD_DEFAULT)
747 sdom.period = scinfo->period;
748 if (scinfo->budget != LIBXL_DOMAIN_SCHED_PARAM_BUDGET_DEFAULT)
749 sdom.budget = scinfo->budget;
750 /* Set extratime by default */
751 if (scinfo->extratime)
752 sdom.flags |= XEN_DOMCTL_SCHEDRT_extra;
753 else
754 sdom.flags &= ~XEN_DOMCTL_SCHEDRT_extra;
755 if (sched_rtds_validate_params(gc, sdom.period, sdom.budget))
756 return ERROR_INVAL;
757
758 rc = xc_sched_rtds_domain_set(CTX->xch, domid, &sdom);
759 if (rc < 0) {
760 LOGED(ERROR, domid, "Setting domain sched rtds");
761 return ERROR_FAIL;
762 }
763
764 return 0;
765 }
766
libxl_domain_sched_params_set(libxl_ctx * ctx,uint32_t domid,const libxl_domain_sched_params * scinfo)767 int libxl_domain_sched_params_set(libxl_ctx *ctx, uint32_t domid,
768 const libxl_domain_sched_params *scinfo)
769 {
770 GC_INIT(ctx);
771 libxl_scheduler sched = scinfo->sched;
772 int ret;
773
774 if (sched == LIBXL_SCHEDULER_UNKNOWN)
775 sched = libxl__domain_scheduler(gc, domid);
776
777 switch (sched) {
778 case LIBXL_SCHEDULER_SEDF:
779 LOGD(ERROR, domid, "SEDF scheduler no longer available");
780 ret=ERROR_FEATURE_REMOVED;
781 break;
782 case LIBXL_SCHEDULER_CREDIT:
783 ret=sched_credit_domain_set(gc, domid, scinfo);
784 break;
785 case LIBXL_SCHEDULER_CREDIT2:
786 ret=sched_credit2_domain_set(gc, domid, scinfo);
787 break;
788 case LIBXL_SCHEDULER_ARINC653:
789 ret=sched_arinc653_domain_set(gc, domid, scinfo);
790 break;
791 case LIBXL_SCHEDULER_RTDS:
792 ret=sched_rtds_domain_set(gc, domid, scinfo);
793 break;
794 case LIBXL_SCHEDULER_NULL:
795 ret=sched_null_domain_set(gc, domid, scinfo);
796 break;
797 default:
798 LOGD(ERROR, domid, "Unknown scheduler");
799 ret=ERROR_INVAL;
800 break;
801 }
802
803 GC_FREE;
804 return ret;
805 }
806
libxl_vcpu_sched_params_set(libxl_ctx * ctx,uint32_t domid,const libxl_vcpu_sched_params * scinfo)807 int libxl_vcpu_sched_params_set(libxl_ctx *ctx, uint32_t domid,
808 const libxl_vcpu_sched_params *scinfo)
809 {
810 GC_INIT(ctx);
811 libxl_scheduler sched = scinfo->sched;
812 int rc;
813
814 if (sched == LIBXL_SCHEDULER_UNKNOWN)
815 sched = libxl__domain_scheduler(gc, domid);
816
817 switch (sched) {
818 case LIBXL_SCHEDULER_SEDF:
819 LOGD(ERROR, domid, "SEDF scheduler no longer available");
820 rc = ERROR_FEATURE_REMOVED;
821 break;
822 case LIBXL_SCHEDULER_CREDIT:
823 case LIBXL_SCHEDULER_CREDIT2:
824 case LIBXL_SCHEDULER_ARINC653:
825 case LIBXL_SCHEDULER_NULL:
826 LOGD(ERROR, domid, "per-VCPU parameter setting not supported for this scheduler");
827 rc = ERROR_INVAL;
828 break;
829 case LIBXL_SCHEDULER_RTDS:
830 rc = sched_rtds_vcpu_set(gc, domid, scinfo);
831 break;
832 default:
833 LOGD(ERROR, domid, "Unknown scheduler");
834 rc = ERROR_INVAL;
835 break;
836 }
837
838 GC_FREE;
839 return rc;
840 }
841
libxl_vcpu_sched_params_set_all(libxl_ctx * ctx,uint32_t domid,const libxl_vcpu_sched_params * scinfo)842 int libxl_vcpu_sched_params_set_all(libxl_ctx *ctx, uint32_t domid,
843 const libxl_vcpu_sched_params *scinfo)
844 {
845 GC_INIT(ctx);
846 libxl_scheduler sched = scinfo->sched;
847 int rc;
848
849 if (sched == LIBXL_SCHEDULER_UNKNOWN)
850 sched = libxl__domain_scheduler(gc, domid);
851
852 switch (sched) {
853 case LIBXL_SCHEDULER_SEDF:
854 LOGD(ERROR, domid, "SEDF scheduler no longer available");
855 rc = ERROR_FEATURE_REMOVED;
856 break;
857 case LIBXL_SCHEDULER_CREDIT:
858 case LIBXL_SCHEDULER_CREDIT2:
859 case LIBXL_SCHEDULER_ARINC653:
860 case LIBXL_SCHEDULER_NULL:
861 LOGD(ERROR, domid, "per-VCPU parameter setting not supported for this scheduler");
862 rc = ERROR_INVAL;
863 break;
864 case LIBXL_SCHEDULER_RTDS:
865 rc = sched_rtds_vcpu_set_all(gc, domid, scinfo);
866 break;
867 default:
868 LOGD(ERROR, domid, "Unknown scheduler");
869 rc = ERROR_INVAL;
870 break;
871 }
872
873 GC_FREE;
874 return rc;
875 }
876
libxl_domain_sched_params_get(libxl_ctx * ctx,uint32_t domid,libxl_domain_sched_params * scinfo)877 int libxl_domain_sched_params_get(libxl_ctx *ctx, uint32_t domid,
878 libxl_domain_sched_params *scinfo)
879 {
880 GC_INIT(ctx);
881 int ret;
882
883 libxl_domain_sched_params_init(scinfo);
884
885 scinfo->sched = libxl__domain_scheduler(gc, domid);
886
887 switch (scinfo->sched) {
888 case LIBXL_SCHEDULER_SEDF:
889 LOGD(ERROR, domid, "SEDF scheduler no longer available");
890 ret=ERROR_FEATURE_REMOVED;
891 break;
892 case LIBXL_SCHEDULER_CREDIT:
893 ret=sched_credit_domain_get(gc, domid, scinfo);
894 break;
895 case LIBXL_SCHEDULER_CREDIT2:
896 ret=sched_credit2_domain_get(gc, domid, scinfo);
897 break;
898 case LIBXL_SCHEDULER_RTDS:
899 ret=sched_rtds_domain_get(gc, domid, scinfo);
900 break;
901 case LIBXL_SCHEDULER_NULL:
902 ret=sched_null_domain_get(gc, domid, scinfo);
903 break;
904 default:
905 LOGD(ERROR, domid, "Unknown scheduler");
906 ret=ERROR_INVAL;
907 break;
908 }
909
910 GC_FREE;
911 return ret;
912 }
913
libxl_vcpu_sched_params_get(libxl_ctx * ctx,uint32_t domid,libxl_vcpu_sched_params * scinfo)914 int libxl_vcpu_sched_params_get(libxl_ctx *ctx, uint32_t domid,
915 libxl_vcpu_sched_params *scinfo)
916 {
917 GC_INIT(ctx);
918 int rc;
919
920 scinfo->sched = libxl__domain_scheduler(gc, domid);
921
922 switch (scinfo->sched) {
923 case LIBXL_SCHEDULER_SEDF:
924 LOGD(ERROR, domid, "SEDF scheduler is no longer available");
925 rc = ERROR_FEATURE_REMOVED;
926 break;
927 case LIBXL_SCHEDULER_CREDIT:
928 case LIBXL_SCHEDULER_CREDIT2:
929 case LIBXL_SCHEDULER_ARINC653:
930 case LIBXL_SCHEDULER_NULL:
931 LOGD(ERROR, domid, "per-VCPU parameter getting not supported for this scheduler");
932 rc = ERROR_INVAL;
933 break;
934 case LIBXL_SCHEDULER_RTDS:
935 rc = sched_rtds_vcpu_get(gc, domid, scinfo);
936 break;
937 default:
938 LOGD(ERROR, domid, "Unknown scheduler");
939 rc = ERROR_INVAL;
940 break;
941 }
942
943 GC_FREE;
944 return rc;
945 }
946
libxl_vcpu_sched_params_get_all(libxl_ctx * ctx,uint32_t domid,libxl_vcpu_sched_params * scinfo)947 int libxl_vcpu_sched_params_get_all(libxl_ctx *ctx, uint32_t domid,
948 libxl_vcpu_sched_params *scinfo)
949 {
950 GC_INIT(ctx);
951 int rc;
952
953 scinfo->sched = libxl__domain_scheduler(gc, domid);
954
955 switch (scinfo->sched) {
956 case LIBXL_SCHEDULER_SEDF:
957 LOGD(ERROR, domid, "SEDF scheduler is no longer available");
958 rc = ERROR_FEATURE_REMOVED;
959 break;
960 case LIBXL_SCHEDULER_CREDIT:
961 case LIBXL_SCHEDULER_CREDIT2:
962 case LIBXL_SCHEDULER_ARINC653:
963 case LIBXL_SCHEDULER_NULL:
964 LOGD(ERROR, domid, "per-VCPU parameter getting not supported for this scheduler");
965 rc = ERROR_INVAL;
966 break;
967 case LIBXL_SCHEDULER_RTDS:
968 rc = sched_rtds_vcpu_get_all(gc, domid, scinfo);
969 break;
970 default:
971 LOGD(ERROR, domid, "Unknown scheduler");
972 rc = ERROR_INVAL;
973 break;
974 }
975
976 GC_FREE;
977 return rc;
978 }
979
980 /*
981 * Local variables:
982 * mode: C
983 * c-basic-offset: 4
984 * indent-tabs-mode: nil
985 * End:
986 */
987