git: 4726b80d9379 - main - OFED: Various changes from Linux 4.20
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
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 ***