summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitko Haralanov <mitko.haralanov@intel.com>2016-02-03 22:37:41 (GMT)
committerDoug Ledford <dledford@redhat.com>2016-03-11 01:38:00 (GMT)
commita402d6ab409e0e943150a803b94dee76c9de5c27 (patch)
tree1ebf2fa694b4ce6573d33a45300f806e73b00759
parent7580fc31dfbfcacab2a3243342d4b5de4b494cbf (diff)
downloadlinux-a402d6ab409e0e943150a803b94dee76c9de5c27.tar.xz
staging/rdma/hfi1: Fix bug that could block the process on context exit
A race was discovred in the user SDMA code, which could result in an process being stuck in the kernel call indefinitely in certain error conditions. If, during the processing of a user SDMA request, there was an error *and* all outstanding SDMA descriptor had been completed by the time the that error case was handled in the calling function, the state of the packet queue would not get correctly updated resulting in the process subsequently getting stuck, thinking that there are more descriptors to be completed. To handle this scenario, the driver now checks the submitted packet count vs. the completed. If all submitted packets have also been completed, the driver can safely free the request and signal user level. Otherwise, this will be handled by the completion callback. Reviewed-by: Dennis Dalessandro <dennis.dalessandro@intel.com> Signed-off-by: Mitko Haralanov <mitko.haralanov@intel.com> Signed-off-by: Jubin John <jubin.john@intel.com> Signed-off-by: Doug Ledford <dledford@redhat.com>
-rw-r--r--drivers/staging/rdma/hfi1/user_sdma.c5
1 files changed, 4 insertions, 1 deletions
diff --git a/drivers/staging/rdma/hfi1/user_sdma.c b/drivers/staging/rdma/hfi1/user_sdma.c
index 55c7e6a..ac90309 100644
--- a/drivers/staging/rdma/hfi1/user_sdma.c
+++ b/drivers/staging/rdma/hfi1/user_sdma.c
@@ -678,7 +678,6 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
ret = user_sdma_send_pkts(req, pcount);
if (unlikely(ret < 0 && ret != -EBUSY)) {
req->status = ret;
- atomic_dec(&pq->n_reqs);
goto free_req;
}
@@ -703,6 +702,9 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
if (ret != -EBUSY) {
req->status = ret;
set_bit(SDMA_REQ_DONE_ERROR, &req->flags);
+ if (ACCESS_ONCE(req->seqcomp) ==
+ req->seqsubmitted - 1)
+ goto free_req;
return ret;
}
wait_event_interruptible_timeout(
@@ -717,6 +719,7 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
return 0;
free_req:
user_sdma_free_request(req, true);
+ pq_update(pq);
set_comp_state(pq, cq, info.comp_idx, ERROR, req->status);
return ret;
}