@@ -459,6 +459,19 @@ static void rdma_unfill_sgid_attr(struct rdma_ah_attr *ah_attr,
459459 rdma_destroy_ah_attr (ah_attr );
460460}
461461
462+ static const struct ib_gid_attr *
463+ rdma_update_sgid_attr (struct rdma_ah_attr * ah_attr ,
464+ const struct ib_gid_attr * old_attr )
465+ {
466+ if (old_attr )
467+ rdma_put_gid_attr (old_attr );
468+ if (ah_attr -> ah_flags & IB_AH_GRH ) {
469+ rdma_hold_gid_attr (ah_attr -> grh .sgid_attr );
470+ return ah_attr -> grh .sgid_attr ;
471+ }
472+ return NULL ;
473+ }
474+
462475static struct ib_ah * _rdma_create_ah (struct ib_pd * pd ,
463476 struct rdma_ah_attr * ah_attr ,
464477 struct ib_udata * udata )
@@ -472,6 +485,8 @@ static struct ib_ah *_rdma_create_ah(struct ib_pd *pd,
472485 ah -> pd = pd ;
473486 ah -> uobject = NULL ;
474487 ah -> type = ah_attr -> type ;
488+ ah -> sgid_attr = rdma_update_sgid_attr (ah_attr , NULL );
489+
475490 atomic_inc (& pd -> usecnt );
476491 }
477492
@@ -871,6 +886,7 @@ int rdma_modify_ah(struct ib_ah *ah, struct rdma_ah_attr *ah_attr)
871886 ah -> device -> modify_ah (ah , ah_attr ) :
872887 - EOPNOTSUPP ;
873888
889+ ah -> sgid_attr = rdma_update_sgid_attr (ah_attr , ah -> sgid_attr );
874890 rdma_unfill_sgid_attr (ah_attr , old_sgid_attr );
875891 return ret ;
876892}
@@ -888,13 +904,17 @@ EXPORT_SYMBOL(rdma_query_ah);
888904
889905int rdma_destroy_ah (struct ib_ah * ah )
890906{
907+ const struct ib_gid_attr * sgid_attr = ah -> sgid_attr ;
891908 struct ib_pd * pd ;
892909 int ret ;
893910
894911 pd = ah -> pd ;
895912 ret = ah -> device -> destroy_ah (ah );
896- if (!ret )
913+ if (!ret ) {
897914 atomic_dec (& pd -> usecnt );
915+ if (sgid_attr )
916+ rdma_put_gid_attr (sgid_attr );
917+ }
898918
899919 return ret ;
900920}
@@ -1573,6 +1593,13 @@ static int _ib_modify_qp(struct ib_qp *qp, struct ib_qp_attr *attr,
15731593 return ret ;
15741594 }
15751595 if (attr_mask & IB_QP_ALT_PATH ) {
1596+ /*
1597+ * FIXME: This does not track the migration state, so if the
1598+ * user loads a new alternate path after the HW has migrated
1599+ * from primary->alternate we will keep the wrong
1600+ * references. This is OK for IB because the reference
1601+ * counting does not serve any functional purpose.
1602+ */
15761603 ret = rdma_fill_sgid_attr (qp -> device , & attr -> alt_ah_attr ,
15771604 & old_sgid_attr_alt_av );
15781605 if (ret )
@@ -1606,8 +1633,17 @@ static int _ib_modify_qp(struct ib_qp *qp, struct ib_qp_attr *attr,
16061633 }
16071634
16081635 ret = ib_security_modify_qp (qp , attr , attr_mask , udata );
1609- if (!ret && (attr_mask & IB_QP_PORT ))
1636+ if (ret )
1637+ goto out ;
1638+
1639+ if (attr_mask & IB_QP_PORT )
16101640 qp -> port = attr -> port_num ;
1641+ if (attr_mask & IB_QP_AV )
1642+ qp -> av_sgid_attr =
1643+ rdma_update_sgid_attr (& attr -> ah_attr , qp -> av_sgid_attr );
1644+ if (attr_mask & IB_QP_ALT_PATH )
1645+ qp -> alt_path_sgid_attr = rdma_update_sgid_attr (
1646+ & attr -> alt_ah_attr , qp -> alt_path_sgid_attr );
16111647
16121648out :
16131649 if (attr_mask & IB_QP_ALT_PATH )
@@ -1765,6 +1801,8 @@ static int __ib_destroy_shared_qp(struct ib_qp *qp)
17651801
17661802int ib_destroy_qp (struct ib_qp * qp )
17671803{
1804+ const struct ib_gid_attr * alt_path_sgid_attr = qp -> alt_path_sgid_attr ;
1805+ const struct ib_gid_attr * av_sgid_attr = qp -> av_sgid_attr ;
17681806 struct ib_pd * pd ;
17691807 struct ib_cq * scq , * rcq ;
17701808 struct ib_srq * srq ;
@@ -1795,6 +1833,10 @@ int ib_destroy_qp(struct ib_qp *qp)
17951833 rdma_restrack_del (& qp -> res );
17961834 ret = qp -> device -> destroy_qp (qp );
17971835 if (!ret ) {
1836+ if (alt_path_sgid_attr )
1837+ rdma_put_gid_attr (alt_path_sgid_attr );
1838+ if (av_sgid_attr )
1839+ rdma_put_gid_attr (av_sgid_attr );
17981840 if (pd )
17991841 atomic_dec (& pd -> usecnt );
18001842 if (scq )
0 commit comments