softirq: Check preemption after reenabling interrupts

raise_softirq_irqoff() disables interrupts and wakes the softirq
daemon, but after reenabling interrupts there is no preemption check,
so the execution of the softirq thread might be delayed arbitrarily.

In principle we could add that check to local_irq_enable/restore, but
that's overkill as the rasie_softirq_irqoff() sections are the only
ones which show this behaviour.

Reported-by: Carsten Emde <cbe@osadl.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: stable-rt@vger.kernel.org
This commit is contained in:
Thomas Gleixner 2011-11-13 17:17:09 +01:00 committed by Alibek Omarov
parent fa863e9259
commit 44eb2c6fd2
4 changed files with 15 additions and 0 deletions

View File

@ -38,6 +38,7 @@ void blk_iopoll_sched(struct blk_iopoll *iop)
list_add_tail(&iop->list, this_cpu_ptr(&blk_cpu_iopoll));
__raise_softirq_irqoff(BLOCK_IOPOLL_SOFTIRQ);
local_irq_restore(flags);
preempt_check_resched_rt();
}
EXPORT_SYMBOL(blk_iopoll_sched);
@ -135,6 +136,7 @@ static void blk_iopoll_softirq(struct softirq_action *h)
__raise_softirq_irqoff(BLOCK_IOPOLL_SOFTIRQ);
local_irq_enable();
preempt_check_resched_rt();
}
/**
@ -204,6 +206,7 @@ static int blk_iopoll_cpu_notify(struct notifier_block *self,
this_cpu_ptr(&blk_cpu_iopoll));
__raise_softirq_irqoff(BLOCK_IOPOLL_SOFTIRQ);
local_irq_enable();
preempt_check_resched_rt();
}
return NOTIFY_OK;

View File

@ -51,6 +51,7 @@ static void trigger_softirq(void *data)
raise_softirq_irqoff(BLOCK_SOFTIRQ);
local_irq_restore(flags);
preempt_check_resched_rt();
}
/*
@ -93,6 +94,7 @@ static int blk_cpu_notify(struct notifier_block *self, unsigned long action,
this_cpu_ptr(&blk_cpu_done));
raise_softirq_irqoff(BLOCK_SOFTIRQ);
local_irq_enable();
preempt_check_resched_rt();
}
return NOTIFY_OK;
@ -150,6 +152,7 @@ do_local:
goto do_local;
local_irq_restore(flags);
preempt_check_resched_rt();
}
/**

View File

@ -51,8 +51,10 @@ do { \
#ifdef CONFIG_PREEMPT_RT_BASE
# define preempt_enable_no_resched() sched_preempt_enable_no_resched()
# define preempt_check_resched_rt() preempt_check_resched()
#else
# define preempt_enable_no_resched() preempt_enable()
# define preempt_check_resched_rt() barrier();
#endif
#ifdef CONFIG_PREEMPT
@ -127,6 +129,7 @@ do { \
#define preempt_disable_notrace() barrier()
#define preempt_enable_no_resched_notrace() barrier()
#define preempt_enable_notrace() barrier()
#define preempt_check_resched_rt() barrier()
#endif /* CONFIG_PREEMPT_COUNT */

View File

@ -2154,6 +2154,7 @@ static inline void __netif_reschedule(struct Qdisc *q)
sd->output_queue_tailp = &q->next_sched;
raise_softirq_irqoff(NET_TX_SOFTIRQ);
local_irq_restore(flags);
preempt_check_resched_rt();
}
void __netif_schedule(struct Qdisc *q)
@ -2188,6 +2189,7 @@ void __dev_kfree_skb_irq(struct sk_buff *skb, enum skb_free_reason reason)
__this_cpu_write(softnet_data.completion_queue, skb);
raise_softirq_irqoff(NET_TX_SOFTIRQ);
local_irq_restore(flags);
preempt_check_resched_rt();
}
EXPORT_SYMBOL(__dev_kfree_skb_irq);
@ -3245,6 +3247,7 @@ enqueue:
rps_unlock(sd);
local_irq_restore(flags);
preempt_check_resched_rt();
atomic_long_inc(&skb->dev->rx_dropped);
kfree_skb(skb);
@ -4196,6 +4199,7 @@ static void net_rps_action_and_irq_enable(struct softnet_data *sd)
} else
#endif
local_irq_enable();
preempt_check_resched_rt();
}
static int process_backlog(struct napi_struct *napi, int quota)
@ -4268,6 +4272,7 @@ void __napi_schedule(struct napi_struct *n)
local_irq_save(flags);
____napi_schedule(&__get_cpu_var(softnet_data), n);
local_irq_restore(flags);
preempt_check_resched_rt();
}
EXPORT_SYMBOL(__napi_schedule);
@ -6876,6 +6881,7 @@ static int dev_cpu_callback(struct notifier_block *nfb,
raise_softirq_irqoff(NET_TX_SOFTIRQ);
local_irq_enable();
preempt_check_resched_rt();
/* Process offline CPU's input_pkt_queue */
while ((skb = __skb_dequeue(&oldsd->process_queue))) {