]> git.baikalelectronics.ru Git - kernel.git/commit
IB/rdmavt: Avoid queuing work into a destroyed cq kthread worker
authorPetr Mladek <pmladek@suse.com>
Wed, 19 Oct 2016 12:07:19 +0000 (14:07 +0200)
committerDoug Ledford <dledford@redhat.com>
Wed, 14 Dec 2016 17:16:11 +0000 (12:16 -0500)
commit38c2969ef89f0e2ebdcdbbc2f62b0325bc90e002
tree24c430ab5e6d794a205bcdfb627fa3ce3422cd38
parent69d3c3b76c6b0cae4f0650ae9b50d1c3dec08f24
IB/rdmavt: Avoid queuing work into a destroyed cq kthread worker

The memory barrier is not enough to protect queuing works into
a destroyed cq kthread. Just imagine the following situation:

CPU1 CPU2

rvt_cq_enter()
  worker =  cq->rdi->worker;

rvt_cq_exit()
  rdi->worker = NULL;
  smp_wmb();
  kthread_flush_worker(worker);
  kthread_stop(worker->task);
  kfree(worker);

  // nothing queued yet =>
  // nothing flushed and
  // happily stopped and freed

  if (likely(worker)) {
     // true => read before CPU2 acted
     cq->notify = RVT_CQ_NONE;
     cq->triggered++;
     kthread_queue_work(worker, &cq->comptask);

  BANG: worker has been flushed/stopped/freed in the meantime.

This patch solves this by protecting the critical sections by
rdi->n_cqs_lock. It seems that this lock is not much contended
and looks reasonable for this purpose.

One catch is that rvt_cq_enter() might be called from IRQ context.
Therefore we must always take the lock with IRQs disabled to avoid
a possible deadlock.

Signed-off-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
drivers/infiniband/sw/rdmavt/cq.c