Currently send_remote_softirq() API's don't allow single call_single_data struct(like per cpu call_single_data) to be used with multiple send_remote_softirq() calls in parallel (as each of the send_remote_softirq() call reinitializes the call_single_data overwriting the inflight usage. Add a new init_remote_softirq_csd() which will init the call_single_data. Second send_remote_softirq() from the same cpu will now wait on the csd_lock() if the prior send_remote_softirq() is not complete. Signed-off-by: Suresh Siddha Cc: David S. Miller Cc: Jens Axboe --- include/linux/interrupt.h | 8 ++++++-- kernel/softirq.c | 41 +++++++++++++++++++++++++++-------------- 2 files changed, 33 insertions(+), 16 deletions(-) Index: tip/kernel/softirq.c =================================================================== --- tip.orig/kernel/softirq.c +++ tip/kernel/softirq.c @@ -578,24 +578,23 @@ static void remote_softirq_receive(void local_irq_restore(flags); } -static int __try_remote_softirq(struct call_single_data *cp, int cpu, int softirq) +static int __try_remote_softirq(struct call_single_data *cp, int cpu) { if (cpu_online(cpu)) { - cp->func = remote_softirq_receive; - cp->info = cp; - cp->flags = 0; - cp->priv = softirq; - __smp_call_function_single(cpu, cp, 0); return 0; } return 1; } #else /* CONFIG_USE_GENERIC_SMP_HELPERS */ -static int __try_remote_softirq(struct call_single_data *cp, int cpu, int softirq) +static int __try_remote_softirq(struct call_single_data *cp, int cpu) { return 1; } +static void remote_softirq_receive(void *data) +{ + return; +} #endif /** @@ -611,12 +610,12 @@ static int __try_remote_softirq(struct c * Interrupts must be disabled. */ void __send_remote_softirq(struct call_single_data *cp, int cpu, int this_cpu, - int softirq, int fallback) + int fallback) { if (cpu == this_cpu) - __local_trigger(cp, softirq); - else if (__try_remote_softirq(cp, cpu, softirq) && fallback) - __local_trigger(cp, softirq); + __local_trigger(cp, cp->priv); + else if (__try_remote_softirq(cp, cpu) && fallback) + __local_trigger(cp, cp->priv); } EXPORT_SYMBOL(__send_remote_softirq); @@ -629,19 +628,33 @@ EXPORT_SYMBOL(__send_remote_softirq); * Like __send_remote_softirq except that disabling interrupts and * computing the current cpu is done for the caller. */ -void send_remote_softirq(struct call_single_data *cp, int cpu, int softirq, - int fallback) +void send_remote_softirq(struct call_single_data *cp, int cpu, int fallback) { unsigned long flags; int this_cpu; local_irq_save(flags); this_cpu = smp_processor_id(); - __send_remote_softirq(cp, cpu, this_cpu, softirq, fallback); + __send_remote_softirq(cp, cpu, this_cpu, fallback); local_irq_restore(flags); } EXPORT_SYMBOL(send_remote_softirq); +/*** + * init_remote_softirq_csd - initialize the smp_call_function_single()'s + * call single data that will be later used by send_remote_softirq() + * @cp: private SMP call function data area to be initialized + * @softirq: the softirq to be used for the work + */ +void init_remote_softirq_csd(struct call_single_data *cp, int softirq) +{ + cp->func = remote_softirq_receive; + cp->info = cp; + cp->flags = 0; + cp->priv = softirq; +} +EXPORT_SYMBOL(init_remote_softirq_csd); + static int __cpuinit remote_softirq_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) { Index: tip/include/linux/interrupt.h =================================================================== --- tip.orig/include/linux/interrupt.h +++ tip/include/linux/interrupt.h @@ -420,13 +420,17 @@ DECLARE_PER_CPU(struct list_head [NR_SOF * work will be queued to the local cpu. */ extern void send_remote_softirq(struct call_single_data *cp, int cpu, - int softirq, int fallback); + int fallback); /* Like send_remote_softirq(), but the caller must disable local cpu interrupts * and compute the current cpu, passed in as 'this_cpu'. */ extern void __send_remote_softirq(struct call_single_data *cp, int cpu, - int this_cpu, int softirq, int fallback); + int this_cpu, int fallback); + +/* Initialize the call_single_data to be later used with send_remote_softirq(). + */ +extern void init_remote_softirq_csd(struct call_single_data *cp, int softirq); /* Tasklets --- multithreaded analogue of BHs. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/