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
295 rc = 0;
296 out:
297 GC_FREE;
298 return rc;
299 }
300
libxl_sched_credit_params_set(libxl_ctx * ctx,uint32_t poolid,libxl_sched_credit_params * scinfo)301 int libxl_sched_credit_params_set(libxl_ctx *ctx, uint32_t poolid,
302 libxl_sched_credit_params *scinfo)
303 {
304 struct xen_sysctl_credit_schedule sparam;
305 int r, rc;
306 GC_INIT(ctx);
307
308 if (scinfo->tslice_ms < XEN_SYSCTL_CSCHED_TSLICE_MIN
309 || scinfo->tslice_ms > XEN_SYSCTL_CSCHED_TSLICE_MAX) {
310 LOG(ERROR, "Time slice out of range, valid range is from %d to %d",
311 XEN_SYSCTL_CSCHED_TSLICE_MIN, XEN_SYSCTL_CSCHED_TSLICE_MAX);
312 rc = ERROR_INVAL;
313 goto out;
314 }
315 rc = sched_ratelimit_check(gc, scinfo->ratelimit_us);
316 if (rc) {
317 goto out;
318 }
319 if (scinfo->ratelimit_us > scinfo->tslice_ms*1000) {
320 LOG(ERROR, "Ratelimit cannot be greater than timeslice");
321 rc = ERROR_INVAL;
322 goto out;
323 }
324
325 sparam.tslice_ms = scinfo->tslice_ms;
326 sparam.ratelimit_us = scinfo->ratelimit_us;
327
328 r = xc_sched_credit_params_set(ctx->xch, poolid, &sparam);
329 if ( r < 0 ) {
330 LOGE(ERROR, "Setting Credit scheduler parameters");
331 rc = ERROR_FAIL;
332 goto out;
333 }
334
335 scinfo->tslice_ms = sparam.tslice_ms;
336 scinfo->ratelimit_us = sparam.ratelimit_us;
337
338 rc = 0;
339 out:
340 GC_FREE;
341 return rc;
342 }
343
libxl_sched_credit2_params_get(libxl_ctx * ctx,uint32_t poolid,libxl_sched_credit2_params * scinfo)344 int libxl_sched_credit2_params_get(libxl_ctx *ctx, uint32_t poolid,
345 libxl_sched_credit2_params *scinfo)
346 {
347 struct xen_sysctl_credit2_schedule sparam;
348 int r, rc;
349 GC_INIT(ctx);
350
351 r = xc_sched_credit2_params_get(ctx->xch, poolid, &sparam);
352 if (r < 0) {
353 LOGE(ERROR, "getting Credit2 scheduler parameters");
354 rc = ERROR_FAIL;
355 goto out;
356 }
357
358 scinfo->ratelimit_us = sparam.ratelimit_us;
359
360 rc = 0;
361 out:
362 GC_FREE;
363 return rc;
364 }
365
libxl_sched_credit2_params_set(libxl_ctx * ctx,uint32_t poolid,libxl_sched_credit2_params * scinfo)366 int libxl_sched_credit2_params_set(libxl_ctx *ctx, uint32_t poolid,
367 libxl_sched_credit2_params *scinfo)
368 {
369 struct xen_sysctl_credit2_schedule sparam;
370 int r, rc;
371 GC_INIT(ctx);
372
373 rc = sched_ratelimit_check(gc, scinfo->ratelimit_us);
374 if (rc) goto out;
375
376 sparam.ratelimit_us = scinfo->ratelimit_us;
377
378 r = xc_sched_credit2_params_set(ctx->xch, poolid, &sparam);
379 if (r < 0) {
380 LOGE(ERROR, "Setting Credit2 scheduler parameters");
381 rc = ERROR_FAIL;
382 goto out;
383 }
384
385 scinfo->ratelimit_us = sparam.ratelimit_us;
386
387 rc = 0;
388 out:
389 GC_FREE;
390 return rc;
391 }
392
sched_credit2_domain_get(libxl__gc * gc,uint32_t domid,libxl_domain_sched_params * scinfo)393 static int sched_credit2_domain_get(libxl__gc *gc, uint32_t domid,
394 libxl_domain_sched_params *scinfo)
395 {
396 struct xen_domctl_sched_credit2 sdom;
397 int rc;
398
399 rc = xc_sched_credit2_domain_get(CTX->xch, domid, &sdom);
400 if (rc != 0) {
401 LOGED(ERROR, domid, "Getting domain sched credit2");
402 return ERROR_FAIL;
403 }
404
405 libxl_domain_sched_params_init(scinfo);
406 scinfo->sched = LIBXL_SCHEDULER_CREDIT2;
407 scinfo->weight = sdom.weight;
408 scinfo->cap = sdom.cap;
409
410 return 0;
411 }
412
sched_credit2_domain_set(libxl__gc * gc,uint32_t domid,const libxl_domain_sched_params * scinfo)413 static int sched_credit2_domain_set(libxl__gc *gc, uint32_t domid,
414 const libxl_domain_sched_params *scinfo)
415 {
416 struct xen_domctl_sched_credit2 sdom;
417 xc_domaininfo_t info;
418 int rc;
419
420 rc = xc_domain_getinfolist(CTX->xch, domid, 1, &info);
421 if (rc < 0) {
422 LOGED(ERROR, domid, "Getting domain info");
423 return ERROR_FAIL;
424 }
425 if (rc != 1 || info.domain != domid)
426 return ERROR_INVAL;
427
428 rc = xc_sched_credit2_domain_get(CTX->xch, domid, &sdom);
429 if (rc != 0) {
430 LOGED(ERROR, domid, "Getting domain sched credit2");
431 return ERROR_FAIL;
432 }
433
434 if (scinfo->weight != LIBXL_DOMAIN_SCHED_PARAM_WEIGHT_DEFAULT) {
435 if (scinfo->weight < 1 || scinfo->weight > 65535) {
436 LOGD(ERROR, domid, "Cpu weight out of range, "
437 "valid values are within range from 1 to 65535");
438 return ERROR_INVAL;
439 }
440 sdom.weight = scinfo->weight;
441 }
442
443 if (scinfo->cap != LIBXL_DOMAIN_SCHED_PARAM_CAP_DEFAULT) {
444 if (scinfo->cap < 0
445 || scinfo->cap > (info.max_vcpu_id + 1) * 100) {
446 LOGD(ERROR, domid, "Cpu cap out of range, "
447 "valid range is from 0 to %d for specified number of vcpus",
448 ((info.max_vcpu_id + 1) * 100));
449 return ERROR_INVAL;
450 }
451 sdom.cap = scinfo->cap;
452 }
453
454 rc = xc_sched_credit2_domain_set(CTX->xch, domid, &sdom);
455 if ( rc < 0 ) {
456 LOGED(ERROR, domid, "Setting domain sched credit2");
457 return ERROR_FAIL;
458 }
459
460 return 0;
461 }
462
sched_rtds_validate_params(libxl__gc * gc,int period,int budget)463 static int sched_rtds_validate_params(libxl__gc *gc, int period, int budget)
464 {
465 int rc;
466
467 if (period < 1) {
468 LOG(ERROR, "Invalid VCPU period of %d (it should be >= 1)", period);
469 rc = ERROR_INVAL;
470 goto out;
471 }
472
473 if (budget < 1) {
474 LOG(ERROR, "Invalid VCPU budget of %d (it should be >= 1)", budget);
475 rc = ERROR_INVAL;
476 goto out;
477 }
478
479 if (budget > period) {
480 LOG(ERROR, "VCPU budget must be smaller than or equal to period, "
481 "but %d > %d", budget, period);
482 rc = ERROR_INVAL;
483 goto out;
484 }
485 rc = 0;
486 out:
487 return rc;
488 }
489
490 /* Get the RTDS scheduling parameters of vcpu(s) */
sched_rtds_vcpu_get(libxl__gc * gc,uint32_t domid,libxl_vcpu_sched_params * scinfo)491 static int sched_rtds_vcpu_get(libxl__gc *gc, uint32_t domid,
492 libxl_vcpu_sched_params *scinfo)
493 {
494 uint32_t num_vcpus;
495 int i, r, rc;
496 xc_dominfo_t info;
497 struct xen_domctl_schedparam_vcpu *vcpus;
498
499 r = xc_domain_getinfo(CTX->xch, domid, 1, &info);
500 if (r < 0) {
501 LOGED(ERROR, domid, "Getting domain info");
502 rc = ERROR_FAIL;
503 goto out;
504 }
505
506 if (scinfo->num_vcpus <= 0) {
507 rc = ERROR_INVAL;
508 goto out;
509 } else {
510 num_vcpus = scinfo->num_vcpus;
511 GCNEW_ARRAY(vcpus, num_vcpus);
512 for (i = 0; i < num_vcpus; i++) {
513 if (scinfo->vcpus[i].vcpuid < 0 ||
514 scinfo->vcpus[i].vcpuid > info.max_vcpu_id) {
515 LOGD(ERROR, domid, "VCPU index is out of range, "
516 "valid values are within range from 0 to %d",
517 info.max_vcpu_id);
518 rc = ERROR_INVAL;
519 goto out;
520 }
521 vcpus[i].vcpuid = scinfo->vcpus[i].vcpuid;
522 }
523 }
524
525 r = xc_sched_rtds_vcpu_get(CTX->xch, domid, vcpus, num_vcpus);
526 if (r != 0) {
527 LOGED(ERROR, domid, "Getting vcpu sched rtds");
528 rc = ERROR_FAIL;
529 goto out;
530 }
531 scinfo->sched = LIBXL_SCHEDULER_RTDS;
532 for (i = 0; i < num_vcpus; i++) {
533 scinfo->vcpus[i].period = vcpus[i].u.rtds.period;
534 scinfo->vcpus[i].budget = vcpus[i].u.rtds.budget;
535 scinfo->vcpus[i].extratime =
536 !!(vcpus[i].u.rtds.flags & XEN_DOMCTL_SCHEDRT_extra);
537 scinfo->vcpus[i].vcpuid = vcpus[i].vcpuid;
538 }
539 rc = 0;
540 out:
541 return rc;
542 }
543
544 /* 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)545 static int sched_rtds_vcpu_get_all(libxl__gc *gc, uint32_t domid,
546 libxl_vcpu_sched_params *scinfo)
547 {
548 uint32_t num_vcpus;
549 int i, r, rc;
550 xc_dominfo_t info;
551 struct xen_domctl_schedparam_vcpu *vcpus;
552
553 r = xc_domain_getinfo(CTX->xch, domid, 1, &info);
554 if (r < 0) {
555 LOGED(ERROR, domid, "Getting domain info");
556 rc = ERROR_FAIL;
557 goto out;
558 }
559
560 if (scinfo->num_vcpus > 0) {
561 rc = ERROR_INVAL;
562 goto out;
563 } else {
564 num_vcpus = info.max_vcpu_id + 1;
565 GCNEW_ARRAY(vcpus, num_vcpus);
566 for (i = 0; i < num_vcpus; i++)
567 vcpus[i].vcpuid = i;
568 }
569
570 r = xc_sched_rtds_vcpu_get(CTX->xch, domid, vcpus, num_vcpus);
571 if (r != 0) {
572 LOGED(ERROR, domid, "Getting vcpu sched rtds");
573 rc = ERROR_FAIL;
574 goto out;
575 }
576 scinfo->sched = LIBXL_SCHEDULER_RTDS;
577 scinfo->num_vcpus = num_vcpus;
578 scinfo->vcpus = libxl__calloc(NOGC, num_vcpus,
579 sizeof(libxl_sched_params));
580
581 for (i = 0; i < num_vcpus; i++) {
582 scinfo->vcpus[i].period = vcpus[i].u.rtds.period;
583 scinfo->vcpus[i].budget = vcpus[i].u.rtds.budget;
584 scinfo->vcpus[i].extratime =
585 !!(vcpus[i].u.rtds.flags & XEN_DOMCTL_SCHEDRT_extra);
586 scinfo->vcpus[i].vcpuid = vcpus[i].vcpuid;
587 }
588 rc = 0;
589 out:
590 return rc;
591 }
592
593 /* Set the RTDS scheduling parameters of vcpu(s) */
sched_rtds_vcpu_set(libxl__gc * gc,uint32_t domid,const libxl_vcpu_sched_params * scinfo)594 static int sched_rtds_vcpu_set(libxl__gc *gc, uint32_t domid,
595 const libxl_vcpu_sched_params *scinfo)
596 {
597 int r, rc;
598 int i;
599 uint16_t max_vcpuid;
600 xc_dominfo_t info;
601 struct xen_domctl_schedparam_vcpu *vcpus;
602
603 r = xc_domain_getinfo(CTX->xch, domid, 1, &info);
604 if (r < 0) {
605 LOGED(ERROR, domid, "Getting domain info");
606 rc = ERROR_FAIL;
607 goto out;
608 }
609 max_vcpuid = info.max_vcpu_id;
610
611 if (scinfo->num_vcpus <= 0) {
612 rc = ERROR_INVAL;
613 goto out;
614 }
615 for (i = 0; i < scinfo->num_vcpus; i++) {
616 if (scinfo->vcpus[i].vcpuid < 0 ||
617 scinfo->vcpus[i].vcpuid > max_vcpuid) {
618 LOGD(ERROR, domid, "Invalid VCPU %d: valid range is [0, %d]",
619 scinfo->vcpus[i].vcpuid, max_vcpuid);
620 rc = ERROR_INVAL;
621 goto out;
622 }
623 rc = sched_rtds_validate_params(gc, scinfo->vcpus[i].period,
624 scinfo->vcpus[i].budget);
625 if (rc) {
626 rc = ERROR_INVAL;
627 goto out;
628 }
629 }
630 GCNEW_ARRAY(vcpus, scinfo->num_vcpus);
631 for (i = 0; i < scinfo->num_vcpus; i++) {
632 vcpus[i].vcpuid = scinfo->vcpus[i].vcpuid;
633 vcpus[i].u.rtds.period = scinfo->vcpus[i].period;
634 vcpus[i].u.rtds.budget = scinfo->vcpus[i].budget;
635 if (scinfo->vcpus[i].extratime)
636 vcpus[i].u.rtds.flags |= XEN_DOMCTL_SCHEDRT_extra;
637 else
638 vcpus[i].u.rtds.flags &= ~XEN_DOMCTL_SCHEDRT_extra;
639 }
640
641 r = xc_sched_rtds_vcpu_set(CTX->xch, domid,
642 vcpus, scinfo->num_vcpus);
643 if (r != 0) {
644 LOGED(ERROR, domid, "Setting vcpu sched rtds");
645 rc = ERROR_FAIL;
646 goto out;
647 }
648 rc = 0;
649 out:
650 return rc;
651 }
652
653 /* 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)654 static int sched_rtds_vcpu_set_all(libxl__gc *gc, uint32_t domid,
655 const libxl_vcpu_sched_params *scinfo)
656 {
657 int r, rc;
658 int i;
659 uint16_t max_vcpuid;
660 xc_dominfo_t info;
661 struct xen_domctl_schedparam_vcpu *vcpus;
662 uint32_t num_vcpus;
663
664 r = xc_domain_getinfo(CTX->xch, domid, 1, &info);
665 if (r < 0) {
666 LOGED(ERROR, domid, "Getting domain info");
667 rc = ERROR_FAIL;
668 goto out;
669 }
670 max_vcpuid = info.max_vcpu_id;
671
672 if (scinfo->num_vcpus != 1) {
673 rc = ERROR_INVAL;
674 goto out;
675 }
676 if (sched_rtds_validate_params(gc, scinfo->vcpus[0].period,
677 scinfo->vcpus[0].budget)) {
678 rc = ERROR_INVAL;
679 goto out;
680 }
681 num_vcpus = max_vcpuid + 1;
682 GCNEW_ARRAY(vcpus, num_vcpus);
683 for (i = 0; i < num_vcpus; i++) {
684 vcpus[i].vcpuid = i;
685 vcpus[i].u.rtds.period = scinfo->vcpus[0].period;
686 vcpus[i].u.rtds.budget = scinfo->vcpus[0].budget;
687 if (scinfo->vcpus[0].extratime)
688 vcpus[i].u.rtds.flags |= XEN_DOMCTL_SCHEDRT_extra;
689 else
690 vcpus[i].u.rtds.flags &= ~XEN_DOMCTL_SCHEDRT_extra;
691 }
692
693 r = xc_sched_rtds_vcpu_set(CTX->xch, domid,
694 vcpus, num_vcpus);
695 if (r != 0) {
696 LOGED(ERROR, domid, "Setting vcpu sched rtds");
697 rc = ERROR_FAIL;
698 goto out;
699 }
700 rc = 0;
701 out:
702 return rc;
703 }
704
sched_rtds_domain_get(libxl__gc * gc,uint32_t domid,libxl_domain_sched_params * scinfo)705 static int sched_rtds_domain_get(libxl__gc *gc, uint32_t domid,
706 libxl_domain_sched_params *scinfo)
707 {
708 struct xen_domctl_sched_rtds sdom;
709 int rc;
710
711 rc = xc_sched_rtds_domain_get(CTX->xch, domid, &sdom);
712 if (rc != 0) {
713 LOGED(ERROR, domid, "Getting domain sched rtds");
714 return ERROR_FAIL;
715 }
716
717 libxl_domain_sched_params_init(scinfo);
718
719 scinfo->sched = LIBXL_SCHEDULER_RTDS;
720 scinfo->period = sdom.period;
721 scinfo->budget = sdom.budget;
722
723 return 0;
724 }
725
sched_rtds_domain_set(libxl__gc * gc,uint32_t domid,const libxl_domain_sched_params * scinfo)726 static int sched_rtds_domain_set(libxl__gc *gc, uint32_t domid,
727 const libxl_domain_sched_params *scinfo)
728 {
729 struct xen_domctl_sched_rtds sdom;
730 int rc;
731
732 rc = xc_sched_rtds_domain_get(CTX->xch, domid, &sdom);
733 if (rc != 0) {
734 LOGED(ERROR, domid, "Getting domain sched rtds");
735 return ERROR_FAIL;
736 }
737 if (scinfo->period != LIBXL_DOMAIN_SCHED_PARAM_PERIOD_DEFAULT)
738 sdom.period = scinfo->period;
739 if (scinfo->budget != LIBXL_DOMAIN_SCHED_PARAM_BUDGET_DEFAULT)
740 sdom.budget = scinfo->budget;
741 /* Set extratime by default */
742 if (scinfo->extratime)
743 sdom.flags |= XEN_DOMCTL_SCHEDRT_extra;
744 else
745 sdom.flags &= ~XEN_DOMCTL_SCHEDRT_extra;
746 if (sched_rtds_validate_params(gc, sdom.period, sdom.budget))
747 return ERROR_INVAL;
748
749 rc = xc_sched_rtds_domain_set(CTX->xch, domid, &sdom);
750 if (rc < 0) {
751 LOGED(ERROR, domid, "Setting domain sched rtds");
752 return ERROR_FAIL;
753 }
754
755 return 0;
756 }
757
libxl_domain_sched_params_set(libxl_ctx * ctx,uint32_t domid,const libxl_domain_sched_params * scinfo)758 int libxl_domain_sched_params_set(libxl_ctx *ctx, uint32_t domid,
759 const libxl_domain_sched_params *scinfo)
760 {
761 GC_INIT(ctx);
762 libxl_scheduler sched = scinfo->sched;
763 int ret;
764
765 if (sched == LIBXL_SCHEDULER_UNKNOWN)
766 sched = libxl__domain_scheduler(gc, domid);
767
768 switch (sched) {
769 case LIBXL_SCHEDULER_SEDF:
770 LOGD(ERROR, domid, "SEDF scheduler no longer available");
771 ret=ERROR_FEATURE_REMOVED;
772 break;
773 case LIBXL_SCHEDULER_CREDIT:
774 ret=sched_credit_domain_set(gc, domid, scinfo);
775 break;
776 case LIBXL_SCHEDULER_CREDIT2:
777 ret=sched_credit2_domain_set(gc, domid, scinfo);
778 break;
779 case LIBXL_SCHEDULER_ARINC653:
780 ret=sched_arinc653_domain_set(gc, domid, scinfo);
781 break;
782 case LIBXL_SCHEDULER_RTDS:
783 ret=sched_rtds_domain_set(gc, domid, scinfo);
784 break;
785 case LIBXL_SCHEDULER_NULL:
786 ret=sched_null_domain_set(gc, domid, scinfo);
787 break;
788 default:
789 LOGD(ERROR, domid, "Unknown scheduler");
790 ret=ERROR_INVAL;
791 break;
792 }
793
794 GC_FREE;
795 return ret;
796 }
797
libxl_vcpu_sched_params_set(libxl_ctx * ctx,uint32_t domid,const libxl_vcpu_sched_params * scinfo)798 int libxl_vcpu_sched_params_set(libxl_ctx *ctx, uint32_t domid,
799 const libxl_vcpu_sched_params *scinfo)
800 {
801 GC_INIT(ctx);
802 libxl_scheduler sched = scinfo->sched;
803 int rc;
804
805 if (sched == LIBXL_SCHEDULER_UNKNOWN)
806 sched = libxl__domain_scheduler(gc, domid);
807
808 switch (sched) {
809 case LIBXL_SCHEDULER_SEDF:
810 LOGD(ERROR, domid, "SEDF scheduler no longer available");
811 rc = ERROR_FEATURE_REMOVED;
812 break;
813 case LIBXL_SCHEDULER_CREDIT:
814 case LIBXL_SCHEDULER_CREDIT2:
815 case LIBXL_SCHEDULER_ARINC653:
816 case LIBXL_SCHEDULER_NULL:
817 LOGD(ERROR, domid, "per-VCPU parameter setting not supported for this scheduler");
818 rc = ERROR_INVAL;
819 break;
820 case LIBXL_SCHEDULER_RTDS:
821 rc = sched_rtds_vcpu_set(gc, domid, scinfo);
822 break;
823 default:
824 LOGD(ERROR, domid, "Unknown scheduler");
825 rc = ERROR_INVAL;
826 break;
827 }
828
829 GC_FREE;
830 return rc;
831 }
832
libxl_vcpu_sched_params_set_all(libxl_ctx * ctx,uint32_t domid,const libxl_vcpu_sched_params * scinfo)833 int libxl_vcpu_sched_params_set_all(libxl_ctx *ctx, uint32_t domid,
834 const libxl_vcpu_sched_params *scinfo)
835 {
836 GC_INIT(ctx);
837 libxl_scheduler sched = scinfo->sched;
838 int rc;
839
840 if (sched == LIBXL_SCHEDULER_UNKNOWN)
841 sched = libxl__domain_scheduler(gc, domid);
842
843 switch (sched) {
844 case LIBXL_SCHEDULER_SEDF:
845 LOGD(ERROR, domid, "SEDF scheduler no longer available");
846 rc = ERROR_FEATURE_REMOVED;
847 break;
848 case LIBXL_SCHEDULER_CREDIT:
849 case LIBXL_SCHEDULER_CREDIT2:
850 case LIBXL_SCHEDULER_ARINC653:
851 case LIBXL_SCHEDULER_NULL:
852 LOGD(ERROR, domid, "per-VCPU parameter setting not supported for this scheduler");
853 rc = ERROR_INVAL;
854 break;
855 case LIBXL_SCHEDULER_RTDS:
856 rc = sched_rtds_vcpu_set_all(gc, domid, scinfo);
857 break;
858 default:
859 LOGD(ERROR, domid, "Unknown scheduler");
860 rc = ERROR_INVAL;
861 break;
862 }
863
864 GC_FREE;
865 return rc;
866 }
867
libxl_domain_sched_params_get(libxl_ctx * ctx,uint32_t domid,libxl_domain_sched_params * scinfo)868 int libxl_domain_sched_params_get(libxl_ctx *ctx, uint32_t domid,
869 libxl_domain_sched_params *scinfo)
870 {
871 GC_INIT(ctx);
872 int ret;
873
874 libxl_domain_sched_params_init(scinfo);
875
876 scinfo->sched = libxl__domain_scheduler(gc, domid);
877
878 switch (scinfo->sched) {
879 case LIBXL_SCHEDULER_SEDF:
880 LOGD(ERROR, domid, "SEDF scheduler no longer available");
881 ret=ERROR_FEATURE_REMOVED;
882 break;
883 case LIBXL_SCHEDULER_CREDIT:
884 ret=sched_credit_domain_get(gc, domid, scinfo);
885 break;
886 case LIBXL_SCHEDULER_CREDIT2:
887 ret=sched_credit2_domain_get(gc, domid, scinfo);
888 break;
889 case LIBXL_SCHEDULER_RTDS:
890 ret=sched_rtds_domain_get(gc, domid, scinfo);
891 break;
892 case LIBXL_SCHEDULER_NULL:
893 ret=sched_null_domain_get(gc, domid, scinfo);
894 break;
895 default:
896 LOGD(ERROR, domid, "Unknown scheduler");
897 ret=ERROR_INVAL;
898 break;
899 }
900
901 GC_FREE;
902 return ret;
903 }
904
libxl_vcpu_sched_params_get(libxl_ctx * ctx,uint32_t domid,libxl_vcpu_sched_params * scinfo)905 int libxl_vcpu_sched_params_get(libxl_ctx *ctx, uint32_t domid,
906 libxl_vcpu_sched_params *scinfo)
907 {
908 GC_INIT(ctx);
909 int rc;
910
911 scinfo->sched = libxl__domain_scheduler(gc, domid);
912
913 switch (scinfo->sched) {
914 case LIBXL_SCHEDULER_SEDF:
915 LOGD(ERROR, domid, "SEDF scheduler is no longer available");
916 rc = ERROR_FEATURE_REMOVED;
917 break;
918 case LIBXL_SCHEDULER_CREDIT:
919 case LIBXL_SCHEDULER_CREDIT2:
920 case LIBXL_SCHEDULER_ARINC653:
921 case LIBXL_SCHEDULER_NULL:
922 LOGD(ERROR, domid, "per-VCPU parameter getting not supported for this scheduler");
923 rc = ERROR_INVAL;
924 break;
925 case LIBXL_SCHEDULER_RTDS:
926 rc = sched_rtds_vcpu_get(gc, domid, scinfo);
927 break;
928 default:
929 LOGD(ERROR, domid, "Unknown scheduler");
930 rc = ERROR_INVAL;
931 break;
932 }
933
934 GC_FREE;
935 return rc;
936 }
937
libxl_vcpu_sched_params_get_all(libxl_ctx * ctx,uint32_t domid,libxl_vcpu_sched_params * scinfo)938 int libxl_vcpu_sched_params_get_all(libxl_ctx *ctx, uint32_t domid,
939 libxl_vcpu_sched_params *scinfo)
940 {
941 GC_INIT(ctx);
942 int rc;
943
944 scinfo->sched = libxl__domain_scheduler(gc, domid);
945
946 switch (scinfo->sched) {
947 case LIBXL_SCHEDULER_SEDF:
948 LOGD(ERROR, domid, "SEDF scheduler is no longer available");
949 rc = ERROR_FEATURE_REMOVED;
950 break;
951 case LIBXL_SCHEDULER_CREDIT:
952 case LIBXL_SCHEDULER_CREDIT2:
953 case LIBXL_SCHEDULER_ARINC653:
954 case LIBXL_SCHEDULER_NULL:
955 LOGD(ERROR, domid, "per-VCPU parameter getting not supported for this scheduler");
956 rc = ERROR_INVAL;
957 break;
958 case LIBXL_SCHEDULER_RTDS:
959 rc = sched_rtds_vcpu_get_all(gc, domid, scinfo);
960 break;
961 default:
962 LOGD(ERROR, domid, "Unknown scheduler");
963 rc = ERROR_INVAL;
964 break;
965 }
966
967 GC_FREE;
968 return rc;
969 }
970
971 /*
972 * Local variables:
973 * mode: C
974 * c-basic-offset: 4
975 * indent-tabs-mode: nil
976 * End:
977 */
978