debuggers.hg

changeset 21095:4d3834df0483

Do not spin on locks that may be held by stop_machine_run() callers.

Currently stop_machine_run() will try to bring all CPUs to softirq
context, with some locks held, like xenpf_lock or cpu_add_remove_lock
etc. However, if another CPU is trying to get these locks, it may
cause deadlock.

This patch replace all such spin_lock with spin_trylock. For
xenpf_lock and sysctl_lock, we try to use hypercall_continuation, so
that we will not cause trouble to user space tools. For
cpu_hot_remove_lock, we simply return EBUSY if failure, since it will
only impact small number of user space tools.

In the end, we should try to make the stop_machine_run as spinlock
free.

Signed-off-by: Jiang, Yunhong <yunhong.jiang@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Mar 22 10:29:13 2010 +0000 (2010-03-22)
parents 81d9132ce00d
children ab5f65e8137c
files xen/arch/x86/platform_hypercall.c xen/arch/x86/smpboot.c xen/common/sysctl.c
line diff
     1.1 --- a/xen/arch/x86/platform_hypercall.c	Mon Mar 22 10:24:17 2010 +0000
     1.2 +++ b/xen/arch/x86/platform_hypercall.c	Mon Mar 22 10:29:13 2010 +0000
     1.3 @@ -73,7 +73,11 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xe
     1.4      if ( op->interface_version != XENPF_INTERFACE_VERSION )
     1.5          return -EACCES;
     1.6  
     1.7 -    spin_lock(&xenpf_lock);
     1.8 +    /* spin_trylock() avoids deadlock with stop_machine_run(). */
     1.9 +    while ( !spin_trylock(&xenpf_lock) )
    1.10 +        if ( hypercall_preempt_check() )
    1.11 +            return hypercall_create_continuation(
    1.12 +                __HYPERVISOR_platform_op, "h", u_xenpf_op);
    1.13  
    1.14      switch ( op->cmd )
    1.15      {
    1.16 @@ -398,7 +402,12 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xe
    1.17  
    1.18          g_info = &op->u.pcpu_info;
    1.19  
    1.20 -        spin_lock(&cpu_add_remove_lock);
    1.21 +        /* spin_trylock() avoids deadlock with stop_machine_run(). */
    1.22 +        if ( !spin_trylock(&cpu_add_remove_lock) )
    1.23 +        {
    1.24 +            ret = -EBUSY;
    1.25 +            break;
    1.26 +        }
    1.27  
    1.28          if ( (g_info->xen_cpuid >= NR_CPUS) ||
    1.29               (g_info->xen_cpuid < 0) ||
     2.1 --- a/xen/arch/x86/smpboot.c	Mon Mar 22 10:24:17 2010 +0000
     2.2 +++ b/xen/arch/x86/smpboot.c	Mon Mar 22 10:29:13 2010 +0000
     2.3 @@ -1342,7 +1342,12 @@ int cpu_down(unsigned int cpu)
     2.4  {
     2.5  	int err = 0;
     2.6  
     2.7 -	spin_lock(&cpu_add_remove_lock);
     2.8 +	/* spin_trylock() avoids deadlock with stop_machine_run(). */
     2.9 +	if (!spin_trylock(&cpu_add_remove_lock)) {
    2.10 +		err = -EBUSY;
    2.11 +		goto out;
    2.12 +	}
    2.13 +
    2.14  	if (num_online_cpus() == 1) {
    2.15  		err = -EBUSY;
    2.16  		goto out;
    2.17 @@ -1384,7 +1389,10 @@ int cpu_up(unsigned int cpu)
    2.18  {
    2.19  	int err = 0;
    2.20  
    2.21 -	spin_lock(&cpu_add_remove_lock);
    2.22 +	/* spin_trylock() avoids deadlock with stop_machine_run(). */
    2.23 +	if (!spin_trylock(&cpu_add_remove_lock))
    2.24 +	    return -EBUSY;
    2.25 +
    2.26  	if (cpu_online(cpu)) {
    2.27  		printk("Bring up a online cpu. Bogus!\n");
    2.28  		err = -EBUSY;
    2.29 @@ -1419,6 +1427,8 @@ void disable_nonboot_cpus(void)
    2.30  		if (cpu == 0)
    2.31  			continue;
    2.32  		error = cpu_down(cpu);
    2.33 +		/* No need to check EBUSY here */
    2.34 +		ASSERT(error != -EBUSY);
    2.35  		if (!error) {
    2.36  			cpu_set(cpu, frozen_cpus);
    2.37  			printk("CPU%d is down\n", cpu);
    2.38 @@ -1439,6 +1449,8 @@ void enable_nonboot_cpus(void)
    2.39  	mtrr_aps_sync_begin();
    2.40  	for_each_cpu_mask(cpu, frozen_cpus) {
    2.41  		error = cpu_up(cpu);
    2.42 +		/* No conflict will happen here */
    2.43 +		ASSERT(error != -EBUSY);
    2.44  		if (!error) {
    2.45  			printk("CPU%d is up\n", cpu);
    2.46  			continue;
    2.47 @@ -1481,7 +1493,9 @@ int cpu_add(uint32_t apic_id, uint32_t a
    2.48  	if ( physid_isset(apic_id, phys_cpu_present_map) )
    2.49  		return -EEXIST;
    2.50  
    2.51 -	spin_lock(&cpu_add_remove_lock);
    2.52 +	/* spin_trylock() avoids deadlock with stop_machine_run(). */
    2.53 +	if (!spin_trylock(&cpu_add_remove_lock))
    2.54 +		return -EBUSY;
    2.55  
    2.56  	cpu = mp_register_lapic(apic_id, 1);
    2.57  
     3.1 --- a/xen/common/sysctl.c	Mon Mar 22 10:24:17 2010 +0000
     3.2 +++ b/xen/common/sysctl.c	Mon Mar 22 10:29:13 2010 +0000
     3.3 @@ -48,7 +48,11 @@ long do_sysctl(XEN_GUEST_HANDLE(xen_sysc
     3.4      if ( op->interface_version != XEN_SYSCTL_INTERFACE_VERSION )
     3.5          return -EACCES;
     3.6  
     3.7 -    spin_lock(&sysctl_lock);
     3.8 +    /* spin_trylock() avoids deadlock with stop_machine_run(). */
     3.9 +    while ( !spin_trylock(&sysctl_lock) )
    3.10 +        if ( hypercall_preempt_check() )
    3.11 +            return hypercall_create_continuation(
    3.12 +                __HYPERVISOR_sysctl, "h", u_sysctl);
    3.13  
    3.14      switch ( op->cmd )
    3.15      {