diff options
| author | Jan Kara <jack@suse.cz> | 2013-10-04 09:29:12 -0400 |
|---|---|---|
| committer | Roland Dreier <roland@purestorage.com> | 2013-11-08 17:43:11 -0500 |
| commit | 603e7729920e42b3c2f4dbfab9eef4878cb6e8fa (patch) | |
| tree | 447d2329598d102375c38230f01396662ef57443 | |
| parent | 4adcf7fb6783e354aab38824d803fa8c4f8e8a27 (diff) | |
IB/qib: Convert qib_user_sdma_pin_pages() to use get_user_pages_fast()
qib_user_sdma_queue_pkts() gets called with mmap_sem held for
writing. Except for get_user_pages() deep down in
qib_user_sdma_pin_pages() we don't seem to need mmap_sem at all. Even
more interestingly the function qib_user_sdma_queue_pkts() (and also
qib_user_sdma_coalesce() called somewhat later) call copy_from_user()
which can hit a page fault and we deadlock on trying to get mmap_sem
when handling that fault.
So just make qib_user_sdma_pin_pages() use get_user_pages_fast() and
leave mmap_sem locking for mm.
This deadlock has actually been observed in the wild when the node
is under memory pressure.
Cc: <stable@vger.kernel.org>
Reviewed-by: Mike Marciniszyn <mike.marciniszyn@intel.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Roland Dreier <roland@purestorage.com>
| -rw-r--r-- | drivers/infiniband/hw/qib/qib_user_sdma.c | 6 |
1 files changed, 1 insertions, 5 deletions
diff --git a/drivers/infiniband/hw/qib/qib_user_sdma.c b/drivers/infiniband/hw/qib/qib_user_sdma.c index d0a0ea0c14d6..165aee2ca8a0 100644 --- a/drivers/infiniband/hw/qib/qib_user_sdma.c +++ b/drivers/infiniband/hw/qib/qib_user_sdma.c | |||
| @@ -594,8 +594,7 @@ static int qib_user_sdma_pin_pages(const struct qib_devdata *dd, | |||
| 594 | else | 594 | else |
| 595 | j = npages; | 595 | j = npages; |
| 596 | 596 | ||
| 597 | ret = get_user_pages(current, current->mm, addr, | 597 | ret = get_user_pages_fast(addr, j, 0, pages); |
| 598 | j, 0, 1, pages, NULL); | ||
| 599 | if (ret != j) { | 598 | if (ret != j) { |
| 600 | i = 0; | 599 | i = 0; |
| 601 | j = ret; | 600 | j = ret; |
| @@ -1294,11 +1293,8 @@ int qib_user_sdma_writev(struct qib_ctxtdata *rcd, | |||
| 1294 | int mxp = 8; | 1293 | int mxp = 8; |
| 1295 | int ndesc = 0; | 1294 | int ndesc = 0; |
| 1296 | 1295 | ||
| 1297 | down_write(¤t->mm->mmap_sem); | ||
| 1298 | ret = qib_user_sdma_queue_pkts(dd, ppd, pq, | 1296 | ret = qib_user_sdma_queue_pkts(dd, ppd, pq, |
| 1299 | iov, dim, &list, &mxp, &ndesc); | 1297 | iov, dim, &list, &mxp, &ndesc); |
| 1300 | up_write(¤t->mm->mmap_sem); | ||
| 1301 | |||
| 1302 | if (ret < 0) | 1298 | if (ret < 0) |
| 1303 | goto done_unlock; | 1299 | goto done_unlock; |
| 1304 | else { | 1300 | else { |
