The branch main has been updated by jhb:

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

commit 4726b80d9379cdefd00ae77d0b91973bde573790
Author:     John Baldwin <[email protected]>
AuthorDate: 2026-06-24 19:30:56 +0000
Commit:     John Baldwin <[email protected]>
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 <[email protected]> (mlx5_ib)
    Tested by:      John Baldwin <[email protected]> (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 ***

Reply via email to