softirq: Use hotplug thread infrastructure
[ paulmck: Call rcu_note_context_switch() with interrupts enabled. ] Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com> Cc: Rusty Russell <rusty@rustcorp.com.au> Reviewed-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Namhyung Kim <namhyung@kernel.org> Link: http://lkml.kernel.org/r/20120716103948.456416747@linutronix.de Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
		
					parent
					
						
							
								3180d89b47
							
						
					
				
			
			
				commit
				
					
						3e339b5dae
					
				
			
		
					 1 changed files with 27 additions and 84 deletions
				
			
		| 
						 | 
					@ -23,6 +23,7 @@
 | 
				
			||||||
#include <linux/rcupdate.h>
 | 
					#include <linux/rcupdate.h>
 | 
				
			||||||
#include <linux/ftrace.h>
 | 
					#include <linux/ftrace.h>
 | 
				
			||||||
#include <linux/smp.h>
 | 
					#include <linux/smp.h>
 | 
				
			||||||
 | 
					#include <linux/smpboot.h>
 | 
				
			||||||
#include <linux/tick.h>
 | 
					#include <linux/tick.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CREATE_TRACE_POINTS
 | 
					#define CREATE_TRACE_POINTS
 | 
				
			||||||
| 
						 | 
					@ -742,49 +743,22 @@ void __init softirq_init(void)
 | 
				
			||||||
	open_softirq(HI_SOFTIRQ, tasklet_hi_action);
 | 
						open_softirq(HI_SOFTIRQ, tasklet_hi_action);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int run_ksoftirqd(void * __bind_cpu)
 | 
					static int ksoftirqd_should_run(unsigned int cpu)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	set_current_state(TASK_INTERRUPTIBLE);
 | 
						return local_softirq_pending();
 | 
				
			||||||
 | 
					 | 
				
			||||||
	while (!kthread_should_stop()) {
 | 
					 | 
				
			||||||
		preempt_disable();
 | 
					 | 
				
			||||||
		if (!local_softirq_pending()) {
 | 
					 | 
				
			||||||
			schedule_preempt_disabled();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		__set_current_state(TASK_RUNNING);
 | 
					static void run_ksoftirqd(unsigned int cpu)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
		while (local_softirq_pending()) {
 | 
					 | 
				
			||||||
			/* Preempt disable stops cpu going offline.
 | 
					 | 
				
			||||||
			   If already offline, we'll be on wrong CPU:
 | 
					 | 
				
			||||||
			   don't process */
 | 
					 | 
				
			||||||
			if (cpu_is_offline((long)__bind_cpu))
 | 
					 | 
				
			||||||
				goto wait_to_die;
 | 
					 | 
				
			||||||
	local_irq_disable();
 | 
						local_irq_disable();
 | 
				
			||||||
			if (local_softirq_pending())
 | 
						if (local_softirq_pending()) {
 | 
				
			||||||
		__do_softirq();
 | 
							__do_softirq();
 | 
				
			||||||
 | 
							rcu_note_context_switch(cpu);
 | 
				
			||||||
		local_irq_enable();
 | 
							local_irq_enable();
 | 
				
			||||||
			sched_preempt_enable_no_resched();
 | 
					 | 
				
			||||||
		cond_resched();
 | 
							cond_resched();
 | 
				
			||||||
			preempt_disable();
 | 
							return;
 | 
				
			||||||
			rcu_note_context_switch((long)__bind_cpu);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
		preempt_enable();
 | 
						local_irq_enable();
 | 
				
			||||||
		set_current_state(TASK_INTERRUPTIBLE);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	__set_current_state(TASK_RUNNING);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
wait_to_die:
 | 
					 | 
				
			||||||
	preempt_enable();
 | 
					 | 
				
			||||||
	/* Wait for kthread_stop */
 | 
					 | 
				
			||||||
	set_current_state(TASK_INTERRUPTIBLE);
 | 
					 | 
				
			||||||
	while (!kthread_should_stop()) {
 | 
					 | 
				
			||||||
		schedule();
 | 
					 | 
				
			||||||
		set_current_state(TASK_INTERRUPTIBLE);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	__set_current_state(TASK_RUNNING);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_HOTPLUG_CPU
 | 
					#ifdef CONFIG_HOTPLUG_CPU
 | 
				
			||||||
| 
						 | 
					@ -850,48 +824,12 @@ static int __cpuinit cpu_callback(struct notifier_block *nfb,
 | 
				
			||||||
				  unsigned long action,
 | 
									  unsigned long action,
 | 
				
			||||||
				  void *hcpu)
 | 
									  void *hcpu)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int hotcpu = (unsigned long)hcpu;
 | 
					 | 
				
			||||||
	struct task_struct *p;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (action) {
 | 
						switch (action) {
 | 
				
			||||||
	case CPU_UP_PREPARE:
 | 
					 | 
				
			||||||
	case CPU_UP_PREPARE_FROZEN:
 | 
					 | 
				
			||||||
		p = kthread_create_on_node(run_ksoftirqd,
 | 
					 | 
				
			||||||
					   hcpu,
 | 
					 | 
				
			||||||
					   cpu_to_node(hotcpu),
 | 
					 | 
				
			||||||
					   "ksoftirqd/%d", hotcpu);
 | 
					 | 
				
			||||||
		if (IS_ERR(p)) {
 | 
					 | 
				
			||||||
			printk("ksoftirqd for %i failed\n", hotcpu);
 | 
					 | 
				
			||||||
			return notifier_from_errno(PTR_ERR(p));
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		kthread_bind(p, hotcpu);
 | 
					 | 
				
			||||||
  		per_cpu(ksoftirqd, hotcpu) = p;
 | 
					 | 
				
			||||||
 		break;
 | 
					 | 
				
			||||||
	case CPU_ONLINE:
 | 
					 | 
				
			||||||
	case CPU_ONLINE_FROZEN:
 | 
					 | 
				
			||||||
		wake_up_process(per_cpu(ksoftirqd, hotcpu));
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
#ifdef CONFIG_HOTPLUG_CPU
 | 
					#ifdef CONFIG_HOTPLUG_CPU
 | 
				
			||||||
	case CPU_UP_CANCELED:
 | 
					 | 
				
			||||||
	case CPU_UP_CANCELED_FROZEN:
 | 
					 | 
				
			||||||
		if (!per_cpu(ksoftirqd, hotcpu))
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		/* Unbind so it can run.  Fall thru. */
 | 
					 | 
				
			||||||
		kthread_bind(per_cpu(ksoftirqd, hotcpu),
 | 
					 | 
				
			||||||
			     cpumask_any(cpu_online_mask));
 | 
					 | 
				
			||||||
	case CPU_DEAD:
 | 
						case CPU_DEAD:
 | 
				
			||||||
	case CPU_DEAD_FROZEN: {
 | 
						case CPU_DEAD_FROZEN:
 | 
				
			||||||
		static const struct sched_param param = {
 | 
							takeover_tasklets((unsigned long)hcpu);
 | 
				
			||||||
			.sched_priority = MAX_RT_PRIO-1
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		p = per_cpu(ksoftirqd, hotcpu);
 | 
					 | 
				
			||||||
		per_cpu(ksoftirqd, hotcpu) = NULL;
 | 
					 | 
				
			||||||
		sched_setscheduler_nocheck(p, SCHED_FIFO, ¶m);
 | 
					 | 
				
			||||||
		kthread_stop(p);
 | 
					 | 
				
			||||||
		takeover_tasklets(hotcpu);
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
#endif /* CONFIG_HOTPLUG_CPU */
 | 
					#endif /* CONFIG_HOTPLUG_CPU */
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return NOTIFY_OK;
 | 
						return NOTIFY_OK;
 | 
				
			||||||
| 
						 | 
					@ -901,14 +839,19 @@ static struct notifier_block __cpuinitdata cpu_nfb = {
 | 
				
			||||||
	.notifier_call = cpu_callback
 | 
						.notifier_call = cpu_callback
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct smp_hotplug_thread softirq_threads = {
 | 
				
			||||||
 | 
						.store			= &ksoftirqd,
 | 
				
			||||||
 | 
						.thread_should_run	= ksoftirqd_should_run,
 | 
				
			||||||
 | 
						.thread_fn		= run_ksoftirqd,
 | 
				
			||||||
 | 
						.thread_comm		= "ksoftirqd/%u",
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static __init int spawn_ksoftirqd(void)
 | 
					static __init int spawn_ksoftirqd(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	void *cpu = (void *)(long)smp_processor_id();
 | 
					 | 
				
			||||||
	int err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	BUG_ON(err != NOTIFY_OK);
 | 
					 | 
				
			||||||
	cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);
 | 
					 | 
				
			||||||
	register_cpu_notifier(&cpu_nfb);
 | 
						register_cpu_notifier(&cpu_nfb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BUG_ON(smpboot_register_percpu_thread(&softirq_threads));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
early_initcall(spawn_ksoftirqd);
 | 
					early_initcall(spawn_ksoftirqd);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue