Commit 31928a00 authored by Hyunchul Lee's avatar Hyunchul Lee Committed by Steve French
Browse files

ksmbd: register ksmbd ib client with ib_register_client()



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: default avatarHyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: default avatarNamjae Jeon <linkinjeon@kernel.org>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent d4eeb826
Loading
Loading
Loading
Loading
+97 −10
Original line number Diff line number Diff line
@@ -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 @@ static int smb_direct_listen(int port)
	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)
	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;

	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;
}

+1 −1
Original line number Diff line number Diff line
@@ -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; }