git: 4726b80d9379 - main - OFED: Various changes from Linux 4.20

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Wed, 24 Jun 2026 19:51:21 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=4726b80d9379cdefd00ae77d0b91973bde573790

commit 4726b80d9379cdefd00ae77d0b91973bde573790
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2026-06-24 19:30:56 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2026-06-24 19:30:56 +0000

    OFED: Various changes from Linux 4.20
    
    This contains changes from the following Linux commits:
    
    627212c9d49b RDMA/core: Replace open-coded variant of get_device
    adee9f3f3bbb RDMA/core: Depend on device_add() to add device attributes
    954a8e3aea87 RDMA/cma: Protect cma dev list with lock
    722c7b2bfead RDMA/{cma, core}: Avoid callback on rdma_addr_cancel()
    f9d08f1e1939 RDMA/core: Rate limit MAD error messages
    e1f540c3ed0e RDMA/core: Define client_data_lock as rwlock instead of spinlock
    2d65f49ff961 RDMA/core: Use simpler spin lock irq API from blocking context
    4512acd0d34c RDMA/core: Remove context entries from list while unregistering device
    f7b65d9bf2db RDMA/core: Use simplified list_for_each
    93688ddbe1da RDMA/core: No need to protect kfree with spin lock and semaphore
    50704e039ab1 RDMA/umem: Restore lockdep check while downgrading lock
    eb93c82ed8c7 RDMA/core: Document QP @event_handler function
    4269024639f6 RDMA/core: Document CM @event_handler function
    77addc524473 RDMA/core: Rename rdma_copy_addr to rdma_copy_src_l2_addr
    a362ea1d9e1a RDMA/core: Introduce and use rdma_set_src_addr() between IPv4 and IPv6
    89c5691cdd95 RDMA/core: Let protocol specific function typecast sockaddr structure
    caf1e3ae9fa6 RDMA/core Introduce and use rdma_find_ndev_for_src_ip_rcu
    c31d4b2ddf07 RDMA/core: Protect against changing dst->dev during destination resolve
    0e9d2c19bff1 RDMA/core: Consider net ns of gid attribute for RoCE
    d6b1764a8c5a RDMA/core: Introduce rdma_read_gid_attr_ndev_rcu() to check GID attribute
    6aaecd385685 RDMA/core: Simplify roce_resolve_route_from_path()
    0965cc953a23 RDMA/core: Properly return the error code of rdma_set_src_addr_rcu
    d4b4dd1b9706 RDMA/umem: Do not use current->tgid to track the mm_struct
    c9990ab39b6e RDMA/umem: Move all the ODP related stuff out of ucontext and into per_mm
    597ecc5a0954 RDMA/umem: Get rid of struct ib_umem.odp_data
    41b4deeaa123 RDMA/umem: Make ib_umem_odp into a sub structure of ib_umem
    b5231b019d76 RDMA/umem: Use ib_umem_odp in all function signatures connected to ODP
    56ac9dd9177c RDMA/umem: Avoid synchronize_srcu in the ODP MR destruction path
    be7a57b41ad8 RDMA/umem: Handle a half-complete start/end sequence
    ca748c39ea3f RDMA/umem: Get rid of per_mm->notifier_count
    f27a0d50a4bc RDMA/umem: Use umem->owning_mm inside ODP
    
    Tested by:      Wafa Hamzah <wafah@nvidia.com> (mlx5_ib)
    Tested by:      John Baldwin <jhb@FreeBSD.org> (iw_cxgbe)
    Sponsored by:   Chelsio Communications
---
 sys/ofed/drivers/infiniband/core/core_priv.h     |  10 +-
 sys/ofed/drivers/infiniband/core/ib_addr.c       | 307 +++++++----
 sys/ofed/drivers/infiniband/core/ib_cache.c      |  33 ++
 sys/ofed/drivers/infiniband/core/ib_cma.c        |  27 +-
 sys/ofed/drivers/infiniband/core/ib_device.c     |  51 +-
 sys/ofed/drivers/infiniband/core/ib_mad.c        |  72 +--
 sys/ofed/drivers/infiniband/core/ib_sa_query.c   |  36 --
 sys/ofed/drivers/infiniband/core/ib_sysfs.c      |  65 ++-
 sys/ofed/drivers/infiniband/core/ib_umem.c       | 100 ++--
 sys/ofed/drivers/infiniband/core/ib_umem_odp.c   | 619 +++++++++++------------
 sys/ofed/drivers/infiniband/core/ib_uverbs_cmd.c |   8 +
 sys/ofed/drivers/infiniband/core/ib_verbs.c      |   2 +-
 sys/ofed/include/rdma/ib_addr.h                  |   7 +-
 sys/ofed/include/rdma/ib_umem.h                  |   9 +-
 sys/ofed/include/rdma/ib_umem_odp.h              |  75 +--
 sys/ofed/include/rdma/ib_verbs.h                 |  17 +-
 sys/ofed/include/rdma/rdma_cm.h                  |   6 +-
 17 files changed, 776 insertions(+), 668 deletions(-)

diff --git a/sys/ofed/drivers/infiniband/core/core_priv.h b/sys/ofed/drivers/infiniband/core/core_priv.h
index 198dac54cdf0..db0a7a0046b8 100644
--- a/sys/ofed/drivers/infiniband/core/core_priv.h
+++ b/sys/ofed/drivers/infiniband/core/core_priv.h
@@ -190,8 +190,16 @@ int rdma_resolve_ip_route(struct sockaddr *src_addr,
 
 int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid,
 				 const union ib_gid *dgid,
-				 u8 *dmac, if_t ndev,
+				 u8 *dmac, const struct ib_gid_attr *sgid_attr,
 				 int *hoplimit);
+void rdma_copy_src_l2_addr(struct rdma_dev_addr *dev_addr,
+                           const if_t dev);
+
+struct sa_path_rec;
+int roce_resolve_route_from_path(struct sa_path_rec *rec,
+				 const struct ib_gid_attr *attr);
+
+if_t rdma_read_gid_attr_ndev_rcu(const struct ib_gid_attr *attr);
 
 struct rdma_umap_priv {
 	struct vm_area_struct *vma;
diff --git a/sys/ofed/drivers/infiniband/core/ib_addr.c b/sys/ofed/drivers/infiniband/core/ib_addr.c
index 1810230c34f5..87370f4aba99 100644
--- a/sys/ofed/drivers/infiniband/core/ib_addr.c
+++ b/sys/ofed/drivers/infiniband/core/ib_addr.c
@@ -45,6 +45,7 @@
 #include <net/route/nhop.h>
 #include <net/netevent.h>
 #include <rdma/ib_addr.h>
+#include <rdma/ib_sa.h>
 #include <rdma/ib.h>
 
 #include <netinet/in_fib.h>
@@ -66,6 +67,7 @@ struct addr_req {
 			 struct rdma_dev_addr *addr, void *context);
 	unsigned long timeout;
 	struct delayed_work work;
+	bool resolve_by_gid_attr;	/* Consider gid attr in resolve phase */
 	int status;
 };
 
@@ -113,9 +115,17 @@ rdma_copy_addr_sub(u8 *dst, const u8 *src, unsigned min, unsigned max)
 	memset(dst + min, 0, max - min);
 }
 
-void rdma_copy_addr(struct rdma_dev_addr *dev_addr,
-		    const if_t dev,
-		    const unsigned char *dst_dev_addr)
+/**
+ * rdma_copy_src_l2_addr - Copy netdevice source addresses
+ * @dev_addr:	Destination address pointer where to copy the addresses
+ * @dev:	Netdevice whose source addresses to copy
+ *
+ * rdma_copy_src_l2_addr() copies source addresses from the specified netdevice.
+ * This includes unicast address, broadcast address, device type and
+ * interface index.
+ */
+void rdma_copy_src_l2_addr(struct rdma_dev_addr *dev_addr,
+			   const if_t dev)
 {
 	int dev_type = if_gettype(dev);
 
@@ -137,50 +147,61 @@ void rdma_copy_addr(struct rdma_dev_addr *dev_addr,
 			   if_getaddrlen(dev), MAX_ADDR_LEN);
 	rdma_copy_addr_sub(dev_addr->broadcast, if_getbroadcastaddr(dev),
 			   if_getaddrlen(dev), MAX_ADDR_LEN);
-	if (dst_dev_addr != NULL) {
-		rdma_copy_addr_sub(dev_addr->dst_dev_addr, dst_dev_addr,
-				   if_getaddrlen(dev), MAX_ADDR_LEN);
-	}
 	dev_addr->bound_dev_if = if_getindex(dev);
 }
-EXPORT_SYMBOL(rdma_copy_addr);
+EXPORT_SYMBOL(rdma_copy_src_l2_addr);
 
-int rdma_translate_ip(const struct sockaddr *addr,
-		      struct rdma_dev_addr *dev_addr)
+static if_t
+rdma_find_ndev_for_src_ip_rcu(struct vnet *net, const struct sockaddr *src_in)
 {
-	if_t dev;
-	int ret = 0;
+	if_t dev = NULL;
+	int ret = -EADDRNOTAVAIL;
 
-	if (dev_addr->bound_dev_if) {
-		dev = dev_get_by_index(dev_addr->net, dev_addr->bound_dev_if);
-	} else switch (addr->sa_family) {
+	switch (src_in->sa_family) {
 #ifdef INET
 	case AF_INET:
-		dev = ip_ifp_find(dev_addr->net,
-			((const struct sockaddr_in *)addr)->sin_addr.s_addr);
+		dev = ip_ifp_find(net,
+			((const struct sockaddr_in *)src_in)->sin_addr.s_addr);
+		if (dev)
+			ret = 0;
 		break;
 #endif
 #ifdef INET6
 	case AF_INET6:
-		dev = ip6_ifp_find(dev_addr->net,
-			((const struct sockaddr_in6 *)addr)->sin6_addr, 0);
+		dev = ip6_ifp_find(net,
+			((const struct sockaddr_in6 *)src_in)->sin6_addr, 0);
+		if (dev)
+			ret = 0;
 		break;
 #endif
-	default:
-		dev = NULL;
-		break;
 	}
+	return ret ? ERR_PTR(ret) : dev;
+}
 
-	if (dev != NULL) {
-		/* disallow connections through 127.0.0.1 itself */
-		if (if_getflags(dev) & IFF_LOOPBACK)
-			ret = -EINVAL;
-		else
-			rdma_copy_addr(dev_addr, dev, NULL);
-		dev_put(dev);
+int rdma_translate_ip(const struct sockaddr *addr,
+		      struct rdma_dev_addr *dev_addr)
+{
+	if_t dev;
+	int ret = 0;
+
+	if (dev_addr->bound_dev_if) {
+		dev = dev_get_by_index(dev_addr->net, dev_addr->bound_dev_if);
+		if (!dev)
+			return -ENODEV;
 	} else {
-		ret = -ENODEV;
+		rcu_read_lock();
+		dev = rdma_find_ndev_for_src_ip_rcu(dev_addr->net, addr);
+		rcu_read_unlock();
+		if (IS_ERR(dev))
+			return PTR_ERR(dev);
 	}
+
+	/* disallow connections through 127.0.0.1 itself */
+	if (if_getflags(dev) & IFF_LOOPBACK)
+		ret = -EINVAL;
+	else
+		rdma_copy_src_l2_addr(dev_addr, dev);
+	dev_put(dev);
 	return ret;
 }
 EXPORT_SYMBOL(rdma_translate_ip);
@@ -226,12 +247,15 @@ static int addr_resolve_multi(u8 *edst, if_t ifp, struct sockaddr *dst_in)
 #endif
 
 #ifdef INET
-static int addr4_resolve(struct sockaddr_in *src_in,
-			 const struct sockaddr_in *dst_in,
+static int addr4_resolve(struct sockaddr *src_sock,
+			 const struct sockaddr *dst_sock,
 			 struct rdma_dev_addr *addr,
 			 u8 *edst,
 			 if_t *ifpp)
 {
+	struct sockaddr_in *src_in = (struct sockaddr_in *)src_sock;
+	const struct sockaddr_in *dst_in =
+			(const struct sockaddr_in *)dst_sock;
 	enum {
 		ADDR_VALID = 0,
 		ADDR_SRC_ANY = 1,
@@ -398,8 +422,8 @@ done:
 	return (-error);
 }
 #else
-static int addr4_resolve(struct sockaddr_in *src_in,
-			 const struct sockaddr_in *dst_in,
+static int addr4_resolve(struct sockaddr *src_sock,
+			 const struct sockaddr *dst_sock,
 			 struct rdma_dev_addr *addr,
 			 u8 *edst,
 			 if_t *ifpp)
@@ -409,12 +433,15 @@ static int addr4_resolve(struct sockaddr_in *src_in,
 #endif
 
 #ifdef INET6
-static int addr6_resolve(struct sockaddr_in6 *src_in,
-			 const struct sockaddr_in6 *dst_in,
+static int addr6_resolve(struct sockaddr *src_sock,
+			 const struct sockaddr *dst_sock,
 			 struct rdma_dev_addr *addr,
 			 u8 *edst,
 			 if_t *ifpp)
 {
+	struct sockaddr_in6 *src_in = (struct sockaddr_in6 *)src_sock;
+	const struct sockaddr_in6 *dst_in =
+				(const struct sockaddr_in6 *)dst_sock;
 	enum {
 		ADDR_VALID = 0,
 		ADDR_SRC_ANY = 1,
@@ -586,8 +613,8 @@ done:
 	return (-error);
 }
 #else
-static int addr6_resolve(struct sockaddr_in6 *src_in,
-			 const struct sockaddr_in6 *dst_in,
+static int addr6_resolve(struct sockaddr *src_sock,
+			 const struct sockaddr *dst_sock,
 			 struct rdma_dev_addr *addr,
 			 u8 *edst,
 			 if_t *ifpp)
@@ -599,11 +626,12 @@ static int addr6_resolve(struct sockaddr_in6 *src_in,
 static int addr_resolve_neigh(if_t dev,
 			      const struct sockaddr *dst_in,
 			      u8 *edst,
-			      struct rdma_dev_addr *addr)
+			      struct rdma_dev_addr *addr,
+			      unsigned int ndev_flags)
 {
-	if (if_getflags(dev) & IFF_LOOPBACK) {
-		int ret;
+	int ret = 0;
 
+	if (ndev_flags & IFF_LOOPBACK) {
 		/*
 		 * Binding to a loopback device is not allowed. Make
 		 * sure the destination device address is global by
@@ -612,66 +640,143 @@ static int addr_resolve_neigh(if_t dev,
 		if (addr->bound_dev_if == if_getindex(dev))
 			addr->bound_dev_if = 0;
 
-		ret = rdma_translate_ip(dst_in, addr);
-		if (ret == 0) {
-			memcpy(addr->dst_dev_addr, addr->src_dev_addr,
-			       MAX_ADDR_LEN);
+		memcpy(addr->dst_dev_addr, addr->src_dev_addr, MAX_ADDR_LEN);
+	} else {
+		if (!(ndev_flags & IFF_NOARP)) {
+			/* If the device doesn't do ARP internally */
+			memcpy(addr->dst_dev_addr, edst, MAX_ADDR_LEN);
 		}
-		return ret;
+        }
+
+	return ret;
+}
+
+static int copy_src_l2_addr(struct rdma_dev_addr *dev_addr,
+			    const struct sockaddr *dst_in,
+			    if_t ndev)
+{
+	int ret = 0;
+
+	if (if_getflags(ndev) & IFF_LOOPBACK)
+		ret = rdma_translate_ip(dst_in, dev_addr);
+	else
+		rdma_copy_src_l2_addr(dev_addr, ndev);
+
+	return ret;
+}
+
+static int rdma_set_src_addr_rcu(struct rdma_dev_addr *dev_addr,
+				 unsigned int *ndev_flags,
+				 const struct sockaddr *dst_in,
+				 if_t ndev)
+{
+	*ndev_flags = if_getflags(ndev);
+	/* A physical device must be the RDMA device to use */
+	if (if_getflags(ndev) & IFF_LOOPBACK) {
+		/*
+		 * RDMA (IB/RoCE, iWarp) doesn't run on lo interface or
+		 * loopback IP address. So if route is resolved to loopback
+		 * interface, translate that to a real ndev based on non
+		 * loopback IP address.
+		 */
+		ndev = rdma_find_ndev_for_src_ip_rcu(dev_net(ndev), dst_in);
+		if (!ndev)
+			return -ENODEV;
 	}
 
-	/* If the device doesn't do ARP internally */
-	if (!(if_getflags(dev) & IFF_NOARP)) {
-		rdma_copy_addr(addr, dev, edst);
-                return 0;
-        }
+	return copy_src_l2_addr(dev_addr, dst_in, ndev);
+}
+
+static int set_addr_netns_by_gid_rcu(struct rdma_dev_addr *addr)
+{
+	if_t ndev;
 
-	rdma_copy_addr(addr, dev, NULL);
+	ndev = rdma_read_gid_attr_ndev_rcu(addr->sgid_attr);
+	if (IS_ERR(ndev))
+		return PTR_ERR(ndev);
 
+	/*
+	 * Since we are holding the rcu, reading net and ifindex
+	 * are safe without any additional reference; because
+	 * change_net_namespace() in net/core/ib_dev.c does rcu sync
+	 * after it changes the state to IFF_DOWN and before
+	 * updating netdev fields {net, ifindex}.
+	 */
+	addr->net = dev_net(ndev);
+	addr->bound_dev_if = if_getindex(ndev);
 	return 0;
 }
 
+static void rdma_addr_set_net_defaults(struct rdma_dev_addr *addr)
+{
+	addr->net = &init_net;
+	addr->bound_dev_if = 0;
+}
+
 static int addr_resolve(struct sockaddr *src_in,
 			const struct sockaddr *dst_in,
-			struct rdma_dev_addr *addr)
+			struct rdma_dev_addr *addr,
+			bool resolve_by_gid_attr)
 {
 	struct epoch_tracker et;
 	if_t ndev = NULL;
 	u8 edst[MAX_ADDR_LEN];
+	unsigned int ndev_flags = 0;
 	int ret;
 
 	if (dst_in->sa_family != src_in->sa_family)
 		return -EINVAL;
 
 	NET_EPOCH_ENTER(et);
+	if (resolve_by_gid_attr) {
+		if (!addr->sgid_attr) {
+			NET_EPOCH_ENTER(et);
+			pr_warn_ratelimited("%s: missing gid_attr\n", __func__);
+			return -EINVAL;
+		}
+		/*
+		 * If the request is for a specific gid attribute of the
+		 * rdma_dev_addr, derive net from the netdevice of the
+		 * GID attribute.
+		 */
+		ret = set_addr_netns_by_gid_rcu(addr);
+		if (ret) {
+			NET_EPOCH_ENTER(et);
+			return ret;
+		}
+	}
 	switch (src_in->sa_family) {
 	case AF_INET:
-		ret = addr4_resolve((struct sockaddr_in *)src_in,
-				    (const struct sockaddr_in *)dst_in,
-				    addr, edst, &ndev);
+		ret = addr4_resolve(src_in, dst_in, addr, edst, &ndev);
 		break;
 	case AF_INET6:
-		ret = addr6_resolve((struct sockaddr_in6 *)src_in,
-				    (const struct sockaddr_in6 *)dst_in, addr,
-				    edst, &ndev);
+		ret = addr6_resolve(src_in, dst_in, addr, edst, &ndev);
 		break;
 	default:
 		ret = -EADDRNOTAVAIL;
 		break;
 	}
+	if (ret) {
+		NET_EPOCH_EXIT(et);
+		goto done;
+	}
+	ret = rdma_set_src_addr_rcu(addr, &ndev_flags, dst_in, ndev);
 	NET_EPOCH_EXIT(et);
 
-	/* check for error */
-	if (ret != 0)
-		return ret;
-
 	/* store MAC addresses and check for loopback */
-	ret = addr_resolve_neigh(ndev, dst_in, edst, addr);
+	if (!ret)
+		ret = addr_resolve_neigh(ndev, dst_in, edst, addr, ndev_flags);
 
 	/* set belonging VNET, if any */
 	addr->net = dev_net(ndev);
 	dev_put(ndev);
-
+done:
+	/*
+	 * Clear the addr net to go back to its original state, only if it was
+	 * derived from GID attribute in this context.
+	 */
+	if (resolve_by_gid_attr)
+		rdma_addr_set_net_defaults(addr);
 	return ret;
 }
 
@@ -685,7 +790,8 @@ static void process_one_req(struct work_struct *_work)
 	if (req->status == -ENODATA) {
 		src_in = (struct sockaddr *)&req->src_addr;
 		dst_in = (struct sockaddr *)&req->dst_addr;
-		req->status = addr_resolve(src_in, dst_in, req->addr);
+		req->status = addr_resolve(src_in, dst_in, req->addr,
+					   req->resolve_by_gid_attr);
 		if (req->status && time_after_eq(jiffies, req->timeout)) {
 			req->status = -ETIMEDOUT;
 		} else if (req->status == -ENODATA) {
@@ -720,6 +826,7 @@ int rdma_resolve_ip(struct sockaddr *src_addr, const struct sockaddr *dst_addr,
 		    struct rdma_dev_addr *addr, int timeout_ms,
 		    void (*callback)(int status, struct sockaddr *src_addr,
 				     struct rdma_dev_addr *addr, void *context),
+		    bool resolve_by_gid_attr,
 		    void *context)
 {
 	struct sockaddr *src_in, *dst_in;
@@ -748,9 +855,11 @@ int rdma_resolve_ip(struct sockaddr *src_addr, const struct sockaddr *dst_addr,
 	req->addr = addr;
 	req->callback = callback;
 	req->context = context;
+	req->resolve_by_gid_attr = resolve_by_gid_attr;
 	INIT_DELAYED_WORK(&req->work, process_one_req);
 
-	req->status = addr_resolve(src_in, dst_in, addr);
+	req->status = addr_resolve(src_in, dst_in, addr,
+				   req->resolve_by_gid_attr);
 	switch (req->status) {
 	case 0:
 		req->timeout = jiffies;
@@ -771,25 +880,49 @@ err:
 }
 EXPORT_SYMBOL(rdma_resolve_ip);
 
-int rdma_resolve_ip_route(struct sockaddr *src_addr,
-			  const struct sockaddr *dst_addr,
-			  struct rdma_dev_addr *addr)
+int roce_resolve_route_from_path(struct sa_path_rec *rec,
+				 const struct ib_gid_attr *attr)
 {
-	struct sockaddr_storage ssrc_addr = {};
-	struct sockaddr *src_in = (struct sockaddr *)&ssrc_addr;
+	union rdma_sockaddr sgid, dgid;
+	struct rdma_dev_addr dev_addr = {};
+	int ret;
 
-	if (src_addr) {
-		if (src_addr->sa_family != dst_addr->sa_family)
-			return -EINVAL;
+	if (rec->roce.route_resolved)
+		return 0;
 
-		memcpy(src_in, src_addr, rdma_addr_size(src_addr));
-	} else {
-		src_in->sa_family = dst_addr->sa_family;
-	}
+	rdma_gid2ip(&sgid._sockaddr, &rec->sgid);
+	rdma_gid2ip(&dgid._sockaddr, &rec->dgid);
+
+	if (sgid._sockaddr.sa_family != dgid._sockaddr.sa_family)
+		return -EINVAL;
+
+	if (!attr || !attr->ndev)
+		return -EINVAL;
 
-	return addr_resolve(src_in, dst_addr, addr);
+	dev_addr.net = &init_net;
+	dev_addr.sgid_attr = attr;
+
+	ret = addr_resolve(&sgid._sockaddr, &dgid._sockaddr,
+			   &dev_addr, true);
+	if (ret)
+		return ret;
+
+	if ((dev_addr.network == RDMA_NETWORK_IPV4 ||
+	     dev_addr.network == RDMA_NETWORK_IPV6) &&
+	    rec->rec_type != SA_PATH_REC_TYPE_ROCE_V2)
+		return -EINVAL;
+
+	rec->roce.route_resolved = true;
+	return 0;
 }
 
+/**
+ * rdma_addr_cancel - Cancel resolve ip request
+ * @addr:	Pointer to address structure given previously
+ *		during rdma_resolve_ip().
+ * rdma_addr_cancel() is synchronous function which cancels any pending
+ * request if there is any.
+ */
 void rdma_addr_cancel(struct rdma_dev_addr *addr)
 {
 	struct addr_req *req, *temp_req;
@@ -817,11 +950,6 @@ void rdma_addr_cancel(struct rdma_dev_addr *addr)
 	 * guarentees no work is running and none will be started.
 	 */
 	cancel_delayed_work_sync(&found->work);
-
-	if (found->callback)
-		found->callback(-ECANCELED, (struct sockaddr *)&found->src_addr,
-			      found->addr, found->context);
-
 	kfree(found);
 }
 EXPORT_SYMBOL(rdma_addr_cancel);
@@ -840,7 +968,7 @@ static void resolve_cb(int status, struct sockaddr *src_addr,
 
 int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid,
 				 const union ib_gid *dgid,
-				 u8 *dmac, if_t ndev,
+				 u8 *dmac, const struct ib_gid_attr *sgid_attr,
 				 int *hoplimit)
 {
 	struct rdma_dev_addr dev_addr;
@@ -852,13 +980,12 @@ int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid,
 	rdma_gid2ip(&dgid_addr._sockaddr, dgid);
 
 	memset(&dev_addr, 0, sizeof(dev_addr));
-
-	dev_addr.bound_dev_if = if_getindex(ndev);
-	dev_addr.net = dev_net(ndev);
+	dev_addr.net = &init_net;
+	dev_addr.sgid_attr = sgid_attr;
 
 	init_completion(&ctx.comp);
 	ret = rdma_resolve_ip(&sgid_addr._sockaddr, &dgid_addr._sockaddr,
-			      &dev_addr, 1000, resolve_cb, &ctx);
+			      &dev_addr, 1000, resolve_cb, true, &ctx);
 	if (ret)
 		return ret;
 
diff --git a/sys/ofed/drivers/infiniband/core/ib_cache.c b/sys/ofed/drivers/infiniband/core/ib_cache.c
index 7bf3213140ff..1ad577ff4b83 100644
--- a/sys/ofed/drivers/infiniband/core/ib_cache.c
+++ b/sys/ofed/drivers/infiniband/core/ib_cache.c
@@ -1265,6 +1265,39 @@ void rdma_hold_gid_attr(const struct ib_gid_attr *attr)
 }
 EXPORT_SYMBOL(rdma_hold_gid_attr);
 
+/**
+ * rdma_read_gid_attr_ndev_rcu - Read GID attribute netdevice
+ * which must be in UP state.
+ *
+ * @attr:Pointer to the GID attribute
+ *
+ * Returns pointer to netdevice if the netdevice was attached to GID and
+ * netdevice is in UP state. Caller must hold RCU lock as this API
+ * reads the netdev flags which can change while netdevice migrates to
+ * different net namespace. Returns ERR_PTR with error code otherwise.
+ *
+ */
+if_t rdma_read_gid_attr_ndev_rcu(const struct ib_gid_attr *attr)
+{
+	struct ib_gid_table_entry *entry =
+			container_of(attr, struct ib_gid_table_entry, attr);
+	struct ib_device *device = entry->attr.device;
+	if_t ndev = ERR_PTR(-ENODEV);
+	u8 port_num = entry->attr.port_num;
+	struct ib_gid_table *table;
+	unsigned long flags;
+	bool valid;
+
+	table = rdma_gid_table(device, port_num);
+
+	read_lock_irqsave(&table->rwlock, flags);
+	valid = is_gid_entry_valid(table->data_vec[attr->index]);
+	if (valid && attr->ndev && (if_getflags(attr->ndev) & IFF_UP))
+		ndev = attr->ndev;
+	read_unlock_irqrestore(&table->rwlock, flags);
+	return ndev;
+}
+
 static int config_non_roce_gid_cache(struct ib_device *device,
 				     u8 port, int gid_tbl_len)
 {
diff --git a/sys/ofed/drivers/infiniband/core/ib_cma.c b/sys/ofed/drivers/infiniband/core/ib_cma.c
index 426c7ae80143..a16e31df6752 100644
--- a/sys/ofed/drivers/infiniband/core/ib_cma.c
+++ b/sys/ofed/drivers/infiniband/core/ib_cma.c
@@ -729,6 +729,7 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
 	dgid = (union ib_gid *) &addr->sib_addr;
 	pkey = ntohs(addr->sib_pkey);
 
+	mutex_lock(&lock);
 	list_for_each_entry(cur_dev, &dev_list, list) {
 		for (p = 1; p <= cur_dev->device->phys_port_cnt; ++p) {
 			if (!rdma_cap_af_ib(cur_dev->device, p))
@@ -755,18 +756,19 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
 					cma_dev = cur_dev;
 					sgid = gid;
 					id_priv->id.port_num = p;
+					goto found;
 				}
 			}
 		}
 	}
-
-	if (!cma_dev)
-		return -ENODEV;
+	mutex_unlock(&lock);
+	return -ENODEV;
 
 found:
 	cma_attach_to_dev(id_priv, cma_dev);
-	addr = (struct sockaddr_ib *) cma_src_addr(id_priv);
-	memcpy(&addr->sib_addr, &sgid, sizeof sgid);
+	mutex_unlock(&lock);
+	addr = (struct sockaddr_ib *)cma_src_addr(id_priv);
+	memcpy(&addr->sib_addr, &sgid, sizeof(sgid));
 	cma_translate_ib(addr, &id_priv->id.route.addr.dev_addr);
 	return 0;
 }
@@ -2104,7 +2106,7 @@ cma_ib_new_conn_id(const struct rdma_cm_id *listen_id,
 		rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path;
 
 	if (net_dev) {
-		rdma_copy_addr(&rt->addr.dev_addr, net_dev, NULL);
+		rdma_copy_src_l2_addr(&rt->addr.dev_addr, net_dev);
 	} else {
 		if (!cma_protocol_roce(listen_id) &&
 		    cma_any_addr(vnet, cma_src_addr(id_priv))) {
@@ -2151,7 +2153,7 @@ cma_ib_new_udp_id(const struct rdma_cm_id *listen_id,
 		goto err;
 
 	if (net_dev) {
-		rdma_copy_addr(&id->route.addr.dev_addr, net_dev, NULL);
+		rdma_copy_src_l2_addr(&id->route.addr.dev_addr, net_dev);
 	} else {
 		if (!cma_any_addr(vnet, cma_src_addr(id_priv))) {
 			ret = cma_translate_addr(cma_src_addr(id_priv),
@@ -3067,13 +3069,11 @@ static void addr_handler(int status, struct sockaddr *src_addr,
 	if (id_priv->id.event_handler(&id_priv->id, &event)) {
 		cma_exch(id_priv, RDMA_CM_DESTROYING);
 		mutex_unlock(&id_priv->handler_mutex);
-		cma_deref_id(id_priv);
 		rdma_destroy_id(&id_priv->id);
 		return;
 	}
 out:
 	mutex_unlock(&id_priv->handler_mutex);
-	cma_deref_id(id_priv);
 }
 
 static int cma_resolve_loopback(struct rdma_id_private *id_priv)
@@ -3171,7 +3171,6 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
 		return -EINVAL;
 
 	memcpy(cma_dst_addr(id_priv), dst_addr, rdma_addr_size(dst_addr));
-	atomic_inc(&id_priv->refcount);
 	if (cma_any_addr(vnet, dst_addr)) {
 		ret = cma_resolve_loopback(id_priv);
 	} else {
@@ -3182,9 +3181,10 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
 			if (ret)
 				goto err;
 
-			ret = rdma_resolve_ip(cma_src_addr(id_priv),
-					      dst_addr, &id->route.addr.dev_addr,
-					      timeout_ms, addr_handler, id_priv);
+			ret = rdma_resolve_ip(cma_src_addr(id_priv), dst_addr,
+					      &id->route.addr.dev_addr,
+					      timeout_ms, addr_handler,
+					      false, id_priv);
 		}
 	}
 	if (ret)
@@ -3193,7 +3193,6 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
 	return 0;
 err:
 	cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, RDMA_CM_ADDR_BOUND);
-	cma_deref_id(id_priv);
 	return ret;
 }
 EXPORT_SYMBOL(rdma_resolve_addr);
diff --git a/sys/ofed/drivers/infiniband/core/ib_device.c b/sys/ofed/drivers/infiniband/core/ib_device.c
index 204466ea5a76..eddb0ac5885f 100644
--- a/sys/ofed/drivers/infiniband/core/ib_device.c
+++ b/sys/ofed/drivers/infiniband/core/ib_device.c
@@ -217,7 +217,7 @@ struct ib_device *ib_alloc_device(size_t size)
 
 	INIT_LIST_HEAD(&device->event_handler_list);
 	spin_lock_init(&device->event_handler_lock);
-	spin_lock_init(&device->client_data_lock);
+	rwlock_init(&device->client_data_lock);
 	INIT_LIST_HEAD(&device->client_data_list);
 	INIT_LIST_HEAD(&device->port_list);
 
@@ -233,6 +233,7 @@ EXPORT_SYMBOL(ib_alloc_device);
  */
 void ib_dealloc_device(struct ib_device *device)
 {
+	WARN_ON(!list_empty(&device->client_data_list));
 	WARN_ON(device->reg_state != IB_DEV_UNREGISTERED &&
 		device->reg_state != IB_DEV_UNINITIALIZED);
 	kobject_put(&device->dev.kobj);
@@ -242,9 +243,8 @@ EXPORT_SYMBOL(ib_dealloc_device);
 static int add_client_context(struct ib_device *device, struct ib_client *client)
 {
 	struct ib_client_data *context;
-	unsigned long flags;
 
-	context = kmalloc(sizeof *context, GFP_KERNEL);
+	context = kmalloc(sizeof(*context), GFP_KERNEL);
 	if (!context)
 		return -ENOMEM;
 
@@ -253,9 +253,9 @@ static int add_client_context(struct ib_device *device, struct ib_client *client
 	context->going_down = false;
 
 	down_write(&lists_rwsem);
-	spin_lock_irqsave(&device->client_data_lock, flags);
+	write_lock_irq(&device->client_data_lock);
 	list_add(&context->list, &device->client_data_list);
-	spin_unlock_irqrestore(&device->client_data_lock, flags);
+	write_unlock_irq(&device->client_data_lock);
 	up_write(&lists_rwsem);
 
 	return 0;
@@ -403,14 +403,13 @@ void ib_unregister_device(struct ib_device *device)
 
 	down_write(&lists_rwsem);
 	list_del(&device->core_list);
-	spin_lock_irqsave(&device->client_data_lock, flags);
-	list_for_each_entry_safe(context, tmp, &device->client_data_list, list)
+	write_lock_irq(&device->client_data_lock);
+	list_for_each_entry(context, &device->client_data_list, list)
 		context->going_down = true;
-	spin_unlock_irqrestore(&device->client_data_lock, flags);
+	write_unlock_irq(&device->client_data_lock);
 	downgrade_write(&lists_rwsem);
 
-	list_for_each_entry_safe(context, tmp, &device->client_data_list,
-				 list) {
+	list_for_each_entry(context, &device->client_data_list, list) {
 		if (context->client->remove)
 			context->client->remove(device, context->data);
 	}
@@ -423,10 +422,13 @@ void ib_unregister_device(struct ib_device *device)
 	ib_cache_cleanup_one(device);
 
 	down_write(&lists_rwsem);
-	spin_lock_irqsave(&device->client_data_lock, flags);
-	list_for_each_entry_safe(context, tmp, &device->client_data_list, list)
+	write_lock_irqsave(&device->client_data_lock, flags);
+	list_for_each_entry_safe(context, tmp, &device->client_data_list,
+				 list) {
+		list_del(&context->list);
 		kfree(context);
-	spin_unlock_irqrestore(&device->client_data_lock, flags);
+	}
+	write_unlock_irqrestore(&device->client_data_lock, flags);
 	up_write(&lists_rwsem);
 
 	device->reg_state = IB_DEV_UNREGISTERED;
@@ -476,9 +478,8 @@ EXPORT_SYMBOL(ib_register_client);
  */
 void ib_unregister_client(struct ib_client *client)
 {
-	struct ib_client_data *context, *tmp;
+	struct ib_client_data *context;
 	struct ib_device *device;
-	unsigned long flags;
 
 	mutex_lock(&device_mutex);
 
@@ -490,14 +491,14 @@ void ib_unregister_client(struct ib_client *client)
 		struct ib_client_data *found_context = NULL;
 
 		down_write(&lists_rwsem);
-		spin_lock_irqsave(&device->client_data_lock, flags);
-		list_for_each_entry_safe(context, tmp, &device->client_data_list, list)
+		write_lock_irq(&device->client_data_lock);
+		list_for_each_entry(context, &device->client_data_list, list)
 			if (context->client == client) {
 				context->going_down = true;
 				found_context = context;
 				break;
 			}
-		spin_unlock_irqrestore(&device->client_data_lock, flags);
+		write_unlock_irq(&device->client_data_lock);
 		up_write(&lists_rwsem);
 
 		if (client->remove)
@@ -511,11 +512,11 @@ void ib_unregister_client(struct ib_client *client)
 		}
 
 		down_write(&lists_rwsem);
-		spin_lock_irqsave(&device->client_data_lock, flags);
+		write_lock_irq(&device->client_data_lock);
 		list_del(&found_context->list);
-		kfree(found_context);
-		spin_unlock_irqrestore(&device->client_data_lock, flags);
+		write_unlock_irq(&device->client_data_lock);
 		up_write(&lists_rwsem);
+		kfree(found_context);
 	}
 
 	mutex_unlock(&device_mutex);
@@ -536,13 +537,13 @@ void *ib_get_client_data(struct ib_device *device, struct ib_client *client)
 	void *ret = NULL;
 	unsigned long flags;
 
-	spin_lock_irqsave(&device->client_data_lock, flags);
+	read_lock_irqsave(&device->client_data_lock, flags);
 	list_for_each_entry(context, &device->client_data_list, list)
 		if (context->client == client) {
 			ret = context->data;
 			break;
 		}
-	spin_unlock_irqrestore(&device->client_data_lock, flags);
+	read_unlock_irqrestore(&device->client_data_lock, flags);
 
 	return ret;
 }
@@ -563,7 +564,7 @@ void ib_set_client_data(struct ib_device *device, struct ib_client *client,
 	struct ib_client_data *context;
 	unsigned long flags;
 
-	spin_lock_irqsave(&device->client_data_lock, flags);
+	write_lock_irqsave(&device->client_data_lock, flags);
 	list_for_each_entry(context, &device->client_data_list, list)
 		if (context->client == client) {
 			context->data = data;
@@ -574,7 +575,7 @@ void ib_set_client_data(struct ib_device *device, struct ib_client *client,
 		device->name, client->name);
 
 out:
-	spin_unlock_irqrestore(&device->client_data_lock, flags);
+	write_unlock_irqrestore(&device->client_data_lock, flags);
 }
 EXPORT_SYMBOL(ib_set_client_data);
 
diff --git a/sys/ofed/drivers/infiniband/core/ib_mad.c b/sys/ofed/drivers/infiniband/core/ib_mad.c
index 94739f6f96a4..a0040749d854 100644
--- a/sys/ofed/drivers/infiniband/core/ib_mad.c
+++ b/sys/ofed/drivers/infiniband/core/ib_mad.c
@@ -224,30 +224,30 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device,
 	/* Validate parameters */
 	qpn = get_spl_qp_index(qp_type);
 	if (qpn == -1) {
-		dev_notice(&device->dev,
-			   "ib_register_mad_agent: invalid QP Type %d\n",
-			   qp_type);
+		dev_dbg_ratelimited(&device->dev, "%s: invalid QP Type %d\n",
+				    __func__, qp_type);
 		goto error1;
 	}
 
 	if (rmpp_version && rmpp_version != IB_MGMT_RMPP_VERSION) {
-		dev_notice(&device->dev,
-			   "ib_register_mad_agent: invalid RMPP Version %u\n",
-			   rmpp_version);
+		dev_dbg_ratelimited(&device->dev,
+				    "%s: invalid RMPP Version %u\n",
+				    __func__, rmpp_version);
 		goto error1;
 	}
 
 	/* Validate MAD registration request if supplied */
 	if (mad_reg_req) {
 		if (mad_reg_req->mgmt_class_version >= MAX_MGMT_VERSION) {
-			dev_notice(&device->dev,
-				   "ib_register_mad_agent: invalid Class Version %u\n",
-				   mad_reg_req->mgmt_class_version);
+			dev_dbg_ratelimited(&device->dev,
+					    "%s: invalid Class Version %u\n",
+					    __func__,
+					    mad_reg_req->mgmt_class_version);
 			goto error1;
 		}
 		if (!recv_handler) {
-			dev_notice(&device->dev,
-				   "ib_register_mad_agent: no recv_handler\n");
+			dev_dbg_ratelimited(&device->dev,
+					    "%s: no recv_handler\n", __func__);
 			goto error1;
 		}
 		if (mad_reg_req->mgmt_class >= MAX_MGMT_CLASS) {
@@ -257,9 +257,9 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device,
 			 */
 			if (mad_reg_req->mgmt_class !=
 			    IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
-				dev_notice(&device->dev,
-					   "ib_register_mad_agent: Invalid Mgmt Class 0x%x\n",
-					   mad_reg_req->mgmt_class);
+				dev_dbg_ratelimited(&device->dev,
+					"%s: Invalid Mgmt Class 0x%x\n",
+					__func__, mad_reg_req->mgmt_class);
 				goto error1;
 			}
 		} else if (mad_reg_req->mgmt_class == 0) {
@@ -267,8 +267,9 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device,
 			 * Class 0 is reserved in IBA and is used for
 			 * aliasing of IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE
 			 */
-			dev_notice(&device->dev,
-				   "ib_register_mad_agent: Invalid Mgmt Class 0\n");
+			dev_dbg_ratelimited(&device->dev,
+					    "%s: Invalid Mgmt Class 0\n",
+					    __func__);
 			goto error1;
 		} else if (is_vendor_class(mad_reg_req->mgmt_class)) {
 			/*
@@ -276,18 +277,19 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device,
 			 * ensure supplied OUI is not zero
 			 */
 			if (!is_vendor_oui(mad_reg_req->oui)) {
-				dev_notice(&device->dev,
-					   "ib_register_mad_agent: No OUI specified for class 0x%x\n",
-					   mad_reg_req->mgmt_class);
+				dev_dbg_ratelimited(&device->dev,
+					"%s: No OUI specified for class 0x%x\n",
+					__func__,
+					mad_reg_req->mgmt_class);
 				goto error1;
 			}
 		}
 		/* Make sure class supplied is consistent with RMPP */
 		if (!ib_is_mad_class_rmpp(mad_reg_req->mgmt_class)) {
 			if (rmpp_version) {
-				dev_notice(&device->dev,
-					   "ib_register_mad_agent: RMPP version for non-RMPP class 0x%x\n",
-					   mad_reg_req->mgmt_class);
*** 1680 LINES SKIPPED ***