提交 90ba118b 编写于 作者: L Li Bin 提交者: Yang Yingliang

iommu/iova: avoid softlockup in fq_flush_timeout

hulk inclusion
category: bugfix
bugzilla: 30859
CVE: NA

---------------------------

There is softlockup under fio pressure test with smmu enabled:
watchdog: BUG: soft lockup - CPU#81 stuck for 22s!  [swapper/81:0]
...
Call trace:
 fq_flush_timeout+0xc0/0x110
 call_timer_fn+0x34/0x178
 expire_timers+0xec/0x158
 run_timer_softirq+0xc0/0x1f8
 __do_softirq+0x120/0x324
 irq_exit+0x11c/0x140
 __handle_domain_irq+0x6c/0xc0
 gic_handle_irq+0x6c/0x170
 el1_irq+0xb8/0x140
 arch_cpu_idle+0x38/0x1c0
 default_idle_call+0x24/0x44
 do_idle+0x1f4/0x2d8
 cpu_startup_entry+0x2c/0x30
 secondary_start_kernel+0x17c/0x1c8

This is because the timer callback fq_flush_timeout may run more than
10ms, and timer may be processed continuously in the softirq so trigger
softlockup. We can use work to deal with fq_ring_free for each cpu which
may take long time, that to avoid triggering softlockup.
Signed-off-by: NLi Bin <huawei.libin@huawei.com>
Reviewed-By: NXie XiuQi <xiexiuqi@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 568ecff8
...@@ -78,6 +78,7 @@ static void free_iova_flush_queue(struct iova_domain *iovad) ...@@ -78,6 +78,7 @@ static void free_iova_flush_queue(struct iova_domain *iovad)
del_timer_sync(&iovad->fq_timer); del_timer_sync(&iovad->fq_timer);
flush_work(&iovad->free_iova_work);
fq_destroy_all_entries(iovad); fq_destroy_all_entries(iovad);
free_percpu(iovad->fq); free_percpu(iovad->fq);
...@@ -87,6 +88,24 @@ static void free_iova_flush_queue(struct iova_domain *iovad) ...@@ -87,6 +88,24 @@ static void free_iova_flush_queue(struct iova_domain *iovad)
iovad->entry_dtor = NULL; iovad->entry_dtor = NULL;
} }
static void fq_ring_free(struct iova_domain *iovad, struct iova_fq *fq);
static void free_iova_work_func(struct work_struct *work)
{
struct iova_domain *iovad;
int cpu;
iovad = container_of(work, struct iova_domain, free_iova_work);
for_each_possible_cpu(cpu) {
unsigned long flags;
struct iova_fq *fq;
fq = per_cpu_ptr(iovad->fq, cpu);
spin_lock_irqsave(&fq->lock, flags);
fq_ring_free(iovad, fq);
spin_unlock_irqrestore(&fq->lock, flags);
}
}
int init_iova_flush_queue(struct iova_domain *iovad, int init_iova_flush_queue(struct iova_domain *iovad,
iova_flush_cb flush_cb, iova_entry_dtor entry_dtor) iova_flush_cb flush_cb, iova_entry_dtor entry_dtor)
{ {
...@@ -117,6 +136,7 @@ int init_iova_flush_queue(struct iova_domain *iovad, ...@@ -117,6 +136,7 @@ int init_iova_flush_queue(struct iova_domain *iovad,
iovad->fq = queue; iovad->fq = queue;
INIT_WORK(&iovad->free_iova_work, free_iova_work_func);
timer_setup(&iovad->fq_timer, fq_flush_timeout, 0); timer_setup(&iovad->fq_timer, fq_flush_timeout, 0);
atomic_set(&iovad->fq_timer_on, 0); atomic_set(&iovad->fq_timer_on, 0);
...@@ -541,20 +561,11 @@ static void fq_destroy_all_entries(struct iova_domain *iovad) ...@@ -541,20 +561,11 @@ static void fq_destroy_all_entries(struct iova_domain *iovad)
static void fq_flush_timeout(struct timer_list *t) static void fq_flush_timeout(struct timer_list *t)
{ {
struct iova_domain *iovad = from_timer(iovad, t, fq_timer); struct iova_domain *iovad = from_timer(iovad, t, fq_timer);
int cpu;
atomic_set(&iovad->fq_timer_on, 0); atomic_set(&iovad->fq_timer_on, 0);
iova_domain_flush(iovad); iova_domain_flush(iovad);
for_each_possible_cpu(cpu) { schedule_work(&iovad->free_iova_work);
unsigned long flags;
struct iova_fq *fq;
fq = per_cpu_ptr(iovad->fq, cpu);
spin_lock_irqsave(&fq->lock, flags);
fq_ring_free(iovad, fq);
spin_unlock_irqrestore(&fq->lock, flags);
}
} }
void queue_iova(struct iova_domain *iovad, void queue_iova(struct iova_domain *iovad,
......
...@@ -97,6 +97,7 @@ struct iova_domain { ...@@ -97,6 +97,7 @@ struct iova_domain {
flush-queues */ flush-queues */
atomic_t fq_timer_on; /* 1 when timer is active, 0 atomic_t fq_timer_on; /* 1 when timer is active, 0
when not */ when not */
struct work_struct free_iova_work;
}; };
static inline unsigned long iova_size(struct iova *iova) static inline unsigned long iova_size(struct iova *iova)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册