ksmbd: fix missing RDMA-capable flag for IPoIB device in ksmbd_rdma_capable_netdev()
authorKangjing Huang <huangkangjing@gmail.com>
Sun, 31 Dec 2023 07:19:04 +0000 (16:19 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 5 Jan 2024 14:19:38 +0000 (15:19 +0100)
[ Upstream commit ecce70cf17d91c3dd87a0c4ea00b2d1387729701 ]

Physical ib_device does not have an underlying net_device, thus its
association with IPoIB net_device cannot be retrieved via
ops.get_netdev() or ib_device_get_by_netdev(). ksmbd reads physical
ib_device port GUID from the lower 16 bytes of the hardware addresses on
IPoIB net_device and match its underlying ib_device using ib_find_gid()

Signed-off-by: Kangjing Huang <huangkangjing@gmail.com>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Reviewed-by: Tom Talpey <tom@talpey.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/smb/server/transport_rdma.c

index 3b269e1..c5629a6 100644 (file)
@@ -2140,8 +2140,7 @@ static int smb_direct_ib_client_add(struct ib_device *ib_dev)
        if (ib_dev->node_type != RDMA_NODE_IB_CA)
                smb_direct_port = SMB_DIRECT_PORT_IWARP;
 
-       if (!ib_dev->ops.get_netdev ||
-           !rdma_frwr_is_supported(&ib_dev->attrs))
+       if (!rdma_frwr_is_supported(&ib_dev->attrs))
                return 0;
 
        smb_dev = kzalloc(sizeof(*smb_dev), GFP_KERNEL);
@@ -2241,17 +2240,38 @@ bool ksmbd_rdma_capable_netdev(struct net_device *netdev)
                for (i = 0; i < smb_dev->ib_dev->phys_port_cnt; i++) {
                        struct net_device *ndev;
 
-                       ndev = smb_dev->ib_dev->ops.get_netdev(smb_dev->ib_dev,
-                                                              i + 1);
-                       if (!ndev)
-                               continue;
+                       if (smb_dev->ib_dev->ops.get_netdev) {
+                               ndev = smb_dev->ib_dev->ops.get_netdev(
+                                       smb_dev->ib_dev, i + 1);
+                               if (!ndev)
+                                       continue;
 
-                       if (ndev == netdev) {
+                               if (ndev == netdev) {
+                                       dev_put(ndev);
+                                       rdma_capable = true;
+                                       goto out;
+                               }
                                dev_put(ndev);
-                               rdma_capable = true;
-                               goto out;
+                       /* if ib_dev does not implement ops.get_netdev
+                        * check for matching infiniband GUID in hw_addr
+                        */
+                       } else if (netdev->type == ARPHRD_INFINIBAND) {
+                               struct netdev_hw_addr *ha;
+                               union ib_gid gid;
+                               u32 port_num;
+                               int ret;
+
+                               netdev_hw_addr_list_for_each(
+                                       ha, &netdev->dev_addrs) {
+                                       memcpy(&gid, ha->addr + 4, sizeof(gid));
+                                       ret = ib_find_gid(smb_dev->ib_dev, &gid,
+                                                         &port_num, NULL);
+                                       if (!ret) {
+                                               rdma_capable = true;
+                                               goto out;
+                                       }
+                               }
                        }
-                       dev_put(ndev);
                }
        }
 out: