1 /******************************************************************************
2 * xc_cpupool.c
3 *
4 * API for manipulating and obtaining information on cpupools.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation;
9 * version 2.1 of the License.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Copyright (c) 2009, J Gross.
20 */
21
22 #include <stdarg.h>
23 #include <unistd.h>
24 #include "xc_private.h"
25
do_sysctl_save(xc_interface * xch,struct xen_sysctl * sysctl)26 static int do_sysctl_save(xc_interface *xch, struct xen_sysctl *sysctl)
27 {
28 int ret;
29
30 do {
31 ret = do_sysctl(xch, sysctl);
32 } while ( (ret < 0) && (errno == EAGAIN) );
33
34 return ret;
35 }
36
xc_cpupool_create(xc_interface * xch,uint32_t * ppoolid,uint32_t sched_id)37 int xc_cpupool_create(xc_interface *xch,
38 uint32_t *ppoolid,
39 uint32_t sched_id)
40 {
41 int err;
42 DECLARE_SYSCTL;
43
44 sysctl.cmd = XEN_SYSCTL_cpupool_op;
45 sysctl.u.cpupool_op.op = XEN_SYSCTL_CPUPOOL_OP_CREATE;
46 sysctl.u.cpupool_op.cpupool_id = (*ppoolid == XC_CPUPOOL_POOLID_ANY) ?
47 XEN_SYSCTL_CPUPOOL_PAR_ANY : *ppoolid;
48 sysctl.u.cpupool_op.sched_id = sched_id;
49 if ( (err = do_sysctl_save(xch, &sysctl)) != 0 )
50 return err;
51
52 *ppoolid = sysctl.u.cpupool_op.cpupool_id;
53 return 0;
54 }
55
xc_cpupool_destroy(xc_interface * xch,uint32_t poolid)56 int xc_cpupool_destroy(xc_interface *xch,
57 uint32_t poolid)
58 {
59 DECLARE_SYSCTL;
60
61 sysctl.cmd = XEN_SYSCTL_cpupool_op;
62 sysctl.u.cpupool_op.op = XEN_SYSCTL_CPUPOOL_OP_DESTROY;
63 sysctl.u.cpupool_op.cpupool_id = poolid;
64 return do_sysctl_save(xch, &sysctl);
65 }
66
xc_cpupool_getinfo(xc_interface * xch,uint32_t poolid)67 xc_cpupoolinfo_t *xc_cpupool_getinfo(xc_interface *xch,
68 uint32_t poolid)
69 {
70 int err = 0;
71 xc_cpupoolinfo_t *info = NULL;
72 int local_size;
73 DECLARE_SYSCTL;
74 DECLARE_HYPERCALL_BUFFER(uint8_t, local);
75
76 local_size = xc_get_cpumap_size(xch);
77 if (local_size <= 0)
78 {
79 PERROR("Could not get number of cpus");
80 return NULL;
81 }
82
83 local = xc_hypercall_buffer_alloc(xch, local, local_size);
84 if ( local == NULL ) {
85 PERROR("Could not allocate locked memory for xc_cpupool_getinfo");
86 return NULL;
87 }
88
89 sysctl.cmd = XEN_SYSCTL_cpupool_op;
90 sysctl.u.cpupool_op.op = XEN_SYSCTL_CPUPOOL_OP_INFO;
91 sysctl.u.cpupool_op.cpupool_id = poolid;
92 set_xen_guest_handle(sysctl.u.cpupool_op.cpumap.bitmap, local);
93 sysctl.u.cpupool_op.cpumap.nr_bits = local_size * 8;
94
95 err = do_sysctl_save(xch, &sysctl);
96
97 if ( err < 0 )
98 goto out;
99
100 info = calloc(1, sizeof(xc_cpupoolinfo_t));
101 if ( !info )
102 goto out;
103
104 info->cpumap = xc_cpumap_alloc(xch);
105 if (!info->cpumap) {
106 free(info);
107 info = NULL;
108 goto out;
109 }
110 info->cpupool_id = sysctl.u.cpupool_op.cpupool_id;
111 info->sched_id = sysctl.u.cpupool_op.sched_id;
112 info->n_dom = sysctl.u.cpupool_op.n_dom;
113 memcpy(info->cpumap, local, local_size);
114
115 out:
116 xc_hypercall_buffer_free(xch, local);
117
118 return info;
119 }
120
xc_cpupool_infofree(xc_interface * xch,xc_cpupoolinfo_t * info)121 void xc_cpupool_infofree(xc_interface *xch,
122 xc_cpupoolinfo_t *info)
123 {
124 free(info->cpumap);
125 free(info);
126 }
127
xc_cpupool_addcpu(xc_interface * xch,uint32_t poolid,int cpu)128 int xc_cpupool_addcpu(xc_interface *xch,
129 uint32_t poolid,
130 int cpu)
131 {
132 DECLARE_SYSCTL;
133
134 sysctl.cmd = XEN_SYSCTL_cpupool_op;
135 sysctl.u.cpupool_op.op = XEN_SYSCTL_CPUPOOL_OP_ADDCPU;
136 sysctl.u.cpupool_op.cpupool_id = poolid;
137 sysctl.u.cpupool_op.cpu = (cpu < 0) ? XEN_SYSCTL_CPUPOOL_PAR_ANY : cpu;
138 return do_sysctl_save(xch, &sysctl);
139 }
140
141 /*
142 * The hypervisor might return EADDRINUSE when trying to remove a cpu from a
143 * cpupool when a domain running in this cpupool has pinned a vcpu
144 * temporarily. Do some retries in this case, perhaps the situation
145 * cleans up.
146 */
147 #define NUM_RMCPU_BUSY_RETRIES 5
148
xc_cpupool_removecpu(xc_interface * xch,uint32_t poolid,int cpu)149 int xc_cpupool_removecpu(xc_interface *xch,
150 uint32_t poolid,
151 int cpu)
152 {
153 unsigned retries;
154 int err = 0;
155 DECLARE_SYSCTL;
156
157 sysctl.cmd = XEN_SYSCTL_cpupool_op;
158 sysctl.u.cpupool_op.op = XEN_SYSCTL_CPUPOOL_OP_RMCPU;
159 sysctl.u.cpupool_op.cpupool_id = poolid;
160 sysctl.u.cpupool_op.cpu = (cpu < 0) ? XEN_SYSCTL_CPUPOOL_PAR_ANY : cpu;
161 for ( retries = 0; retries < NUM_RMCPU_BUSY_RETRIES; retries++ ) {
162 err = do_sysctl_save(xch, &sysctl);
163 if ( err == 0 || errno != EADDRINUSE )
164 break;
165 }
166 return err;
167 }
168
xc_cpupool_movedomain(xc_interface * xch,uint32_t poolid,uint32_t domid)169 int xc_cpupool_movedomain(xc_interface *xch,
170 uint32_t poolid,
171 uint32_t domid)
172 {
173 DECLARE_SYSCTL;
174
175 sysctl.cmd = XEN_SYSCTL_cpupool_op;
176 sysctl.u.cpupool_op.op = XEN_SYSCTL_CPUPOOL_OP_MOVEDOMAIN;
177 sysctl.u.cpupool_op.cpupool_id = poolid;
178 sysctl.u.cpupool_op.domid = domid;
179 return do_sysctl_save(xch, &sysctl);
180 }
181
xc_cpupool_freeinfo(xc_interface * xch)182 xc_cpumap_t xc_cpupool_freeinfo(xc_interface *xch)
183 {
184 int err = -1;
185 xc_cpumap_t cpumap = NULL;
186 int mapsize;
187 DECLARE_SYSCTL;
188 DECLARE_HYPERCALL_BUFFER(uint8_t, local);
189
190 mapsize = xc_get_cpumap_size(xch);
191 if (mapsize <= 0)
192 return NULL;
193
194 local = xc_hypercall_buffer_alloc(xch, local, mapsize);
195 if ( local == NULL ) {
196 PERROR("Could not allocate locked memory for xc_cpupool_freeinfo");
197 return NULL;
198 }
199
200 sysctl.cmd = XEN_SYSCTL_cpupool_op;
201 sysctl.u.cpupool_op.op = XEN_SYSCTL_CPUPOOL_OP_FREEINFO;
202 set_xen_guest_handle(sysctl.u.cpupool_op.cpumap.bitmap, local);
203 sysctl.u.cpupool_op.cpumap.nr_bits = mapsize * 8;
204
205 err = do_sysctl_save(xch, &sysctl);
206
207 if ( err < 0 )
208 goto out;
209
210 cpumap = xc_cpumap_alloc(xch);
211 if (cpumap == NULL)
212 goto out;
213
214 memcpy(cpumap, local, mapsize);
215
216 out:
217 xc_hypercall_buffer_free(xch, local);
218 return cpumap;
219 }
220