ksmbd: register ksmbd ib client with ib_register_client()
authorHyunchul Lee <hyc.lee@gmail.com>
Wed, 29 Dec 2021 14:02:15 +0000 (23:02 +0900)
committerSteve French <stfrench@microsoft.com>
Mon, 10 Jan 2022 18:44:19 +0000 (12:44 -0600)
Register ksmbd ib client with ib_register_client() to find the rdma capable
network adapter. If ops.get_netdev(Chelsio NICs) is NULL, ksmbd will find
it using ib_device_get_by_netdev in old way.

Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/ksmbd/transport_rdma.c
fs/ksmbd/transport_rdma.h

index 7e57cbb..339fa4f 100644 (file)
@@ -79,6 +79,14 @@ static int smb_direct_max_read_write_size = 1024 * 1024;
 
 static int smb_direct_max_outstanding_rw_ops = 8;
 
+static LIST_HEAD(smb_direct_device_list);
+static DEFINE_RWLOCK(smb_direct_device_lock);
+
+struct smb_direct_device {
+       struct ib_device        *ib_dev;
+       struct list_head        list;
+};
+
 static struct smb_direct_listener {
        struct rdma_cm_id       *cm_id;
 } smb_direct_listener;
@@ -2007,12 +2015,61 @@ err:
        return ret;
 }
 
+static int smb_direct_ib_client_add(struct ib_device *ib_dev)
+{
+       struct smb_direct_device *smb_dev;
+
+       if (!ib_dev->ops.get_netdev ||
+           !rdma_frwr_is_supported(&ib_dev->attrs))
+               return 0;
+
+       smb_dev = kzalloc(sizeof(*smb_dev), GFP_KERNEL);
+       if (!smb_dev)
+               return -ENOMEM;
+       smb_dev->ib_dev = ib_dev;
+
+       write_lock(&smb_direct_device_lock);
+       list_add(&smb_dev->list, &smb_direct_device_list);
+       write_unlock(&smb_direct_device_lock);
+
+       ksmbd_debug(RDMA, "ib device added: name %s\n", ib_dev->name);
+       return 0;
+}
+
+static void smb_direct_ib_client_remove(struct ib_device *ib_dev,
+                                       void *client_data)
+{
+       struct smb_direct_device *smb_dev, *tmp;
+
+       write_lock(&smb_direct_device_lock);
+       list_for_each_entry_safe(smb_dev, tmp, &smb_direct_device_list, list) {
+               if (smb_dev->ib_dev == ib_dev) {
+                       list_del(&smb_dev->list);
+                       kfree(smb_dev);
+                       break;
+               }
+       }
+       write_unlock(&smb_direct_device_lock);
+}
+
+static struct ib_client smb_direct_ib_client = {
+       .name   = "ksmbd_smb_direct_ib",
+       .add    = smb_direct_ib_client_add,
+       .remove = smb_direct_ib_client_remove,
+};
+
 int ksmbd_rdma_init(void)
 {
        int ret;
 
        smb_direct_listener.cm_id = NULL;
 
+       ret = ib_register_client(&smb_direct_ib_client);
+       if (ret) {
+               pr_err("failed to ib_register_client\n");
+               return ret;
+       }
+
        /* When a client is running out of send credits, the credits are
         * granted by the server's sending a packet using this queue.
         * This avoids the situation that a clients cannot send packets
@@ -2036,30 +2093,60 @@ int ksmbd_rdma_init(void)
        return 0;
 }
 
-int ksmbd_rdma_destroy(void)
+void ksmbd_rdma_destroy(void)
 {
-       if (smb_direct_listener.cm_id)
-               rdma_destroy_id(smb_direct_listener.cm_id);
+       if (!smb_direct_listener.cm_id)
+               return;
+
+       ib_unregister_client(&smb_direct_ib_client);
+       rdma_destroy_id(smb_direct_listener.cm_id);
+
        smb_direct_listener.cm_id = NULL;
 
        if (smb_direct_wq) {
                destroy_workqueue(smb_direct_wq);
                smb_direct_wq = NULL;
        }
-       return 0;
 }
 
 bool ksmbd_rdma_capable_netdev(struct net_device *netdev)
 {
-       struct ib_device *ibdev;
+       struct smb_direct_device *smb_dev;
+       int i;
        bool rdma_capable = false;
 
-       ibdev = ib_device_get_by_netdev(netdev, RDMA_DRIVER_UNKNOWN);
-       if (ibdev) {
-               if (rdma_frwr_is_supported(&ibdev->attrs))
-                       rdma_capable = true;
-               ib_device_put(ibdev);
+       read_lock(&smb_direct_device_lock);
+       list_for_each_entry(smb_dev, &smb_direct_device_list, list) {
+               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 (ndev == netdev) {
+                               dev_put(ndev);
+                               rdma_capable = true;
+                               goto out;
+                       }
+                       dev_put(ndev);
+               }
+       }
+out:
+       read_unlock(&smb_direct_device_lock);
+
+       if (rdma_capable == false) {
+               struct ib_device *ibdev;
+
+               ibdev = ib_device_get_by_netdev(netdev, RDMA_DRIVER_UNKNOWN);
+               if (ibdev) {
+                       if (rdma_frwr_is_supported(&ibdev->attrs))
+                               rdma_capable = true;
+                       ib_device_put(ibdev);
+               }
        }
+
        return rdma_capable;
 }
 
index 0fa8adc..ab9250a 100644 (file)
@@ -52,7 +52,7 @@ struct smb_direct_data_transfer {
 
 #ifdef CONFIG_SMB_SERVER_SMBDIRECT
 int ksmbd_rdma_init(void);
-int ksmbd_rdma_destroy(void);
+void ksmbd_rdma_destroy(void);
 bool ksmbd_rdma_capable_netdev(struct net_device *netdev);
 #else
 static inline int ksmbd_rdma_init(void) { return 0; }