Skip to content

Commit 1c7edde

Browse files
DeanLuickrleon
authored andcommitted
IB/hfi1: Immediately remove invalid memory from hardware
When a user expected receive page is unmapped, it should be immediately removed from hardware rather than depend on a reaction from user space. Fixes: 2677a76 ("IB/hfi1: Fix memory leak during unexpected shutdown") Signed-off-by: Dean Luick <[email protected]> Signed-off-by: Dennis Dalessandro <[email protected]> Link: https://lore.kernel.org/r/167328548663.1472310.7871808081861622659.stgit@awfm-02.cornelisnetworks.com Signed-off-by: Leon Romanovsky <[email protected]>
1 parent e0c4a42 commit 1c7edde

File tree

2 files changed

+30
-14
lines changed

2 files changed

+30
-14
lines changed

drivers/infiniband/hw/hfi1/user_exp_rcv.c

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ static int program_rcvarray(struct hfi1_filedata *fd, struct tid_user_buf *,
2828
unsigned int start, u16 count,
2929
u32 *tidlist, unsigned int *tididx,
3030
unsigned int *pmapped);
31-
static int unprogram_rcvarray(struct hfi1_filedata *fd, u32 tidinfo,
32-
struct tid_group **grp);
31+
static int unprogram_rcvarray(struct hfi1_filedata *fd, u32 tidinfo);
32+
static void __clear_tid_node(struct hfi1_filedata *fd,
33+
struct tid_rb_node *node);
3334
static void clear_tid_node(struct hfi1_filedata *fd, struct tid_rb_node *node);
3435

3536
static const struct mmu_interval_notifier_ops tid_mn_ops = {
@@ -469,7 +470,7 @@ int hfi1_user_exp_rcv_clear(struct hfi1_filedata *fd,
469470

470471
mutex_lock(&uctxt->exp_mutex);
471472
for (tididx = 0; tididx < tinfo->tidcnt; tididx++) {
472-
ret = unprogram_rcvarray(fd, tidinfo[tididx], NULL);
473+
ret = unprogram_rcvarray(fd, tidinfo[tididx]);
473474
if (ret) {
474475
hfi1_cdbg(TID, "Failed to unprogram rcv array %d",
475476
ret);
@@ -723,6 +724,7 @@ static int set_rcvarray_entry(struct hfi1_filedata *fd,
723724
}
724725

725726
node->fdata = fd;
727+
mutex_init(&node->invalidate_mutex);
726728
node->phys = page_to_phys(pages[0]);
727729
node->npages = npages;
728730
node->rcventry = rcventry;
@@ -762,8 +764,7 @@ static int set_rcvarray_entry(struct hfi1_filedata *fd,
762764
return -EFAULT;
763765
}
764766

765-
static int unprogram_rcvarray(struct hfi1_filedata *fd, u32 tidinfo,
766-
struct tid_group **grp)
767+
static int unprogram_rcvarray(struct hfi1_filedata *fd, u32 tidinfo)
767768
{
768769
struct hfi1_ctxtdata *uctxt = fd->uctxt;
769770
struct hfi1_devdata *dd = uctxt->dd;
@@ -786,33 +787,41 @@ static int unprogram_rcvarray(struct hfi1_filedata *fd, u32 tidinfo,
786787
if (!node || node->rcventry != (uctxt->expected_base + rcventry))
787788
return -EBADF;
788789

789-
if (grp)
790-
*grp = node->grp;
791-
792790
if (fd->use_mn)
793791
mmu_interval_notifier_remove(&node->notifier);
794792
cacheless_tid_rb_remove(fd, node);
795793

796794
return 0;
797795
}
798796

799-
static void clear_tid_node(struct hfi1_filedata *fd, struct tid_rb_node *node)
797+
static void __clear_tid_node(struct hfi1_filedata *fd, struct tid_rb_node *node)
800798
{
801799
struct hfi1_ctxtdata *uctxt = fd->uctxt;
802800
struct hfi1_devdata *dd = uctxt->dd;
803801

802+
mutex_lock(&node->invalidate_mutex);
803+
if (node->freed)
804+
goto done;
805+
node->freed = true;
806+
804807
trace_hfi1_exp_tid_unreg(uctxt->ctxt, fd->subctxt, node->rcventry,
805808
node->npages,
806809
node->notifier.interval_tree.start, node->phys,
807810
node->dma_addr);
808811

809-
/*
810-
* Make sure device has seen the write before we unpin the
811-
* pages.
812-
*/
812+
/* Make sure device has seen the write before pages are unpinned */
813813
hfi1_put_tid(dd, node->rcventry, PT_INVALID_FLUSH, 0, 0);
814814

815815
unpin_rcv_pages(fd, NULL, node, 0, node->npages, true);
816+
done:
817+
mutex_unlock(&node->invalidate_mutex);
818+
}
819+
820+
static void clear_tid_node(struct hfi1_filedata *fd, struct tid_rb_node *node)
821+
{
822+
struct hfi1_ctxtdata *uctxt = fd->uctxt;
823+
824+
__clear_tid_node(fd, node);
816825

817826
node->grp->used--;
818827
node->grp->map &= ~(1 << (node->rcventry - node->grp->base));
@@ -871,10 +880,16 @@ static bool tid_rb_invalidate(struct mmu_interval_notifier *mni,
871880
if (node->freed)
872881
return true;
873882

883+
/* take action only if unmapping */
884+
if (range->event != MMU_NOTIFY_UNMAP)
885+
return true;
886+
874887
trace_hfi1_exp_tid_inval(uctxt->ctxt, fdata->subctxt,
875888
node->notifier.interval_tree.start,
876889
node->rcventry, node->npages, node->dma_addr);
877-
node->freed = true;
890+
891+
/* clear the hardware rcvarray entry */
892+
__clear_tid_node(fdata, node);
878893

879894
spin_lock(&fdata->invalid_lock);
880895
if (fdata->invalid_tid_idx < uctxt->expected_count) {

drivers/infiniband/hw/hfi1/user_exp_rcv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ struct tid_user_buf {
2727
struct tid_rb_node {
2828
struct mmu_interval_notifier notifier;
2929
struct hfi1_filedata *fdata;
30+
struct mutex invalidate_mutex; /* covers hw removal */
3031
unsigned long phys;
3132
struct tid_group *grp;
3233
u32 rcventry;

0 commit comments

Comments
 (0)