On Thu, 15 Feb 2018 18:20:41 +0100
Sebastian Andrzej Siewior <bige...@linutronix.de> wrote:

> -void __tasklet_schedule(struct tasklet_struct *t)
> +static void __tasklet_schedule_common(struct tasklet_struct *t,
> +                                   struct tasklet_head *head,
> +                                   unsigned int softirq_nr)
>  {
>       unsigned long flags;
>  
>       local_irq_save(flags);

If you look at the original patch, it did not move local_irq_save()
into the common function.

>       t->next = NULL;
> -     *__this_cpu_read(tasklet_vec.tail) = t;
> -     __this_cpu_write(tasklet_vec.tail, &(t->next));
> -     raise_softirq_irqoff(TASKLET_SOFTIRQ);
> +     *head->tail = t;
> +     head->tail = &(t->next);
> +     raise_softirq_irqoff(softirq_nr);
>       local_irq_restore(flags);
>  }
> +
> +void __tasklet_schedule(struct tasklet_struct *t)
> +{
> +     __tasklet_schedule_common(t, this_cpu_ptr(&tasklet_vec),

What can happen is, we reference (tasklet_vec) on one CPU, get
preempted (running in ksoftirqd), scheduled on another CPU, then when
inside the common code, we are executing on a different CPU than the
tasklet is for. The rasise_softirq() is happening on the wrong CPU.

The local_irq_save() can't be moved to the common function. It must be
done by each individual function.

-- Steve


> +                               TASKLET_SOFTIRQ);
> +}
>  EXPORT_SYMBOL(__tasklet_schedule);

Reply via email to