From 0568c4640e2b12df063d1761fd4d53af24dc4018 Mon Sep 17 00:00:00 2001 From: "Vishwanathapura, Niranjana" Date: Wed, 14 Jun 2017 12:34:41 -0700 Subject: [PATCH 1/4] IB/opa_vnic: Use GFP_ATOMIC while sending trap Pass GFP_ATOMIC flag to ib_create_send_mad() while sending trap as it can be triggered from the atomic context. Fix the following trace with debug kernel. BUG: sleeping function called from invalid context at mm/slab.h:432 in_atomic(): 1, irqs_disabled(): 0, pid: 1771, name: NetworkManager Call Trace: dump_stack+0x63/0x90 ___might_sleep+0xda/0x130 __might_sleep+0x4a/0x90 __kmalloc+0x19e/0x220 ? ib_create_send_mad+0xea/0x390 [ib_core] ib_create_send_mad+0xea/0x390 [ib_core] opa_vnic_vema_send_trap+0x17b/0x460 [opa_vnic] opa_vnic_vema_report_event+0x57/0x80 [opa_vnic] opa_vnic_mac_send_event+0xaa/0xf0 [opa_vnic] opa_vnic_set_rx_mode+0x17/0x30 [opa_vnic] __dev_set_rx_mode+0x52/0x90 dev_set_rx_mode+0x26/0x40 __dev_open+0xe8/0x140 Reviewed-by: Mike Marciniszyn Reviewed-by: Dennis Dalessandro Signed-off-by: Niranjana Vishwanathapura Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c b/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c index 875694f9a7f9..cf768dd78d1b 100644 --- a/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c +++ b/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c @@ -794,7 +794,7 @@ void opa_vnic_vema_send_trap(struct opa_vnic_adapter *adapter, send_buf = ib_create_send_mad(port->mad_agent, 1, pkey_idx, 0, IB_MGMT_VENDOR_HDR, IB_MGMT_MAD_DATA, - GFP_KERNEL, OPA_MGMT_BASE_VERSION); + GFP_ATOMIC, OPA_MGMT_BASE_VERSION); if (IS_ERR(send_buf)) { c_err("%s:Couldn't allocate send buf\n", __func__); goto err_sndbuf; From a379d69f00f28063a7a1c3de235e2996c2c5a6f5 Mon Sep 17 00:00:00 2001 From: "Vishwanathapura, Niranjana" Date: Wed, 14 Jun 2017 12:34:42 -0700 Subject: [PATCH 2/4] IB/opa_vnic: Use spinlock instead of mutex for stats_lock Stats can be read from atomic context, hence make stats_lock as a spinlock. Fix the following trace with debug kernel. BUG: sleeping function called from invalid context at kernel/locking/mutex.c:238 in_atomic(): 1, irqs_disabled(): 0, pid: 6487, name: sadc Call Trace: dump_stack+0x63/0x90 ___might_sleep+0xda/0x130 __might_sleep+0x4a/0x90 mutex_lock+0x20/0x50 opa_vnic_get_stats64+0x56/0x140 [opa_vnic] dev_get_stats+0x74/0x130 dev_seq_printf_stats+0x37/0x120 dev_seq_show+0x14/0x30 seq_read+0x26d/0x3d0 Reviewed-by: Mike Marciniszyn Reviewed-by: Dennis Dalessandro Signed-off-by: Niranjana Vishwanathapura Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/opa_vnic/opa_vnic_ethtool.c | 4 ++-- drivers/infiniband/ulp/opa_vnic/opa_vnic_internal.h | 2 +- drivers/infiniband/ulp/opa_vnic/opa_vnic_netdev.c | 8 +++----- drivers/infiniband/ulp/opa_vnic/opa_vnic_vema_iface.c | 8 ++++---- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/infiniband/ulp/opa_vnic/opa_vnic_ethtool.c b/drivers/infiniband/ulp/opa_vnic/opa_vnic_ethtool.c index d66540e24885..62390e9e0023 100644 --- a/drivers/infiniband/ulp/opa_vnic/opa_vnic_ethtool.c +++ b/drivers/infiniband/ulp/opa_vnic/opa_vnic_ethtool.c @@ -146,15 +146,15 @@ static void vnic_get_ethtool_stats(struct net_device *netdev, int i; memset(&vstats, 0, sizeof(vstats)); - mutex_lock(&adapter->stats_lock); + spin_lock(&adapter->stats_lock); adapter->rn_ops->ndo_get_stats64(netdev, &vstats.netstats); + spin_unlock(&adapter->stats_lock); for (i = 0; i < VNIC_STATS_LEN; i++) { char *p = (char *)&vstats + vnic_gstrings_stats[i].stat_offset; data[i] = (vnic_gstrings_stats[i].sizeof_stat == sizeof(u64)) ? *(u64 *)p : *(u32 *)p; } - mutex_unlock(&adapter->stats_lock); } /* vnic_get_strings - get strings */ diff --git a/drivers/infiniband/ulp/opa_vnic/opa_vnic_internal.h b/drivers/infiniband/ulp/opa_vnic/opa_vnic_internal.h index 6bba886bec1f..ca29e6d5aedc 100644 --- a/drivers/infiniband/ulp/opa_vnic/opa_vnic_internal.h +++ b/drivers/infiniband/ulp/opa_vnic/opa_vnic_internal.h @@ -214,7 +214,7 @@ struct opa_vnic_adapter { struct mutex mactbl_lock; /* Lock used to protect access to vnic counters */ - struct mutex stats_lock; + spinlock_t stats_lock; u8 flow_tbl[OPA_VNIC_FLOW_TBL_SIZE]; diff --git a/drivers/infiniband/ulp/opa_vnic/opa_vnic_netdev.c b/drivers/infiniband/ulp/opa_vnic/opa_vnic_netdev.c index 905f39dda5aa..78d9007bc2f6 100644 --- a/drivers/infiniband/ulp/opa_vnic/opa_vnic_netdev.c +++ b/drivers/infiniband/ulp/opa_vnic/opa_vnic_netdev.c @@ -69,9 +69,9 @@ static void opa_vnic_get_stats64(struct net_device *netdev, struct opa_vnic_stats vstats; memset(&vstats, 0, sizeof(vstats)); - mutex_lock(&adapter->stats_lock); + spin_lock(&adapter->stats_lock); adapter->rn_ops->ndo_get_stats64(netdev, &vstats.netstats); - mutex_unlock(&adapter->stats_lock); + spin_unlock(&adapter->stats_lock); memcpy(stats, &vstats.netstats, sizeof(*stats)); } @@ -344,7 +344,7 @@ struct opa_vnic_adapter *opa_vnic_add_netdev(struct ib_device *ibdev, netdev->hard_header_len += OPA_VNIC_SKB_HEADROOM; mutex_init(&adapter->lock); mutex_init(&adapter->mactbl_lock); - mutex_init(&adapter->stats_lock); + spin_lock_init(&adapter->stats_lock); SET_NETDEV_DEV(netdev, ibdev->dev.parent); @@ -364,7 +364,6 @@ struct opa_vnic_adapter *opa_vnic_add_netdev(struct ib_device *ibdev, netdev_err: mutex_destroy(&adapter->lock); mutex_destroy(&adapter->mactbl_lock); - mutex_destroy(&adapter->stats_lock); kfree(adapter); adapter_err: ibdev->free_rdma_netdev(netdev); @@ -383,7 +382,6 @@ void opa_vnic_rem_netdev(struct opa_vnic_adapter *adapter) opa_vnic_release_mac_tbl(adapter); mutex_destroy(&adapter->lock); mutex_destroy(&adapter->mactbl_lock); - mutex_destroy(&adapter->stats_lock); kfree(adapter); ibdev->free_rdma_netdev(netdev); } diff --git a/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema_iface.c b/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema_iface.c index a51bf977f4d6..c2733964379c 100644 --- a/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema_iface.c +++ b/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema_iface.c @@ -89,9 +89,9 @@ void opa_vnic_get_summary_counters(struct opa_vnic_adapter *adapter, u64 *src; memset(&vstats, 0, sizeof(vstats)); - mutex_lock(&adapter->stats_lock); + spin_lock(&adapter->stats_lock); adapter->rn_ops->ndo_get_stats64(adapter->netdev, &vstats.netstats); - mutex_unlock(&adapter->stats_lock); + spin_unlock(&adapter->stats_lock); cntrs->vp_instance = cpu_to_be16(adapter->vport_num); cntrs->vesw_id = cpu_to_be16(adapter->info.vesw.vesw_id); @@ -128,9 +128,9 @@ void opa_vnic_get_error_counters(struct opa_vnic_adapter *adapter, struct opa_vnic_stats vstats; memset(&vstats, 0, sizeof(vstats)); - mutex_lock(&adapter->stats_lock); + spin_lock(&adapter->stats_lock); adapter->rn_ops->ndo_get_stats64(adapter->netdev, &vstats.netstats); - mutex_unlock(&adapter->stats_lock); + spin_unlock(&adapter->stats_lock); cntrs->vp_instance = cpu_to_be16(adapter->vport_num); cntrs->vesw_id = cpu_to_be16(adapter->info.vesw.vesw_id); From 5ecce4c9b17bed4dc9cb58bfb10447307569b77b Mon Sep 17 00:00:00 2001 From: Boris Pismenny Date: Tue, 27 Jun 2017 15:09:13 +0300 Subject: [PATCH 3/4] RDMA/uverbs: Check port number supplied by user verbs cmds The ib_uverbs_create_ah() ind ib_uverbs_modify_qp() calls receive the port number from user input as part of its attributes and assumes it is valid. Down on the stack, that parameter is used to access kernel data structures. If the value is invalid, the kernel accesses memory it should not. To prevent this, verify the port number before using it. BUG: KASAN: use-after-free in ib_uverbs_create_ah+0x6d5/0x7b0 Read of size 4 at addr ffff880018d67ab8 by task syz-executor/313 BUG: KASAN: slab-out-of-bounds in modify_qp.isra.4+0x19d0/0x1ef0 Read of size 4 at addr ffff88006c40ec58 by task syz-executor/819 Fixes: 67cdb40ca444 ("[IB] uverbs: Implement more commands") Fixes: 189aba99e70 ("IB/uverbs: Extend modify_qp and support packet pacing") Cc: # v2.6.14+ Cc: Cc: Yevgeny Kliteynik Cc: Tziporet Koren Cc: Alex Polak Signed-off-by: Boris Pismenny Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/uverbs_cmd.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 70b7fb156414..e63f2a13c5e1 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -1931,6 +1931,11 @@ static int modify_qp(struct ib_uverbs_file *file, goto out; } + if (!rdma_is_port_valid(qp->device, cmd->base.port_num)) { + ret = -EINVAL; + goto release_qp; + } + attr->qp_state = cmd->base.qp_state; attr->cur_qp_state = cmd->base.cur_qp_state; attr->path_mtu = cmd->base.path_mtu; @@ -2541,6 +2546,9 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file, if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; + if (!rdma_is_port_valid(ib_dev, cmd.attr.port_num)) + return -EINVAL; + INIT_UDATA(&udata, buf + sizeof(cmd), (unsigned long)cmd.response + sizeof(resp), in_len - sizeof(cmd), out_len - sizeof(resp)); From 8e959601996dc645f4ed7004482a1667c27deb39 Mon Sep 17 00:00:00 2001 From: Niranjana Vishwanathapura Date: Fri, 30 Jun 2017 13:14:46 -0700 Subject: [PATCH 4/4] IB/core, opa_vnic, hfi1, mlx5: Properly free rdma_netdev IPOIB is calling free_rdma_netdev even though alloc_rdma_netdev has returned -EOPNOTSUPP. Move free_rdma_netdev from ib_device structure to rdma_netdev structure thus ensuring proper cleanup function is called for the rdma net device. Fix the following trace: ib0: Failed to modify QP to ERROR state BUG: unable to handle kernel paging request at 0000000000001d20 IP: hfi1_vnic_free_rn+0x26/0xb0 [hfi1] Call Trace: ipoib_remove_one+0xbe/0x160 [ib_ipoib] ib_unregister_device+0xd0/0x170 [ib_core] rvt_unregister_device+0x29/0x90 [rdmavt] hfi1_unregister_ib_device+0x1a/0x100 [hfi1] remove_one+0x4b/0x220 [hfi1] pci_device_remove+0x39/0xc0 device_release_driver_internal+0x141/0x200 driver_detach+0x3f/0x80 bus_remove_driver+0x55/0xd0 driver_unregister+0x2c/0x50 pci_unregister_driver+0x2a/0xa0 hfi1_mod_cleanup+0x10/0xf65 [hfi1] SyS_delete_module+0x171/0x250 do_syscall_64+0x67/0x150 entry_SYSCALL64_slow_path+0x25/0x25 Reviewed-by: Dennis Dalessandro Signed-off-by: Niranjana Vishwanathapura Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/verbs.c | 1 - drivers/infiniband/hw/hfi1/vnic.h | 1 - drivers/infiniband/hw/hfi1/vnic_main.c | 19 ++++++------- drivers/infiniband/hw/mlx5/main.c | 27 ++++++++++++------- drivers/infiniband/ulp/ipoib/ipoib_main.c | 8 +++--- .../infiniband/ulp/opa_vnic/opa_vnic_netdev.c | 8 +++--- include/rdma/ib_verbs.h | 6 +++-- 7 files changed, 39 insertions(+), 31 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c index 90e7b77d68e8..2d19f9bb434d 100644 --- a/drivers/infiniband/hw/hfi1/verbs.c +++ b/drivers/infiniband/hw/hfi1/verbs.c @@ -1779,7 +1779,6 @@ int hfi1_register_ib_device(struct hfi1_devdata *dd) ibdev->alloc_hw_stats = alloc_hw_stats; ibdev->get_hw_stats = get_hw_stats; ibdev->alloc_rdma_netdev = hfi1_vnic_alloc_rn; - ibdev->free_rdma_netdev = hfi1_vnic_free_rn; /* keep process mad in the driver */ ibdev->process_mad = hfi1_process_mad; diff --git a/drivers/infiniband/hw/hfi1/vnic.h b/drivers/infiniband/hw/hfi1/vnic.h index e2c455299b53..4a621cde4abb 100644 --- a/drivers/infiniband/hw/hfi1/vnic.h +++ b/drivers/infiniband/hw/hfi1/vnic.h @@ -176,7 +176,6 @@ struct net_device *hfi1_vnic_alloc_rn(struct ib_device *device, const char *name, unsigned char name_assign_type, void (*setup)(struct net_device *)); -void hfi1_vnic_free_rn(struct net_device *netdev); int hfi1_vnic_send_dma(struct hfi1_devdata *dd, u8 q_idx, struct hfi1_vnic_vport_info *vinfo, struct sk_buff *skb, u64 pbc, u8 plen); diff --git a/drivers/infiniband/hw/hfi1/vnic_main.c b/drivers/infiniband/hw/hfi1/vnic_main.c index b601c2929f8f..339f0cdd56d6 100644 --- a/drivers/infiniband/hw/hfi1/vnic_main.c +++ b/drivers/infiniband/hw/hfi1/vnic_main.c @@ -833,6 +833,15 @@ static const struct net_device_ops hfi1_netdev_ops = { .ndo_get_stats64 = hfi1_vnic_get_stats64, }; +static void hfi1_vnic_free_rn(struct net_device *netdev) +{ + struct hfi1_vnic_vport_info *vinfo = opa_vnic_dev_priv(netdev); + + hfi1_vnic_deinit(vinfo); + mutex_destroy(&vinfo->lock); + free_netdev(netdev); +} + struct net_device *hfi1_vnic_alloc_rn(struct ib_device *device, u8 port_num, enum rdma_netdev_t type, @@ -864,6 +873,7 @@ struct net_device *hfi1_vnic_alloc_rn(struct ib_device *device, vinfo->num_tx_q = dd->chip_sdma_engines; vinfo->num_rx_q = HFI1_NUM_VNIC_CTXT; vinfo->netdev = netdev; + rn->free_rdma_netdev = hfi1_vnic_free_rn; rn->set_id = hfi1_vnic_set_vesw_id; netdev->features = NETIF_F_HIGHDMA | NETIF_F_SG; @@ -892,12 +902,3 @@ struct net_device *hfi1_vnic_alloc_rn(struct ib_device *device, free_netdev(netdev); return ERR_PTR(rc); } - -void hfi1_vnic_free_rn(struct net_device *netdev) -{ - struct hfi1_vnic_vport_info *vinfo = opa_vnic_dev_priv(netdev); - - hfi1_vnic_deinit(vinfo); - mutex_destroy(&vinfo->lock); - free_netdev(netdev); -} diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 9ecc089d4529..afa5f6e88e1d 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -3542,6 +3542,11 @@ static int mlx5_ib_get_hw_stats(struct ib_device *ibdev, return num_counters; } +static void mlx5_ib_free_rdma_netdev(struct net_device *netdev) +{ + return mlx5_rdma_netdev_free(netdev); +} + static struct net_device* mlx5_ib_alloc_rdma_netdev(struct ib_device *hca, u8 port_num, @@ -3550,16 +3555,19 @@ mlx5_ib_alloc_rdma_netdev(struct ib_device *hca, unsigned char name_assign_type, void (*setup)(struct net_device *)) { + struct net_device *netdev; + struct rdma_netdev *rn; + if (type != RDMA_NETDEV_IPOIB) return ERR_PTR(-EOPNOTSUPP); - return mlx5_rdma_netdev_alloc(to_mdev(hca)->mdev, hca, - name, setup); -} - -static void mlx5_ib_free_rdma_netdev(struct net_device *netdev) -{ - return mlx5_rdma_netdev_free(netdev); + netdev = mlx5_rdma_netdev_alloc(to_mdev(hca)->mdev, hca, + name, setup); + if (likely(!IS_ERR_OR_NULL(netdev))) { + rn = netdev_priv(netdev); + rn->free_rdma_netdev = mlx5_ib_free_rdma_netdev; + } + return netdev; } static void *mlx5_ib_add(struct mlx5_core_dev *mdev) @@ -3692,10 +3700,9 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev) dev->ib_dev.check_mr_status = mlx5_ib_check_mr_status; dev->ib_dev.get_port_immutable = mlx5_port_immutable; dev->ib_dev.get_dev_fw_str = get_dev_fw_str; - if (MLX5_CAP_GEN(mdev, ipoib_enhanced_offloads)) { + if (MLX5_CAP_GEN(mdev, ipoib_enhanced_offloads)) dev->ib_dev.alloc_rdma_netdev = mlx5_ib_alloc_rdma_netdev; - dev->ib_dev.free_rdma_netdev = mlx5_ib_free_rdma_netdev; - } + if (mlx5_core_is_pf(mdev)) { dev->ib_dev.get_vf_config = mlx5_ib_get_vf_config; dev->ib_dev.set_vf_link_state = mlx5_ib_set_vf_link_state; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 1015a63de6ae..9ec0dbea3b6b 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1893,6 +1893,7 @@ static struct net_device rn->send = ipoib_send; rn->attach_mcast = ipoib_mcast_attach; rn->detach_mcast = ipoib_mcast_detach; + rn->free_rdma_netdev = free_netdev; rn->hca = hca; dev->netdev_ops = &ipoib_netdev_default_pf; @@ -2288,6 +2289,8 @@ static void ipoib_remove_one(struct ib_device *device, void *client_data) return; list_for_each_entry_safe(priv, tmp, dev_list, list) { + struct rdma_netdev *rn = netdev_priv(priv->dev); + ib_unregister_event_handler(&priv->event_handler); flush_workqueue(ipoib_workqueue); @@ -2304,10 +2307,7 @@ static void ipoib_remove_one(struct ib_device *device, void *client_data) flush_workqueue(priv->wq); unregister_netdev(priv->dev); - if (device->free_rdma_netdev) - device->free_rdma_netdev(priv->dev); - else - free_netdev(priv->dev); + rn->free_rdma_netdev(priv->dev); list_for_each_entry_safe(cpriv, tcpriv, &priv->child_intfs, list) kfree(cpriv); diff --git a/drivers/infiniband/ulp/opa_vnic/opa_vnic_netdev.c b/drivers/infiniband/ulp/opa_vnic/opa_vnic_netdev.c index 78d9007bc2f6..1a89c6033358 100644 --- a/drivers/infiniband/ulp/opa_vnic/opa_vnic_netdev.c +++ b/drivers/infiniband/ulp/opa_vnic/opa_vnic_netdev.c @@ -323,13 +323,13 @@ struct opa_vnic_adapter *opa_vnic_add_netdev(struct ib_device *ibdev, else if (IS_ERR(netdev)) return ERR_CAST(netdev); + rn = netdev_priv(netdev); adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); if (!adapter) { rc = -ENOMEM; goto adapter_err; } - rn = netdev_priv(netdev); rn->clnt_priv = adapter; rn->hca = ibdev; rn->port_num = port_num; @@ -366,7 +366,7 @@ struct opa_vnic_adapter *opa_vnic_add_netdev(struct ib_device *ibdev, mutex_destroy(&adapter->mactbl_lock); kfree(adapter); adapter_err: - ibdev->free_rdma_netdev(netdev); + rn->free_rdma_netdev(netdev); return ERR_PTR(rc); } @@ -375,7 +375,7 @@ struct opa_vnic_adapter *opa_vnic_add_netdev(struct ib_device *ibdev, void opa_vnic_rem_netdev(struct opa_vnic_adapter *adapter) { struct net_device *netdev = adapter->netdev; - struct ib_device *ibdev = adapter->ibdev; + struct rdma_netdev *rn = netdev_priv(netdev); v_info("removing\n"); unregister_netdev(netdev); @@ -383,5 +383,5 @@ void opa_vnic_rem_netdev(struct opa_vnic_adapter *adapter) mutex_destroy(&adapter->lock); mutex_destroy(&adapter->mactbl_lock); kfree(adapter); - ibdev->free_rdma_netdev(netdev); + rn->free_rdma_netdev(netdev); } diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index ba8314ec5768..71313d5ca1c8 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -1927,6 +1927,9 @@ struct rdma_netdev { struct ib_device *hca; u8 port_num; + /* cleanup function must be specified */ + void (*free_rdma_netdev)(struct net_device *netdev); + /* control functions */ void (*set_id)(struct net_device *netdev, int id); /* send packet */ @@ -2194,7 +2197,7 @@ struct ib_device { struct ib_udata *udata); int (*destroy_rwq_ind_table)(struct ib_rwq_ind_table *wq_ind_table); /** - * rdma netdev operations + * rdma netdev operation * * Driver implementing alloc_rdma_netdev must return -EOPNOTSUPP if it * doesn't support the specified rdma netdev type. @@ -2206,7 +2209,6 @@ struct ib_device { const char *name, unsigned char name_assign_type, void (*setup)(struct net_device *)); - void (*free_rdma_netdev)(struct net_device *netdev); struct module *owner; struct device dev;