Commit e0c4a422 authored by Dean Luick's avatar Dean Luick Committed by Leon Romanovsky

IB/hfi1: Fix expected receive setup error exit issues

Fix three error exit issues in expected receive setup.
Re-arrange error exits to increase readability.

Issues and fixes:
1. Possible missed page unpin if tidlist copyout fails and
   not all pinned pages where made part of a TID.
   Fix: Unpin the unused pages.

2. Return success with unset return values tidcnt and length
   when no pages were pinned.
   Fix: Return -ENOSPC if no pages were pinned.

3. Return success with unset return values tidcnt and length when
   no rcvarray entries available.
   Fix: Return -ENOSPC if no rcvarray entries are available.

Fixes: 7e7a436e ("staging/hfi1: Add TID entry program function body")
Fixes: 97736f36 ("IB/hfi1: Validate page aligned for a given virtual addres")
Fixes: f404ca4c ("IB/hfi1: Refactor hfi_user_exp_rcv_setup() IOCTL")
Signed-off-by: default avatarDean Luick <dean.luick@cornelisnetworks.com>
Signed-off-by: default avatarDennis Dalessandro <dennis.dalessandro@cornelisnetworks.com>
Link: https://lore.kernel.org/r/167328548150.1472310.1492305874804187634.stgit@awfm-02.cornelisnetworks.comSigned-off-by: default avatarLeon Romanovsky <leon@kernel.org>
parent ecf91551
...@@ -268,15 +268,14 @@ int hfi1_user_exp_rcv_setup(struct hfi1_filedata *fd, ...@@ -268,15 +268,14 @@ int hfi1_user_exp_rcv_setup(struct hfi1_filedata *fd,
tidbuf->psets = kcalloc(uctxt->expected_count, sizeof(*tidbuf->psets), tidbuf->psets = kcalloc(uctxt->expected_count, sizeof(*tidbuf->psets),
GFP_KERNEL); GFP_KERNEL);
if (!tidbuf->psets) { if (!tidbuf->psets) {
kfree(tidbuf); ret = -ENOMEM;
return -ENOMEM; goto fail_release_mem;
} }
pinned = pin_rcv_pages(fd, tidbuf); pinned = pin_rcv_pages(fd, tidbuf);
if (pinned <= 0) { if (pinned <= 0) {
kfree(tidbuf->psets); ret = (pinned < 0) ? pinned : -ENOSPC;
kfree(tidbuf); goto fail_unpin;
return pinned;
} }
/* Find sets of physically contiguous pages */ /* Find sets of physically contiguous pages */
...@@ -291,14 +290,16 @@ int hfi1_user_exp_rcv_setup(struct hfi1_filedata *fd, ...@@ -291,14 +290,16 @@ int hfi1_user_exp_rcv_setup(struct hfi1_filedata *fd,
fd->tid_used += pageset_count; fd->tid_used += pageset_count;
spin_unlock(&fd->tid_lock); spin_unlock(&fd->tid_lock);
if (!pageset_count) if (!pageset_count) {
goto bail; ret = -ENOSPC;
goto fail_unreserve;
}
ngroups = pageset_count / dd->rcv_entries.group_size; ngroups = pageset_count / dd->rcv_entries.group_size;
tidlist = kcalloc(pageset_count, sizeof(*tidlist), GFP_KERNEL); tidlist = kcalloc(pageset_count, sizeof(*tidlist), GFP_KERNEL);
if (!tidlist) { if (!tidlist) {
ret = -ENOMEM; ret = -ENOMEM;
goto nomem; goto fail_unreserve;
} }
tididx = 0; tididx = 0;
...@@ -394,44 +395,60 @@ int hfi1_user_exp_rcv_setup(struct hfi1_filedata *fd, ...@@ -394,44 +395,60 @@ int hfi1_user_exp_rcv_setup(struct hfi1_filedata *fd,
} }
unlock: unlock:
mutex_unlock(&uctxt->exp_mutex); mutex_unlock(&uctxt->exp_mutex);
nomem:
hfi1_cdbg(TID, "total mapped: tidpairs:%u pages:%u (%d)", tididx, hfi1_cdbg(TID, "total mapped: tidpairs:%u pages:%u (%d)", tididx,
mapped_pages, ret); mapped_pages, ret);
/* fail if nothing was programmed, set error if none provided */
if (tididx == 0) {
if (ret >= 0)
ret = -ENOSPC;
goto fail_unreserve;
}
/* adjust reserved tid_used to actual count */ /* adjust reserved tid_used to actual count */
spin_lock(&fd->tid_lock); spin_lock(&fd->tid_lock);
fd->tid_used -= pageset_count - tididx; fd->tid_used -= pageset_count - tididx;
spin_unlock(&fd->tid_lock); spin_unlock(&fd->tid_lock);
if (tididx) {
/* unpin all pages not covered by a TID */
unpin_rcv_pages(fd, tidbuf, NULL, mapped_pages, pinned - mapped_pages,
false);
tinfo->tidcnt = tididx; tinfo->tidcnt = tididx;
tinfo->length = mapped_pages * PAGE_SIZE; tinfo->length = mapped_pages * PAGE_SIZE;
if (copy_to_user(u64_to_user_ptr(tinfo->tidlist), if (copy_to_user(u64_to_user_ptr(tinfo->tidlist),
tidlist, sizeof(tidlist[0]) * tididx)) { tidlist, sizeof(tidlist[0]) * tididx)) {
/*
* On failure to copy to the user level, we need to undo
* everything done so far so we don't leak resources.
*/
tinfo->tidlist = (unsigned long)&tidlist;
hfi1_user_exp_rcv_clear(fd, tinfo);
tinfo->tidlist = 0;
ret = -EFAULT; ret = -EFAULT;
goto bail; goto fail_unprogram;
}
} }
/* kfree(tidbuf->pages);
* If not everything was mapped (due to insufficient RcvArray entries,
* for example), unpin all unmapped pages so we can pin them nex time.
*/
if (mapped_pages != pinned)
unpin_rcv_pages(fd, tidbuf, NULL, mapped_pages,
(pinned - mapped_pages), false);
bail:
kfree(tidbuf->psets); kfree(tidbuf->psets);
kfree(tidbuf);
kfree(tidlist); kfree(tidlist);
return 0;
fail_unprogram:
/* unprogram, unmap, and unpin all allocated TIDs */
tinfo->tidlist = (unsigned long)tidlist;
hfi1_user_exp_rcv_clear(fd, tinfo);
tinfo->tidlist = 0;
pinned = 0; /* nothing left to unpin */
pageset_count = 0; /* nothing left reserved */
fail_unreserve:
spin_lock(&fd->tid_lock);
fd->tid_used -= pageset_count;
spin_unlock(&fd->tid_lock);
fail_unpin:
if (pinned > 0)
unpin_rcv_pages(fd, tidbuf, NULL, 0, pinned, false);
fail_release_mem:
kfree(tidbuf->pages); kfree(tidbuf->pages);
kfree(tidbuf->psets);
kfree(tidbuf); kfree(tidbuf);
return ret > 0 ? 0 : ret; kfree(tidlist);
return ret;
} }
int hfi1_user_exp_rcv_clear(struct hfi1_filedata *fd, int hfi1_user_exp_rcv_clear(struct hfi1_filedata *fd,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment