Re: [PATCH 1/2] kernel/sofirq: consolidate common code in __tasklet_schedule() + _hi_

From: Steven Rostedt
Date: Thu Feb 15 2018 - 15:07:15 EST


On Thu, 15 Feb 2018 18:20:41 +0100
Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> 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);