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