--- /dev/null
+From: Vladimir Sokolovsky <vlad@mellanox.com>
+Subject: [PATCH] BACKPORT: ib_core
+
+Signed-off-by: Vladimir Sokolovsky <vlad@mellanox.com>
+---
+ drivers/infiniband/core/addr.c | 51 +++-
+ drivers/infiniband/core/cma.c | 27 ++
+ drivers/infiniband/core/cma_configfs.c | 104 ++++++++
+ drivers/infiniband/core/core_priv.h | 38 +++
+ drivers/infiniband/core/cq.c | 35 ++-
+ drivers/infiniband/core/device.c | 75 ++++++
+ drivers/infiniband/core/fmr_pool.c | 55 +++++
+ drivers/infiniband/core/iwpm_util.c | 8 +
+ drivers/infiniband/core/mad.c | 7 +
+ drivers/infiniband/core/netlink.c | 29 +++
+ drivers/infiniband/core/nldev.c | 316 ++++++++++++++++++++++++
+ drivers/infiniband/core/rdma_core.c | 131 +++++++++-
+ drivers/infiniband/core/restrack.c | 4 +
+ drivers/infiniband/core/restrack.h | 15 ++
+ drivers/infiniband/core/roce_gid_mgmt.c | 58 +++++
+ drivers/infiniband/core/rw.c | 6 +
+ drivers/infiniband/core/sa_query.c | 87 ++++++-
+ drivers/infiniband/core/ucma.c | 19 ++
+ drivers/infiniband/core/umem.c | 78 ++++++
+ drivers/infiniband/core/user_mad.c | 61 +++++
+ drivers/infiniband/core/uverbs.h | 6 +
+ drivers/infiniband/core/uverbs_cmd.c | 13 +
+ drivers/infiniband/core/uverbs_ioctl.c | 6 +
+ drivers/infiniband/core/uverbs_main.c | 75 ++++++
+ drivers/infiniband/core/uverbs_uapi.c | 8 +
+ drivers/infiniband/core/verbs.c | 14 ++
+ include/rdma/ib_addr.h | 31 +++
+ include/rdma/ib_verbs.h | 155 ++++++++++++
+ include/rdma/rdma_netlink.h | 4 +
+ include/rdma/restrack.h | 9 +
+ include/rdma/uverbs_ioctl.h | 3 +
+ include/trace/events/ib_mad.h | 7 +
+ 32 files changed, 1528 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/addr.c
++++ b/drivers/infiniband/core/addr.c
+@@ -42,7 +42,9 @@
+ #include <net/neighbour.h>
+ #include <net/route.h>
+ #include <net/netevent.h>
++#ifdef HAVE_IPV6_STUBS
+ #include <net/ipv6_stubs.h>
++#endif
+ #include <net/ip6_route.h>
+ #include <rdma/ib_addr.h>
+ #include <rdma/ib_cache.h>
+@@ -87,7 +89,11 @@ static inline bool ib_nl_is_good_ip_resp(const struct nlmsghdr *nlh)
+ if (nlh->nlmsg_flags & RDMA_NL_LS_F_ERR)
+ return false;
+
++#ifdef HAVE_NLA_PARSE_DEPRECATED
+ ret = nla_parse_deprecated(tb, LS_NLA_TYPE_MAX - 1, nlmsg_data(nlh),
++#else
++ ret = nla_parse(tb, LS_NLA_TYPE_MAX - 1, nlmsg_data(nlh),
++#endif
+ nlmsg_len(nlh), ib_nl_addr_policy, NULL);
+ if (ret)
+ return false;
+@@ -129,11 +135,26 @@ static void ib_nl_process_good_ip_rsep(const struct nlmsghdr *nlh)
+ }
+
+ int ib_nl_handle_ip_res_resp(struct sk_buff *skb,
++#ifdef HAVE_NETLINK_EXT_ACK
+ struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack)
+ {
++#else
++ struct netlink_callback *cb)
++{
++ const struct nlmsghdr *nlh = (struct nlmsghdr *)cb->nlh;
++
++#endif
+ if ((nlh->nlmsg_flags & NLM_F_REQUEST) ||
++#ifdef HAVE_NETLINK_CAPABLE
++#ifdef HAVE_NETLINK_SKB_PARMS_SK
+ !(NETLINK_CB(skb).sk))
++#else
++ !(NETLINK_CB(skb).ssk))
++#endif
++#else
++ sock_net(skb->sk) != &init_net)
++#endif
+ return -EPERM;
+
+ if (ib_nl_is_good_ip_resp(nlh))
+@@ -177,7 +198,8 @@ static int ib_nl_ip_send_msg(struct rdma_dev_addr *dev_addr,
+ }
+
+ /* Construct the family header first */
+- header = skb_put(skb, NLMSG_ALIGN(sizeof(*header)));
++ header = (struct rdma_ls_ip_resolve_header *)
++ skb_put(skb, NLMSG_ALIGN(sizeof(*header)));
+ header->ifindex = dev_addr->bound_dev_if;
+ nla_put(skb, attrtype, size, daddr);
+
+@@ -345,14 +367,24 @@ static int dst_fetch_ha(const struct dst_entry *dst,
+ return ret;
+ }
+
++#ifdef HAVE_RT_USES_GATEWAY
+ static bool has_gateway(const struct dst_entry *dst, sa_family_t family)
++#else
++static bool has_gateway(const struct dst_entry *dst, const void *daddr, sa_family_t family)
++#endif
+ {
+ struct rtable *rt;
+ struct rt6_info *rt6;
+
+ if (family == AF_INET) {
+ rt = container_of(dst, struct rtable, dst);
++#ifdef HAVE_RT_GW_FAMILY
+ return rt->rt_gw_family == AF_INET;
++#elif defined (HAVE_RT_USES_GATEWAY)
++ return rt->rt_uses_gateway;
++#else
++ return (rt->rt_gateway != *(__be32 *)daddr);
++#endif
+ }
+
+ rt6 = container_of(dst, struct rt6_info, dst);
+@@ -371,8 +403,12 @@ static int fetch_ha(const struct dst_entry *dst, struct rdma_dev_addr *dev_addr,
+ (const void *)&dst_in6->sin6_addr;
+ sa_family_t family = dst_in->sa_family;
+
++#ifndef HAVE_RT_USES_GATEWAY
++ if (seq && has_gateway(dst, daddr, family) && dst->dev->type == ARPHRD_INFINIBAND)
++#else
+ /* If we have a gateway in IB mode then it must be an IB network */
+ if (has_gateway(dst, family) && dev_addr->network == RDMA_NETWORK_IB)
++#endif
+ return ib_nl_fetch_ha(dev_addr, daddr, seq, family);
+ else
+ return dst_fetch_ha(dst, dev_addr, daddr);
+@@ -475,6 +511,15 @@ static int copy_src_l2_addr(struct rdma_dev_addr *dev_addr,
+ const struct net_device *ndev)
+ {
+ int ret = 0;
++#ifndef HAVE_RT_USES_GATEWAY
++ const struct sockaddr_in *dst_in4 =
++ (const struct sockaddr_in *)dst_in;
++ const struct sockaddr_in6 *dst_in6 =
++ (const struct sockaddr_in6 *)dst_in;
++ const void *daddr = (dst_in->sa_family == AF_INET) ?
++ (const void *)&dst_in4->sin_addr.s_addr :
++ (const void *)&dst_in6->sin6_addr;
++#endif
+
+ if (dst->dev->flags & IFF_LOOPBACK)
+ ret = rdma_translate_ip(dst_in, dev_addr);
+@@ -486,7 +531,11 @@ static int copy_src_l2_addr(struct rdma_dev_addr *dev_addr,
+ * we're definitely in RoCE v2 (as RoCE v1 isn't routable) set the
+ * network type accordingly.
+ */
++#ifdef HAVE_RT_USES_GATEWAY
+ if (has_gateway(dst, dst_in->sa_family) &&
++#else
++ if (has_gateway(dst, daddr, dst_in->sa_family) &&
++#endif
+ ndev->type != ARPHRD_INFINIBAND)
+ dev_addr->network = dst_in->sa_family == AF_INET ?
+ RDMA_NETWORK_IPV4 :
+diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/cma.c
++++ b/drivers/infiniband/core/cma.c
+@@ -1428,7 +1428,11 @@ static bool validate_ipv4_net_dev(struct net_device *net_dev,
+ fl4.saddr = saddr;
+
+ rcu_read_lock();
++#ifdef HAVE_FIB_LOOKUP_4_PARAMS
+ err = fib_lookup(dev_net(net_dev), &fl4, &res, 0);
++#else
++ err = fib_lookup(dev_net(net_dev), &fl4, &res);
++#endif
+ ret = err == 0 && FIB_RES_DEV(res) == net_dev;
+ rcu_read_unlock();
+
+@@ -1444,7 +1448,11 @@ static bool validate_ipv6_net_dev(struct net_device *net_dev,
+ IPV6_ADDR_LINKLOCAL;
+ struct rt6_info *rt = rt6_lookup(dev_net(net_dev), &dst_addr->sin6_addr,
+ &src_addr->sin6_addr, net_dev->ifindex,
++#ifdef HAVE_RT6_LOOKUP_6_PARAMS
+ NULL, strict);
++#else
++ strict);
++#endif
+ bool ret;
+
+ if (!rt)
+@@ -2827,6 +2835,7 @@ static int cma_resolve_iw_route(struct rdma_id_private *id_priv)
+ return 0;
+ }
+
++#if defined(HAVE_VLAN_DEV_GET_EGRESS_QOS_MASK) && defined(HAVE_NETDEV_GET_PRIO_TC_MAP)
+ static int iboe_tos_to_sl(struct net_device *ndev, int tos)
+ {
+ int prio;
+@@ -2844,6 +2853,7 @@ static int iboe_tos_to_sl(struct net_device *ndev, int tos)
+ #endif
+ return 0;
+ }
++#endif
+
+ static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
+ {
+@@ -2889,7 +2899,16 @@ static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
+ route->path_rec->reversible = 1;
+ route->path_rec->pkey = cpu_to_be16(0xffff);
+ route->path_rec->mtu_selector = IB_SA_EQ;
++#if defined(HAVE_VLAN_DEV_GET_EGRESS_QOS_MASK) && defined(HAVE_NETDEV_GET_PRIO_TC_MAP)
+ route->path_rec->sl = iboe_tos_to_sl(ndev, tos);
++#elif defined(HAVE_NETDEV_GET_PRIO_TC_MAP)
++ route->path_rec->sl = netdev_get_prio_tc_map(
++ ndev->priv_flags & IFF_802_1Q_VLAN ?
++ vlan_dev_real_dev(ndev) : ndev,
++ rt_tos2priority(tos));
++#else
++ route->path_rec->sl = tos >> 5;
++#endif
+ route->path_rec->traffic_class = tos;
+ route->path_rec->mtu = iboe_get_mtu(ndev->mtu);
+ route->path_rec->rate_selector = IB_SA_EQ;
+@@ -3327,7 +3346,11 @@ static int cma_alloc_any_port(enum rdma_ucm_port_space ps,
+ unsigned int rover;
+ struct net *net = id_priv->id.route.addr.dev_addr.net;
+
++#ifdef HAVE_INET_GET_LOCAL_PORT_RANGE_3_PARAMS
+ inet_get_local_port_range(net, &low, &high);
++#else
++ inet_get_local_port_range(&low, &high);
++#endif
+ remaining = (high - low) + 1;
+ rover = prandom_u32() % remaining + low;
+ retry:
+@@ -4287,7 +4310,11 @@ static int cma_join_ib_multicast(struct rdma_id_private *id_priv,
+ id_priv->id.port_num, &rec,
+ comp_mask, GFP_KERNEL,
+ cma_ib_mc_handler, mc);
++#ifdef HAVE_PTR_ERR_OR_ZERO
+ return PTR_ERR_OR_ZERO(mc->multicast.ib);
++#else
++ return PTR_RET(mc->multicast.ib);
++#endif
+ }
+
+ static void iboe_mcast_work_handler(struct work_struct *work)
+diff --git a/drivers/infiniband/core/cma_configfs.c b/drivers/infiniband/core/cma_configfs.c
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/cma_configfs.c
++++ b/drivers/infiniband/core/cma_configfs.c
+@@ -38,6 +38,10 @@
+ #include "core_priv.h"
+ #include "cma_priv.h"
+
++#ifndef CONFIGFS_ATTR
++#define HAVE_OLD_CONFIGFS_API
++#endif
++
+ struct cma_device;
+
+ struct cma_dev_group;
+@@ -55,6 +59,23 @@ struct cma_dev_group {
+ struct cma_dev_port_group *ports;
+ };
+
++#ifdef HAVE_OLD_CONFIGFS_API
++struct cma_configfs_attr {
++ struct configfs_attribute attr;
++ ssize_t (*show)(struct config_item *item,
++ char *buf);
++ ssize_t (*store)(struct config_item *item,
++ const char *buf, size_t count);
++};
++#define CONFIGFS_ATTR(dummy, _name) \
++static struct cma_configfs_attr attr_##_name = \
++ __CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, _name##_show, _name##_store)
++
++#define CONFIGFS_ATTR_ADD(name) &name.attr
++#else
++#define CONFIGFS_ATTR_ADD(name) &name
++#endif /* HAVE_OLD_CONFIGFS_API */
++
+ static struct cma_dev_port_group *to_dev_port_group(struct config_item *item)
+ {
+ struct config_group *group;
+@@ -71,6 +92,34 @@ static bool filter_by_name(struct ib_device *ib_dev, void *cookie)
+ return !strcmp(dev_name(&ib_dev->dev), cookie);
+ }
+
++#ifdef HAVE_OLD_CONFIGFS_API
++static ssize_t cma_configfs_attr_show(struct config_item *item,
++ struct configfs_attribute *attr,
++ char *buf)
++{
++ struct cma_configfs_attr *ca =
++ container_of(attr, struct cma_configfs_attr, attr);
++
++ if (ca->show)
++ return ca->show(item, buf);
++
++ return -EINVAL;
++}
++
++static ssize_t cma_configfs_attr_store(struct config_item *item,
++ struct configfs_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct cma_configfs_attr *ca =
++ container_of(attr, struct cma_configfs_attr, attr);
++
++ if (ca->store)
++ return ca->store(item, buf, count);
++
++ return -EINVAL;
++}
++#endif /* HAVE_OLD_CONFIGFS_API */
++
+ static int cma_configfs_params_get(struct config_item *item,
+ struct cma_device **pcma_dev,
+ struct cma_dev_port_group **pgroup)
+@@ -189,7 +238,22 @@ static struct configfs_attribute *cma_configfs_attributes[] = {
+ NULL,
+ };
+
++#ifdef HAVE_OLD_CONFIGFS_API
++static struct configfs_item_operations cma_item_ops = {
++ .show_attribute = cma_configfs_attr_show,
++ .store_attribute = cma_configfs_attr_store,
++};
++#else /* HAVE_OLD_CONFIGFS_API */
++static struct configfs_item_operations cma_item_ops = {
++};
++#endif
++
++#ifdef CONFIG_GROUP_INIT_TYPE_NAME_PARAM_3_IS_CONST
+ static const struct config_item_type cma_port_group_type = {
++#else
++static struct config_item_type cma_port_group_type = {
++#endif
++ .ct_item_ops = &cma_item_ops,
+ .ct_attrs = cma_configfs_attributes,
+ .ct_owner = THIS_MODULE
+ };
+@@ -217,6 +281,14 @@ static int make_cma_ports(struct cma_dev_group *cma_dev_group,
+ goto free;
+ }
+
++#ifndef HAVE_CONFIGFS_DEFAULT_GROUPS_LIST
++ cma_dev_group->ports_group.default_groups = kcalloc((ports_num + 1),
++ sizeof(struct config_group *),
++ GFP_KERNEL);
++ if (!cma_dev_group->ports_group.default_groups)
++ goto free;
++#endif
++
+ for (i = 0; i < ports_num; i++) {
+ char port_str[10];
+
+@@ -226,10 +298,17 @@ static int make_cma_ports(struct cma_dev_group *cma_dev_group,
+ config_group_init_type_name(&ports[i].group,
+ port_str,
+ &cma_port_group_type);
++#ifdef HAVE_CONFIGFS_DEFAULT_GROUPS_LIST
+ configfs_add_default_group(&ports[i].group,
+ &cma_dev_group->ports_group);
++#else
++ cma_dev_group->ports_group.default_groups[i] = &ports[i].group;
++#endif
+
+ }
++#ifndef HAVE_CONFIGFS_DEFAULT_GROUPS_LIST
++ cma_dev_group->ports_group.default_groups[i] = NULL;
++#endif
+ cma_dev_group->ports = ports;
+
+ return 0;
+@@ -266,7 +345,11 @@ static struct configfs_item_operations cma_ports_item_ops = {
+ .release = release_cma_ports_group
+ };
+
++#ifdef CONFIG_GROUP_INIT_TYPE_NAME_PARAM_3_IS_CONST
+ static const struct config_item_type cma_ports_group_type = {
++#else
++static struct config_item_type cma_ports_group_type = {
++#endif
+ .ct_item_ops = &cma_ports_item_ops,
+ .ct_owner = THIS_MODULE
+ };
+@@ -275,7 +358,11 @@ static struct configfs_item_operations cma_device_item_ops = {
+ .release = release_cma_dev
+ };
+
++#ifdef CONFIG_GROUP_INIT_TYPE_NAME_PARAM_3_IS_CONST
+ static const struct config_item_type cma_device_group_type = {
++#else
++static struct config_item_type cma_device_group_type = {
++#endif
+ .ct_item_ops = &cma_device_item_ops,
+ .ct_owner = THIS_MODULE
+ };
+@@ -305,16 +392,29 @@ static struct config_group *make_cma_dev(struct config_group *group,
+
+ err = make_cma_ports(cma_dev_group, cma_dev);
+ if (err)
++#ifdef HAVE_CONFIGFS_DEFAULT_GROUPS_LIST
+ goto fail;
++#else
++ goto fail_free;
++#endif
+
+ config_group_init_type_name(&cma_dev_group->device_group, name,
+ &cma_device_group_type);
++#ifdef HAVE_CONFIGFS_DEFAULT_GROUPS_LIST
+ configfs_add_default_group(&cma_dev_group->ports_group,
+ &cma_dev_group->device_group);
++#else
++ cma_dev_group->device_group.default_groups[0] = &cma_dev_group->ports_group;
++ cma_dev_group->device_group.default_groups[1] = NULL;
++#endif
+
+ cma_deref_dev(cma_dev);
+ return &cma_dev_group->device_group;
+
++#ifndef HAVE_CONFIGFS_DEFAULT_GROUPS_LIST
++fail_free:
++ kfree(cma_dev_group->device_group.default_groups);
++#endif
+ fail:
+ if (cma_dev)
+ cma_deref_dev(cma_dev);
+@@ -326,7 +426,11 @@ static struct configfs_group_operations cma_subsys_group_ops = {
+ .make_group = make_cma_dev,
+ };
+
++#ifdef CONFIG_GROUP_INIT_TYPE_NAME_PARAM_3_IS_CONST
+ static const struct config_item_type cma_subsys_type = {
++#else
++static struct config_item_type cma_subsys_type = {
++#endif
+ .ct_group_ops = &cma_subsys_group_ops,
+ .ct_owner = THIS_MODULE,
+ };
+diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/core_priv.h
++++ b/drivers/infiniband/core/core_priv.h
+@@ -130,6 +130,7 @@ int ib_cache_setup_one(struct ib_device *device);
+ void ib_cache_cleanup_one(struct ib_device *device);
+ void ib_cache_release_one(struct ib_device *device);
+
++#ifdef HAVE_CGROUP_RDMA_H
+ #ifdef CONFIG_CGROUP_RDMA
+ void ib_device_register_rdmacg(struct ib_device *device);
+ void ib_device_unregister_rdmacg(struct ib_device *device);
+@@ -163,11 +164,39 @@ static inline void ib_rdmacg_uncharge(struct ib_rdmacg_object *cg_obj,
+ {
+ }
+ #endif
++#endif /* HAVE_CGROUP_RDMA_H */
+
+ static inline bool rdma_is_upper_dev_rcu(struct net_device *dev,
+ struct net_device *upper)
+ {
++#if defined(HAVE_NETDEV_HAS_UPPER_DEV_ALL_RCU)
+ return netdev_has_upper_dev_all_rcu(dev, upper);
++#elif defined(HAVE_NETDEV_FOR_EACH_ALL_UPPER_DEV_RCU)
++ struct net_device *_upper = NULL;
++ struct list_head *iter;
++
++ netdev_for_each_all_upper_dev_rcu(dev, _upper, iter)
++ if (_upper == upper)
++ break;
++
++ return _upper == upper;
++#else
++ struct net_device *rdev_upper;
++ struct net_device *master;
++ bool ret;
++
++ if (!upper || !dev)
++ ret = false;
++
++ rdev_upper = rdma_vlan_dev_real_dev(upper);
++ master = netdev_master_upper_dev_get_rcu(dev);
++
++ ret = (upper == master) ||
++ (rdev_upper && (rdev_upper == master)) ||
++ (rdev_upper == dev);
++
++ return ret;
++#endif
+ }
+
+ int addr_init(void);
+@@ -182,6 +211,7 @@ void ib_sa_cleanup(void);
+ int rdma_nl_init(void);
+ void rdma_nl_exit(void);
+
++#ifdef HAVE_NETLINK_EXT_ACK
+ int ib_nl_handle_resolve_resp(struct sk_buff *skb,
+ struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack);
+@@ -191,6 +221,14 @@ int ib_nl_handle_set_timeout(struct sk_buff *skb,
+ int ib_nl_handle_ip_res_resp(struct sk_buff *skb,
+ struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack);
++#else
++int ib_nl_handle_resolve_resp(struct sk_buff *skb,
++ struct netlink_callback *cb);
++int ib_nl_handle_set_timeout(struct sk_buff *skb,
++ struct netlink_callback *cb);
++int ib_nl_handle_ip_res_resp(struct sk_buff *skb,
++ struct netlink_callback *cb);
++#endif
+
+ int ib_get_cached_subnet_prefix(struct ib_device *device,
+ u8 port_num,
+diff --git a/drivers/infiniband/core/cq.c b/drivers/infiniband/core/cq.c
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/cq.c
++++ b/drivers/infiniband/core/cq.c
+@@ -122,6 +122,7 @@ static void ib_cq_completion_direct(struct ib_cq *cq, void *private)
+ WARN_ONCE(1, "got unsolicited completion for CQ 0x%p\n", cq);
+ }
+
++#if defined(HAVE_IRQ_POLL_H) && IS_ENABLED(CONFIG_IRQ_POLL)
+ static int ib_poll_handler(struct irq_poll *iop, int budget)
+ {
+ struct ib_cq *cq = container_of(iop, struct ib_cq, iop);
+@@ -145,6 +146,30 @@ static void ib_cq_completion_softirq(struct ib_cq *cq, void *private)
+ {
+ irq_poll_sched(&cq->iop);
+ }
++#else
++static int ib_poll_handler(struct blk_iopoll *iop, int budget)
++{
++ struct ib_cq *cq = container_of(iop, struct ib_cq, iop);
++ int completed;
++
++ completed = __ib_process_cq(cq, budget);
++ if (completed < budget) {
++ blk_iopoll_complete(&cq->iop);
++ if (ib_req_notify_cq(cq, IB_POLL_FLAGS) > 0) {
++ if (!blk_iopoll_sched_prep(&cq->iop))
++ blk_iopoll_sched(&cq->iop);
++ }
++ }
++
++ return completed;
++}
++
++static void ib_cq_completion_softirq(struct ib_cq *cq, void *private)
++{
++ if (!blk_iopoll_sched_prep(&cq->iop))
++ blk_iopoll_sched(&cq->iop);
++}
++#endif
+
+ static void ib_cq_poll_work(struct work_struct *work)
+ {
+@@ -222,8 +247,12 @@ struct ib_cq *__ib_alloc_cq_user(struct ib_device *dev, void *private,
+ break;
+ case IB_POLL_SOFTIRQ:
+ cq->comp_handler = ib_cq_completion_softirq;
+-
++#if defined(HAVE_IRQ_POLL_H) && IS_ENABLED(CONFIG_IRQ_POLL)
+ irq_poll_init(&cq->iop, IB_POLL_BUDGET_IRQ, ib_poll_handler);
++#else
++ blk_iopoll_init(&cq->iop, IB_POLL_BUDGET_IRQ, ib_poll_handler);
++ blk_iopoll_enable(&cq->iop);
++#endif
+ ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
+ break;
+ case IB_POLL_WORKQUEUE:
+@@ -266,7 +295,11 @@ void ib_free_cq_user(struct ib_cq *cq, struct ib_udata *udata)
+ case IB_POLL_DIRECT:
+ break;
+ case IB_POLL_SOFTIRQ:
++#if defined(HAVE_IRQ_POLL_H) && IS_ENABLED(CONFIG_IRQ_POLL)
+ irq_poll_disable(&cq->iop);
++#else
++ blk_iopoll_disable(&cq->iop);
++#endif
+ break;
+ case IB_POLL_WORKQUEUE:
+ case IB_POLL_UNBOUND_WORKQUEUE:
+diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/device.c
++++ b/drivers/infiniband/core/device.c
+@@ -199,6 +199,7 @@ static DECLARE_HASHTABLE(ndev_hash, 5);
+ static void free_netdevs(struct ib_device *ib_dev);
+ static void ib_unregister_work(struct work_struct *work);
+ static void __ib_unregister_device(struct ib_device *device);
++#if defined(HAVE_REGISTER_LSM_NOTIFIER) || defined(HAVE_REGISTER_BLOCKING_LSM_NOTIFIER)
+ static int ib_security_change(struct notifier_block *nb, unsigned long event,
+ void *lsm_data);
+ static void ib_policy_change_task(struct work_struct *work);
+@@ -267,6 +268,7 @@ define_ibdev_printk_level(ibdev_info, KERN_INFO);
+ static struct notifier_block ibdev_lsm_nb = {
+ .notifier_call = ib_security_change,
+ };
++#endif
+
+ static int rdma_dev_change_netns(struct ib_device *device, struct net *cur_net,
+ struct net *net);
+@@ -467,17 +469,29 @@ static int alloc_name(struct ib_device *ibdev, const char *name)
+ {
+ struct ib_device *device;
+ unsigned long index;
++#ifdef HAVE_IDA_ALLOC
+ struct ida inuse;
+ int rc;
+ int i;
++#else
++ unsigned long *inuse;
++ int i;
++
++ inuse = (unsigned long *) get_zeroed_page(GFP_KERNEL);
++ if (!inuse)
++ return -ENOMEM;
++#endif
+
+ lockdep_assert_held_write(&devices_rwsem);
++#ifdef HAVE_IDA_ALLOC
+ ida_init(&inuse);
++#endif
+ xa_for_each (&devices, index, device) {
+ char buf[IB_DEVICE_NAME_MAX];
+
+ if (sscanf(dev_name(&device->dev), name, &i) != 1)
+ continue;
++#ifdef HAVE_IDA_ALLOC
+ if (i < 0 || i >= INT_MAX)
+ continue;
+ snprintf(buf, sizeof buf, name, i);
+@@ -497,6 +511,17 @@ static int alloc_name(struct ib_device *ibdev, const char *name)
+ out:
+ ida_destroy(&inuse);
+ return rc;
++#else
++ if (i < 0 || i >= PAGE_SIZE * 8)
++ continue;
++ snprintf(buf, sizeof buf, name, i);
++ if (!strcmp(buf, dev_name(&device->dev)))
++ set_bit(i, inuse);
++ }
++ i = find_first_zero_bit(inuse, PAGE_SIZE * 8);
++ free_page((unsigned long) inuse);
++ return dev_set_name(&ibdev->dev, name, i);
++#endif
+ }
+
+ static void ib_device_release(struct device *device)
+@@ -819,6 +844,7 @@ void ib_get_device_fw_str(struct ib_device *dev, char *str)
+ }
+ EXPORT_SYMBOL(ib_get_device_fw_str);
+
++#if defined(HAVE_REGISTER_LSM_NOTIFIER) || defined(HAVE_REGISTER_BLOCKING_LSM_NOTIFIER)
+ static void ib_policy_change_task(struct work_struct *work)
+ {
+ struct ib_device *dev;
+@@ -843,7 +869,9 @@ static void ib_policy_change_task(struct work_struct *work)
+ }
+ up_read(&devices_rwsem);
+ }
++#endif /* HAVE_REGISTER_LSM_NOTIFIER */
+
++#if defined(HAVE_REGISTER_LSM_NOTIFIER) || defined(HAVE_REGISTER_BLOCKING_LSM_NOTIFIER)
+ static int ib_security_change(struct notifier_block *nb, unsigned long event,
+ void *lsm_data)
+ {
+@@ -855,6 +883,7 @@ static int ib_security_change(struct notifier_block *nb, unsigned long event,
+
+ return NOTIFY_OK;
+ }
++#endif /* HAVE_REGISTER_LSM_NOTIFIER */
+
+ static void compatdev_release(struct device *dev)
+ {
+@@ -1169,6 +1198,7 @@ out:
+
+ static void setup_dma_device(struct ib_device *device)
+ {
++#ifdef HAVE_DEVICE_DMA_OPS
+ struct device *parent = device->dev.parent;
+
+ WARN_ON_ONCE(device->dma_device);
+@@ -1200,6 +1230,15 @@ static void setup_dma_device(struct ib_device *device)
+ WARN_ON_ONCE(!parent);
+ device->dma_device = parent;
+ }
++#else /* HAVE_DEVICE_DMA_OPS */
++ WARN_ON_ONCE(!device->dev.parent && !device->dma_device);
++ WARN_ON_ONCE(device->dev.parent && device->dma_device
++ && device->dev.parent != device->dma_device);
++ if (!device->dev.parent)
++ device->dev.parent = device->dma_device;
++ if (!device->dma_device)
++ device->dma_device = device->dev.parent;
++#endif /* HAVE_DEVICE_DMA_OPS */
+ /* Setup default max segment size for all IB devices */
+ dma_set_max_seg_size(device->dma_device, SZ_2G);
+
+@@ -1348,7 +1387,9 @@ int ib_register_device(struct ib_device *device, const char *name)
+ return ret;
+ }
+
++#ifdef HAVE_CGROUP_RDMA_H
+ ib_device_register_rdmacg(device);
++#endif
+
+ rdma_counter_init(device);
+
+@@ -1401,7 +1442,9 @@ dev_cleanup:
+ device_del(&device->dev);
+ cg_cleanup:
+ dev_set_uevent_suppress(&device->dev, false);
++#ifdef HAVE_CGROUP_RDMA_H
+ ib_device_unregister_rdmacg(device);
++#endif
+ ib_cache_cleanup_one(device);
+ return ret;
+ }
+@@ -1428,7 +1471,9 @@ static void __ib_unregister_device(struct ib_device *ib_dev)
+
+ ib_device_unregister_sysfs(ib_dev);
+ device_del(&ib_dev->dev);
++#ifdef HAVE_CGROUP_RDMA_H
+ ib_device_unregister_rdmacg(ib_dev);
++#endif
+ ib_cache_cleanup_one(ib_dev);
+
+ /*
+@@ -2617,15 +2662,27 @@ EXPORT_SYMBOL(ib_set_device_ops);
+
+ static const struct rdma_nl_cbs ibnl_ls_cb_table[RDMA_NL_LS_NUM_OPS] = {
+ [RDMA_NL_LS_OP_RESOLVE] = {
++#ifdef HAVE_NETLINK_EXT_ACK
+ .doit = ib_nl_handle_resolve_resp,
++#else
++ .dump = ib_nl_handle_resolve_resp,
++#endif
+ .flags = RDMA_NL_ADMIN_PERM,
+ },
+ [RDMA_NL_LS_OP_SET_TIMEOUT] = {
++#ifdef HAVE_NETLINK_EXT_ACK
+ .doit = ib_nl_handle_set_timeout,
++#else
++ .dump = ib_nl_handle_set_timeout,
++#endif
+ .flags = RDMA_NL_ADMIN_PERM,
+ },
+ [RDMA_NL_LS_OP_IP_RESOLVE] = {
++#ifdef HAVE_NETLINK_EXT_ACK
+ .doit = ib_nl_handle_ip_res_resp,
++#else
++ .dump = ib_nl_handle_ip_res_resp,
++#endif
+ .flags = RDMA_NL_ADMIN_PERM,
+ },
+ };
+@@ -2684,11 +2741,17 @@ static int __init ib_core_init(void)
+ goto err_mad;
+ }
+
++#if defined(HAVE_REGISTER_LSM_NOTIFIER) || defined(HAVE_REGISTER_BLOCKING_LSM_NOTIFIER)
++#ifdef HAVE_REGISTER_BLOCKING_LSM_NOTIFIER
+ ret = register_blocking_lsm_notifier(&ibdev_lsm_nb);
++#else
++ ret = register_lsm_notifier(&ibdev_lsm_nb);
++#endif
+ if (ret) {
+ pr_warn("Couldn't register LSM notifier. ret %d\n", ret);
+ goto err_sa;
+ }
++#endif
+
+ ret = register_pernet_device(&rdma_dev_net_ops);
+ if (ret) {
+@@ -2703,9 +2766,15 @@ static int __init ib_core_init(void)
+ return 0;
+
+ err_compat:
++#if defined(HAVE_REGISTER_LSM_NOTIFIER) || defined(HAVE_REGISTER_BLOCKING_LSM_NOTIFIER)
++#ifdef HAVE_REGISTER_BLOCKING_LSM_NOTIFIER
+ unregister_blocking_lsm_notifier(&ibdev_lsm_nb);
++#else
++ unregister_lsm_notifier(&ibdev_lsm_nb);
++#endif
+ err_sa:
+ ib_sa_cleanup();
++#endif
+ err_mad:
+ ib_mad_cleanup();
+ err_addr:
+@@ -2729,7 +2798,13 @@ static void __exit ib_core_cleanup(void)
+ nldev_exit();
+ rdma_nl_unregister(RDMA_NL_LS);
+ unregister_pernet_device(&rdma_dev_net_ops);
++#if defined(HAVE_REGISTER_LSM_NOTIFIER) || defined(HAVE_REGISTER_BLOCKING_LSM_NOTIFIER)
++#ifdef HAVE_REGISTER_BLOCKING_LSM_NOTIFIER
+ unregister_blocking_lsm_notifier(&ibdev_lsm_nb);
++#else
++ unregister_lsm_notifier(&ibdev_lsm_nb);
++#endif
++#endif
+ ib_sa_cleanup();
+ ib_mad_cleanup();
+ addr_cleanup();
+diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/fmr_pool.c
++++ b/drivers/infiniband/core/fmr_pool.c
+@@ -96,8 +96,12 @@ struct ib_fmr_pool {
+ void * arg);
+ void *flush_arg;
+
++#ifdef HAVE_KTHREAD_QUEUE_WORK
+ struct kthread_worker *worker;
+ struct kthread_work work;
++#else
++ struct task_struct *thread;
++#endif
+
+ atomic_t req_ser;
+ atomic_t flush_ser;
+@@ -175,6 +179,7 @@ static void ib_fmr_batch_release(struct ib_fmr_pool *pool)
+ spin_unlock_irq(&pool->pool_lock);
+ }
+
++#ifdef HAVE_KTHREAD_QUEUE_WORK
+ static void ib_fmr_cleanup_func(struct kthread_work *work)
+ {
+ struct ib_fmr_pool *pool = container_of(work, struct ib_fmr_pool, work);
+@@ -189,6 +194,32 @@ static void ib_fmr_cleanup_func(struct kthread_work *work)
+ if (atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) < 0)
+ kthread_queue_work(pool->worker, &pool->work);
+ }
++#else /* HAVE_KTHREAD_QUEUE_WORK */
++static int ib_fmr_cleanup_thread(void *pool_ptr)
++{
++ struct ib_fmr_pool *pool = pool_ptr;
++
++ do {
++ if (atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) < 0) {
++ ib_fmr_batch_release(pool);
++
++ atomic_inc(&pool->flush_ser);
++ wake_up_interruptible(&pool->force_wait);
++
++ if (pool->flush_function)
++ pool->flush_function(pool, pool->flush_arg);
++ }
++
++ set_current_state(TASK_INTERRUPTIBLE);
++ if (atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) >= 0 &&
++ !kthread_should_stop())
++ schedule();
++ __set_current_state(TASK_RUNNING);
++ } while (!kthread_should_stop());
++
++ return 0;
++}
++#endif /* HAVE_KTHREAD_QUEUE_WORK */
+
+ /**
+ * ib_create_fmr_pool - Create an FMR pool
+@@ -257,6 +288,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
+ atomic_set(&pool->flush_ser, 0);
+ init_waitqueue_head(&pool->force_wait);
+
++#ifdef HAVE_KTHREAD_QUEUE_WORK
+ pool->worker =
+ kthread_create_worker(0, "ib_fmr(%s)", dev_name(&device->dev));
+ if (IS_ERR(pool->worker)) {
+@@ -265,6 +297,17 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
+ goto out_free_pool;
+ }
+ kthread_init_work(&pool->work, ib_fmr_cleanup_func);
++#else
++ pool->thread = kthread_run(ib_fmr_cleanup_thread,
++ pool,
++ "ib_fmr(%s)",
++ device->name);
++ if (IS_ERR(pool->thread)) {
++ pr_warn(PFX "couldn't start cleanup thread\n");
++ ret = PTR_ERR(pool->thread);
++ goto out_free_pool;
++ }
++#endif
+
+ {
+ struct ib_pool_fmr *fmr;
+@@ -329,7 +372,11 @@ void ib_destroy_fmr_pool(struct ib_fmr_pool *pool)
+ LIST_HEAD(fmr_list);
+ int i;
+
++#ifdef HAVE_KTHREAD_QUEUE_WORK
+ kthread_destroy_worker(pool->worker);
++#else
++ kthread_stop(pool->thread);
++#endif
+ ib_fmr_batch_release(pool);
+
+ i = 0;
+@@ -379,7 +426,11 @@ int ib_flush_fmr_pool(struct ib_fmr_pool *pool)
+ spin_unlock_irq(&pool->pool_lock);
+
+ serial = atomic_inc_return(&pool->req_ser);
++#ifdef HAVE_KTHREAD_QUEUE_WORK
+ kthread_queue_work(pool->worker, &pool->work);
++#else
++ wake_up_process(pool->thread);
++#endif
+
+ if (wait_event_interruptible(pool->force_wait,
+ atomic_read(&pool->flush_ser) - serial >= 0))
+@@ -491,7 +542,11 @@ void ib_fmr_pool_unmap(struct ib_pool_fmr *fmr)
+ list_add_tail(&fmr->list, &pool->dirty_list);
+ if (++pool->dirty_len >= pool->dirty_watermark) {
+ atomic_inc(&pool->req_ser);
++#ifdef HAVE_KTHREAD_QUEUE_WORK
+ kthread_queue_work(pool->worker, &pool->work);
++#else
++ wake_up_process(pool->thread);
++#endif
+ }
+ }
+ }
+diff --git a/drivers/infiniband/core/iwpm_util.c b/drivers/infiniband/core/iwpm_util.c
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/iwpm_util.c
++++ b/drivers/infiniband/core/iwpm_util.c
+@@ -506,13 +506,21 @@ int iwpm_parse_nlmsg(struct netlink_callback *cb, int policy_max,
+ int ret;
+ const char *err_str = "";
+
++#ifdef HAVE_NLMSG_VALIDATE_DEPRECATED
+ ret = nlmsg_validate_deprecated(cb->nlh, nlh_len, policy_max - 1,
+ nlmsg_policy, NULL);
++#else
++ ret = nlmsg_validate(cb->nlh, nlh_len, policy_max - 1, nlmsg_policy, NULL);
++#endif
+ if (ret) {
+ err_str = "Invalid attribute";
+ goto parse_nlmsg_error;
+ }
++#ifdef HAVE_NLMSG_PARSE_DEPRECATED
+ ret = nlmsg_parse_deprecated(cb->nlh, nlh_len, nltb, policy_max - 1,
++#else
++ ret = nlmsg_parse(cb->nlh, nlh_len, nltb, policy_max - 1,
++#endif
+ nlmsg_policy, NULL);
+ if (ret) {
+ err_str = "Unable to parse the nlmsg";
+diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/mad.c
++++ b/drivers/infiniband/core/mad.c
+@@ -35,6 +35,9 @@
+ *
+ */
+
++#ifdef pr_fmt
++#undef pr_fmt
++#endif
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+ #include <linux/dma-mapping.h>
+@@ -57,7 +60,11 @@
+ #ifdef CONFIG_TRACEPOINTS
+ static void create_mad_addr_info(struct ib_mad_send_wr_private *mad_send_wr,
+ struct ib_mad_qp_info *qp_info,
++#ifdef HAVE_TRACE_EVENT_RAW_IB_MAD_SEND_TEMPLATE
+ struct trace_event_raw_ib_mad_send_template *entry)
++#else
++ struct ftrace_raw_ib_mad_send_template *entry)
++#endif
+ {
+ u16 pkey;
+ struct ib_device *dev = qp_info->port_priv->device;
+diff --git a/drivers/infiniband/core/netlink.c b/drivers/infiniband/core/netlink.c
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/netlink.c
++++ b/drivers/infiniband/core/netlink.c
+@@ -31,6 +31,9 @@
+ * SOFTWARE.
+ */
+
++#ifdef pr_fmt
++#undef pr_fmt
++#endif
+ #define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
+
+ #include <linux/export.h>
+@@ -153,8 +156,12 @@ int ibnl_put_attr(struct sk_buff *skb, struct nlmsghdr *nlh,
+ }
+ EXPORT_SYMBOL(ibnl_put_attr);
+
++#ifdef HAVE_NETLINK_EXT_ACK
+ static int rdma_nl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack)
++#else
++static int rdma_nl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
++#endif
+ {
+ int type = nlh->nlmsg_type;
+ unsigned int index = RDMA_NL_GET_CLIENT(type);
+@@ -176,7 +183,11 @@ static int rdma_nl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
+ */
+ if (index == RDMA_NL_LS) {
+ if (cb_table[op].doit)
++#ifdef HAVE_NETLINK_EXT_ACK
+ return cb_table[op].doit(skb, nlh, extack);
++#else
++ return cb_table[op].doit(skb, nlh);
++#endif
+ return -EINVAL;
+ }
+ /* FIXME: Convert IWCM to properly handle doit callbacks */
+@@ -190,7 +201,11 @@ static int rdma_nl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
+ }
+
+ if (cb_table[op].doit)
++#ifdef HAVE_NETLINK_EXT_ACK
+ return cb_table[op].doit(skb, nlh, extack);
++#else
++ return cb_table[op].doit(skb, nlh);
++#endif
+
+ return 0;
+ }
+@@ -202,10 +217,16 @@ static int rdma_nl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
+ * for that consumer only.
+ */
+ static int rdma_nl_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *,
++#ifdef HAVE_NETLINK_EXT_ACK
+ struct nlmsghdr *,
+ struct netlink_ext_ack *))
++#else
++ struct nlmsghdr *))
++#endif
+ {
++#ifdef HAVE_NETLINK_EXT_ACK
+ struct netlink_ext_ack extack = {};
++#endif
+ struct nlmsghdr *nlh;
+ int err;
+
+@@ -233,13 +254,21 @@ static int rdma_nl_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *,
+ if (nlh->nlmsg_type < NLMSG_MIN_TYPE)
+ goto ack;
+
++#ifdef HAVE_NETLINK_EXT_ACK
+ err = cb(skb, nlh, &extack);
++#else
++ err = cb(skb, nlh);
++#endif
+ if (err == -EINTR)
+ goto skip;
+
+ ack:
+ if (nlh->nlmsg_flags & NLM_F_ACK || err)
++#ifdef HAVE_NETLINK_EXT_ACK
+ netlink_ack(skb, nlh, err, &extack);
++#else
++ netlink_ack(skb, nlh, err);
++#endif
+
+ skip:
+ msglen = NLMSG_ALIGN(nlh->nlmsg_len);
+diff --git a/drivers/infiniband/core/nldev.c b/drivers/infiniband/core/nldev.c
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/nldev.c
++++ b/drivers/infiniband/core/nldev.c
+@@ -339,8 +339,12 @@ static int fill_res_info_entry(struct sk_buff *msg,
+ {
+ struct nlattr *entry_attr;
+
++#ifdef HAVE_NLA_NEST_START_NOFLAG
+ entry_attr = nla_nest_start_noflag(msg,
+ RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY);
++#else
++ entry_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY);
++#endif
+ if (!entry_attr)
+ return -EMSGSIZE;
+
+@@ -375,7 +379,11 @@ static int fill_res_info(struct sk_buff *msg, struct ib_device *device)
+ if (fill_nldev_handle(msg, device))
+ return -EMSGSIZE;
+
++#ifdef HAVE_NLA_NEST_START_NOFLAG
+ table_attr = nla_nest_start_noflag(msg, RDMA_NLDEV_ATTR_RES_SUMMARY);
++#else
++ table_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_RES_SUMMARY);
++#endif
+ if (!table_attr)
+ return -EMSGSIZE;
+
+@@ -795,8 +803,12 @@ static int fill_res_counter_entry(struct sk_buff *msg, bool has_cap_net_admin,
+ return 0;
+ }
+
++#ifdef HAVE_NETLINK_EXT_ACK
+ static int nldev_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack)
++#else
++static int nldev_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
++#endif
+ {
+ struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
+ struct ib_device *device;
+@@ -804,8 +816,16 @@ static int nldev_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ u32 index;
+ int err;
+
++#ifdef HAVE_NLMSG_PARSE_DEPRECATED
+ err = nlmsg_parse_deprecated(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
++#else
++ err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
++#endif/*HAVE_NLMSG_PARSE_DEPRECATED*/
++#ifdef HAVE_NETLINK_EXT_ACK
+ nldev_policy, extack);
++#else
++ nldev_policy, NULL);
++#endif
+ if (err || !tb[RDMA_NLDEV_ATTR_DEV_INDEX])
+ return -EINVAL;
+
+@@ -821,7 +841,11 @@ static int nldev_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ goto err;
+ }
+
++#ifdef HAVE_NETLINK_SKB_PARMS_PORTID
+ nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq,
++#else
++ nlh = nlmsg_put(msg, NETLINK_CB(skb).pid, nlh->nlmsg_seq,
++#endif
+ RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET),
+ 0, 0);
+
+@@ -832,7 +856,11 @@ static int nldev_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ nlmsg_end(msg, nlh);
+
+ ib_device_put(device);
++#ifdef HAVE_NETLINK_SKB_PARMS_PORTID
+ return rdma_nl_unicast(msg, NETLINK_CB(skb).portid);
++#else
++ return rdma_nl_unicast(msg, NETLINK_CB(skb).pid);
++#endif
+
+ err_free:
+ nlmsg_free(msg);
+@@ -841,16 +869,29 @@ err:
+ return err;
+ }
+
++#ifdef HAVE_NETLINK_EXT_ACK
+ static int nldev_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack)
++#else
++static int nldev_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
++#endif
+ {
+ struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
+ struct ib_device *device;
+ u32 index;
+ int err;
+
++#ifdef HAVE_NETLINK_EXT_ACK
++#ifdef HAVE_NLMSG_PARSE_DEPRECATED
+ err = nlmsg_parse_deprecated(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
+ nldev_policy, extack);
++#else
++ err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
++ nldev_policy, extack);
++#endif /*HAVE_NLMSG_PARSE_DEPRECATED*/
++#else
++ err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, nldev_policy, NULL);
++#endif
+ if (err || !tb[RDMA_NLDEV_ATTR_DEV_INDEX])
+ return -EINVAL;
+
+@@ -901,7 +942,11 @@ static int _nldev_get_dumpit(struct ib_device *device,
+ if (idx < start)
+ return 0;
+
++#ifdef HAVE_NETLINK_SKB_PARMS_PORTID
+ nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
++#else
++ nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
++#endif
+ RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET),
+ 0, NLM_F_MULTI);
+
+@@ -927,8 +972,12 @@ static int nldev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
+ return ib_enum_all_devs(_nldev_get_dumpit, skb, cb);
+ }
+
++#ifdef HAVE_NETLINK_EXT_ACK
+ static int nldev_port_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack)
++#else
++static int nldev_port_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
++#endif
+ {
+ struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
+ struct ib_device *device;
+@@ -937,8 +986,16 @@ static int nldev_port_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ u32 port;
+ int err;
+
++#ifdef HAVE_NLMSG_PARSE_DEPRECATED
+ err = nlmsg_parse_deprecated(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
++#else
++ err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
++#endif /*HAVE_NLMSG_PARSE_DEPRECATED*/
++#ifdef HAVE_NETLINK_EXT_ACK
+ nldev_policy, extack);
++#else
++ nldev_policy, NULL);
++#endif
+ if (err ||
+ !tb[RDMA_NLDEV_ATTR_DEV_INDEX] ||
+ !tb[RDMA_NLDEV_ATTR_PORT_INDEX])
+@@ -961,7 +1018,11 @@ static int nldev_port_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ goto err;
+ }
+
++#ifdef HAVE_NETLINK_SKB_PARMS_PORTID
+ nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq,
++#else
++ nlh = nlmsg_put(msg, NETLINK_CB(skb).pid, nlh->nlmsg_seq,
++#endif
+ RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET),
+ 0, 0);
+
+@@ -972,7 +1033,11 @@ static int nldev_port_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ nlmsg_end(msg, nlh);
+ ib_device_put(device);
+
++#ifdef HAVE_NETLINK_SKB_PARMS_PORTID
+ return rdma_nl_unicast(msg, NETLINK_CB(skb).portid);
++#else
++ return rdma_nl_unicast(msg, NETLINK_CB(skb).pid);
++#endif
+
+ err_free:
+ nlmsg_free(msg);
+@@ -993,7 +1058,11 @@ static int nldev_port_get_dumpit(struct sk_buff *skb,
+ int err;
+ unsigned int p;
+
++#ifdef HAVE_NLMSG_PARSE_DEPRECATED
+ err = nlmsg_parse_deprecated(cb->nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
++#else
++ err = nlmsg_parse(cb->nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
++#endif
+ nldev_policy, NULL);
+ if (err || !tb[RDMA_NLDEV_ATTR_DEV_INDEX])
+ return -EINVAL;
+@@ -1019,7 +1088,11 @@ static int nldev_port_get_dumpit(struct sk_buff *skb,
+ continue;
+ }
+
++#ifdef HAVE_NETLINK_SKB_PARMS_PORTID
+ nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid,
++#else
++ nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).pid,
++#endif
+ cb->nlh->nlmsg_seq,
+ RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
+ RDMA_NLDEV_CMD_PORT_GET),
+@@ -1039,8 +1112,12 @@ out:
+ return skb->len;
+ }
+
++#ifdef HAVE_NETLINK_EXT_ACK
+ static int nldev_res_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack)
++#else
++static int nldev_res_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
++#endif
+ {
+ struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
+ struct ib_device *device;
+@@ -1048,8 +1125,16 @@ static int nldev_res_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ u32 index;
+ int ret;
+
++#ifdef HAVE_NLMSG_PARSE_DEPRECATED
+ ret = nlmsg_parse_deprecated(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
++#else
++ ret = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
++#endif /*HAVE_NLMSG_PARSE_DEPRECATED*/
++#ifdef HAVE_NETLINK_EXT_ACK
+ nldev_policy, extack);
++#else
++ nldev_policy, NULL);
++#endif
+ if (ret || !tb[RDMA_NLDEV_ATTR_DEV_INDEX])
+ return -EINVAL;
+
+@@ -1064,7 +1149,11 @@ static int nldev_res_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ goto err;
+ }
+
++#ifdef HAVE_NETLINK_SKB_PARMS_PORTID
+ nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq,
++#else
++ nlh = nlmsg_put(msg, NETLINK_CB(skb).pid, nlh->nlmsg_seq,
++#endif
+ RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_RES_GET),
+ 0, 0);
+
+@@ -1074,7 +1163,11 @@ static int nldev_res_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+
+ nlmsg_end(msg, nlh);
+ ib_device_put(device);
++#ifdef HAVE_NETLINK_SKB_PARMS_PORTID
+ return rdma_nl_unicast(msg, NETLINK_CB(skb).portid);
++#else
++ return rdma_nl_unicast(msg, NETLINK_CB(skb).pid);
++#endif
+
+ err_free:
+ nlmsg_free(msg);
+@@ -1094,7 +1187,11 @@ static int _nldev_res_get_dumpit(struct ib_device *device,
+ if (idx < start)
+ return 0;
+
++#ifdef HAVE_NETLINK_SKB_PARMS_PORTID
+ nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
++#else
++ nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
++#endif
+ RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_RES_GET),
+ 0, NLM_F_MULTI);
+
+@@ -1180,7 +1277,9 @@ static const struct nldev_fill_res_entry fill_entries[RDMA_RESTRACK_MAX] = {
+ };
+
+ static int res_get_common_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
++#ifdef HAVE_NETLINK_EXT_ACK
+ struct netlink_ext_ack *extack,
++#endif
+ enum rdma_restrack_type res_type)
+ {
+ const struct nldev_fill_res_entry *fe = &fill_entries[res_type];
+@@ -1192,8 +1291,16 @@ static int res_get_common_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct sk_buff *msg;
+ int ret;
+
++#ifdef HAVE_NLMSG_PARSE_DEPRECATED
+ ret = nlmsg_parse_deprecated(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
++#else
++ ret = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
++#endif
++#ifdef HAVE_NETLINK_EXT_ACK
+ nldev_policy, extack);
++#else
++ nldev_policy, NULL);
++#endif
+ if (ret || !tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !fe->id || !tb[fe->id])
+ return -EINVAL;
+
+@@ -1243,7 +1350,11 @@ static int res_get_common_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ goto err_free;
+ }
+
++#ifdef HAVE_NETLINK_CAPABLE
+ has_cap_net_admin = netlink_capable(skb, CAP_NET_ADMIN);
++#else
++ has_cap_net_admin = (sock_net(skb->sk) == &init_net);
++#endif
+ ret = fe->fill_res_func(msg, has_cap_net_admin, res, port);
+ rdma_restrack_put(res);
+ if (ret)
+@@ -1269,19 +1380,30 @@ static int res_get_common_dumpit(struct sk_buff *skb,
+ const struct nldev_fill_res_entry *fe = &fill_entries[res_type];
+ struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
+ struct rdma_restrack_entry *res;
++#ifdef HAVE_XARRAY
+ struct rdma_restrack_root *rt;
++#endif
+ int err, ret = 0, idx = 0;
+ struct nlattr *table_attr;
++#ifdef HAVE_XARRAY
+ struct nlattr *entry_attr;
++#endif
+ struct ib_device *device;
+ int start = cb->args[0];
+ bool has_cap_net_admin;
+ struct nlmsghdr *nlh;
++#ifdef HAVE_XARRAY
+ unsigned long id;
++#endif
+ u32 index, port = 0;
+ bool filled = false;
++ COMPAT_HL_NODE
+
++#ifdef HAVE_NLMSG_PARSE_DEPRECATED
+ err = nlmsg_parse_deprecated(cb->nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
++#else
++ err = nlmsg_parse(cb->nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
++#endif
+ nldev_policy, NULL);
+ /*
+ * Right now, we are expecting the device index to get res information,
+@@ -1310,7 +1432,11 @@ static int res_get_common_dumpit(struct sk_buff *skb,
+ }
+ }
+
++#ifdef HAVE_NETLINK_SKB_PARMS_PORTID
+ nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
++#else
++ nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
++#endif
+ RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, fe->nldev_cmd),
+ 0, NLM_F_MULTI);
+
+@@ -1319,14 +1445,23 @@ static int res_get_common_dumpit(struct sk_buff *skb,
+ goto err;
+ }
+
++#ifdef HAVE_NLA_NEST_START_NOFLAG
+ table_attr = nla_nest_start_noflag(skb, fe->nldev_attr);
++#else
++ table_attr = nla_nest_start(skb, fe->nldev_attr);
++#endif
+ if (!table_attr) {
+ ret = -EMSGSIZE;
+ goto err;
+ }
+
++#ifdef HAVE_NETLINK_CAPABLE
+ has_cap_net_admin = netlink_capable(cb->skb, CAP_NET_ADMIN);
++#else
++ has_cap_net_admin = (sock_net(cb->skb->sk) == &init_net);
++#endif
+
++#ifdef HAVE_XARRAY
+ rt = &device->res[res_type];
+ xa_lock(&rt->xa);
+ /*
+@@ -1345,7 +1480,11 @@ static int res_get_common_dumpit(struct sk_buff *skb,
+
+ filled = true;
+
++#ifdef HAVE_NLA_NEST_START_NOFLAG
+ entry_attr = nla_nest_start_noflag(skb, fe->entry);
++#else
++ entry_attr = nla_nest_start(skb, fe->entry);
++#endif
+ if (!entry_attr) {
+ ret = -EMSGSIZE;
+ rdma_restrack_put(res);
+@@ -1386,7 +1525,79 @@ msg_full:
+
+ res_err:
+ nla_nest_cancel(skb, table_attr);
++#else /*HAVE_XARRAY */
++ down_read(&device->res->rwsem);
++#ifdef HAVE_HLIST_FOR_EACH_ENTRY_3_PARAMS
++ hash_for_each_possible(device->res->hash, res, node, res_type) {
++#else
++ hash_for_each_possible(device->res->hash, res, hlnode, node, res_type) {
++#endif
++ if (idx < start)
++ goto next;
++
++ if ((rdma_is_kernel_res(res) &&
++ task_active_pid_ns(current) != &init_pid_ns) ||
++ (!rdma_is_kernel_res(res) && task_active_pid_ns(current) !=
++ task_active_pid_ns(res->task)))
++ /*
++ * 1. Kern resources should be visible in init
++ * namspace only
++ * 2. Present only resources visible in the current
++ * namespace
++ */
++ goto next;
++
++ if (!rdma_restrack_get(res))
++ /*
++ * Resource is under release now, but we are not
++ * relesing lock now, so it will be released in
++ * our next pass, once we will get ->next pointer.
++ */
++ goto next;
++
++ filled = true;
+
++ up_read(&device->res->rwsem);
++ ret = fe->fill_res_func(skb, cb, res, port);
++ down_read(&device->res->rwsem);
++ /*
++ * Return resource back, but it won't be released till
++ * the &device->res.rwsem will be released for write.
++ */
++ rdma_restrack_put(res);
++
++ if (ret == -EMSGSIZE)
++ /*
++ * There is a chance to optimize here.
++ * It can be done by using list_prepare_entry
++ * and list_for_each_entry_continue afterwards.
++ */
++ break;
++ if (ret)
++ goto res_err;
++next: idx++;
++ }
++ up_read(&device->res->rwsem);
++
++ nla_nest_end(skb, table_attr);
++ nlmsg_end(skb, nlh);
++ cb->args[0] = idx;
++
++ /*
++ * No more entries to fill, cancel the message and
++ * return 0 to mark end of dumpit.
++ */
++ if (!filled)
++ goto err;
++
++ ib_device_put(device);
++ return skb->len;
++
++res_err:
++ nla_nest_cancel(skb, table_attr);
++ up_read(&device->res->rwsem);
++
++#endif /*HAVE_XARRAY */
+ err:
+ nlmsg_cancel(skb, nlh);
+
+@@ -1395,6 +1606,7 @@ err_index:
+ return ret;
+ }
+
++#ifdef HAVE_NETLINK_EXT_ACK
+ #define RES_GET_FUNCS(name, type) \
+ static int nldev_res_get_##name##_dumpit(struct sk_buff *skb, \
+ struct netlink_callback *cb) \
+@@ -1407,6 +1619,19 @@ err_index:
+ { \
+ return res_get_common_doit(skb, nlh, extack, type); \
+ }
++#else
++#define RES_GET_FUNCS(name, type) \
++ static int nldev_res_get_##name##_dumpit(struct sk_buff *skb, \
++ struct netlink_callback *cb) \
++ { \
++ return res_get_common_dumpit(skb, cb, type); \
++ } \
++ static int nldev_res_get_##name##_doit(struct sk_buff *skb, \
++ struct nlmsghdr *nlh) \
++ { \
++ return res_get_common_doit(skb, nlh, type); \
++ }
++#endif
+
+ RES_GET_FUNCS(qp, RDMA_RESTRACK_QP);
+ RES_GET_FUNCS(cm_id, RDMA_RESTRACK_CM_ID);
+@@ -1450,8 +1675,12 @@ void rdma_link_unregister(struct rdma_link_ops *ops)
+ }
+ EXPORT_SYMBOL(rdma_link_unregister);
+
++#ifdef HAVE_NETLINK_EXT_ACK
+ static int nldev_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack)
++#else
++static int nldev_newlink(struct sk_buff *skb, struct nlmsghdr *nlh)
++#endif
+ {
+ struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
+ char ibdev_name[IB_DEVICE_NAME_MAX];
+@@ -1461,8 +1690,16 @@ static int nldev_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
+ char type[IFNAMSIZ];
+ int err;
+
++#ifdef HAVE_NLMSG_PARSE_DEPRECATED
+ err = nlmsg_parse_deprecated(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
++#else
++ err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
++#endif
++#ifdef HAVE_NETLINK_EXT_ACK
+ nldev_policy, extack);
++#else
++ nldev_policy, NULL);
++#endif
+ if (err || !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
+ !tb[RDMA_NLDEV_ATTR_LINK_TYPE] || !tb[RDMA_NLDEV_ATTR_NDEV_NAME])
+ return -EINVAL;
+@@ -1497,16 +1734,28 @@ static int nldev_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
+ return err;
+ }
+
++#ifdef HAVE_NETLINK_EXT_ACK
+ static int nldev_dellink(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack)
++#else
++static int nldev_dellink(struct sk_buff *skb, struct nlmsghdr *nlh)
++#endif
+ {
+ struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
+ struct ib_device *device;
+ u32 index;
+ int err;
+
++#ifdef HAVE_NLMSG_PARSE_DEPRECATED
+ err = nlmsg_parse_deprecated(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
++#else
++ err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
++#endif
++#ifdef HAVE_NETLINK_EXT_ACK
+ nldev_policy, extack);
++#else
++ nldev_policy, NULL);
++#endif
+ if (err || !tb[RDMA_NLDEV_ATTR_DEV_INDEX])
+ return -EINVAL;
+
+@@ -1524,8 +1773,12 @@ static int nldev_dellink(struct sk_buff *skb, struct nlmsghdr *nlh,
+ return 0;
+ }
+
++#ifdef HAVE_NETLINK_EXT_ACK
+ static int nldev_get_chardev(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack)
++#else
++static int nldev_get_chardev(struct sk_buff *skb, struct nlmsghdr *nlh)
++#endif
+ {
+ struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
+ char client_name[RDMA_NLDEV_ATTR_CHARDEV_TYPE_SIZE];
+@@ -1535,8 +1788,13 @@ static int nldev_get_chardev(struct sk_buff *skb, struct nlmsghdr *nlh,
+ u32 index;
+ int err;
+
++#ifdef HAVE_NETLINK_EXT_ACK
+ err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, nldev_policy,
+ extack);
++#else
++ err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, nldev_policy,
++ NULL);
++#endif
+ if (err || !tb[RDMA_NLDEV_ATTR_CHARDEV_TYPE])
+ return -EINVAL;
+
+@@ -1608,15 +1866,23 @@ out_put:
+ return err;
+ }
+
++#ifdef HAVE_NETLINK_EXT_ACK
+ static int nldev_sys_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack)
++#else
++static int nldev_sys_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
++#endif
+ {
+ struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
+ struct sk_buff *msg;
+ int err;
+
+ err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
++#ifdef HAVE_NETLINK_EXT_ACK
+ nldev_policy, extack);
++#else
++ nldev_policy, NULL);
++#endif
+ if (err)
+ return err;
+
+@@ -1639,15 +1905,23 @@ static int nldev_sys_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ return rdma_nl_unicast(msg, NETLINK_CB(skb).portid);
+ }
+
++#ifdef HAVE_NETLINK_EXT_ACK
+ static int nldev_set_sys_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack)
++#else
++static int nldev_set_sys_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
++#endif
+ {
+ struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
+ u8 enable;
+ int err;
+
+ err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
++#ifdef HAVE_NETLINK_EXT_ACK
+ nldev_policy, extack);
++#else
++ nldev_policy, NULL);
++#endif
+ if (err || !tb[RDMA_NLDEV_SYS_ATTR_NETNS_MODE])
+ return -EINVAL;
+
+@@ -1660,8 +1934,12 @@ static int nldev_set_sys_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ return err;
+ }
+
++#ifdef HAVE_NETLINK_EXT_ACK
+ static int nldev_stat_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack)
++#else
++static int nldev_stat_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
++#endif
+ {
+ u32 index, port, mode, mask = 0, qpn, cntn = 0;
+ struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
+@@ -1670,7 +1948,11 @@ static int nldev_stat_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ int ret;
+
+ ret = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
++#ifdef HAVE_NETLINK_EXT_ACK
+ nldev_policy, extack);
++#else
++ nldev_policy, NULL);
++#endif
+ /* Currently only counter for QP is supported */
+ if (ret || !tb[RDMA_NLDEV_ATTR_STAT_RES] ||
+ !tb[RDMA_NLDEV_ATTR_DEV_INDEX] ||
+@@ -1745,8 +2027,12 @@ err:
+ return ret;
+ }
+
++#ifdef HAVE_NETLINK_EXT_ACK
+ static int nldev_stat_del_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack)
++#else
++static int nldev_stat_del_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
++#endif
+ {
+ struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
+ struct ib_device *device;
+@@ -1755,7 +2041,11 @@ static int nldev_stat_del_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ int ret;
+
+ ret = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
++#ifdef HAVE_NETLINK_EXT_ACK
+ nldev_policy, extack);
++#else
++ nldev_policy, NULL);
++#endif
+ if (ret || !tb[RDMA_NLDEV_ATTR_STAT_RES] ||
+ !tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_PORT_INDEX] ||
+ !tb[RDMA_NLDEV_ATTR_STAT_COUNTER_ID] ||
+@@ -1815,7 +2105,9 @@ err:
+
+ static int stat_get_doit_default_counter(struct sk_buff *skb,
+ struct nlmsghdr *nlh,
++#ifdef HAVE_NETLINK_EXT_ACK
+ struct netlink_ext_ack *extack,
++#endif
+ struct nlattr *tb[])
+ {
+ struct rdma_hw_stats *stats;
+@@ -1907,7 +2199,11 @@ err:
+ }
+
+ static int stat_get_doit_qp(struct sk_buff *skb, struct nlmsghdr *nlh,
++#ifdef HAVE_NETLINK_EXT_ACK
+ struct netlink_ext_ack *extack, struct nlattr *tb[])
++#else
++ struct nlattr *tb[])
++#endif
+
+ {
+ static enum rdma_nl_counter_mode mode;
+@@ -1918,7 +2214,11 @@ static int stat_get_doit_qp(struct sk_buff *skb, struct nlmsghdr *nlh,
+ int ret;
+
+ if (tb[RDMA_NLDEV_ATTR_STAT_COUNTER_ID])
++#ifdef HAVE_NETLINK_EXT_ACK
+ return nldev_res_get_counter_doit(skb, nlh, extack);
++#else
++ return nldev_res_get_counter_doit(skb, nlh);
++#endif
+
+ if (!tb[RDMA_NLDEV_ATTR_STAT_MODE] ||
+ !tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_PORT_INDEX])
+@@ -1970,23 +2270,39 @@ err:
+ return ret;
+ }
+
++#ifdef HAVE_NETLINK_EXT_ACK
+ static int nldev_stat_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack)
++#else
++static int nldev_stat_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
++#endif
+ {
+ struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
+ int ret;
+
+ ret = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
++#ifdef HAVE_NETLINK_EXT_ACK
+ nldev_policy, extack);
++#else
++ nldev_policy, NULL);
++#endif
+ if (ret)
+ return -EINVAL;
+
+ if (!tb[RDMA_NLDEV_ATTR_STAT_RES])
++#ifdef HAVE_NETLINK_EXT_ACK
+ return stat_get_doit_default_counter(skb, nlh, extack, tb);
++#else
++ return stat_get_doit_default_counter(skb, nlh, tb);
++#endif
+
+ switch (nla_get_u32(tb[RDMA_NLDEV_ATTR_STAT_RES])) {
+ case RDMA_NLDEV_ATTR_RES_QP:
++#ifdef HAVE_NETLINK_EXT_ACK
+ ret = stat_get_doit_qp(skb, nlh, extack, tb);
++#else
++ ret = stat_get_doit_qp(skb, nlh, tb);
++#endif
+ break;
+
+ default:
+diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/rdma_core.c
++++ b/drivers/infiniband/core/rdma_core.c
+@@ -79,7 +79,13 @@ static int uverbs_try_lock_object(struct ib_uobject *uobj,
+ */
+ switch (mode) {
+ case UVERBS_LOOKUP_READ:
++#ifdef HAVE_ATOMIC_FETCH_ADD_UNLESS
+ return atomic_fetch_add_unless(&uobj->usecnt, 1, -1) == -1 ?
++#elif defined(HAVE___ATOMIC_ADD_UNLESS)
++ return __atomic_add_unless(&uobj->usecnt, 1, -1) == -1 ?
++#else
++ return atomic_add_unless(&uobj->usecnt, 1, -1) == -1 ?
++#endif
+ -EBUSY : 0;
+ case UVERBS_LOOKUP_WRITE:
+ /* lock is exclusive */
+@@ -297,13 +303,50 @@ static struct ib_uobject *alloc_uobj(struct ib_uverbs_file *ufile,
+
+ static int idr_add_uobj(struct ib_uobject *uobj)
+ {
++ int ret;
+ /*
+ * We start with allocating an idr pointing to NULL. This represents an
+ * object which isn't initialized yet. We'll replace it later on with
+ * the real object once we commit.
+ */
++#ifdef HAVE_XARRAY
+ return xa_alloc(&uobj->ufile->idr, &uobj->id, NULL, xa_limit_32b,
+ GFP_KERNEL);
++#elif defined(HAVE_IDR_ALLOC)
++ idr_preload(GFP_KERNEL);
++ spin_lock(&uobj->ufile->idr_lock);
++
++ /*
++ * * We start with allocating an idr pointing to NULL. This
++ * represents an
++ * * object which isn't initialized yet. We'll replace
++ * it later on with
++ * * the real object once we commit.
++ * */
++ ret = idr_alloc(&uobj->ufile->idr, NULL, 0,
++ min_t(unsigned long, U32_MAX - 1, INT_MAX), GFP_NOWAIT);
++ if (ret >= 0)
++ uobj->id = ret;
++
++ spin_unlock(&uobj->ufile->idr_lock);
++ idr_preload_end();
++
++ return ret < 0 ? ret : 0;
++#else
++retry:
++ if (!idr_pre_get(&uobj->ufile->idr, GFP_KERNEL))
++ return -ENOMEM;
++
++ spin_lock(&uobj->ufile->idr_lock);
++ ret = idr_get_new(&uobj->ufile->idr, NULL, &uobj->id);
++ spin_unlock(&uobj->ufile->idr_lock);
++
++ if (ret == -EAGAIN)
++ goto retry;
++
++ return ret;
++
++#endif
+ }
+
+ /* Returns the ib_uobject or an error. The caller should check for IS_ERR. */
+@@ -313,11 +356,13 @@ lookup_get_idr_uobject(const struct uverbs_api_object *obj,
+ enum rdma_lookup_mode mode)
+ {
+ struct ib_uobject *uobj;
++ unsigned long idrno = id;
+
+ if (id < 0 || id > ULONG_MAX)
+ return ERR_PTR(-EINVAL);
+
+ rcu_read_lock();
++#ifdef HAVE_XARRAY
+ /*
+ * The idr_find is guaranteed to return a pointer to something that
+ * isn't freed yet, or NULL, as the free after idr_remove goes through
+@@ -329,6 +374,27 @@ lookup_get_idr_uobject(const struct uverbs_api_object *obj,
+ uobj = ERR_PTR(-ENOENT);
+ rcu_read_unlock();
+ return uobj;
++#else
++ /* object won't be released as we're protected in rcu */
++ uobj = idr_find(&ufile->idr, idrno);
++ if (!uobj) {
++ uobj = ERR_PTR(-ENOENT);
++ goto free;
++ }
++
++ /*
++ * The idr_find is guaranteed to return a pointer to something that
++ * isn't freed yet, or NULL, as the free after idr_remove goes through
++ * kfree_rcu(). However the object may still have been released and
++ * kfree() could be called at any time.
++ */
++ if (!kref_get_unless_zero(&uobj->ref))
++ uobj = ERR_PTR(-ENOENT);
++
++free:
++ rcu_read_unlock();
++ return uobj;
++#endif
+ }
+
+ static struct ib_uobject *
+@@ -437,15 +503,25 @@ alloc_begin_idr_uobject(const struct uverbs_api_object *obj,
+ if (ret)
+ goto uobj_put;
+
++#ifdef HAVE_CGROUP_RDMA_H
+ ret = ib_rdmacg_try_charge(&uobj->cg_obj, uobj->context->device,
+ RDMACG_RESOURCE_HCA_OBJECT);
+ if (ret)
+ goto remove;
+
++#endif
+ return uobj;
+
++#ifdef HAVE_CGROUP_RDMA_H
+ remove:
++#ifdef HAVE_XARRAY
+ xa_erase(&ufile->idr, uobj->id);
++#else
++ spin_lock(&ufile->idr_lock);
++ idr_remove(&ufile->idr, uobj->id);
++ spin_unlock(&ufile->idr_lock);
++#endif
++#endif
+ uobj_put:
+ uverbs_uobject_put(uobj);
+ return ERR_PTR(ret);
+@@ -503,10 +579,17 @@ struct ib_uobject *rdma_alloc_begin_uobject(const struct uverbs_api_object *obj,
+
+ static void alloc_abort_idr_uobject(struct ib_uobject *uobj)
+ {
++#ifdef HAVE_CGROUP_RDMA_H
+ ib_rdmacg_uncharge(&uobj->cg_obj, uobj->context->device,
+ RDMACG_RESOURCE_HCA_OBJECT);
+-
++#endif
++#ifdef HAVE_XARRAY
+ xa_erase(&uobj->ufile->idr, uobj->id);
++#else
++ spin_lock(&uobj->ufile->idr_lock);
++ idr_remove(&uobj->ufile->idr, uobj->id);
++ spin_unlock(&uobj->ufile->idr_lock);
++#endif
+ }
+
+ static int __must_check destroy_hw_idr_uobject(struct ib_uobject *uobj,
+@@ -529,15 +612,22 @@ static int __must_check destroy_hw_idr_uobject(struct ib_uobject *uobj,
+ if (why == RDMA_REMOVE_ABORT)
+ return 0;
+
++#ifdef HAVE_CGROUP_RDMA_H
+ ib_rdmacg_uncharge(&uobj->cg_obj, uobj->context->device,
+ RDMACG_RESOURCE_HCA_OBJECT);
+-
++#endif
+ return 0;
+ }
+
+ static void remove_handle_idr_uobject(struct ib_uobject *uobj)
+ {
++#ifdef HAVE_XARRAY
+ xa_erase(&uobj->ufile->idr, uobj->id);
++#else
++ spin_lock(&uobj->ufile->idr_lock);
++ idr_remove(&uobj->ufile->idr, uobj->id);
++ spin_unlock(&uobj->ufile->idr_lock);
++#endif
+ /* Matches the kref in alloc_commit_idr_uobject */
+ uverbs_uobject_put(uobj);
+ }
+@@ -568,6 +658,7 @@ static void remove_handle_fd_uobject(struct ib_uobject *uobj)
+ static int alloc_commit_idr_uobject(struct ib_uobject *uobj)
+ {
+ struct ib_uverbs_file *ufile = uobj->ufile;
++#ifdef HAVE_XARRAY
+ void *old;
+
+ /*
+@@ -579,7 +670,18 @@ static int alloc_commit_idr_uobject(struct ib_uobject *uobj)
+ */
+ old = xa_store(&ufile->idr, uobj->id, uobj, GFP_KERNEL);
+ WARN_ON(old != NULL);
+-
++#else
++ spin_lock(&ufile->idr_lock);
++ /*
++ * We already allocated this IDR with a NULL object, so
++ * this shouldn't fail.
++ *
++ * NOTE: Once we set the IDR we loose ownership of our kref on uobj.
++ * It will be put by remove_commit_idr_uobject()
++ */
++ WARN_ON(idr_replace(&ufile->idr, uobj, uobj->id));
++ spin_unlock(&ufile->idr_lock);
++#endif
+ return 0;
+ }
+
+@@ -712,13 +814,22 @@ void rdma_lookup_put_uobject(struct ib_uobject *uobj,
+
+ void setup_ufile_idr_uobject(struct ib_uverbs_file *ufile)
+ {
++#ifdef HAVE_XARRAY
+ xa_init_flags(&ufile->idr, XA_FLAGS_ALLOC);
++#else
++ spin_lock_init(&ufile->idr_lock);
++ idr_init(&ufile->idr);
++#endif
+ }
+
+ void release_ufile_idr_uobject(struct ib_uverbs_file *ufile)
+ {
+ struct ib_uobject *entry;
+- unsigned long id;
++#ifdef HAVE_XARRAY
++ long unsigned int id;
++#else
++ int id;
++#endif
+
+ /*
+ * At this point uverbs_cleanup_ufile() is guaranteed to have run, and
+@@ -728,12 +839,22 @@ void release_ufile_idr_uobject(struct ib_uverbs_file *ufile)
+ *
+ * This is an optimized equivalent to remove_handle_idr_uobject
+ */
++
++#ifdef HAVE_XARRAY
+ xa_for_each(&ufile->idr, id, entry) {
+ WARN_ON(entry->object);
+ uverbs_uobject_put(entry);
+ }
+
+ xa_destroy(&ufile->idr);
++#else
++ compat_idr_for_each_entry(&ufile->idr, entry, id) {
++ WARN_ON(entry->object);
++ uverbs_uobject_put(entry);
++ }
++
++ idr_destroy(&ufile->idr);
++#endif
+ }
+
+ const struct uverbs_obj_type_class uverbs_idr_class = {
+@@ -811,8 +932,10 @@ static void ufile_destroy_ucontext(struct ib_uverbs_file *ufile,
+ ib_dev->ops.disassociate_ucontext(ucontext);
+ }
+
++#ifdef HAVE_CGROUP_RDMA_H
+ ib_rdmacg_uncharge(&ucontext->cg_obj, ib_dev,
+ RDMACG_RESOURCE_HCA_HANDLE);
++#endif
+
+ rdma_restrack_del(&ucontext->res);
+
+diff --git a/drivers/infiniband/core/restrack.c b/drivers/infiniband/core/restrack.c
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/restrack.c
++++ b/drivers/infiniband/core/restrack.c
+@@ -14,6 +14,10 @@
+ #include "cma_priv.h"
+ #include "restrack.h"
+
++#ifndef CUT_HERE
++#define CUT_HERE "------------[ cut here ]------------\n"
++#endif
++
+ /**
+ * rdma_restrack_init() - initialize and allocate resource tracking
+ * @dev: IB device
+diff --git a/drivers/infiniband/core/restrack.h b/drivers/infiniband/core/restrack.h
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/restrack.h
++++ b/drivers/infiniband/core/restrack.h
+@@ -8,11 +8,26 @@
+
+ #include <linux/mutex.h>
+
++#ifndef HAVE_XARRAY
++#define RDMA_RESTRACK_HASH_BITS 8
++#endif
++
+ /**
+ * struct rdma_restrack_root - main resource tracking management
+ * entity, per-device
+ */
+ struct rdma_restrack_root {
++#ifndef HAVE_XARRAY
++ /*
++ * * @rwsem: Read/write lock to protect lists
++ * */
++ struct rw_semaphore rwsem;
++ /**
++ * * @hash: global database for all resources
++ * per-device
++ * */
++ DECLARE_HASHTABLE(hash, RDMA_RESTRACK_HASH_BITS);
++#endif
+ /**
+ * @xa: Array of XArray structure to hold restrack entries.
+ */
+diff --git a/drivers/infiniband/core/roce_gid_mgmt.c b/drivers/infiniband/core/roce_gid_mgmt.c
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/roce_gid_mgmt.c
++++ b/drivers/infiniband/core/roce_gid_mgmt.c
+@@ -130,12 +130,17 @@ static enum bonding_slave_state is_eth_active_slave_of_bonding_rcu(struct net_de
+ struct net_device *upper)
+ {
+ if (upper && netif_is_bond_master(upper)) {
++#ifdef HAVE_BONDING_H
+ struct net_device *pdev =
+ bond_option_active_slave_get_rcu(netdev_priv(upper));
+
+ if (pdev)
+ return dev == pdev ? BONDING_SLAVE_STATE_ACTIVE :
+ BONDING_SLAVE_STATE_INACTIVE;
++#else
++ return memcmp(upper->dev_addr, dev->dev_addr, ETH_ALEN) ?
++ BONDING_SLAVE_STATE_INACTIVE : BONDING_SLAVE_STATE_ACTIVE;
++#endif
+ }
+
+ return BONDING_SLAVE_STATE_NA;
+@@ -481,7 +486,9 @@ static void enum_all_gids_of_dev_cb(struct ib_device *ib_dev,
+ * our feet
+ */
+ rtnl_lock();
++#ifdef HAVE_NET_RWSEM
+ down_read(&net_rwsem);
++#endif
+ for_each_net(net)
+ for_each_netdev(net, ndev) {
+ /*
+@@ -497,7 +504,9 @@ static void enum_all_gids_of_dev_cb(struct ib_device *ib_dev,
+ rdma_ndev, ndev))
+ _add_netdev_ips(ib_dev, port, ndev);
+ }
++#ifdef HAVE_NET_RWSEM
+ up_read(&net_rwsem);
++#endif
+ rtnl_unlock();
+ }
+
+@@ -526,6 +535,7 @@ static void callback_for_addr_gid_device_scan(struct ib_device *device,
+ &parsed->gid_attr);
+ }
+
++#ifdef HAVE_NETDEV_WALK_ALL_UPPER_DEV_RCU
+ struct upper_list {
+ struct list_head list;
+ struct net_device *upper;
+@@ -545,7 +555,9 @@ static int netdev_upper_walk(struct net_device *upper, void *data)
+
+ return 0;
+ }
++#endif /* HAVE_NETDEV_WALK_ALL_UPPER_DEV_RCU */
+
++#ifdef HAVE_NETDEV_NOTIFIER_CHANGEUPPER_INFO
+ static void handle_netdev_upper(struct ib_device *ib_dev, u8 port,
+ void *cookie,
+ void (*handle_netdev)(struct ib_device *ib_dev,
+@@ -553,12 +565,38 @@ static void handle_netdev_upper(struct ib_device *ib_dev, u8 port,
+ struct net_device *ndev))
+ {
+ struct net_device *ndev = cookie;
++#ifndef HAVE_NETDEV_WALK_ALL_UPPER_DEV_RCU
++ struct upper_list {
++ struct list_head list;
++ struct net_device *upper;
++ };
++ struct net_device *upper;
++#endif /* HAVE_NETDEV_WALK_ALL_UPPER_DEV_RCU */
+ struct upper_list *upper_iter;
+ struct upper_list *upper_temp;
+ LIST_HEAD(upper_list);
+
+ rcu_read_lock();
++#ifndef HAVE_NETDEV_WALK_ALL_UPPER_DEV_RCU
++ for_each_netdev(dev_net(ndev), upper) {
++ struct upper_list *entry;
++
++ if (!rdma_is_upper_dev_rcu(ndev, upper))
++ continue;
++
++ entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
++ if (!entry) {
++ pr_info("roce_gid_mgmt: couldn't allocate entry to delete ndev\n");
++ continue;
++ }
++
++ list_add_tail(&entry->list, &upper_list);
++ dev_hold(upper);
++ entry->upper = upper;
++ }
++#else /* HAVE_NETDEV_WALK_ALL_UPPER_DEV_RCU */
+ netdev_walk_all_upper_dev_rcu(ndev, netdev_upper_walk, &upper_list);
++#endif /* HAVE_NETDEV_WALK_ALL_UPPER_DEV_RCU */
+ rcu_read_unlock();
+
+ handle_netdev(ib_dev, port, ndev);
+@@ -588,6 +626,7 @@ static void add_netdev_upper_ips(struct ib_device *ib_dev, u8 port,
+ {
+ handle_netdev_upper(ib_dev, port, cookie, _add_netdev_ips);
+ }
++#endif
+
+ static void del_netdev_default_ips_join(struct ib_device *ib_dev, u8 port,
+ struct net_device *rdma_ndev,
+@@ -662,6 +701,7 @@ static const struct netdev_event_work_cmd add_cmd = {
+ .filter = is_eth_port_of_netdev_filter
+ };
+
++#ifdef HAVE_NETDEV_NOTIFIER_CHANGEUPPER_INFO
+ static const struct netdev_event_work_cmd add_cmd_upper_ips = {
+ .cb = add_netdev_upper_ips,
+ .filter = is_eth_port_of_netdev_filter
+@@ -681,6 +721,7 @@ ndev_event_unlink(struct netdev_notifier_changeupper_info *changeupper_info,
+ cmds[0].ndev = changeupper_info->upper_dev;
+ cmds[1] = add_cmd;
+ }
++#endif
+
+ static const struct netdev_event_work_cmd bonding_default_add_cmd = {
+ .cb = add_default_gids,
+@@ -734,6 +775,10 @@ static const struct netdev_event_work_cmd add_default_gid_cmd = {
+ static int netdevice_event(struct notifier_block *this, unsigned long event,
+ void *ptr)
+ {
++#ifndef HAVE_NETDEV_NOTIFIER_CHANGEUPPER_INFO
++ static const struct netdev_event_work_cmd add_cmd = {
++ .cb = add_netdev_ips, .filter = is_eth_port_of_netdev};
++#endif
+ static const struct netdev_event_work_cmd del_cmd = {
+ .cb = del_netdev_ips, .filter = pass_all_filter};
+ static const struct netdev_event_work_cmd
+@@ -747,7 +792,11 @@ static int netdevice_event(struct notifier_block *this, unsigned long event,
+ .filter = is_eth_port_of_netdev_filter
+ };
+ static const struct netdev_event_work_cmd bonding_event_ips_del_cmd = {
++#ifdef HAVE_NETDEV_NOTIFIER_CHANGEUPPER_INFO
+ .cb = del_netdev_upper_ips, .filter = upper_device_filter};
++#else
++ .cb = del_netdev_ips, .filter = upper_device_filter};
++#endif
+ struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
+ struct netdev_event_work_cmd cmds[ROCE_NETDEV_CALLBACK_SZ] = { {NULL} };
+
+@@ -757,6 +806,9 @@ static int netdevice_event(struct notifier_block *this, unsigned long event,
+ switch (event) {
+ case NETDEV_REGISTER:
+ case NETDEV_UP:
++#ifndef HAVE_NETDEV_NOTIFIER_CHANGEUPPER_INFO
++ case NETDEV_JOIN:
++#endif
+ cmds[0] = bonding_default_del_cmd_join;
+ cmds[1] = add_default_gid_cmd;
+ cmds[2] = add_cmd;
+@@ -777,18 +829,24 @@ static int netdevice_event(struct notifier_block *this, unsigned long event,
+ }
+ break;
+
++#ifdef HAVE_NETDEV_NOTIFIER_CHANGEUPPER_INFO
+ case NETDEV_CHANGEUPPER:
+ netdevice_event_changeupper(ndev,
+ container_of(ptr, struct netdev_notifier_changeupper_info, info),
+ cmds);
+ break;
++#endif
+
+ case NETDEV_BONDING_FAILOVER:
+ cmds[0] = bonding_event_ips_del_cmd;
+ /* Add default GIDs of the bond device */
+ cmds[1] = bonding_default_add_cmd;
+ /* Add IP based GIDs of the bond device */
++#ifdef HAVE_NETDEV_NOTIFIER_CHANGEUPPER_INFO
+ cmds[2] = add_cmd_upper_ips;
++#else
++ cmds[2] = add_cmd;
++#endif
+ break;
+
+ default:
+diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/rw.c
++++ b/drivers/infiniband/core/rw.c
+@@ -4,7 +4,9 @@
+ */
+ #include <linux/moduleparam.h>
+ #include <linux/slab.h>
++#ifdef HAVE_PCI_P2PDMA_H
+ #include <linux/pci-p2pdma.h>
++#endif
+ #include <rdma/mr_pool.h>
+ #include <rdma/rw.h>
+
+@@ -290,9 +292,11 @@ int rdma_rw_ctx_init(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u8 port_num,
+ struct ib_device *dev = qp->pd->device;
+ int ret;
+
++#ifdef HAVE_PCI_P2PDMA_H
+ if (is_pci_p2pdma_page(sg_page(sg)))
+ ret = pci_p2pdma_map_sg(dev->dma_device, sg, sg_cnt, dir);
+ else
++#endif
+ ret = ib_dma_map_sg(dev, sg, sg_cnt, dir);
+
+ if (!ret)
+@@ -584,7 +588,9 @@ void rdma_rw_ctx_destroy(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u8 port_num,
+ }
+
+ /* P2PDMA contexts do not need to be unmapped */
++#ifdef HAVE_PCI_P2PDMA_H
+ if (!is_pci_p2pdma_page(sg_page(sg)))
++#endif
+ ib_dma_unmap_sg(qp->pd->device, sg, sg_cnt, dir);
+ }
+ EXPORT_SYMBOL(rdma_rw_ctx_destroy);
+diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/sa_query.c
++++ b/drivers/infiniband/core/sa_query.c
+@@ -186,6 +186,12 @@ static struct ib_client sa_client = {
+ static DEFINE_XARRAY_FLAGS(queries, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
+
+ static DEFINE_SPINLOCK(tid_lock);
++#ifndef HAVE_XARRAY
++#ifdef HAVE_IDR_ALLOC
++static DEFINE_SPINLOCK(idr_lock);
++static DEFINE_IDR(query_idr);
++#endif
++#endif
+ static u32 tid;
+
+ #define PATH_REC_FIELD(field) \
+@@ -1012,9 +1018,15 @@ static void ib_nl_request_timeout(struct work_struct *work)
+ }
+
+ int ib_nl_handle_set_timeout(struct sk_buff *skb,
++#ifdef HAVE_NETLINK_EXT_ACK
+ struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack)
+ {
++#else
++ struct netlink_callback *cb)
++{
++ const struct nlmsghdr *nlh = (struct nlmsghdr *)cb->nlh;
++#endif
+ int timeout, delta, abs_delta;
+ const struct nlattr *attr;
+ unsigned long flags;
+@@ -1024,11 +1036,24 @@ int ib_nl_handle_set_timeout(struct sk_buff *skb,
+ int ret;
+
+ if (!(nlh->nlmsg_flags & NLM_F_REQUEST) ||
++#ifdef HAVE_NETLINK_CAPABLE
++#ifdef HAVE_NETLINK_SKB_PARMS_SK
+ !(NETLINK_CB(skb).sk))
++#else
++ !(NETLINK_CB(skb).ssk))
++#endif
++#else
++ sock_net(skb->sk) != &init_net)
++#endif
+ return -EPERM;
+
++#ifdef HAVE_NLA_PARSE_DEPRECATED
+ ret = nla_parse_deprecated(tb, LS_NLA_TYPE_MAX - 1, nlmsg_data(nlh),
+ nlmsg_len(nlh), ib_nl_policy, NULL);
++#else
++ ret = nla_parse(tb, LS_NLA_TYPE_MAX - 1, nlmsg_data(nlh),
++ nlmsg_len(nlh), ib_nl_policy, NULL);
++#endif /*HAVE_NLA_PARSE_DEPRECATED*/
+ attr = (const struct nlattr *)tb[LS_NLA_TYPE_TIMEOUT];
+ if (ret || !attr)
+ goto settimeout_out;
+@@ -1079,8 +1104,13 @@ static inline int ib_nl_is_good_resolve_resp(const struct nlmsghdr *nlh)
+ if (nlh->nlmsg_flags & RDMA_NL_LS_F_ERR)
+ return 0;
+
++#ifdef HAVE_NLA_PARSE_DEPRECATED
+ ret = nla_parse_deprecated(tb, LS_NLA_TYPE_MAX - 1, nlmsg_data(nlh),
+ nlmsg_len(nlh), ib_nl_policy, NULL);
++#else
++ ret = nla_parse(tb, LS_NLA_TYPE_MAX - 1, nlmsg_data(nlh),
++ nlmsg_len(nlh), ib_nl_policy, NULL);
++#endif
+ if (ret)
+ return 0;
+
+@@ -1088,9 +1118,15 @@ static inline int ib_nl_is_good_resolve_resp(const struct nlmsghdr *nlh)
+ }
+
+ int ib_nl_handle_resolve_resp(struct sk_buff *skb,
++#ifdef HAVE_NETLINK_EXT_ACK
+ struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack)
+ {
++#else
++ struct netlink_callback *cb)
++{
++ const struct nlmsghdr *nlh = (struct nlmsghdr *)cb->nlh;
++#endif
+ unsigned long flags;
+ struct ib_sa_query *query;
+ struct ib_mad_send_buf *send_buf;
+@@ -1099,7 +1135,15 @@ int ib_nl_handle_resolve_resp(struct sk_buff *skb,
+ int ret;
+
+ if ((nlh->nlmsg_flags & NLM_F_REQUEST) ||
++#ifdef HAVE_NETLINK_CAPABLE
++#ifdef HAVE_NETLINK_SKB_PARMS_SK
+ !(NETLINK_CB(skb).sk))
++#else
++ !(NETLINK_CB(skb).ssk))
++#endif
++#else
++ sock_net(skb->sk) != &init_net)
++#endif
+ return -EPERM;
+
+ spin_lock_irqsave(&ib_nl_request_lock, flags);
+@@ -1365,12 +1409,47 @@ static int send_mad(struct ib_sa_query *query, unsigned long timeout_ms,
+ unsigned long flags;
+ int ret, id;
+
++#ifdef HAVE_XARRAY
+ xa_lock_irqsave(&queries, flags);
+ ret = __xa_alloc(&queries, &id, query, xa_limit_32b, gfp_mask);
+ xa_unlock_irqrestore(&queries, flags);
+ if (ret < 0)
+ return ret;
+-
++#else /* HAVE_XARRAY */
++
++#ifdef HAVE_IDR_ALLOC
++#ifdef __GFP_WAIT
++ bool preload = !!(gfp_mask & __GFP_WAIT);
++#else
++ bool preload = gfpflags_allow_blocking(gfp_mask);
++#endif
++#endif
++
++#ifdef HAVE_IDR_ALLOC
++ if (preload)
++ idr_preload(gfp_mask);
++ spin_lock_irqsave(&idr_lock, flags);
++
++ id = idr_alloc(&query_idr, query, 0, 0, GFP_NOWAIT);
++
++ spin_unlock_irqrestore(&idr_lock, flags);
++ if (preload)
++ idr_preload_end();
++ if (id < 0)
++ return id;
++#else
++retry:
++ if (!idr_pre_get(&query_idr, gfp_mask))
++ return -ENOMEM;
++ spin_lock_irqsave(&idr_lock, flags);
++ ret = idr_get_new(&query_idr, query, &id);
++ spin_unlock_irqrestore(&idr_lock, flags);
++ if (ret == -EAGAIN)
++ goto retry;
++ if (ret)
++ return ret;
++#endif /*HAVE_IDR_ALLOC*/
++#endif /*HAVE_XARRAY*/
+ query->mad_buf->timeout_ms = timeout_ms;
+ query->mad_buf->context[0] = query;
+ query->id = id;
+@@ -1386,9 +1465,15 @@ static int send_mad(struct ib_sa_query *query, unsigned long timeout_ms,
+
+ ret = ib_post_send_mad(query->mad_buf, NULL);
+ if (ret) {
++#ifdef HAVE_XARRAY
+ xa_lock_irqsave(&queries, flags);
+ __xa_erase(&queries, id);
+ xa_unlock_irqrestore(&queries, flags);
++#else
++ spin_lock_irqsave(&idr_lock, flags);
++ idr_remove(&query_idr, id);
++ spin_unlock_irqrestore(&idr_lock, flags);
++#endif /*HAVE_XARRAY*/
+ }
+
+ /*
+diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/ucma.c
++++ b/drivers/infiniband/core/ucma.c
+@@ -1688,6 +1688,7 @@ static ssize_t ucma_write(struct file *filp, const char __user *buf,
+ return ret;
+ }
+
++#ifdef EPOLLIN
+ static __poll_t ucma_poll(struct file *filp, struct poll_table_struct *wait)
+ {
+ struct ucma_file *file = filp->private_data;
+@@ -1700,6 +1701,20 @@ static __poll_t ucma_poll(struct file *filp, struct poll_table_struct *wait)
+
+ return mask;
+ }
++#else
++static unsigned int ucma_poll(struct file *filp, struct poll_table_struct *wait)
++{
++ struct ucma_file *file = filp->private_data;
++ unsigned int mask = 0;
++
++ poll_wait(filp, &file->poll_wait, wait);
++
++ if (!list_empty(&file->event_list))
++ mask = POLLIN | POLLRDNORM;
++
++ return mask;
++}
++#endif
+
+ /*
+ * ucma_open() does not need the BKL:
+@@ -1732,7 +1747,11 @@ static int ucma_open(struct inode *inode, struct file *filp)
+ filp->private_data = file;
+ file->filp = filp;
+
++#ifdef HAVE_STREAM_OPEN
+ return stream_open(inode, filp);
++#else
++ return nonseekable_open(inode, filp);
++#endif
+ }
+
+ static int ucma_close(struct inode *inode, struct file *filp)
+diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/umem.c
++++ b/drivers/infiniband/core/umem.c
+@@ -200,14 +200,22 @@ struct ib_umem *ib_umem_get(struct ib_udata *udata, unsigned long addr,
+ struct ib_umem *umem;
+ struct page **page_list;
+ unsigned long lock_limit;
++#ifdef HAVE_PINNED_VM
+ unsigned long new_pinned;
++#endif
+ unsigned long cur_base;
+ struct mm_struct *mm;
+ unsigned long npages;
+ int ret;
++#ifdef HAVE_STRUCT_DMA_ATTRS
++ DEFINE_DMA_ATTRS(dma_attrs);
++#else
+ unsigned long dma_attrs = 0;
++#endif
+ struct scatterlist *sg;
++#ifdef HAVE_GET_USER_PAGES_GUP_FLAGS
+ unsigned int gup_flags = FOLL_WRITE;
++#endif
+
+ if (!udata)
+ return ERR_PTR(-EIO);
+@@ -218,7 +226,11 @@ struct ib_umem *ib_umem_get(struct ib_udata *udata, unsigned long addr,
+ return ERR_PTR(-EIO);
+
+ if (dmasync)
++#ifdef HAVE_STRUCT_DMA_ATTRS
++ dma_set_attr(DMA_ATTR_WRITE_BARRIER, &dma_attrs);
++#else
+ dma_attrs |= DMA_ATTR_WRITE_BARRIER;
++#endif
+
+ /*
+ * If the combination of the addr and size requested for this memory
+@@ -275,9 +287,27 @@ struct ib_umem *ib_umem_get(struct ib_udata *udata, unsigned long addr,
+
+ lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+
++#ifdef HAVE_PINNED_VM
++#ifdef HAVE_ATOMIC_PINNED_VM
+ new_pinned = atomic64_add_return(npages, &mm->pinned_vm);
+ if (new_pinned > lock_limit && !capable(CAP_IPC_LOCK)) {
++#else
++ if (check_add_overflow(mm->pinned_vm, npages, &new_pinned) ||
++ (new_pinned > lock_limit && !capable(CAP_IPC_LOCK))) {
++#endif
++#else
++ current->mm->locked_vm += npages;
++ if ((current->mm->locked_vm > lock_limit) && !capable(CAP_IPC_LOCK)) {
++#endif
++#ifdef HAVE_PINNED_VM
++#ifdef HAVE_ATOMIC_PINNED_VM
+ atomic64_sub(npages, &mm->pinned_vm);
++#else
++ mm->pinned_vm -= npages;
++#endif
++ pr_debug("%s: requested to lock(%lu) while limit is(%lu)\n",
++ __func__, new_pinned, lock_limit);
++#endif
+ ret = -ENOMEM;
+ goto out;
+ }
+@@ -288,18 +318,46 @@ struct ib_umem *ib_umem_get(struct ib_udata *udata, unsigned long addr,
+ if (ret)
+ goto vma;
+
++#ifdef HAVE_GET_USER_PAGES_GUP_FLAGS
+ if (!umem->writable)
+ gup_flags |= FOLL_FORCE;
++#endif
+
+ sg = umem->sg_head.sgl;
+
+ while (npages) {
+ down_read(&mm->mmap_sem);
++#ifdef HAVE_FOLL_LONGTERM
+ ret = get_user_pages(cur_base,
+ min_t(unsigned long, npages,
+ PAGE_SIZE / sizeof (struct page *)),
+ gup_flags | FOLL_LONGTERM,
+ page_list, NULL);
++#elif defined(HAVE_GET_USER_PAGES_LONGTERM)
++ ret = get_user_pages_longterm(cur_base,
++ min_t(unsigned long, npages,
++ PAGE_SIZE / sizeof (struct page *)),
++ gup_flags, page_list, NULL);
++#elif defined(HAVE_GET_USER_PAGES_8_PARAMS)
++ ret = get_user_pages(current, current->mm, cur_base,
++ min_t(unsigned long, npages,
++ PAGE_SIZE / sizeof (struct page *)),
++ 1, !umem->writable, page_list, NULL);
++#else
++#ifdef HAVE_GET_USER_PAGES_7_PARAMS
++ ret = get_user_pages(current, current->mm, cur_base,
++#else
++ ret = get_user_pages(cur_base,
++#endif
++ min_t(unsigned long, npages,
++ PAGE_SIZE / sizeof (struct page *)),
++#ifdef HAVE_GET_USER_PAGES_GUP_FLAGS
++ gup_flags, page_list, NULL);
++#else
++ 1, !umem->writable, page_list, NULL);
++#endif
++#endif
++
+ if (ret < 0) {
+ up_read(&mm->mmap_sem);
+ goto umem_release;
+@@ -321,7 +379,11 @@ struct ib_umem *ib_umem_get(struct ib_udata *udata, unsigned long addr,
+ umem->sg_head.sgl,
+ umem->sg_nents,
+ DMA_BIDIRECTIONAL,
++#ifdef HAVE_STRUCT_DMA_ATTRS
++ &dma_attrs);
++#else
+ dma_attrs);
++#endif
+
+ if (!umem->nmap) {
+ ret = -ENOMEM;
+@@ -334,7 +396,15 @@ struct ib_umem *ib_umem_get(struct ib_udata *udata, unsigned long addr,
+ umem_release:
+ __ib_umem_release(context->device, umem, 0);
+ vma:
++#ifdef HAVE_PINNED_VM
++#ifdef HAVE_ATOMIC_PINNED_VM
+ atomic64_sub(ib_umem_num_pages(umem), &mm->pinned_vm);
++#else
++ mm->pinned_vm -= ib_umem_num_pages(umem);
++#endif
++#else
++ mm->locked_vm -= ib_umem_num_pages(umem);
++#endif
+ out:
+ free_page((unsigned long) page_list);
+ umem_kfree:
+@@ -372,7 +442,15 @@ void ib_umem_release(struct ib_umem *umem)
+
+ __ib_umem_release(umem->context->device, umem, 1);
+
++#ifdef HAVE_PINNED_VM
++#ifdef HAVE_ATOMIC_PINNED_VM
+ atomic64_sub(ib_umem_num_pages(umem), &umem->owning_mm->pinned_vm);
++#else
++ umem->owning_mm->pinned_vm -= ib_umem_num_pages(umem);
++#endif /*HAVE_ATOMIC_PINNED_VM*/
++#else
++ umem->owning_mm->locked_vm -= ib_umem_num_pages(umem);
++#endif
+ __ib_umem_release_tail(umem);
+ }
+ EXPORT_SYMBOL(ib_umem_release);
+diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/user_mad.c
++++ b/drivers/infiniband/core/user_mad.c
+@@ -33,6 +33,9 @@
+ * SOFTWARE.
+ */
+
++#ifdef pr_fmt
++#undef pr_fmt
++#endif
+ #define pr_fmt(fmt) "user_mad: " fmt
+
+ #include <linux/module.h>
+@@ -140,7 +143,11 @@ static const dev_t base_issm_dev = MKDEV(IB_UMAD_MAJOR, IB_UMAD_MINOR_BASE) +
+ static dev_t dynamic_umad_dev;
+ static dev_t dynamic_issm_dev;
+
++#ifdef HAVE_IDA_ALLOC_MAX
+ static DEFINE_IDA(umad_ida);
++#else
++static DECLARE_BITMAP(dev_map, IB_UMAD_MAX_PORTS);
++#endif
+
+ static void ib_umad_add_one(struct ib_device *device);
+ static void ib_umad_remove_one(struct ib_device *device, void *client_data);
+@@ -646,6 +653,7 @@ err:
+ return ret;
+ }
+
++#ifdef EPOLLIN
+ static __poll_t ib_umad_poll(struct file *filp, struct poll_table_struct *wait)
+ {
+ struct ib_umad_file *file = filp->private_data;
+@@ -660,6 +668,22 @@ static __poll_t ib_umad_poll(struct file *filp, struct poll_table_struct *wait)
+
+ return mask;
+ }
++#else
++static unsigned int ib_umad_poll(struct file *filp, struct poll_table_struct *wait)
++{
++ struct ib_umad_file *file = filp->private_data;
++
++ /* we will always be able to post a MAD send */
++ unsigned int mask = POLLOUT | POLLWRNORM;
++
++ poll_wait(filp, &file->recv_wait, wait);
++
++ if (!list_empty(&file->recv_list))
++ mask |= POLLIN | POLLRDNORM;
++
++ return mask;
++}
++#endif
+
+ static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg,
+ int compat_method_mask)
+@@ -1007,7 +1031,11 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
+
+ list_add_tail(&file->port_list, &port->file_list);
+
++#ifdef HAVE_STREAM_OPEN
+ stream_open(inode, filp);
++#else
++ nonseekable_open(inode, filp);
++#endif
+ out:
+ mutex_unlock(&port->file_mutex);
+ return ret;
+@@ -1203,11 +1231,17 @@ static struct attribute *umad_class_dev_attrs[] = {
+ };
+ ATTRIBUTE_GROUPS(umad_class_dev);
+
++#ifndef HAVE_CLASS_GROUPS
++static CLASS_ATTR_STRING(abi_version, S_IRUGO,
++ __stringify(IB_USER_MAD_ABI_VERSION));
++#endif
++
+ static char *umad_devnode(struct device *dev, umode_t *mode)
+ {
+ return kasprintf(GFP_KERNEL, "infiniband/%s", dev_name(dev));
+ }
+
++#ifdef HAVE_CLASS_GROUPS
+ static ssize_t abi_version_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+ {
+@@ -1220,11 +1254,14 @@ static struct attribute *umad_class_attrs[] = {
+ NULL,
+ };
+ ATTRIBUTE_GROUPS(umad_class);
++#endif
+
+ static struct class umad_class = {
+ .name = "infiniband_mad",
+ .devnode = umad_devnode,
++#ifdef HAVE_CLASS_GROUPS
+ .class_groups = umad_class_groups,
++#endif
+ .dev_groups = umad_class_dev_groups,
+ };
+
+@@ -1257,10 +1294,18 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
+ dev_t base_issm;
+ int ret;
+
++#ifdef HAVE_IDA_ALLOC_MAX
+ devnum = ida_alloc_max(&umad_ida, IB_UMAD_MAX_PORTS - 1, GFP_KERNEL);
+ if (devnum < 0)
+ return -1;
++#else
++ devnum = find_first_zero_bit(dev_map, IB_UMAD_MAX_PORTS);
++ if (devnum >= IB_UMAD_MAX_PORTS)
++#endif
+ port->dev_num = devnum;
++#ifndef HAVE_IDA_ALLOC_MAX
++ set_bit(devnum, dev_map);
++#endif
+ if (devnum >= IB_UMAD_NUM_FIXED_MINOR) {
+ base_umad = dynamic_umad_dev + devnum - IB_UMAD_NUM_FIXED_MINOR;
+ base_issm = dynamic_issm_dev + devnum - IB_UMAD_NUM_FIXED_MINOR;
+@@ -1303,7 +1348,11 @@ err_dev:
+ cdev_device_del(&port->cdev, &port->dev);
+ err_cdev:
+ put_device(&port->dev);
++#ifndef HAVE_IDA_ALLOC_MAX
++ clear_bit(devnum, dev_map);
++#else
+ ida_free(&umad_ida, devnum);
++#endif
+ return ret;
+ }
+
+@@ -1333,7 +1382,11 @@ static void ib_umad_kill_port(struct ib_umad_port *port)
+
+ cdev_device_del(&port->sm_cdev, &port->sm_dev);
+ cdev_device_del(&port->cdev, &port->dev);
++#ifndef HAVE_IDA_ALLOC_MAX
++ clear_bit(port->dev_num, dev_map);
++#else
+ ida_free(&umad_ida, port->dev_num);
++#endif
+
+ /* balances device_initialize() */
+ put_device(&port->sm_dev);
+@@ -1428,6 +1481,14 @@ static int __init ib_umad_init(void)
+ goto out_chrdev;
+ }
+
++#ifndef HAVE_CLASS_GROUPS
++ ret = class_create_file(&umad_class, &class_attr_abi_version.attr);
++ if (ret) {
++ pr_err("couldn't create abi_version attribute\n");
++ goto out_class;
++ }
++#endif
++
+ ret = ib_register_client(&umad_client);
+ if (ret)
+ goto out_class;
+diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/uverbs.h
++++ b/drivers/infiniband/core/uverbs.h
+@@ -162,7 +162,13 @@ struct ib_uverbs_file {
+ struct list_head umaps;
+ struct page *disassociate_page;
+
++#ifdef HAVE_XARRAY
+ struct xarray idr;
++#else
++ struct idr idr;
++ /* spinlock protects write access to idr */
++ spinlock_t idr_lock;
++#endif
+ };
+
+ struct ib_uverbs_event {
+diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/uverbs_cmd.c
++++ b/drivers/infiniband/core/uverbs_cmd.c
+@@ -210,7 +210,9 @@ static int ib_uverbs_get_context(struct uverbs_attr_bundle *attrs)
+ struct ib_uverbs_get_context_resp resp;
+ struct ib_ucontext *ucontext;
+ struct file *filp;
++#ifdef HAVE_CGROUP_RDMA_H
+ struct ib_rdmacg_object cg_obj;
++#endif
+ struct ib_device *ib_dev;
+ int ret;
+
+@@ -231,9 +233,11 @@ static int ib_uverbs_get_context(struct uverbs_attr_bundle *attrs)
+ goto err;
+ }
+
++#ifdef HAVE_CGROUP_RDMA_H
+ ret = ib_rdmacg_try_charge(&cg_obj, ib_dev, RDMACG_RESOURCE_HCA_HANDLE);
+ if (ret)
+ goto err;
++#endif
+
+ ucontext = rdma_zalloc_drv_obj(ib_dev, ib_ucontext);
+ if (!ucontext) {
+@@ -245,7 +249,9 @@ static int ib_uverbs_get_context(struct uverbs_attr_bundle *attrs)
+
+ ucontext->res.type = RDMA_RESTRACK_CTX;
+ ucontext->device = ib_dev;
++#ifdef HAVE_CGROUP_RDMA_H
+ ucontext->cg_obj = cg_obj;
++#endif
+ /* ufile is required when some objects are released */
+ ucontext->ufile = file;
+
+@@ -286,7 +292,12 @@ static int ib_uverbs_get_context(struct uverbs_attr_bundle *attrs)
+ * Make sure that ib_uverbs_get_ucontext() sees the pointer update
+ * only after all writes to setup the ucontext have completed
+ */
++#ifdef HAVE_SMP_LOAD_ACQUIRE
+ smp_store_release(&file->ucontext, ucontext);
++#else
++ smp_wmb();
++ file->ucontext = ucontext;
++#endif
+
+ mutex_unlock(&file->ucontext_lock);
+
+@@ -303,7 +314,9 @@ err_free:
+ kfree(ucontext);
+
+ err_alloc:
++#ifdef HAVE_CGROUP_RDMA_H
+ ib_rdmacg_uncharge(&cg_obj, ib_dev, RDMACG_RESOURCE_HCA_HANDLE);
++#endif
+
+ err:
+ mutex_unlock(&file->ucontext_lock);
+diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/uverbs_ioctl.c
++++ b/drivers/infiniband/core/uverbs_ioctl.c
+@@ -568,10 +568,16 @@ static int ib_uverbs_cmd_verbs(struct ib_uverbs_file *ufile,
+ if (unlikely(hdr->driver_id != uapi->driver_id))
+ return -EINVAL;
+
++#ifdef HAVE_RADIX_TREE_ITER_LOOKUP
+ slot = radix_tree_iter_lookup(
+ &uapi->radix, &attrs_iter,
+ uapi_key_obj(hdr->object_id) |
+ uapi_key_ioctl_method(hdr->method_id));
++#else
++ radix_tree_iter_init(&attrs_iter, uapi_key_obj(hdr->object_id) |
++ uapi_key_ioctl_method(hdr->method_id));
++ slot = radix_tree_next_chunk(&uapi->radix, &attrs_iter, RADIX_TREE_ITER_CONTIG);
++#endif
+ if (unlikely(!slot))
+ return -EPROTONOSUPPORT;
+ method_elm = rcu_dereference_protected(*slot, true);
+diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/uverbs_main.c
++++ b/drivers/infiniband/core/uverbs_main.c
+@@ -74,7 +74,11 @@ enum {
+ static dev_t dynamic_uverbs_dev;
+ static struct class *uverbs_class;
+
++#ifndef HAVE_IDA_ALLOC_MAX
++static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES);
++#else
+ static DEFINE_IDA(uverbs_ida);
++#endif
+ static void ib_uverbs_add_one(struct ib_device *device);
+ static void ib_uverbs_remove_one(struct ib_device *device, void *client_data);
+
+@@ -298,6 +302,7 @@ static ssize_t ib_uverbs_comp_event_read(struct file *filp, char __user *buf,
+ sizeof(struct ib_uverbs_comp_event_desc));
+ }
+
++#ifdef EPOLLIN
+ static __poll_t ib_uverbs_event_poll(struct ib_uverbs_event_queue *ev_queue,
+ struct file *filp,
+ struct poll_table_struct *wait)
+@@ -328,6 +333,38 @@ static __poll_t ib_uverbs_comp_event_poll(struct file *filp,
+
+ return ib_uverbs_event_poll(&comp_ev_file->ev_queue, filp, wait);
+ }
++#else
++static unsigned int ib_uverbs_event_poll(struct ib_uverbs_event_queue *ev_queue,
++ struct file *filp,
++ struct poll_table_struct *wait)
++{
++ unsigned int pollflags = 0;
++
++ poll_wait(filp, &ev_queue->poll_wait, wait);
++
++ spin_lock_irq(&ev_queue->lock);
++ if (!list_empty(&ev_queue->event_list))
++ pollflags = POLLIN | POLLRDNORM;
++ spin_unlock_irq(&ev_queue->lock);
++
++ return pollflags;
++}
++
++static unsigned int ib_uverbs_async_event_poll(struct file *filp,
++ struct poll_table_struct *wait)
++{
++ return ib_uverbs_event_poll(filp->private_data, filp, wait);
++}
++
++static unsigned int ib_uverbs_comp_event_poll(struct file *filp,
++ struct poll_table_struct *wait)
++{
++ struct ib_uverbs_completion_event_file *comp_ev_file =
++ filp->private_data;
++
++ return ib_uverbs_event_poll(&comp_ev_file->ev_queue, filp, wait);
++}
++#endif
+
+ static int ib_uverbs_async_event_fasync(int fd, struct file *filp, int on)
+ {
+@@ -618,8 +655,14 @@ static ssize_t verify_hdr(struct ib_uverbs_cmd_hdr *hdr,
+ if (hdr->out_words * 8 < method_elm->resp_size)
+ return -ENOSPC;
+
++#ifdef HAVE_ACCESS_OK_HAS_3_PARAMS
++ if (!access_ok(VERIFY_WRITE,
++ u64_to_user_ptr(ex_hdr->response),
++ (hdr->out_words + ex_hdr->provider_out_words) * 8))
++#else
+ if (!access_ok(u64_to_user_ptr(ex_hdr->response),
+ (hdr->out_words + ex_hdr->provider_out_words) * 8))
++#endif
+ return -EFAULT;
+ } else {
+ if (hdr->out_words || ex_hdr->provider_out_words)
+@@ -885,11 +928,20 @@ static void rdma_umap_close(struct vm_area_struct *vma)
+ * Once the zap_vma_ptes has been called touches to the VMA will come here and
+ * we return a dummy writable zero page for all the pfns.
+ */
++#ifdef HAVE_VM_FAULT_T
++#ifdef HAVE_VM_OPERATIONS_STRUCT_HAS_FAULT
+ static vm_fault_t rdma_umap_fault(struct vm_fault *vmf)
++#else
++static int rdma_umap_fault(struct vm_fault *vmf)
++#endif/*HAVE_VM_OPERATIONS_STRUCT_HAS_FAULT*/
+ {
+ struct ib_uverbs_file *ufile = vmf->vma->vm_file->private_data;
+ struct rdma_umap_priv *priv = vmf->vma->vm_private_data;
++#ifdef HAVE_VM_FAULT_T
+ vm_fault_t ret = 0;
++#else
++ int ret = 0;
++#endif
+
+ if (!priv)
+ return VM_FAULT_SIGBUS;
+@@ -920,11 +972,14 @@ static vm_fault_t rdma_umap_fault(struct vm_fault *vmf)
+
+ return ret;
+ }
++#endif
+
+ static const struct vm_operations_struct rdma_umap_ops = {
+ .open = rdma_umap_open,
+ .close = rdma_umap_close,
++#ifdef HAVE_VM_FAULT_T
+ .fault = rdma_umap_fault,
++#endif
+ };
+
+ /*
+@@ -1098,7 +1153,11 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp)
+
+ setup_ufile_idr_uobject(file);
+
++#ifdef HAVE_STREAM_OPEN
+ return stream_open(inode, filp);
++#else
++ return nonseekable_open(inode, filp);
++#endif
+
+ err_module:
+ module_put(ib_dev->ops.owner);
+@@ -1285,11 +1344,19 @@ static void ib_uverbs_add_one(struct ib_device *device)
+ rcu_assign_pointer(uverbs_dev->ib_dev, device);
+ uverbs_dev->num_comp_vectors = device->num_comp_vectors;
+
++#ifdef HAVE_IDA_ALLOC_MAX
+ devnum = ida_alloc_max(&uverbs_ida, IB_UVERBS_MAX_DEVICES - 1,
+ GFP_KERNEL);
+ if (devnum < 0)
++#else
++ devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES);
++ if (devnum >= IB_UVERBS_MAX_DEVICES)
++#endif
+ goto err;
+ uverbs_dev->devnum = devnum;
++#ifndef HAVE_IDA_ALLOC_MAX
++ set_bit(devnum, dev_map);
++#endif
+ if (devnum >= IB_UVERBS_NUM_FIXED_MINOR)
+ base = dynamic_uverbs_dev + devnum - IB_UVERBS_NUM_FIXED_MINOR;
+ else
+@@ -1313,7 +1380,11 @@ static void ib_uverbs_add_one(struct ib_device *device)
+ return;
+
+ err_uapi:
++#ifndef HAVE_IDA_ALLOC_MAX
++ clear_bit(devnum, dev_map);
++#else
+ ida_free(&uverbs_ida, devnum);
++#endif
+ err:
+ if (atomic_dec_and_test(&uverbs_dev->refcount))
+ ib_uverbs_comp_dev(uverbs_dev);
+@@ -1388,7 +1459,11 @@ static void ib_uverbs_remove_one(struct ib_device *device, void *client_data)
+ return;
+
+ cdev_device_del(&uverbs_dev->cdev, &uverbs_dev->dev);
++#ifndef HAVE_IDA_ALLOC_MAX
++ clear_bit(uverbs_dev->devnum, dev_map);
++#else
+ ida_free(&uverbs_ida, uverbs_dev->devnum);
++#endif
+
+ if (device->ops.disassociate_ucontext) {
+ /* We disassociate HW resources and immediately return.
+diff --git a/drivers/infiniband/core/uverbs_uapi.c b/drivers/infiniband/core/uverbs_uapi.c
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/uverbs_uapi.c
++++ b/drivers/infiniband/core/uverbs_uapi.c
+@@ -478,7 +478,11 @@ static void uapi_remove_range(struct uverbs_api *uapi, u32 start, u32 last)
+ if (iter.index > last)
+ return;
+ kfree(rcu_dereference_protected(*slot, true));
++#if defined(HAVE_RADIX_TREE_ITER_DELETE) && defined (HAVE_RADIX_TREE_ITER_DELETE_EXPORTED)
+ radix_tree_iter_delete(&uapi->radix, &iter, slot);
++#else
++ radix_tree_delete(&uapi->radix, iter.index);
++#endif
+ }
+ }
+
+@@ -567,7 +571,11 @@ again:
+
+ if (method_elm->disabled) {
+ kfree(method_elm);
++#if defined(HAVE_RADIX_TREE_ITER_DELETE) && defined (HAVE_RADIX_TREE_ITER_DELETE_EXPORTED)
+ radix_tree_iter_delete(&uapi->radix, &iter, slot);
++#else
++ radix_tree_delete(&uapi->radix, iter.index);
++#endif
+ }
+ continue;
+ }
+diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
+index xxxxxxx..xxxxxxx 100644
+--- a/drivers/infiniband/core/verbs.c
++++ b/drivers/infiniband/core/verbs.c
+@@ -1743,7 +1743,11 @@ int ib_get_eth_speed(struct ib_device *dev, u8 port_num, u8 *speed, u8 *width)
+ int rc;
+ u32 netdev_speed;
+ struct net_device *netdev;
++#ifdef HAVE___ETHTOOL_GET_LINK_KSETTINGS
+ struct ethtool_link_ksettings lksettings;
++#else
++ struct ethtool_cmd lksettings;
++#endif
+
+ if (rdma_port_get_link_layer(dev, port_num) != IB_LINK_LAYER_ETHERNET)
+ return -EINVAL;
+@@ -1753,13 +1757,21 @@ int ib_get_eth_speed(struct ib_device *dev, u8 port_num, u8 *speed, u8 *width)
+ return -ENODEV;
+
+ rtnl_lock();
++#ifdef HAVE___ETHTOOL_GET_LINK_KSETTINGS
+ rc = __ethtool_get_link_ksettings(netdev, &lksettings);
++#else
++ rc = __ethtool_get_settings(netdev, &lksettings);
++#endif
+ rtnl_unlock();
+
+ dev_put(netdev);
+
+ if (!rc) {
++#ifdef HAVE___ETHTOOL_GET_LINK_KSETTINGS
+ netdev_speed = lksettings.base.speed;
++#else
++ netdev_speed = ethtool_cmd_speed(&lksettings);
++#endif
+ } else {
+ netdev_speed = SPEED_1000;
+ pr_warn("%s speed is unknown, defaulting to %d\n", netdev->name,
+@@ -2417,6 +2429,7 @@ int ib_check_mr_status(struct ib_mr *mr, u32 check_mask,
+ }
+ EXPORT_SYMBOL(ib_check_mr_status);
+
++#ifdef HAVE_NDO_SET_VF_MAC
+ int ib_set_vf_link_state(struct ib_device *device, int vf, u8 port,
+ int state)
+ {
+@@ -2456,6 +2469,7 @@ int ib_set_vf_guid(struct ib_device *device, int vf, u8 port, u64 guid,
+ return device->ops.set_vf_guid(device, vf, port, guid, type);
+ }
+ EXPORT_SYMBOL(ib_set_vf_guid);
++#endif /* HAVE_NDO_SET_VF_MAC */
+
+ /**
+ * ib_map_mr_sg_pi() - Map the dma mapped SG lists for PI (protection
+diff --git a/include/rdma/ib_addr.h b/include/rdma/ib_addr.h
+index xxxxxxx..xxxxxxx 100644
+--- a/include/rdma/ib_addr.h
++++ b/include/rdma/ib_addr.h
+@@ -132,7 +132,11 @@ static inline int rdma_addr_gid_offset(struct rdma_dev_addr *dev_addr)
+ return dev_addr->dev_type == ARPHRD_INFINIBAND ? 4 : 0;
+ }
+
++#ifdef HAVE_IS_VLAN_DEV_CONST
+ static inline u16 rdma_vlan_dev_vlan_id(const struct net_device *dev)
++#else
++static inline u16 rdma_vlan_dev_vlan_id(struct net_device *dev)
++#endif
+ {
+ return is_vlan_dev(dev) ? vlan_dev_vlan_id(dev) : 0xffff;
+ }
+@@ -222,15 +226,25 @@ static inline enum ib_mtu iboe_get_mtu(int mtu)
+
+ static inline int iboe_get_rate(struct net_device *dev)
+ {
++#ifdef HAVE___ETHTOOL_GET_LINK_KSETTINGS
+ struct ethtool_link_ksettings cmd;
++#else
++ struct ethtool_cmd cmd;
++ u32 speed;
++#endif
+ int err;
+
+ rtnl_lock();
++#ifdef HAVE___ETHTOOL_GET_LINK_KSETTINGS
+ err = __ethtool_get_link_ksettings(dev, &cmd);
++#else
++ err = __ethtool_get_settings(dev, &cmd);
++#endif
+ rtnl_unlock();
+ if (err)
+ return IB_RATE_PORT_CURRENT;
+
++#ifdef HAVE___ETHTOOL_GET_LINK_KSETTINGS
+ if (cmd.base.speed >= 40000)
+ return IB_RATE_40_GBPS;
+ else if (cmd.base.speed >= 30000)
+@@ -241,6 +255,19 @@ static inline int iboe_get_rate(struct net_device *dev)
+ return IB_RATE_10_GBPS;
+ else
+ return IB_RATE_PORT_CURRENT;
++#else
++ speed = ethtool_cmd_speed(&cmd);
++ if (speed >= 40000)
++ return IB_RATE_40_GBPS;
++ else if (speed >= 30000)
++ return IB_RATE_30_GBPS;
++ else if (speed >= 20000)
++ return IB_RATE_20_GBPS;
++ else if (speed >= 10000)
++ return IB_RATE_10_GBPS;
++ else
++ return IB_RATE_PORT_CURRENT;
++#endif
+ }
+
+ static inline int rdma_link_local_addr(struct in6_addr *addr)
+@@ -288,7 +315,11 @@ static inline u16 rdma_get_vlan_id(union ib_gid *dgid)
+ return vid < 0x1000 ? vid : 0xffff;
+ }
+
++#ifdef HAVE_IS_VLAN_DEV_CONST
+ static inline struct net_device *rdma_vlan_dev_real_dev(const struct net_device *dev)
++#else
++static inline struct net_device *rdma_vlan_dev_real_dev(struct net_device *dev)
++#endif
+ {
+ return is_vlan_dev(dev) ? vlan_dev_real_dev(dev) : NULL;
+ }
+diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
+index xxxxxxx..xxxxxxx 100644
+--- a/include/rdma/ib_verbs.h
++++ b/include/rdma/ib_verbs.h
+@@ -46,7 +46,11 @@
+ #include <linux/list.h>
+ #include <linux/rwsem.h>
+ #include <linux/workqueue.h>
++#if defined(HAVE_IRQ_POLL_H) && IS_ENABLED(CONFIG_IRQ_POLL)
+ #include <linux/irq_poll.h>
++#else
++#include <linux/blk-iopoll.h>
++#endif
+ #include <uapi/linux/if_ether.h>
+ #include <net/ipv6.h>
+ #include <net/ip.h>
+@@ -1399,11 +1403,13 @@ enum rdma_remove_reason {
+ RDMA_REMOVE_ABORT,
+ };
+
++#ifdef HAVE_CGROUP_RDMA_H
+ struct ib_rdmacg_object {
+ #ifdef CONFIG_CGROUP_RDMA
+ struct rdma_cgroup *cg; /* owner rdma cgroup */
+ #endif
+ };
++#endif
+
+ struct ib_ucontext {
+ struct ib_device *device;
+@@ -1422,7 +1428,9 @@ struct ib_ucontext {
+ struct mutex per_mm_list_lock;
+ struct list_head per_mm_list;
+
++#ifdef HAVE_CGROUP_RDMA_H
+ struct ib_rdmacg_object cg_obj;
++#endif
+ /*
+ * Implementation details of the RDMA core, don't use in drivers:
+ */
+@@ -1437,7 +1445,9 @@ struct ib_uobject {
+ struct ib_ucontext *context; /* associated user context */
+ void *object; /* containing object */
+ struct list_head list; /* link to context's list */
++#ifdef HAVE_CGROUP_RDMA_H
+ struct ib_rdmacg_object cg_obj; /* rdmacg object */
++#endif
+ int id; /* index into kernel idr */
+ struct kref ref;
+ atomic_t usecnt; /* protects exclusive access */
+@@ -1506,7 +1516,11 @@ struct ib_cq {
+ enum ib_poll_context poll_ctx;
+ struct ib_wc *wc;
+ union {
++#if defined(HAVE_IRQ_POLL_H) && IS_ENABLED(CONFIG_IRQ_POLL)
+ struct irq_poll iop;
++#else
++ struct blk_iopoll iop;
++#endif
+ struct work_struct work;
+ };
+ struct workqueue_struct *comp_wq;
+@@ -2105,6 +2119,63 @@ struct ib_cache {
+ struct ib_event_handler event_handler;
+ };
+
++#ifndef HAVE_DEVICE_DMA_OPS
++struct ib_dma_mapping_ops {
++ int (*mapping_error)(struct ib_device *dev,
++ u64 dma_addr);
++ u64 (*map_single)(struct ib_device *dev,
++ void *ptr, size_t size,
++ enum dma_data_direction direction);
++ void (*unmap_single)(struct ib_device *dev,
++ u64 addr, size_t size,
++ enum dma_data_direction direction);
++ u64 (*map_page)(struct ib_device *dev,
++ struct page *page, unsigned long offset,
++ size_t size,
++ enum dma_data_direction direction);
++ void (*unmap_page)(struct ib_device *dev,
++ u64 addr, size_t size,
++ enum dma_data_direction direction);
++ int (*map_sg)(struct ib_device *dev,
++ struct scatterlist *sg, int nents,
++ enum dma_data_direction direction);
++ void (*unmap_sg)(struct ib_device *dev,
++ struct scatterlist *sg, int nents,
++ enum dma_data_direction direction);
++ int (*map_sg_attrs)(struct ib_device *dev,
++ struct scatterlist *sg, int nents,
++ enum dma_data_direction direction,
++#ifdef HAVE_STRUCT_DMA_ATTRS
++ struct dma_attrs *attrs);
++#else
++ unsigned long attrs);
++#endif
++ void (*unmap_sg_attrs)(struct ib_device *dev,
++ struct scatterlist *sg, int nents,
++ enum dma_data_direction direction,
++#ifdef HAVE_STRUCT_DMA_ATTRS
++ struct dma_attrs *attrs);
++#else
++ unsigned long attrs);
++#endif
++ void (*sync_single_for_cpu)(struct ib_device *dev,
++ u64 dma_handle,
++ size_t size,
++ enum dma_data_direction dir);
++ void (*sync_single_for_device)(struct ib_device *dev,
++ u64 dma_handle,
++ size_t size,
++ enum dma_data_direction dir);
++ void *(*alloc_coherent)(struct ib_device *dev,
++ size_t size,
++ u64 *dma_handle,
++ gfp_t flag);
++ void (*free_coherent)(struct ib_device *dev,
++ size_t size, void *cpu_addr,
++ u64 dma_handle);
++};
++#endif
++
+ struct ib_port_immutable {
+ int pkey_tbl_len;
+ int gid_tbl_len;
+@@ -2396,6 +2467,7 @@ struct ib_device_ops {
+ struct ib_flow_action *action,
+ const struct ib_flow_action_attrs_esp *attr,
+ struct uverbs_attr_bundle *attrs);
++#ifdef HAVE_NDO_SET_VF_MAC
+ int (*set_vf_link_state)(struct ib_device *device, int vf, u8 port,
+ int state);
+ int (*get_vf_config)(struct ib_device *device, int vf, u8 port,
+@@ -2404,6 +2476,7 @@ struct ib_device_ops {
+ struct ifla_vf_stats *stats);
+ int (*set_vf_guid)(struct ib_device *device, int vf, u8 port, u64 guid,
+ int type);
++#endif
+ struct ib_wq *(*create_wq)(struct ib_pd *pd,
+ struct ib_wq_init_attr *init_attr,
+ struct ib_udata *udata);
+@@ -2594,6 +2667,9 @@ struct ib_device {
+ struct rdma_restrack_root *res;
+
+ const struct uapi_definition *driver_def;
++#ifndef HAVE_DEVICE_DMA_OPS
++ struct ib_dma_mapping_ops *dma_ops;
++#endif
+
+ /*
+ * Positive refcount indicates that the device is currently
+@@ -3251,14 +3327,18 @@ static inline unsigned int rdma_find_pg_bit(unsigned long addr,
+ return __fls(pgsz);
+ }
+
++#ifdef HAVE_NDO_SET_VF_MAC
+ int ib_set_vf_link_state(struct ib_device *device, int vf, u8 port,
+ int state);
+ int ib_get_vf_config(struct ib_device *device, int vf, u8 port,
+ struct ifla_vf_info *info);
++#ifdef HAVE_NDO_GET_VF_STATS
+ int ib_get_vf_stats(struct ib_device *device, int vf, u8 port,
+ struct ifla_vf_stats *stats);
++#endif
+ int ib_set_vf_guid(struct ib_device *device, int vf, u8 port, u64 guid,
+ int type);
++#endif
+
+ int ib_query_pkey(struct ib_device *device,
+ u8 port_num, u16 index, u16 *pkey);
+@@ -3863,6 +3943,10 @@ static inline int ib_req_ncomp_notif(struct ib_cq *cq, int wc_cnt)
+ */
+ static inline int ib_dma_mapping_error(struct ib_device *dev, u64 dma_addr)
+ {
++#ifndef HAVE_DEVICE_DMA_OPS
++ if (dev->dma_ops)
++ return dev->dma_ops->mapping_error(dev, dma_addr);
++#endif
+ return dma_mapping_error(dev->dma_device, dma_addr);
+ }
+
+@@ -3877,6 +3961,10 @@ static inline u64 ib_dma_map_single(struct ib_device *dev,
+ void *cpu_addr, size_t size,
+ enum dma_data_direction direction)
+ {
++#ifndef HAVE_DEVICE_DMA_OPS
++ if (dev->dma_ops)
++ return dev->dma_ops->map_single(dev, cpu_addr, size, direction);
++#endif
+ return dma_map_single(dev->dma_device, cpu_addr, size, direction);
+ }
+
+@@ -3891,6 +3979,11 @@ static inline void ib_dma_unmap_single(struct ib_device *dev,
+ u64 addr, size_t size,
+ enum dma_data_direction direction)
+ {
++#ifndef HAVE_DEVICE_DMA_OPS
++ if (dev->dma_ops)
++ dev->dma_ops->unmap_single(dev, addr, size, direction);
++ else
++#endif
+ dma_unmap_single(dev->dma_device, addr, size, direction);
+ }
+
+@@ -3908,6 +4001,10 @@ static inline u64 ib_dma_map_page(struct ib_device *dev,
+ size_t size,
+ enum dma_data_direction direction)
+ {
++#ifndef HAVE_DEVICE_DMA_OPS
++ if (dev->dma_ops)
++ return dev->dma_ops->map_page(dev, page, offset, size, direction);
++#endif
+ return dma_map_page(dev->dma_device, page, offset, size, direction);
+ }
+
+@@ -3922,6 +4019,11 @@ static inline void ib_dma_unmap_page(struct ib_device *dev,
+ u64 addr, size_t size,
+ enum dma_data_direction direction)
+ {
++#ifndef HAVE_DEVICE_DMA_OPS
++ if (dev->dma_ops)
++ dev->dma_ops->unmap_page(dev, addr, size, direction);
++ else
++#endif
+ dma_unmap_page(dev->dma_device, addr, size, direction);
+ }
+
+@@ -3936,6 +4038,10 @@ static inline int ib_dma_map_sg(struct ib_device *dev,
+ struct scatterlist *sg, int nents,
+ enum dma_data_direction direction)
+ {
++#ifndef HAVE_DEVICE_DMA_OPS
++ if (dev->dma_ops)
++ return dev->dma_ops->map_sg(dev, sg, nents, direction);
++#endif
+ return dma_map_sg(dev->dma_device, sg, nents, direction);
+ }
+
+@@ -3950,14 +4056,28 @@ static inline void ib_dma_unmap_sg(struct ib_device *dev,
+ struct scatterlist *sg, int nents,
+ enum dma_data_direction direction)
+ {
++#ifndef HAVE_DEVICE_DMA_OPS
++ if (dev->dma_ops)
++ dev->dma_ops->unmap_sg(dev, sg, nents, direction);
++ else
++#endif
+ dma_unmap_sg(dev->dma_device, sg, nents, direction);
+ }
+
+ static inline int ib_dma_map_sg_attrs(struct ib_device *dev,
+ struct scatterlist *sg, int nents,
+ enum dma_data_direction direction,
++#ifdef HAVE_STRUCT_DMA_ATTRS
++ struct dma_attrs *dma_attrs)
++#else
+ unsigned long dma_attrs)
++#endif
+ {
++#ifndef HAVE_DEVICE_DMA_OPS
++ if (dev->dma_ops)
++ return dev->dma_ops->map_sg_attrs(dev, sg, nents, direction,
++ dma_attrs);
++#endif
+ return dma_map_sg_attrs(dev->dma_device, sg, nents, direction,
+ dma_attrs);
+ }
+@@ -3965,8 +4085,18 @@ static inline int ib_dma_map_sg_attrs(struct ib_device *dev,
+ static inline void ib_dma_unmap_sg_attrs(struct ib_device *dev,
+ struct scatterlist *sg, int nents,
+ enum dma_data_direction direction,
++#ifdef HAVE_STRUCT_DMA_ATTRS
++ struct dma_attrs *dma_attrs)
++#else
+ unsigned long dma_attrs)
++#endif
+ {
++#ifndef HAVE_DEVICE_DMA_OPS
++ if (dev->dma_ops)
++ return dev->dma_ops->unmap_sg_attrs(dev, sg, nents, direction,
++ dma_attrs);
++ else
++#endif
+ dma_unmap_sg_attrs(dev->dma_device, sg, nents, direction, dma_attrs);
+ }
+
+@@ -3995,6 +4125,11 @@ static inline void ib_dma_sync_single_for_cpu(struct ib_device *dev,
+ size_t size,
+ enum dma_data_direction dir)
+ {
++#ifndef HAVE_DEVICE_DMA_OPS
++ if (dev->dma_ops)
++ dev->dma_ops->sync_single_for_cpu(dev, addr, size, dir);
++ else
++#endif
+ dma_sync_single_for_cpu(dev->dma_device, addr, size, dir);
+ }
+
+@@ -4010,6 +4145,11 @@ static inline void ib_dma_sync_single_for_device(struct ib_device *dev,
+ size_t size,
+ enum dma_data_direction dir)
+ {
++#ifndef HAVE_DEVICE_DMA_OPS
++ if (dev->dma_ops)
++ dev->dma_ops->sync_single_for_device(dev, addr, size, dir);
++ else
++#endif
+ dma_sync_single_for_device(dev->dma_device, addr, size, dir);
+ }
+
+@@ -4025,6 +4165,16 @@ static inline void *ib_dma_alloc_coherent(struct ib_device *dev,
+ dma_addr_t *dma_handle,
+ gfp_t flag)
+ {
++#ifndef HAVE_DEVICE_DMA_OPS
++ if (dev->dma_ops) {
++ u64 handle;
++ void *ret;
++
++ ret = dev->dma_ops->alloc_coherent(dev, size, &handle, flag);
++ *dma_handle = handle;
++ return ret;
++ }
++#endif
+ return dma_alloc_coherent(dev->dma_device, size, dma_handle, flag);
+ }
+
+@@ -4039,6 +4189,11 @@ static inline void ib_dma_free_coherent(struct ib_device *dev,
+ size_t size, void *cpu_addr,
+ dma_addr_t dma_handle)
+ {
++#ifndef HAVE_DEVICE_DMA_OPS
++ if (dev->dma_ops)
++ dev->dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
++ else
++#endif
+ dma_free_coherent(dev->dma_device, size, cpu_addr, dma_handle);
+ }
+
+diff --git a/include/rdma/rdma_netlink.h b/include/rdma/rdma_netlink.h
+index xxxxxxx..xxxxxxx 100644
+--- a/include/rdma/rdma_netlink.h
++++ b/include/rdma/rdma_netlink.h
+@@ -13,8 +13,12 @@ enum {
+ };
+
+ struct rdma_nl_cbs {
++#ifdef HAVE_NETLINK_EXT_ACK
+ int (*doit)(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack);
++#else
++ int (*doit)(struct sk_buff *skb, struct nlmsghdr *nlh);
++#endif
+ int (*dump)(struct sk_buff *skb, struct netlink_callback *nlcb);
+ u8 flags;
+ };
+diff --git a/include/rdma/restrack.h b/include/rdma/restrack.h
+index xxxxxxx..xxxxxxx 100644
+--- a/include/rdma/restrack.h
++++ b/include/rdma/restrack.h
+@@ -10,7 +10,10 @@
+ #include <linux/sched.h>
+ #include <linux/kref.h>
+ #include <linux/completion.h>
++#ifdef HAVE_LINUX_SCHED_TASK_H
+ #include <linux/sched/task.h>
++#endif
++#include <linux/hashtable.h>
+ #include <uapi/rdma/rdma_netlink.h>
+ #include <linux/xarray.h>
+
+@@ -90,6 +93,12 @@ struct rdma_restrack_entry {
+ * @kern_name: name of owner for the kernel created entities.
+ */
+ const char *kern_name;
++#ifndef HAVE_XARRAY
++ /**
++ * @node: hash table entry
++ */
++ struct hlist_node node;
++#endif
+ /**
+ * @type: various objects in restrack database
+ */
+diff --git a/include/rdma/uverbs_ioctl.h b/include/rdma/uverbs_ioctl.h
+index xxxxxxx..xxxxxxx 100644
+--- a/include/rdma/uverbs_ioctl.h
++++ b/include/rdma/uverbs_ioctl.h
+@@ -872,6 +872,9 @@ int uverbs_get_flags32(u32 *to, const struct uverbs_attr_bundle *attrs_bundle,
+ size_t idx, u64 allowed_bits);
+ int uverbs_copy_to(const struct uverbs_attr_bundle *attrs_bundle, size_t idx,
+ const void *from, size_t size);
++#ifndef __malloc
++#define __malloc
++#endif
+ __malloc void *_uverbs_alloc(struct uverbs_attr_bundle *bundle, size_t size,
+ gfp_t flags);
+
+diff --git a/include/trace/events/ib_mad.h b/include/trace/events/ib_mad.h
+index xxxxxxx..xxxxxxx 100644
+--- a/include/trace/events/ib_mad.h
++++ b/include/trace/events/ib_mad.h
+@@ -14,10 +14,17 @@
+ #include <rdma/ib_mad.h>
+
+ #ifdef CONFIG_TRACEPOINTS
++#ifdef HAVE_TRACE_EVENT_RAW_IB_MAD_SEND_TEMPLATE
+ struct trace_event_raw_ib_mad_send_template;
+ static void create_mad_addr_info(struct ib_mad_send_wr_private *mad_send_wr,
+ struct ib_mad_qp_info *qp_info,
+ struct trace_event_raw_ib_mad_send_template *entry);
++#else
++struct ftrace_raw_ib_mad_send_template;
++static void create_mad_addr_info(struct ib_mad_send_wr_private *mad_send_wr,
++ struct ib_mad_qp_info *qp_info,
++ struct ftrace_raw_ib_mad_send_template *entry);
++#endif
+ #endif
+
+ DECLARE_EVENT_CLASS(ib_mad_send_template,