# HG changeset patch # User juergen.gross@ts.fujitsu.com # Date 1262180329 -3600 # Node ID 1aa6f84167e2b4bcfed265d775bc3ac72ce321ed # Parent 3f654b88e201a1341786a0e8725c25f40c1162b7 Signed-off-by: juergen.gross@ts.fujitsu.com continue_hypercall_on_cpu rework using tasklets diff -r 3f654b88e201 -r 1aa6f84167e2 xen/arch/x86/domain.c --- a/xen/arch/x86/domain.c Tue Dec 29 15:11:47 2009 +0000 +++ b/xen/arch/x86/domain.c Wed Dec 30 14:38:49 2009 +0100 @@ -1506,42 +1506,71 @@ } struct migrate_info { + struct tasklet tasklet; long (*func)(void *data); void *data; void (*saved_schedule_tail)(struct vcpu *); - cpumask_t saved_affinity; unsigned int nest; + int ret; + struct vcpu *v; + volatile int ready; }; + +static DEFINE_PER_CPU(struct migrate_info *, mig_info); static void continue_hypercall_on_cpu_helper(struct vcpu *v) { struct cpu_user_regs *regs = guest_cpu_user_regs(); struct migrate_info *info = v->arch.continue_info; - cpumask_t mask = info->saved_affinity; void (*saved_schedule_tail)(struct vcpu *) = info->saved_schedule_tail; - regs->eax = info->func(info->data); + while ( !info->ready ) + cpu_relax(); + + regs->eax = info->ret; if ( info->nest-- == 0 ) { + tasklet_kill(&info->tasklet); xfree(info); v->arch.schedule_tail = saved_schedule_tail; v->arch.continue_info = NULL; - vcpu_unlock_affinity(v, &mask); } (*saved_schedule_tail)(v); +} + +static void continue_hypercall_on_cpu_tasklet(struct migrate_info *info) +{ + this_cpu(mig_info) = info; + + while ( !vcpu_runnable(info->v) && info->v->is_running ) + cpu_relax(); + + info->ret = info->func(info->data); + + if ( info->nest == 0 ) + { + info->ready = 1; + vcpu_wake(info->v); + } + + this_cpu(mig_info) = NULL; + + return; } int continue_hypercall_on_cpu(int cpu, long (*func)(void *data), void *data) { struct vcpu *v = current; struct migrate_info *info; - cpumask_t mask = cpumask_of_cpu(cpu); - int rc; if ( cpu == smp_processor_id() ) return func(data); + + info = this_cpu(mig_info); + if ( info != NULL ) + v = info->v; info = v->arch.continue_info; if ( info == NULL ) @@ -1550,16 +1579,12 @@ if ( info == NULL ) return -ENOMEM; - rc = vcpu_lock_affinity(v, &mask); - if ( rc ) - { - xfree(info); - return rc; - } - info->saved_schedule_tail = v->arch.schedule_tail; - info->saved_affinity = mask; info->nest = 0; + info->v = v; + tasklet_init(&info->tasklet, + (void(*)(unsigned long))continue_hypercall_on_cpu_tasklet, + (unsigned long)info); v->arch.schedule_tail = continue_hypercall_on_cpu_helper; v->arch.continue_info = info; @@ -1567,17 +1592,18 @@ else { BUG_ON(info->nest != 0); - rc = vcpu_locked_change_affinity(v, &mask); - if ( rc ) - return rc; info->nest++; } info->func = func; info->data = data; + info->ready = 0; + + tasklet_schedule_cpu(&info->tasklet, cpu); + vcpu_sleep_nosync(v); + raise_softirq(SCHEDULE_SOFTIRQ); /* Dummy return value will be overwritten by new schedule_tail. */ - BUG_ON(!test_bit(SCHEDULE_SOFTIRQ, &softirq_pending(smp_processor_id()))); return 0; } diff -r 3f654b88e201 -r 1aa6f84167e2 xen/common/schedule.c --- a/xen/common/schedule.c Tue Dec 29 15:11:47 2009 +0000 +++ b/xen/common/schedule.c Wed Dec 30 14:38:49 2009 +0100 @@ -367,26 +367,17 @@ } } -static int __vcpu_set_affinity( - struct vcpu *v, cpumask_t *affinity, - bool_t old_lock_status, bool_t new_lock_status) +int vcpu_set_affinity(struct vcpu *v, cpumask_t *affinity) { cpumask_t online_affinity, old_affinity; + if ( v->domain->is_pinned ) + return -EINVAL; cpus_and(online_affinity, *affinity, cpu_online_map); if ( cpus_empty(online_affinity) ) return -EINVAL; vcpu_schedule_lock_irq(v); - - if ( v->affinity_locked != old_lock_status ) - { - BUG_ON(!v->affinity_locked); - vcpu_schedule_unlock_irq(v); - return -EBUSY; - } - - v->affinity_locked = new_lock_status; old_affinity = v->cpu_affinity; v->cpu_affinity = *affinity; @@ -403,36 +394,6 @@ } return 0; -} - -int vcpu_set_affinity(struct vcpu *v, cpumask_t *affinity) -{ - if ( v->domain->is_pinned ) - return -EINVAL; - return __vcpu_set_affinity(v, affinity, 0, 0); -} - -int vcpu_lock_affinity(struct vcpu *v, cpumask_t *affinity) -{ - return __vcpu_set_affinity(v, affinity, 0, 1); -} - -int vcpu_locked_change_affinity(struct vcpu *v, cpumask_t *affinity) -{ - return __vcpu_set_affinity(v, affinity, 1, 1); -} - -void vcpu_unlock_affinity(struct vcpu *v, cpumask_t *affinity) -{ - cpumask_t online_affinity; - - /* Do not fail if no CPU in old affinity mask is online. */ - cpus_and(online_affinity, *affinity, cpu_online_map); - if ( cpus_empty(online_affinity) ) - *affinity = cpu_online_map; - - if ( __vcpu_set_affinity(v, affinity, 1, 0) != 0 ) - BUG(); } /* Block the currently-executing domain until a pertinent event occurs. */ diff -r 3f654b88e201 -r 1aa6f84167e2 xen/common/softirq.c --- a/xen/common/softirq.c Tue Dec 29 15:11:47 2009 +0000 +++ b/xen/common/softirq.c Wed Dec 30 14:38:49 2009 +0100 @@ -88,9 +88,11 @@ } static LIST_HEAD(tasklet_list); +static DEFINE_PER_CPU(struct list_head, tasklet_list_pcpu); static DEFINE_SPINLOCK(tasklet_lock); -void tasklet_schedule(struct tasklet *t) +static void tasklet_schedule_list(struct tasklet *t, struct list_head *tlist, + int cpu) { unsigned long flags; @@ -101,28 +103,44 @@ if ( !t->is_scheduled && !t->is_running ) { BUG_ON(!list_empty(&t->list)); - list_add_tail(&t->list, &tasklet_list); + list_add_tail(&t->list, tlist); } t->is_scheduled = 1; - raise_softirq(TASKLET_SOFTIRQ); + if ( cpu == smp_processor_id() ) + raise_softirq(TASKLET_SOFTIRQ); + else + cpu_raise_softirq(cpu, TASKLET_SOFTIRQ); } spin_unlock_irqrestore(&tasklet_lock, flags); } +void tasklet_schedule(struct tasklet *t) +{ + tasklet_schedule_list(t, &tasklet_list, smp_processor_id()); +} + +void tasklet_schedule_cpu(struct tasklet *t, int cpu) +{ + tasklet_schedule_list(t, &per_cpu(tasklet_list_pcpu, cpu), cpu); +} + static void tasklet_action(void) { + struct list_head *tlist; struct tasklet *t; spin_lock_irq(&tasklet_lock); - if ( list_empty(&tasklet_list) ) + tlist = ( list_empty(&this_cpu(tasklet_list_pcpu)) ) ? &tasklet_list : + &this_cpu(tasklet_list_pcpu); + if ( list_empty(tlist) ) { spin_unlock_irq(&tasklet_lock); return; } - t = list_entry(tasklet_list.next, struct tasklet, list); + t = list_entry(tlist->next, struct tasklet, list); list_del_init(&t->list); BUG_ON(t->is_dead || t->is_running || !t->is_scheduled); @@ -138,14 +156,15 @@ if ( t->is_scheduled ) { BUG_ON(t->is_dead || !list_empty(&t->list)); - list_add_tail(&t->list, &tasklet_list); + list_add_tail(&t->list, tlist); } /* * If there is more work to do then reschedule. We don't grab more work * immediately as we want to allow other softirq work to happen first. */ - if ( !list_empty(&tasklet_list) ) + if ( !list_empty(&tasklet_list) || + !list_empty(&this_cpu(tasklet_list_pcpu)) ) raise_softirq(TASKLET_SOFTIRQ); spin_unlock_irq(&tasklet_lock); @@ -186,6 +205,12 @@ void __init softirq_init(void) { + int i; + + for_each_possible_cpu ( i ) + { + INIT_LIST_HEAD(&per_cpu(tasklet_list_pcpu, i)); + } open_softirq(TASKLET_SOFTIRQ, tasklet_action); } diff -r 3f654b88e201 -r 1aa6f84167e2 xen/include/xen/sched.h --- a/xen/include/xen/sched.h Tue Dec 29 15:11:47 2009 +0000 +++ b/xen/include/xen/sched.h Wed Dec 30 14:38:49 2009 +0100 @@ -130,8 +130,6 @@ bool_t defer_shutdown; /* VCPU is paused following shutdown request (d->is_shutting_down)? */ bool_t paused_for_shutdown; - /* VCPU affinity is temporarily locked from controller changes? */ - bool_t affinity_locked; /* * > 0: a single port is being polled; @@ -579,9 +577,6 @@ void vcpu_force_reschedule(struct vcpu *v); void cpu_disable_scheduler(void); int vcpu_set_affinity(struct vcpu *v, cpumask_t *affinity); -int vcpu_lock_affinity(struct vcpu *v, cpumask_t *affinity); -int vcpu_locked_change_affinity(struct vcpu *v, cpumask_t *affinity); -void vcpu_unlock_affinity(struct vcpu *v, cpumask_t *affinity); void vcpu_runstate_get(struct vcpu *v, struct vcpu_runstate_info *runstate); uint64_t get_cpu_idle_time(unsigned int cpu); diff -r 3f654b88e201 -r 1aa6f84167e2 xen/include/xen/softirq.h --- a/xen/include/xen/softirq.h Tue Dec 29 15:11:47 2009 +0000 +++ b/xen/include/xen/softirq.h Wed Dec 30 14:38:49 2009 +0100 @@ -58,6 +58,7 @@ struct tasklet name = { LIST_HEAD_INIT(name.list), 0, 0, 0, func, data } void tasklet_schedule(struct tasklet *t); +void tasklet_schedule_cpu(struct tasklet *t, int cpu); void tasklet_kill(struct tasklet *t); void tasklet_init( struct tasklet *t, void (*func)(unsigned long), unsigned long data);