diff options
Diffstat (limited to 'kernel/cpu.c')
| -rw-r--r-- | kernel/cpu.c | 66 | 
1 files changed, 32 insertions, 34 deletions
diff --git a/kernel/cpu.c b/kernel/cpu.c index 36e70845cfc..208cf3497c1 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -97,7 +97,7 @@ static inline void check_for_tasks(int cpu)  		    (!cputime_eq(p->utime, cputime_zero) ||  		     !cputime_eq(p->stime, cputime_zero)))  			printk(KERN_WARNING "Task %s (pid = %d) is on cpu %d\ -				(state = %ld, flags = %lx) \n", +				(state = %ld, flags = %x) \n",  				 p->comm, p->pid, cpu, p->state, p->flags);  	}  	write_unlock_irq(&tasklist_lock); @@ -120,11 +120,13 @@ static int take_cpu_down(void *unused)  }  /* Requires cpu_add_remove_lock to be held */ -static int _cpu_down(unsigned int cpu) +static int _cpu_down(unsigned int cpu, int tasks_frozen)  { -	int err; +	int err, nr_calls = 0;  	struct task_struct *p;  	cpumask_t old_allowed, tmp; +	void *hcpu = (void *)(long)cpu; +	unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;  	if (num_online_cpus() == 1)  		return -EBUSY; @@ -132,12 +134,16 @@ static int _cpu_down(unsigned int cpu)  	if (!cpu_online(cpu))  		return -EINVAL; -	err = raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE, -						(void *)(long)cpu); +	raw_notifier_call_chain(&cpu_chain, CPU_LOCK_ACQUIRE, hcpu); +	err = __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE | mod, +					hcpu, -1, &nr_calls);  	if (err == NOTIFY_BAD) { +		__raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod, +					  hcpu, nr_calls, NULL);  		printk("%s: attempt to take down CPU %u failed\n",  				__FUNCTION__, cpu); -		return -EINVAL; +		err = -EINVAL; +		goto out_release;  	}  	/* Ensure that we are not runnable on dying cpu */ @@ -152,8 +158,8 @@ static int _cpu_down(unsigned int cpu)  	if (IS_ERR(p) || cpu_online(cpu)) {  		/* CPU didn't die: tell everyone.  Can't complain. */ -		if (raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED, -				(void *)(long)cpu) == NOTIFY_BAD) +		if (raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod, +					    hcpu) == NOTIFY_BAD)  			BUG();  		if (IS_ERR(p)) { @@ -170,13 +176,9 @@ static int _cpu_down(unsigned int cpu)  	/* This actually kills the CPU. */  	__cpu_die(cpu); -	/* Move it here so it can run. */ -	kthread_bind(p, get_cpu()); -	put_cpu(); -  	/* CPU is completely dead: tell everyone.  Too late to complain. */ -	if (raw_notifier_call_chain(&cpu_chain, CPU_DEAD, -			(void *)(long)cpu) == NOTIFY_BAD) +	if (raw_notifier_call_chain(&cpu_chain, CPU_DEAD | mod, +				    hcpu) == NOTIFY_BAD)  		BUG();  	check_for_tasks(cpu); @@ -185,6 +187,8 @@ out_thread:  	err = kthread_stop(p);  out_allowed:  	set_cpus_allowed(current, old_allowed); +out_release: +	raw_notifier_call_chain(&cpu_chain, CPU_LOCK_RELEASE, hcpu);  	return err;  } @@ -196,7 +200,7 @@ int cpu_down(unsigned int cpu)  	if (cpu_hotplug_disabled)  		err = -EBUSY;  	else -		err = _cpu_down(cpu); +		err = _cpu_down(cpu, 0);  	mutex_unlock(&cpu_add_remove_lock);  	return err; @@ -204,15 +208,18 @@ int cpu_down(unsigned int cpu)  #endif /*CONFIG_HOTPLUG_CPU*/  /* Requires cpu_add_remove_lock to be held */ -static int __cpuinit _cpu_up(unsigned int cpu) +static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)  { -	int ret; +	int ret, nr_calls = 0;  	void *hcpu = (void *)(long)cpu; +	unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;  	if (cpu_online(cpu) || !cpu_present(cpu))  		return -EINVAL; -	ret = raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu); +	raw_notifier_call_chain(&cpu_chain, CPU_LOCK_ACQUIRE, hcpu); +	ret = __raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE | mod, hcpu, +							-1, &nr_calls);  	if (ret == NOTIFY_BAD) {  		printk("%s: attempt to bring up CPU %u failed\n",  				__FUNCTION__, cpu); @@ -229,12 +236,13 @@ static int __cpuinit _cpu_up(unsigned int cpu)  	BUG_ON(!cpu_online(cpu));  	/* Now call notifier in preparation. */ -	raw_notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu); +	raw_notifier_call_chain(&cpu_chain, CPU_ONLINE | mod, hcpu);  out_notify:  	if (ret != 0) -		raw_notifier_call_chain(&cpu_chain, -				CPU_UP_CANCELED, hcpu); +		__raw_notifier_call_chain(&cpu_chain, +				CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL); +	raw_notifier_call_chain(&cpu_chain, CPU_LOCK_RELEASE, hcpu);  	return ret;  } @@ -247,19 +255,13 @@ int __cpuinit cpu_up(unsigned int cpu)  	if (cpu_hotplug_disabled)  		err = -EBUSY;  	else -		err = _cpu_up(cpu); +		err = _cpu_up(cpu, 0);  	mutex_unlock(&cpu_add_remove_lock);  	return err;  }  #ifdef CONFIG_SUSPEND_SMP -/* Needed to prevent the microcode driver from requesting firmware in its CPU - * hotplug notifier during the suspend/resume. - */ -int suspend_cpu_hotplug; -EXPORT_SYMBOL(suspend_cpu_hotplug); -  static cpumask_t frozen_cpus;  int disable_nonboot_cpus(void) @@ -267,7 +269,6 @@ int disable_nonboot_cpus(void)  	int cpu, first_cpu, error = 0;  	mutex_lock(&cpu_add_remove_lock); -	suspend_cpu_hotplug = 1;  	first_cpu = first_cpu(cpu_online_map);  	/* We take down all of the non-boot CPUs in one shot to avoid races  	 * with the userspace trying to use the CPU hotplug at the same time @@ -277,7 +278,7 @@ int disable_nonboot_cpus(void)  	for_each_online_cpu(cpu) {  		if (cpu == first_cpu)  			continue; -		error = _cpu_down(cpu); +		error = _cpu_down(cpu, 1);  		if (!error) {  			cpu_set(cpu, frozen_cpus);  			printk("CPU%d is down\n", cpu); @@ -294,7 +295,6 @@ int disable_nonboot_cpus(void)  	} else {  		printk(KERN_ERR "Non-boot CPUs are not disabled\n");  	} -	suspend_cpu_hotplug = 0;  	mutex_unlock(&cpu_add_remove_lock);  	return error;  } @@ -309,10 +309,9 @@ void enable_nonboot_cpus(void)  	if (cpus_empty(frozen_cpus))  		goto out; -	suspend_cpu_hotplug = 1;  	printk("Enabling non-boot CPUs ...\n");  	for_each_cpu_mask(cpu, frozen_cpus) { -		error = _cpu_up(cpu); +		error = _cpu_up(cpu, 1);  		if (!error) {  			printk("CPU%d is up\n", cpu);  			continue; @@ -320,7 +319,6 @@ void enable_nonboot_cpus(void)  		printk(KERN_WARNING "Error taking CPU%d up: %d\n", cpu, error);  	}  	cpus_clear(frozen_cpus); -	suspend_cpu_hotplug = 0;  out:  	mutex_unlock(&cpu_add_remove_lock);  }  | 
