static int sys_vperfctr_read_sum(struct vperfctr *perfctr, struct perfctr_struct_buf *argp, const struct task_struct *tsk) { struct perfctr_sum_ctrs sum; if (tsk == current) { preempt_disable(); vperfctr_sample(perfctr); } //sum = perfctr->cpu_state.sum; { int j; sum.tsc = perfctr->cpu_state.tsc_sum; for(j = 0; j < ARRAY_SIZE(sum.pmc); ++j) sum.pmc[j] = perfctr->cpu_state.pmc[j].sum; } if (tsk == current) preempt_enable(); return perfctr_copy_to_user(argp, &sum, &perfctr_sum_ctrs_sdesc); }
static int do_vperfctr_read(struct vperfctr *perfctr, unsigned int domain, void __user *dstp, unsigned int dstbytes, struct task_struct *tsk) { union { struct perfctr_sum_ctrs sum; struct vperfctr_control control; struct perfctr_sum_ctrs children; } *tmp; unsigned int tmpbytes; int ret; tmpbytes = dstbytes; if (tmpbytes > PAGE_SIZE) /* primitive sanity check */ return -EINVAL; if (tmpbytes < sizeof(*tmp)) tmpbytes = sizeof(*tmp); tmp = kmem_alloc(tmpbytes); if (!tmp) return -ENOMEM; /* PREEMPT note: While we're reading our own control, another process may ptrace ATTACH to us and update our control. Disable preemption to ensure we get a consistent copy. Not needed for other cases since the perfctr is either unlinked or its owner is ptrace ATTACH suspended by us. */ switch (domain) { case VPERFCTR_DOMAIN_SUM: { int j; vperfctr_sample(perfctr); tmp->sum.tsc = perfctr->cpu_state.user.tsc_sum; for(j = 0; j < ARRAY_SIZE(tmp->sum.pmc); ++j) tmp->sum.pmc[j] = perfctr->cpu_state.user.pmc[j].sum; ret = sizeof(tmp->sum); break; } case VPERFCTR_DOMAIN_CONTROL: tmp->control.si_signo = perfctr->si_signo; tmp->control.preserve = perfctr->preserve; ret = sizeof(tmp->control); break; case VPERFCTR_DOMAIN_CHILDREN: if (tsk) spin_lock(&perfctr->children_lock); tmp->children = perfctr->children; if (tsk) spin_unlock(&perfctr->children_lock); ret = sizeof(tmp->children); break; case PERFCTR_DOMAIN_CPU_CONTROL: if (tmpbytes > sizeof(perfctr->cpu_state.control.header)) tmpbytes = sizeof(perfctr->cpu_state.control.header); memcpy(tmp, &perfctr->cpu_state.control.header, tmpbytes); ret = tmpbytes; break; case PERFCTR_DOMAIN_CPU_MAP: if (tmpbytes > sizeof(perfctr->cpu_state.control.pmc_map)) tmpbytes = sizeof(perfctr->cpu_state.control.pmc_map); memcpy(tmp, perfctr->cpu_state.control.pmc_map, tmpbytes); ret = tmpbytes; break; default: ret = -EFAULT; if (copy_from_user(tmp, dstp, dstbytes) == 0) ret = perfctr_cpu_control_read(&perfctr->cpu_state.control, domain, tmp, dstbytes); } if (ret > 0) { if (ret > dstbytes) ret = dstbytes; if (ret > 0 && copy_to_user(dstp, tmp, ret)) ret = -EFAULT; } kmem_free(tmp); return ret; }
/* Called from update_one_process() [triggered by timer interrupt]. * PRE: perfctr == current->thread.perfctr. * Sample the counters but do not suspend them. * Needed to avoid precision loss due to multiple counter * wraparounds between resume/suspend for CPU-bound processes. * PREEMPT note: called in IRQ context with preemption disabled. */ void __vperfctr_sample(struct vperfctr *perfctr) { if (perfctr->sampling_timer == 0) vperfctr_sample(perfctr); }
// sys_vperfctr_read() -> this() static int do_vperfctr_read(struct vperfctr *perfctr, unsigned int cmd, void __user *argp, unsigned int argbytes, struct task_struct *tsk) { union { struct perfctr_sum_ctrs sum; struct vperfctr_control control; struct perfctr_sum_ctrs children; } *tmp; unsigned int tmpbytes; int ret; /* The state snapshot can be large, so kmalloc() it instead of storing it on the stack. We must use task-private storage to prevent racing with a monitor process attaching to us during the preemptible copy_to_user() step. Therefore we cannot store the snapshot in the perfctr object itself. */ tmp = kmalloc(sizeof(*tmp), GFP_USER); if (!tmp) return -ENOMEM; /* PREEMPT note: While we're reading our own control, another process may ptrace ATTACH to us and update our control. Disable preemption to ensure we get a consistent copy. Not needed for other cases since the perfctr is either unlinked or its owner is ptrace ATTACH suspended by us. */ if (tsk == current) preempt_disable(); switch (cmd) { case VPERFCTR_READ_SUM: { int j; vperfctr_sample(perfctr); tmp->sum.tsc = perfctr->cpu_state.tsc_sum; for(j = 0; j < ARRAY_SIZE(tmp->sum.pmc); ++j) tmp->sum.pmc[j] = perfctr->cpu_state.pmc[j].sum; tmpbytes = sizeof(tmp->sum); } break; case VPERFCTR_READ_CONTROL: tmp->control.si_signo = perfctr->si_signo; tmp->control.cpu_control = perfctr->cpu_state.control; tmp->control.preserve = 0; tmpbytes = sizeof(tmp->control); break; case VPERFCTR_READ_CHILDREN: if (tsk) spin_lock(&perfctr->children_lock); tmp->children = perfctr->children; if (tsk) spin_unlock(&perfctr->children_lock); tmpbytes = sizeof(tmp->children); break; default: tmpbytes = 0; } if (tsk == current) preempt_enable(); ret = -EINVAL; if (tmpbytes > argbytes) tmpbytes = argbytes; if (tmpbytes > 0) { ret = tmpbytes; if (copy_to_user(argp, tmp, tmpbytes)) ret = -EFAULT; } kfree(tmp); return ret; }