debuggers.hg

annotate xen/common/sysctl.c @ 22848:6341fe0f4e5a

Added tag 4.1.0-rc2 for changeset 9dca60d88c63
author Keir Fraser <keir@xen.org>
date Tue Jan 25 14:06:55 2011 +0000 (2011-01-25)
parents 7d07116efc25
children
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 */