@@ -120,17 +120,20 @@ void rvt_cq_enter(struct rvt_cq *cq, struct ib_wc *entry, bool solicited)
if (cq->notify == IB_CQ_NEXT_COMP ||
(cq->notify == IB_CQ_SOLICITED &&
(solicited || entry->status != IB_WC_SUCCESS))) {
+ struct kthread_worker *worker;
+
/*
* This will cause send_complete() to be called in
* another thread.
*/
- spin_lock(&cq->rdi->n_cqs_lock);
- if (likely(cq->rdi->worker)) {
+ rcu_read_lock();
+ worker = rcu_dereference(cq->rdi->worker);
+ if (likely(worker)) {
cq->notify = RVT_CQ_NONE;
cq->triggered++;
- kthread_queue_work(cq->rdi->worker, &cq->comptask);
+ kthread_queue_work(worker, &cq->comptask);
}
- spin_unlock(&cq->rdi->n_cqs_lock);
+ rcu_read_unlock();
}
spin_unlock_irqrestore(&cq->lock, flags);
@@ -512,7 +515,7 @@ int rvt_driver_cq_init(struct rvt_dev_info *rdi)
int cpu;
struct kthread_worker *worker;
- if (rdi->worker)
+ if (rcu_access_pointer(rdi->worker))
return 0;
spin_lock_init(&rdi->n_cqs_lock);
@@ -524,7 +527,7 @@ int rvt_driver_cq_init(struct rvt_dev_info *rdi)
return PTR_ERR(worker);
set_user_nice(worker->task, MIN_NICE);
- rdi->worker = worker;
+ RCU_INIT_POINTER(rdi->worker, worker);
return 0;
}
@@ -536,15 +539,19 @@ void rvt_cq_exit(struct rvt_dev_info *rdi)
{
struct kthread_worker *worker;
- /* block future queuing from send_complete() */
- spin_lock_irq(&rdi->n_cqs_lock);
- worker = rdi->worker;
+ if (!rcu_access_pointer(rdi->worker))
+ return;
+
+ spin_lock(&rdi->n_cqs_lock);
+ worker = rcu_dereference_protected(rdi->worker,
+ lockdep_is_held(&rdi->n_cqs_lock));
if (!worker) {
- spin_unlock_irq(&rdi->n_cqs_lock);
+ spin_unlock(&rdi->n_cqs_lock);
return;
}
- rdi->worker = NULL;
- spin_unlock_irq(&rdi->n_cqs_lock);
+ RCU_INIT_POINTER(rdi->worker, NULL);
+ spin_unlock(&rdi->n_cqs_lock);
+ synchronize_rcu();
kthread_destroy_worker(worker);
}
@@ -402,7 +402,7 @@ struct rvt_dev_info {
spinlock_t pending_lock; /* protect pending mmap list */
/* CQ */
- struct kthread_worker *worker; /* per device cq worker */
+ struct kthread_worker __rcu *worker; /* per device cq worker */
u32 n_cqs_allocated; /* number of CQs allocated for device */
spinlock_t n_cqs_lock; /* protect count of in use cqs */