[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v14 for-xen-4.5 11/21] x86/VPMU: Interface for setting PMU mode and flags
>>> On 17.10.14 at 23:17, <boris.ostrovsky@xxxxxxxxxx> wrote: > --- a/xen/arch/x86/hvm/vpmu.c > +++ b/xen/arch/x86/hvm/vpmu.c > @@ -21,6 +21,8 @@ > #include <xen/config.h> > #include <xen/sched.h> > #include <xen/xenoprof.h> > +#include <xen/event.h> > +#include <xen/guest_access.h> > #include <asm/regs.h> > #include <asm/types.h> > #include <asm/msr.h> > @@ -32,8 +34,11 @@ > #include <asm/hvm/svm/vmcb.h> > #include <asm/apic.h> > #include <public/pmu.h> > +#include <xen/tasklet.h> > +#include <xsm/xsm.h> Please put the xen/ one alongside the other xen/ ones. > +static int vpmu_force_context_switch(void) > +{ > + unsigned i, numcpus, mycpu; > + static s_time_t start; > + struct vcpu *curr_vcpu = current; > + static DEFINE_PER_CPU(struct tasklet *, sync_task); > + int ret = 0; > + > + numcpus = num_online_cpus(); I think you'd be better off counting these as you schedule the tasklets. > + mycpu = smp_processor_id(); > + > + if ( sync_vcpu != NULL ) /* if set, we may be in hypercall continuation > */ > + { > + if (sync_vcpu != curr_vcpu ) Coding style. > + /* We are not the original caller */ > + return -EAGAIN; That would seem to be the wrong return value then. Also, the HAP side fix for XSA-97 taught us that identifying a caller by vCPU is problematic - in the course of the retries the kernel's scheduler may move the calling process to a different vCPU, yet it's still the legitimate original caller. > + goto cont_wait; > + } > + > + for_each_online_cpu ( i ) > + { > + if ( i == mycpu ) > + continue; > + > + per_cpu(sync_task, i) = xmalloc(struct tasklet); > + if ( per_cpu(sync_task, i) == NULL ) > + { > + printk(XENLOG_WARNING "vpmu_force_context_switch: out of > memory\n"); > + ret = -ENOMEM; > + goto out; > + } > + tasklet_init(per_cpu(sync_task, i), vpmu_sched_checkin, 0); > + } > + > + /* First count is for self */ > + atomic_set(&vpmu_sched_counter, 1); > + > + for_each_online_cpu ( i ) > + { > + if ( i != mycpu ) > + tasklet_schedule_on_cpu(per_cpu(sync_task, i), i); > + } > + > + vpmu_save(current); > + > + sync_vcpu = curr_vcpu; > + start = NOW(); > + > + cont_wait: > + /* > + * Note that we may fail here if a CPU is hot-plugged while we are > + * waiting. We will then time out. > + */ And I continue to miss the handling of the hot-unplug case (or at the very least a note on this being unimplemented [and going to crash], to at least clarify matters to the curious reader). > + while ( atomic_read(&vpmu_sched_counter) != numcpus ) > + { > + s_time_t now; > + > + cpu_relax(); > + > + now = NOW(); > + > + /* Give up after (arbitrarily chosen) 5 seconds */ > + if ( now > start + SECONDS(5) ) > + { > + printk(XENLOG_WARNING > + "vpmu_force_context_switch: failed to sync\n"); > + ret = -EBUSY; > + break; > + } > + > + if ( hypercall_preempt_check() ) > + return hypercall_create_continuation( > + __HYPERVISOR_xenpmu_op, "i", XENPMU_mode_set); Did you test this code path? I don't see how with the missing second hypercall argument the continuation could reliably succeed. > + case XENPMU_mode_set: > + { > + uint32_t current_mode; > + > + if ( copy_from_guest(&pmu_params, arg, 1) ) > + return -EFAULT; > + > + if ( pmu_params.val & ~(XENPMU_MODE_SELF | XENPMU_MODE_HV) ) > + return -EINVAL; > + > + /* 32-bit dom0 can only sample itself */ > + if ( is_pv_32bit_vcpu(current) && (pmu_params.val & XENPMU_MODE_HV) ) > + return -EINVAL; > + > + /* > + * Return error is someone else is in the middle of changing mode --- > + * this is most likely indication of two system administrators > + * working against each other. > + * If continuation from vpmu_force_context_switch() is still pending > + * we can proceed here without getting the lock: > + * vpmu_force_context_switch() will check whether we are the vcpu > that > + * initialted it. > + */ > + if ( (sync_vcpu == NULL) && !spin_trylock(&xenpmu_mode_lock) ) > + return -EAGAIN; Continuing without holding the lock when sync_vcpu != NULL is bogus: What if sync_vcpu got cleared by the time vpmu_force_context_switch() gets around to look at it? > + > + current_mode = vpmu_mode; > + vpmu_mode = pmu_params.val; > + > + if ( vpmu_mode == XENPMU_MODE_OFF ) > + { > + /* > + * Make sure all (non-dom0) VCPUs have unloaded their VPMUs. This > + * can be achieved by having all physical processors go through > + * context_switch(). > + */ > + ret = vpmu_force_context_switch(); > + if ( ret ) > + vpmu_mode = current_mode; > + } > + > + if ( spin_is_locked(&xenpmu_mode_lock) ) > + spin_unlock(&xenpmu_mode_lock); spin_is_locked() only tells you that _someone_ holds the lock - that isn't necessarily the current vCPU. > + break; > + } > + > + case XENPMU_mode_get: > + /* See whether we are in the middle of mode change */ Please make your comments conform to ./CODING_STYLE. > + if ( (sync_vcpu != NULL) || !spin_trylock(&xenpmu_mode_lock) ) > + return -EAGAIN; > + > + memset(&pmu_params, 0, sizeof(pmu_params)); > + pmu_params.val = vpmu_mode; > + spin_unlock(&xenpmu_mode_lock); Is it really meaningful to do this under lock? By the time the caller gets to see it it's stale anyway. > @@ -116,5 +109,21 @@ void vpmu_dump(struct vcpu *v); > extern int acquire_pmu_ownership(int pmu_ownership); > extern void release_pmu_ownership(int pmu_ownership); > > +extern uint64_t vpmu_mode; > +extern uint64_t vpmu_features; Any particular reason for these to not be unsigned int? Jan _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |