Skip to content

Commit e0c4a42

Browse files
DeanLuickrleon
authored andcommitted
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: 7e7a436 ("staging/hfi1: Add TID entry program function body") Fixes: 97736f3 ("IB/hfi1: Validate page aligned for a given virtual addres") Fixes: f404ca4 ("IB/hfi1: Refactor hfi_user_exp_rcv_setup() IOCTL") Signed-off-by: Dean Luick <[email protected]> Signed-off-by: Dennis Dalessandro <[email protected]> Link: https://lore.kernel.org/r/167328548150.1472310.1492305874804187634.stgit@awfm-02.cornelisnetworks.com Signed-off-by: Leon Romanovsky <[email protected]>
1 parent ecf9155 commit e0c4a42

File tree

1 file changed

+50
-33
lines changed

1 file changed

+50
-33
lines changed

drivers/infiniband/hw/hfi1/user_exp_rcv.c

Lines changed: 50 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -268,15 +268,14 @@ int hfi1_user_exp_rcv_setup(struct hfi1_filedata *fd,
268268
tidbuf->psets = kcalloc(uctxt->expected_count, sizeof(*tidbuf->psets),
269269
GFP_KERNEL);
270270
if (!tidbuf->psets) {
271-
kfree(tidbuf);
272-
return -ENOMEM;
271+
ret = -ENOMEM;
272+
goto fail_release_mem;
273273
}
274274

275275
pinned = pin_rcv_pages(fd, tidbuf);
276276
if (pinned <= 0) {
277-
kfree(tidbuf->psets);
278-
kfree(tidbuf);
279-
return pinned;
277+
ret = (pinned < 0) ? pinned : -ENOSPC;
278+
goto fail_unpin;
280279
}
281280

282281
/* Find sets of physically contiguous pages */
@@ -291,14 +290,16 @@ int hfi1_user_exp_rcv_setup(struct hfi1_filedata *fd,
291290
fd->tid_used += pageset_count;
292291
spin_unlock(&fd->tid_lock);
293292

294-
if (!pageset_count)
295-
goto bail;
293+
if (!pageset_count) {
294+
ret = -ENOSPC;
295+
goto fail_unreserve;
296+
}
296297

297298
ngroups = pageset_count / dd->rcv_entries.group_size;
298299
tidlist = kcalloc(pageset_count, sizeof(*tidlist), GFP_KERNEL);
299300
if (!tidlist) {
300301
ret = -ENOMEM;
301-
goto nomem;
302+
goto fail_unreserve;
302303
}
303304

304305
tididx = 0;
@@ -394,44 +395,60 @@ int hfi1_user_exp_rcv_setup(struct hfi1_filedata *fd,
394395
}
395396
unlock:
396397
mutex_unlock(&uctxt->exp_mutex);
397-
nomem:
398398
hfi1_cdbg(TID, "total mapped: tidpairs:%u pages:%u (%d)", tididx,
399399
mapped_pages, ret);
400+
401+
/* fail if nothing was programmed, set error if none provided */
402+
if (tididx == 0) {
403+
if (ret >= 0)
404+
ret = -ENOSPC;
405+
goto fail_unreserve;
406+
}
407+
400408
/* adjust reserved tid_used to actual count */
401409
spin_lock(&fd->tid_lock);
402410
fd->tid_used -= pageset_count - tididx;
403411
spin_unlock(&fd->tid_lock);
404-
if (tididx) {
405-
tinfo->tidcnt = tididx;
406-
tinfo->length = mapped_pages * PAGE_SIZE;
407412

408-
if (copy_to_user(u64_to_user_ptr(tinfo->tidlist),
409-
tidlist, sizeof(tidlist[0]) * tididx)) {
410-
/*
411-
* On failure to copy to the user level, we need to undo
412-
* everything done so far so we don't leak resources.
413-
*/
414-
tinfo->tidlist = (unsigned long)&tidlist;
415-
hfi1_user_exp_rcv_clear(fd, tinfo);
416-
tinfo->tidlist = 0;
417-
ret = -EFAULT;
418-
goto bail;
419-
}
413+
/* unpin all pages not covered by a TID */
414+
unpin_rcv_pages(fd, tidbuf, NULL, mapped_pages, pinned - mapped_pages,
415+
false);
416+
417+
tinfo->tidcnt = tididx;
418+
tinfo->length = mapped_pages * PAGE_SIZE;
419+
420+
if (copy_to_user(u64_to_user_ptr(tinfo->tidlist),
421+
tidlist, sizeof(tidlist[0]) * tididx)) {
422+
ret = -EFAULT;
423+
goto fail_unprogram;
420424
}
421425

422-
/*
423-
* If not everything was mapped (due to insufficient RcvArray entries,
424-
* for example), unpin all unmapped pages so we can pin them nex time.
425-
*/
426-
if (mapped_pages != pinned)
427-
unpin_rcv_pages(fd, tidbuf, NULL, mapped_pages,
428-
(pinned - mapped_pages), false);
429-
bail:
426+
kfree(tidbuf->pages);
430427
kfree(tidbuf->psets);
428+
kfree(tidbuf);
431429
kfree(tidlist);
430+
return 0;
431+
432+
fail_unprogram:
433+
/* unprogram, unmap, and unpin all allocated TIDs */
434+
tinfo->tidlist = (unsigned long)tidlist;
435+
hfi1_user_exp_rcv_clear(fd, tinfo);
436+
tinfo->tidlist = 0;
437+
pinned = 0; /* nothing left to unpin */
438+
pageset_count = 0; /* nothing left reserved */
439+
fail_unreserve:
440+
spin_lock(&fd->tid_lock);
441+
fd->tid_used -= pageset_count;
442+
spin_unlock(&fd->tid_lock);
443+
fail_unpin:
444+
if (pinned > 0)
445+
unpin_rcv_pages(fd, tidbuf, NULL, 0, pinned, false);
446+
fail_release_mem:
432447
kfree(tidbuf->pages);
448+
kfree(tidbuf->psets);
433449
kfree(tidbuf);
434-
return ret > 0 ? 0 : ret;
450+
kfree(tidlist);
451+
return ret;
435452
}
436453

437454
int hfi1_user_exp_rcv_clear(struct hfi1_filedata *fd,

0 commit comments

Comments
 (0)