rev |
line source |
kfraser@11295
|
1 /******************************************************************************
|
kfraser@11295
|
2 * sysctl.c
|
kfraser@11295
|
3 *
|
kfraser@11295
|
4 * System management operations. For use by node control stack.
|
kfraser@11295
|
5 *
|
kfraser@11295
|
6 * Copyright (c) 2002-2006, K Fraser
|
kfraser@11295
|
7 */
|
kfraser@11295
|
8
|
kfraser@11295
|
9 #include <xen/config.h>
|
kfraser@11295
|
10 #include <xen/types.h>
|
kfraser@11295
|
11 #include <xen/lib.h>
|
kfraser@11295
|
12 #include <xen/mm.h>
|
kfraser@11295
|
13 #include <xen/sched.h>
|
kfraser@11295
|
14 #include <xen/domain.h>
|
kfraser@11295
|
15 #include <xen/event.h>
|
kfraser@11295
|
16 #include <xen/domain_page.h>
|
kfraser@11295
|
17 #include <xen/trace.h>
|
kfraser@11295
|
18 #include <xen/console.h>
|
kfraser@11295
|
19 #include <xen/iocap.h>
|
kfraser@11295
|
20 #include <xen/guest_access.h>
|
kfraser@14347
|
21 #include <xen/keyhandler.h>
|
kfraser@11295
|
22 #include <asm/current.h>
|
keir@20323
|
23 #include <xen/hypercall.h>
|
kfraser@11295
|
24 #include <public/sysctl.h>
|
kfraser@15572
|
25 #include <asm/numa.h>
|
kfraser@15572
|
26 #include <xen/nodemask.h>
|
kfraser@15846
|
27 #include <xsm/xsm.h>
|
keir@20323
|
28 #include <xen/pmstat.h>
|
keir@17688
|
29
|
kfraser@13632
|
30 extern long arch_do_sysctl(
|
kfraser@11295
|
31 struct xen_sysctl *op, XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl);
|
keir@20350
|
32 #ifdef LOCK_PROFILE
|
keir@20350
|
33 extern int spinlock_profile_control(xen_sysctl_lockprof_op_t *pc);
|
keir@20350
|
34 #endif
|
kfraser@11295
|
35
|
kfraser@13632
|
36 long do_sysctl(XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl)
|
kfraser@11295
|
37 {
|
kfraser@13632
|
38 long ret = 0;
|
kfraser@11295
|
39 struct xen_sysctl curop, *op = &curop;
|
kfraser@11295
|
40 static DEFINE_SPINLOCK(sysctl_lock);
|
kfraser@11295
|
41
|
kfraser@11295
|
42 if ( !IS_PRIV(current->domain) )
|
kfraser@11295
|
43 return -EPERM;
|
kfraser@11295
|
44
|
kfraser@11295
|
45 if ( copy_from_guest(op, u_sysctl, 1) )
|
kfraser@11295
|
46 return -EFAULT;
|
kfraser@11295
|
47
|
kfraser@11295
|
48 if ( op->interface_version != XEN_SYSCTL_INTERFACE_VERSION )
|
kfraser@11295
|
49 return -EACCES;
|
kfraser@11295
|
50
|
keir@21225
|
51 /*
|
keir@21225
|
52 * Trylock here avoids deadlock with an existing sysctl critical section
|
keir@21225
|
53 * which might (for some current or future reason) want to synchronise
|
keir@21225
|
54 * with this vcpu.
|
keir@21225
|
55 */
|
keir@21095
|
56 while ( !spin_trylock(&sysctl_lock) )
|
keir@21095
|
57 if ( hypercall_preempt_check() )
|
keir@21095
|
58 return hypercall_create_continuation(
|
keir@21095
|
59 __HYPERVISOR_sysctl, "h", u_sysctl);
|
kfraser@11295
|
60
|
kfraser@11295
|
61 switch ( op->cmd )
|
kfraser@11295
|
62 {
|
kfraser@11295
|
63 case XEN_SYSCTL_readconsole:
|
kfraser@11295
|
64 {
|
kfraser@15846
|
65 ret = xsm_readconsole(op->u.readconsole.clear);
|
kfraser@15846
|
66 if ( ret )
|
kfraser@15846
|
67 break;
|
kfraser@15846
|
68
|
keir@16294
|
69 ret = read_console_ring(&op->u.readconsole);
|
kfraser@11295
|
70 if ( copy_to_guest(u_sysctl, op, 1) )
|
kfraser@11295
|
71 ret = -EFAULT;
|
kfraser@11295
|
72 }
|
kfraser@11295
|
73 break;
|
kfraser@11295
|
74
|
kfraser@11295
|
75 case XEN_SYSCTL_tbuf_op:
|
kfraser@11295
|
76 {
|
kfraser@15846
|
77 ret = xsm_tbufcontrol();
|
kfraser@15846
|
78 if ( ret )
|
kfraser@15846
|
79 break;
|
kfraser@15846
|
80
|
kfraser@11295
|
81 ret = tb_control(&op->u.tbuf_op);
|
kfraser@11295
|
82 if ( copy_to_guest(u_sysctl, op, 1) )
|
kfraser@11295
|
83 ret = -EFAULT;
|
kfraser@11295
|
84 }
|
kfraser@11295
|
85 break;
|
kfraser@11295
|
86
|
kfraser@11295
|
87 case XEN_SYSCTL_sched_id:
|
kfraser@11295
|
88 {
|
kfraser@15846
|
89 ret = xsm_sched_id();
|
kfraser@15846
|
90 if ( ret )
|
kfraser@15846
|
91 break;
|
kfraser@15846
|
92
|
kfraser@11295
|
93 op->u.sched_id.sched_id = sched_id();
|
kfraser@11295
|
94 if ( copy_to_guest(u_sysctl, op, 1) )
|
kfraser@11295
|
95 ret = -EFAULT;
|
kfraser@11295
|
96 else
|
kfraser@11295
|
97 ret = 0;
|
kfraser@11295
|
98 }
|
kfraser@11295
|
99 break;
|
kfraser@11295
|
100
|
kfraser@11295
|
101 case XEN_SYSCTL_getdomaininfolist:
|
kfraser@11295
|
102 {
|
kfraser@11295
|
103 struct domain *d;
|
kfraser@11295
|
104 struct xen_domctl_getdomaininfo info;
|
kfraser@11295
|
105 u32 num_domains = 0;
|
kfraser@11295
|
106
|
kfraser@14074
|
107 rcu_read_lock(&domlist_read_lock);
|
kfraser@11295
|
108
|
kfraser@11295
|
109 for_each_domain ( d )
|
kfraser@11295
|
110 {
|
kfraser@11295
|
111 if ( d->domain_id < op->u.getdomaininfolist.first_domain )
|
kfraser@11295
|
112 continue;
|
kfraser@11295
|
113 if ( num_domains == op->u.getdomaininfolist.max_domains )
|
kfraser@11295
|
114 break;
|
kfraser@11295
|
115
|
kfraser@15846
|
116 ret = xsm_getdomaininfo(d);
|
kfraser@15846
|
117 if ( ret )
|
kfraser@15846
|
118 continue;
|
kfraser@15846
|
119
|
kfraser@11295
|
120 getdomaininfo(d, &info);
|
kfraser@11295
|
121
|
kfraser@13632
|
122 if ( copy_to_guest_offset(op->u.getdomaininfolist.buffer,
|
kfraser@13632
|
123 num_domains, &info, 1) )
|
kfraser@11295
|
124 {
|
kfraser@11295
|
125 ret = -EFAULT;
|
kfraser@11295
|
126 break;
|
kfraser@11295
|
127 }
|
kfraser@11295
|
128
|
kfraser@11295
|
129 num_domains++;
|
kfraser@11295
|
130 }
|
kfraser@11295
|
131
|
kfraser@14074
|
132 rcu_read_unlock(&domlist_read_lock);
|
kfraser@11295
|
133
|
kfraser@11295
|
134 if ( ret != 0 )
|
kfraser@11295
|
135 break;
|
kfraser@11295
|
136
|
kfraser@11295
|
137 op->u.getdomaininfolist.num_domains = num_domains;
|
kfraser@11295
|
138
|
kfraser@11295
|
139 if ( copy_to_guest(u_sysctl, op, 1) )
|
kfraser@11295
|
140 ret = -EFAULT;
|
kfraser@11295
|
141 }
|
kfraser@11295
|
142 break;
|
kfraser@11295
|
143
|
kfraser@11295
|
144 #ifdef PERF_COUNTERS
|
steven@11310
|
145 case XEN_SYSCTL_perfc_op:
|
kfraser@11295
|
146 {
|
kfraser@15846
|
147 ret = xsm_perfcontrol();
|
kfraser@15846
|
148 if ( ret )
|
kfraser@15846
|
149 break;
|
kfraser@15846
|
150
|
steven@11310
|
151 ret = perfc_control(&op->u.perfc_op);
|
kfraser@11295
|
152 if ( copy_to_guest(u_sysctl, op, 1) )
|
kfraser@11295
|
153 ret = -EFAULT;
|
kfraser@11295
|
154 }
|
kfraser@11295
|
155 break;
|
kfraser@11295
|
156 #endif
|
kfraser@11295
|
157
|
keir@20350
|
158 #ifdef LOCK_PROFILE
|
keir@20350
|
159 case XEN_SYSCTL_lockprof_op:
|
keir@20350
|
160 {
|
keir@20350
|
161 ret = spinlock_profile_control(&op->u.lockprof_op);
|
keir@20350
|
162 if ( copy_to_guest(u_sysctl, op, 1) )
|
keir@20350
|
163 ret = -EFAULT;
|
keir@20350
|
164 }
|
keir@20350
|
165 break;
|
keir@20350
|
166 #endif
|
kfraser@14347
|
167 case XEN_SYSCTL_debug_keys:
|
kfraser@14347
|
168 {
|
kfraser@14347
|
169 char c;
|
kfraser@14347
|
170 uint32_t i;
|
kfraser@14347
|
171
|
keir@18461
|
172 ret = xsm_debug_keys();
|
keir@18461
|
173 if ( ret )
|
keir@18461
|
174 break;
|
keir@18461
|
175
|
keir@21206
|
176 ret = -EFAULT;
|
kfraser@14347
|
177 for ( i = 0; i < op->u.debug_keys.nr_keys; i++ )
|
kfraser@14347
|
178 {
|
kfraser@14347
|
179 if ( copy_from_guest_offset(&c, op->u.debug_keys.keys, i, 1) )
|
keir@21206
|
180 goto out;
|
kfraser@14347
|
181 handle_keypress(c, guest_cpu_user_regs());
|
kfraser@14347
|
182 }
|
keir@21206
|
183 ret = 0;
|
kfraser@14347
|
184 }
|
kfraser@14347
|
185 break;
|
kfraser@14347
|
186
|
keir@15469
|
187 case XEN_SYSCTL_getcpuinfo:
|
steven@15465
|
188 {
|
steven@15465
|
189 uint32_t i, nr_cpus;
|
keir@15469
|
190 struct xen_sysctl_cpuinfo cpuinfo;
|
steven@15465
|
191
|
keir@15469
|
192 nr_cpus = min_t(uint32_t, op->u.getcpuinfo.max_cpus, NR_CPUS);
|
steven@15465
|
193
|
keir@18461
|
194 ret = xsm_getcpuinfo();
|
keir@18461
|
195 if ( ret )
|
keir@18461
|
196 break;
|
keir@18461
|
197
|
steven@15465
|
198 for ( i = 0; i < nr_cpus; i++ )
|
steven@15465
|
199 {
|
keir@18936
|
200 cpuinfo.idletime = get_cpu_idle_time(i);
|
keir@15467
|
201
|
keir@16037
|
202 ret = -EFAULT;
|
keir@15469
|
203 if ( copy_to_guest_offset(op->u.getcpuinfo.info, i, &cpuinfo, 1) )
|
keir@16037
|
204 goto out;
|
steven@15465
|
205 }
|
steven@15465
|
206
|
keir@15469
|
207 op->u.getcpuinfo.nr_cpus = i;
|
keir@16037
|
208 ret = copy_to_guest(u_sysctl, op, 1) ? -EFAULT : 0;
|
steven@15465
|
209 }
|
steven@15465
|
210 break;
|
steven@15465
|
211
|
kfraser@15572
|
212 case XEN_SYSCTL_availheap:
|
kfraser@15572
|
213 {
|
keir@18461
|
214 ret = xsm_availheap();
|
keir@18461
|
215 if ( ret )
|
keir@18461
|
216 break;
|
keir@18461
|
217
|
kfraser@15572
|
218 op->u.availheap.avail_bytes = avail_domheap_pages_region(
|
kfraser@15572
|
219 op->u.availheap.node,
|
kfraser@15572
|
220 op->u.availheap.min_bitwidth,
|
kfraser@15572
|
221 op->u.availheap.max_bitwidth);
|
kfraser@15572
|
222 op->u.availheap.avail_bytes <<= PAGE_SHIFT;
|
kfraser@15572
|
223
|
kfraser@15572
|
224 ret = copy_to_guest(u_sysctl, op, 1) ? -EFAULT : 0;
|
kfraser@15572
|
225 }
|
kfraser@15572
|
226 break;
|
kfraser@15572
|
227
|
keir@17688
|
228 case XEN_SYSCTL_get_pmstat:
|
keir@17688
|
229 {
|
keir@19540
|
230 ret = xsm_get_pmstat();
|
keir@19540
|
231 if ( ret )
|
keir@19540
|
232 break;
|
keir@19540
|
233
|
keir@17688
|
234 ret = do_get_pm_info(&op->u.get_pmstat);
|
keir@17688
|
235 if ( ret )
|
keir@17688
|
236 break;
|
keir@17688
|
237
|
keir@17688
|
238 if ( copy_to_guest(u_sysctl, op, 1) )
|
keir@17688
|
239 {
|
keir@17688
|
240 ret = -EFAULT;
|
keir@17688
|
241 break;
|
keir@17688
|
242 }
|
keir@17688
|
243 }
|
keir@17688
|
244 break;
|
keir@17688
|
245
|
keir@18932
|
246 case XEN_SYSCTL_pm_op:
|
keir@18932
|
247 {
|
keir@19540
|
248 ret = xsm_pm_op();
|
keir@19540
|
249 if ( ret )
|
keir@19540
|
250 break;
|
keir@19540
|
251
|
keir@18932
|
252 ret = do_pm_op(&op->u.pm_op);
|
keir@18932
|
253 if ( ret && (ret != -EAGAIN) )
|
keir@18932
|
254 break;
|
keir@18932
|
255
|
keir@19393
|
256 if ( copy_to_guest(u_sysctl, op, 1) )
|
keir@19393
|
257 {
|
keir@19393
|
258 ret = -EFAULT;
|
keir@19393
|
259 break;
|
keir@19393
|
260 }
|
keir@18932
|
261 }
|
keir@18932
|
262 break;
|
keir@18932
|
263
|
keir@19324
|
264 case XEN_SYSCTL_page_offline_op:
|
keir@19324
|
265 {
|
keir@19324
|
266 uint32_t *status, *ptr;
|
keir@19324
|
267 unsigned long pfn;
|
keir@19324
|
268
|
keir@19324
|
269 ptr = status = xmalloc_bytes( sizeof(uint32_t) *
|
keir@19324
|
270 (op->u.page_offline.end -
|
keir@19324
|
271 op->u.page_offline.start + 1));
|
keir@19381
|
272 if ( !status )
|
keir@19324
|
273 {
|
keir@19324
|
274 dprintk(XENLOG_WARNING, "Out of memory for page offline op\n");
|
keir@19324
|
275 ret = -ENOMEM;
|
keir@19324
|
276 break;
|
keir@19324
|
277 }
|
keir@19324
|
278
|
keir@19324
|
279 memset(status, PG_OFFLINE_INVALID, sizeof(uint32_t) *
|
keir@19324
|
280 (op->u.page_offline.end - op->u.page_offline.start + 1));
|
keir@19324
|
281
|
keir@19324
|
282 for ( pfn = op->u.page_offline.start;
|
keir@19324
|
283 pfn <= op->u.page_offline.end;
|
keir@19324
|
284 pfn ++ )
|
keir@19324
|
285 {
|
keir@19381
|
286 switch ( op->u.page_offline.cmd )
|
keir@19324
|
287 {
|
keir@19324
|
288 /* Shall revert her if failed, or leave caller do it? */
|
keir@19324
|
289 case sysctl_page_offline:
|
keir@19324
|
290 ret = offline_page(pfn, 0, ptr++);
|
keir@19324
|
291 break;
|
keir@19324
|
292 case sysctl_page_online:
|
keir@19324
|
293 ret = online_page(pfn, ptr++);
|
keir@19324
|
294 break;
|
keir@19324
|
295 case sysctl_query_page_offline:
|
keir@19324
|
296 ret = query_page_offline(pfn, ptr++);
|
keir@19324
|
297 break;
|
keir@19324
|
298 default:
|
keir@19324
|
299 gdprintk(XENLOG_WARNING, "invalid page offline op %x\n",
|
keir@19324
|
300 op->u.page_offline.cmd);
|
keir@19324
|
301 ret = -EINVAL;
|
keir@19324
|
302 break;
|
keir@19324
|
303 }
|
keir@19324
|
304
|
keir@19324
|
305 if (ret)
|
keir@19324
|
306 break;
|
keir@19324
|
307 }
|
keir@19324
|
308
|
keir@19381
|
309 if ( copy_to_guest(
|
keir@19381
|
310 op->u.page_offline.status, status,
|
keir@19381
|
311 op->u.page_offline.end - op->u.page_offline.start + 1) )
|
keir@19324
|
312 {
|
keir@19324
|
313 ret = -EFAULT;
|
keir@19324
|
314 break;
|
keir@19324
|
315 }
|
keir@19381
|
316
|
keir@19324
|
317 xfree(status);
|
keir@19324
|
318 }
|
keir@19324
|
319 break;
|
keir@19324
|
320
|
keir@21326
|
321 case XEN_SYSCTL_cpupool_op:
|
keir@21326
|
322 {
|
keir@21326
|
323 ret = cpupool_do_sysctl(&op->u.cpupool_op);
|
keir@21326
|
324 if ( (ret == 0) && copy_to_guest(u_sysctl, op, 1) )
|
keir@21326
|
325 ret = -EFAULT;
|
keir@21326
|
326 }
|
keir@21326
|
327 break;
|
keir@21326
|
328
|
keir@21328
|
329 case XEN_SYSCTL_scheduler_op:
|
keir@21328
|
330 {
|
keir@21328
|
331 ret = sched_adjust_global(&op->u.scheduler_op);
|
keir@21328
|
332 if ( (ret == 0) && copy_to_guest(u_sysctl, op, 1) )
|
keir@21328
|
333 ret = -EFAULT;
|
keir@21328
|
334 }
|
keir@21328
|
335 break;
|
keir@21328
|
336
|
kfraser@11295
|
337 default:
|
kfraser@11295
|
338 ret = arch_do_sysctl(op, u_sysctl);
|
kfraser@11295
|
339 break;
|
kfraser@11295
|
340 }
|
kfraser@11295
|
341
|
keir@16037
|
342 out:
|
kfraser@11295
|
343 spin_unlock(&sysctl_lock);
|
kfraser@11295
|
344
|
kfraser@11295
|
345 return ret;
|
kfraser@11295
|
346 }
|
kfraser@11295
|
347
|
kfraser@11295
|
348 /*
|
kfraser@11295
|
349 * Local variables:
|
kfraser@11295
|
350 * mode: C
|
kfraser@11295
|
351 * c-set-style: "BSD"
|
kfraser@11295
|
352 * c-basic-offset: 4
|
kfraser@11295
|
353 * tab-width: 4
|
kfraser@11295
|
354 * indent-tabs-mode: nil
|
kfraser@11295
|
355 * End:
|
kfraser@11295
|
356 */
|