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
				
			
		
							
								
								
									
										111
									
								
								kernel/softirq.c
									
										
									
									
									
								
							
							
						
						
									
										111
									
								
								kernel/softirq.c
									
										
									
									
									
								
							|  | @ -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()) { | static void run_ksoftirqd(unsigned int cpu) | ||||||
| 		preempt_disable(); | { | ||||||
| 		if (!local_softirq_pending()) { | 	local_irq_disable(); | ||||||
| 			schedule_preempt_disabled(); | 	if (local_softirq_pending()) { | ||||||
| 		} | 		__do_softirq(); | ||||||
| 
 | 		rcu_note_context_switch(cpu); | ||||||
| 		__set_current_state(TASK_RUNNING); | 		local_irq_enable(); | ||||||
| 
 | 		cond_resched(); | ||||||
| 		while (local_softirq_pending()) { | 		return; | ||||||
| 			/* 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(); |  | ||||||
| 			if (local_softirq_pending()) |  | ||||||
| 				__do_softirq(); |  | ||||||
| 			local_irq_enable(); |  | ||||||
| 			sched_preempt_enable_no_resched(); |  | ||||||
| 			cond_resched(); |  | ||||||
| 			preempt_disable(); |  | ||||||
| 			rcu_note_context_switch((long)__bind_cpu); |  | ||||||
| 		} |  | ||||||
| 		preempt_enable(); |  | ||||||
| 		set_current_state(TASK_INTERRUPTIBLE); |  | ||||||
| 	} | 	} | ||||||
| 	__set_current_state(TASK_RUNNING); | 	local_irq_enable(); | ||||||
| 	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,50 +824,14 @@ 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
	
	 Thomas Gleixner
				Thomas Gleixner