fd = kzalloc(sizeof(*fd), GFP_KERNEL);
 
-       if (fd) {
-               fd->rec_cpu_num = -1; /* no cpu affinity by default */
-               fd->mm = current->mm;
-               mmgrab(fd->mm);
-               fd->dd = dd;
-               kobject_get(&fd->dd->kobj);
-               fp->private_data = fd;
-       } else {
-               fp->private_data = NULL;
-
-               if (atomic_dec_and_test(&dd->user_refcount))
-                       complete(&dd->user_comp);
-
-               return -ENOMEM;
-       }
-
+       if (!fd || init_srcu_struct(&fd->pq_srcu))
+               goto nomem;
+       spin_lock_init(&fd->pq_rcu_lock);
+       spin_lock_init(&fd->tid_lock);
+       spin_lock_init(&fd->invalid_lock);
+       fd->rec_cpu_num = -1; /* no cpu affinity by default */
+       fd->mm = current->mm;
+       mmgrab(fd->mm);
+       fd->dd = dd;
+       kobject_get(&fd->dd->kobj);
+       fp->private_data = fd;
        return 0;
+nomem:
+       kfree(fd);
+       fp->private_data = NULL;
+       if (atomic_dec_and_test(&dd->user_refcount))
+               complete(&dd->user_comp);
+       return -ENOMEM;
 }
 
 static long hfi1_file_ioctl(struct file *fp, unsigned int cmd,
 static ssize_t hfi1_write_iter(struct kiocb *kiocb, struct iov_iter *from)
 {
        struct hfi1_filedata *fd = kiocb->ki_filp->private_data;
-       struct hfi1_user_sdma_pkt_q *pq = fd->pq;
+       struct hfi1_user_sdma_pkt_q *pq;
        struct hfi1_user_sdma_comp_q *cq = fd->cq;
        int done = 0, reqs = 0;
        unsigned long dim = from->nr_segs;
+       int idx;
 
-       if (!cq || !pq)
+       idx = srcu_read_lock(&fd->pq_srcu);
+       pq = srcu_dereference(fd->pq, &fd->pq_srcu);
+       if (!cq || !pq) {
+               srcu_read_unlock(&fd->pq_srcu, idx);
                return -EIO;
+       }
 
-       if (!iter_is_iovec(from) || !dim)
+       if (!iter_is_iovec(from) || !dim) {
+               srcu_read_unlock(&fd->pq_srcu, idx);
                return -EINVAL;
+       }
 
        trace_hfi1_sdma_request(fd->dd, fd->uctxt->ctxt, fd->subctxt, dim);
 
-       if (atomic_read(&pq->n_reqs) == pq->n_max_reqs)
+       if (atomic_read(&pq->n_reqs) == pq->n_max_reqs) {
+               srcu_read_unlock(&fd->pq_srcu, idx);
                return -ENOSPC;
+       }
 
        while (dim) {
                int ret;
                reqs++;
        }
 
+       srcu_read_unlock(&fd->pq_srcu, idx);
        return reqs;
 }
 
        if (atomic_dec_and_test(&dd->user_refcount))
                complete(&dd->user_comp);
 
+       cleanup_srcu_struct(&fdata->pq_srcu);
        kfree(fdata);
        return 0;
 }
 
 
 /* Private data for file operations */
 struct hfi1_filedata {
+       struct srcu_struct pq_srcu;
        struct hfi1_devdata *dd;
        struct hfi1_ctxtdata *uctxt;
        struct hfi1_user_sdma_comp_q *cq;
-       struct hfi1_user_sdma_pkt_q *pq;
+       /* update side lock for SRCU */
+       spinlock_t pq_rcu_lock;
+       struct hfi1_user_sdma_pkt_q __rcu *pq;
        u16 subctxt;
        /* for cpu affinity; -1 if none */
        int rec_cpu_num;
 
        pq = kzalloc(sizeof(*pq), GFP_KERNEL);
        if (!pq)
                return -ENOMEM;
-
        pq->dd = dd;
        pq->ctxt = uctxt->ctxt;
        pq->subctxt = fd->subctxt;
                goto pq_mmu_fail;
        }
 
-       fd->pq = pq;
+       rcu_assign_pointer(fd->pq, pq);
        fd->cq = cq;
 
        return 0;
 
        trace_hfi1_sdma_user_free_queues(uctxt->dd, uctxt->ctxt, fd->subctxt);
 
-       pq = fd->pq;
+       spin_lock(&fd->pq_rcu_lock);
+       pq = srcu_dereference_check(fd->pq, &fd->pq_srcu,
+                                   lockdep_is_held(&fd->pq_rcu_lock));
        if (pq) {
+               rcu_assign_pointer(fd->pq, NULL);
+               spin_unlock(&fd->pq_rcu_lock);
+               synchronize_srcu(&fd->pq_srcu);
+               /* at this point there can be no more new requests */
                if (pq->handler)
                        hfi1_mmu_rb_unregister(pq->handler);
                iowait_sdma_drain(&pq->busy);
                kfree(pq->req_in_use);
                kmem_cache_destroy(pq->txreq_cache);
                kfree(pq);
-               fd->pq = NULL;
+       } else {
+               spin_unlock(&fd->pq_rcu_lock);
        }
        if (fd->cq) {
                vfree(fd->cq->comps);
 {
        int ret = 0, i;
        struct hfi1_ctxtdata *uctxt = fd->uctxt;
-       struct hfi1_user_sdma_pkt_q *pq = fd->pq;
+       struct hfi1_user_sdma_pkt_q *pq =
+               srcu_dereference(fd->pq, &fd->pq_srcu);
        struct hfi1_user_sdma_comp_q *cq = fd->cq;
        struct hfi1_devdata *dd = pq->dd;
        unsigned long idx = 0;