ucma.c

来自「linux 内核源代码」· C语言 代码 · 共 1,148 行 · 第 1/2 页

C
1,148
字号
	case 1:		ib_copy_path_rec_to_user(&resp->ib_route[0],					 &route->path_rec[0]);		break;	default:		break;	}}static ssize_t ucma_query_route(struct ucma_file *file,				const char __user *inbuf,				int in_len, int out_len){	struct rdma_ucm_query_route cmd;	struct rdma_ucm_query_route_resp resp;	struct ucma_context *ctx;	struct sockaddr *addr;	int ret = 0;	if (out_len < sizeof(resp))		return -ENOSPC;	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))		return -EFAULT;	ctx = ucma_get_ctx(file, cmd.id);	if (IS_ERR(ctx))		return PTR_ERR(ctx);	memset(&resp, 0, sizeof resp);	addr = &ctx->cm_id->route.addr.src_addr;	memcpy(&resp.src_addr, addr, addr->sa_family == AF_INET ?				     sizeof(struct sockaddr_in) :				     sizeof(struct sockaddr_in6));	addr = &ctx->cm_id->route.addr.dst_addr;	memcpy(&resp.dst_addr, addr, addr->sa_family == AF_INET ?				     sizeof(struct sockaddr_in) :				     sizeof(struct sockaddr_in6));	if (!ctx->cm_id->device)		goto out;	resp.node_guid = ctx->cm_id->device->node_guid;	resp.port_num = ctx->cm_id->port_num;	switch (rdma_node_get_transport(ctx->cm_id->device->node_type)) {	case RDMA_TRANSPORT_IB:		ucma_copy_ib_route(&resp, &ctx->cm_id->route);		break;	default:		break;	}out:	if (copy_to_user((void __user *)(unsigned long)cmd.response,			 &resp, sizeof(resp)))		ret = -EFAULT;	ucma_put_ctx(ctx);	return ret;}static void ucma_copy_conn_param(struct rdma_conn_param *dst,				 struct rdma_ucm_conn_param *src){	dst->private_data = src->private_data;	dst->private_data_len = src->private_data_len;	dst->responder_resources =src->responder_resources;	dst->initiator_depth = src->initiator_depth;	dst->flow_control = src->flow_control;	dst->retry_count = src->retry_count;	dst->rnr_retry_count = src->rnr_retry_count;	dst->srq = src->srq;	dst->qp_num = src->qp_num;}static ssize_t ucma_connect(struct ucma_file *file, const char __user *inbuf,			    int in_len, int out_len){	struct rdma_ucm_connect cmd;	struct rdma_conn_param conn_param;	struct ucma_context *ctx;	int ret;	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))		return -EFAULT;	if (!cmd.conn_param.valid)		return -EINVAL;	ctx = ucma_get_ctx(file, cmd.id);	if (IS_ERR(ctx))		return PTR_ERR(ctx);	ucma_copy_conn_param(&conn_param, &cmd.conn_param);	ret = rdma_connect(ctx->cm_id, &conn_param);	ucma_put_ctx(ctx);	return ret;}static ssize_t ucma_listen(struct ucma_file *file, const char __user *inbuf,			   int in_len, int out_len){	struct rdma_ucm_listen cmd;	struct ucma_context *ctx;	int ret;	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))		return -EFAULT;	ctx = ucma_get_ctx(file, cmd.id);	if (IS_ERR(ctx))		return PTR_ERR(ctx);	ctx->backlog = cmd.backlog > 0 && cmd.backlog < UCMA_MAX_BACKLOG ?		       cmd.backlog : UCMA_MAX_BACKLOG;	ret = rdma_listen(ctx->cm_id, ctx->backlog);	ucma_put_ctx(ctx);	return ret;}static ssize_t ucma_accept(struct ucma_file *file, const char __user *inbuf,			   int in_len, int out_len){	struct rdma_ucm_accept cmd;	struct rdma_conn_param conn_param;	struct ucma_context *ctx;	int ret;	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))		return -EFAULT;	ctx = ucma_get_ctx(file, cmd.id);	if (IS_ERR(ctx))		return PTR_ERR(ctx);	if (cmd.conn_param.valid) {		ctx->uid = cmd.uid;		ucma_copy_conn_param(&conn_param, &cmd.conn_param);		ret = rdma_accept(ctx->cm_id, &conn_param);	} else		ret = rdma_accept(ctx->cm_id, NULL);	ucma_put_ctx(ctx);	return ret;}static ssize_t ucma_reject(struct ucma_file *file, const char __user *inbuf,			   int in_len, int out_len){	struct rdma_ucm_reject cmd;	struct ucma_context *ctx;	int ret;	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))		return -EFAULT;	ctx = ucma_get_ctx(file, cmd.id);	if (IS_ERR(ctx))		return PTR_ERR(ctx);	ret = rdma_reject(ctx->cm_id, cmd.private_data, cmd.private_data_len);	ucma_put_ctx(ctx);	return ret;}static ssize_t ucma_disconnect(struct ucma_file *file, const char __user *inbuf,			       int in_len, int out_len){	struct rdma_ucm_disconnect cmd;	struct ucma_context *ctx;	int ret;	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))		return -EFAULT;	ctx = ucma_get_ctx(file, cmd.id);	if (IS_ERR(ctx))		return PTR_ERR(ctx);	ret = rdma_disconnect(ctx->cm_id);	ucma_put_ctx(ctx);	return ret;}static ssize_t ucma_init_qp_attr(struct ucma_file *file,				 const char __user *inbuf,				 int in_len, int out_len){	struct rdma_ucm_init_qp_attr cmd;	struct ib_uverbs_qp_attr resp;	struct ucma_context *ctx;	struct ib_qp_attr qp_attr;	int ret;	if (out_len < sizeof(resp))		return -ENOSPC;	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))		return -EFAULT;	ctx = ucma_get_ctx(file, cmd.id);	if (IS_ERR(ctx))		return PTR_ERR(ctx);	resp.qp_attr_mask = 0;	memset(&qp_attr, 0, sizeof qp_attr);	qp_attr.qp_state = cmd.qp_state;	ret = rdma_init_qp_attr(ctx->cm_id, &qp_attr, &resp.qp_attr_mask);	if (ret)		goto out;	ib_copy_qp_attr_to_user(&resp, &qp_attr);	if (copy_to_user((void __user *)(unsigned long)cmd.response,			 &resp, sizeof(resp)))		ret = -EFAULT;out:	ucma_put_ctx(ctx);	return ret;}static int ucma_set_option_id(struct ucma_context *ctx, int optname,			      void *optval, size_t optlen){	int ret = 0;	switch (optname) {	case RDMA_OPTION_ID_TOS:		if (optlen != sizeof(u8)) {			ret = -EINVAL;			break;		}		rdma_set_service_type(ctx->cm_id, *((u8 *) optval));		break;	default:		ret = -ENOSYS;	}	return ret;}static int ucma_set_option_level(struct ucma_context *ctx, int level,				 int optname, void *optval, size_t optlen){	int ret;	switch (level) {	case RDMA_OPTION_ID:		ret = ucma_set_option_id(ctx, optname, optval, optlen);		break;	default:		ret = -ENOSYS;	}	return ret;}static ssize_t ucma_set_option(struct ucma_file *file, const char __user *inbuf,			       int in_len, int out_len){	struct rdma_ucm_set_option cmd;	struct ucma_context *ctx;	void *optval;	int ret;	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))		return -EFAULT;	ctx = ucma_get_ctx(file, cmd.id);	if (IS_ERR(ctx))		return PTR_ERR(ctx);	optval = kmalloc(cmd.optlen, GFP_KERNEL);	if (!optval) {		ret = -ENOMEM;		goto out1;	}	if (copy_from_user(optval, (void __user *) (unsigned long) cmd.optval,			   cmd.optlen)) {		ret = -EFAULT;		goto out2;	}	ret = ucma_set_option_level(ctx, cmd.level, cmd.optname, optval,				    cmd.optlen);out2:	kfree(optval);out1:	ucma_put_ctx(ctx);	return ret;}static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf,			   int in_len, int out_len){	struct rdma_ucm_notify cmd;	struct ucma_context *ctx;	int ret;	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))		return -EFAULT;	ctx = ucma_get_ctx(file, cmd.id);	if (IS_ERR(ctx))		return PTR_ERR(ctx);	ret = rdma_notify(ctx->cm_id, (enum ib_event_type) cmd.event);	ucma_put_ctx(ctx);	return ret;}static ssize_t ucma_join_multicast(struct ucma_file *file,				   const char __user *inbuf,				   int in_len, int out_len){	struct rdma_ucm_join_mcast cmd;	struct rdma_ucm_create_id_resp resp;	struct ucma_context *ctx;	struct ucma_multicast *mc;	int ret;	if (out_len < sizeof(resp))		return -ENOSPC;	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))		return -EFAULT;	ctx = ucma_get_ctx(file, cmd.id);	if (IS_ERR(ctx))		return PTR_ERR(ctx);	mutex_lock(&file->mut);	mc = ucma_alloc_multicast(ctx);	if (IS_ERR(mc)) {		ret = PTR_ERR(mc);		goto err1;	}	mc->uid = cmd.uid;	memcpy(&mc->addr, &cmd.addr, sizeof cmd.addr);	ret = rdma_join_multicast(ctx->cm_id, &mc->addr, mc);	if (ret)		goto err2;	resp.id = mc->id;	if (copy_to_user((void __user *)(unsigned long)cmd.response,			 &resp, sizeof(resp))) {		ret = -EFAULT;		goto err3;	}	mutex_unlock(&file->mut);	ucma_put_ctx(ctx);	return 0;err3:	rdma_leave_multicast(ctx->cm_id, &mc->addr);	ucma_cleanup_mc_events(mc);err2:	mutex_lock(&mut);	idr_remove(&multicast_idr, mc->id);	mutex_unlock(&mut);	list_del(&mc->list);	kfree(mc);err1:	mutex_unlock(&file->mut);	ucma_put_ctx(ctx);	return ret;}static ssize_t ucma_leave_multicast(struct ucma_file *file,				    const char __user *inbuf,				    int in_len, int out_len){	struct rdma_ucm_destroy_id cmd;	struct rdma_ucm_destroy_id_resp resp;	struct ucma_multicast *mc;	int ret = 0;	if (out_len < sizeof(resp))		return -ENOSPC;	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))		return -EFAULT;	mutex_lock(&mut);	mc = idr_find(&multicast_idr, cmd.id);	if (!mc)		mc = ERR_PTR(-ENOENT);	else if (mc->ctx->file != file)		mc = ERR_PTR(-EINVAL);	else {		idr_remove(&multicast_idr, mc->id);		atomic_inc(&mc->ctx->ref);	}	mutex_unlock(&mut);	if (IS_ERR(mc)) {		ret = PTR_ERR(mc);		goto out;	}	rdma_leave_multicast(mc->ctx->cm_id, &mc->addr);	mutex_lock(&mc->ctx->file->mut);	ucma_cleanup_mc_events(mc);	list_del(&mc->list);	mutex_unlock(&mc->ctx->file->mut);	ucma_put_ctx(mc->ctx);	resp.events_reported = mc->events_reported;	kfree(mc);	if (copy_to_user((void __user *)(unsigned long)cmd.response,			 &resp, sizeof(resp)))		ret = -EFAULT;out:	return ret;}static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,				   const char __user *inbuf,				   int in_len, int out_len) = {	[RDMA_USER_CM_CMD_CREATE_ID]	= ucma_create_id,	[RDMA_USER_CM_CMD_DESTROY_ID]	= ucma_destroy_id,	[RDMA_USER_CM_CMD_BIND_ADDR]	= ucma_bind_addr,	[RDMA_USER_CM_CMD_RESOLVE_ADDR]	= ucma_resolve_addr,	[RDMA_USER_CM_CMD_RESOLVE_ROUTE]= ucma_resolve_route,	[RDMA_USER_CM_CMD_QUERY_ROUTE]	= ucma_query_route,	[RDMA_USER_CM_CMD_CONNECT]	= ucma_connect,	[RDMA_USER_CM_CMD_LISTEN]	= ucma_listen,	[RDMA_USER_CM_CMD_ACCEPT]	= ucma_accept,	[RDMA_USER_CM_CMD_REJECT]	= ucma_reject,	[RDMA_USER_CM_CMD_DISCONNECT]	= ucma_disconnect,	[RDMA_USER_CM_CMD_INIT_QP_ATTR]	= ucma_init_qp_attr,	[RDMA_USER_CM_CMD_GET_EVENT]	= ucma_get_event,	[RDMA_USER_CM_CMD_GET_OPTION]	= NULL,	[RDMA_USER_CM_CMD_SET_OPTION]	= ucma_set_option,	[RDMA_USER_CM_CMD_NOTIFY]	= ucma_notify,	[RDMA_USER_CM_CMD_JOIN_MCAST]	= ucma_join_multicast,	[RDMA_USER_CM_CMD_LEAVE_MCAST]	= ucma_leave_multicast,};static ssize_t ucma_write(struct file *filp, const char __user *buf,			  size_t len, loff_t *pos){	struct ucma_file *file = filp->private_data;	struct rdma_ucm_cmd_hdr hdr;	ssize_t ret;	if (len < sizeof(hdr))		return -EINVAL;	if (copy_from_user(&hdr, buf, sizeof(hdr)))		return -EFAULT;	if (hdr.cmd < 0 || hdr.cmd >= ARRAY_SIZE(ucma_cmd_table))		return -EINVAL;	if (hdr.in + sizeof(hdr) > len)		return -EINVAL;	if (!ucma_cmd_table[hdr.cmd])		return -ENOSYS;	ret = ucma_cmd_table[hdr.cmd](file, buf + sizeof(hdr), hdr.in, hdr.out);	if (!ret)		ret = len;	return ret;}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;}static int ucma_open(struct inode *inode, struct file *filp){	struct ucma_file *file;	file = kmalloc(sizeof *file, GFP_KERNEL);	if (!file)		return -ENOMEM;	INIT_LIST_HEAD(&file->event_list);	INIT_LIST_HEAD(&file->ctx_list);	init_waitqueue_head(&file->poll_wait);	mutex_init(&file->mut);	filp->private_data = file;	file->filp = filp;	return 0;}static int ucma_close(struct inode *inode, struct file *filp){	struct ucma_file *file = filp->private_data;	struct ucma_context *ctx, *tmp;	mutex_lock(&file->mut);	list_for_each_entry_safe(ctx, tmp, &file->ctx_list, list) {		mutex_unlock(&file->mut);		mutex_lock(&mut);		idr_remove(&ctx_idr, ctx->id);		mutex_unlock(&mut);		ucma_free_ctx(ctx);		mutex_lock(&file->mut);	}	mutex_unlock(&file->mut);	kfree(file);	return 0;}static const struct file_operations ucma_fops = {	.owner 	 = THIS_MODULE,	.open 	 = ucma_open,	.release = ucma_close,	.write	 = ucma_write,	.poll    = ucma_poll,};static struct miscdevice ucma_misc = {	.minor	= MISC_DYNAMIC_MINOR,	.name	= "rdma_cm",	.fops	= &ucma_fops,};static ssize_t show_abi_version(struct device *dev,				struct device_attribute *attr,				char *buf){	return sprintf(buf, "%d\n", RDMA_USER_CM_ABI_VERSION);}static DEVICE_ATTR(abi_version, S_IRUGO, show_abi_version, NULL);static int __init ucma_init(void){	int ret;	ret = misc_register(&ucma_misc);	if (ret)		return ret;	ret = device_create_file(ucma_misc.this_device, &dev_attr_abi_version);	if (ret) {		printk(KERN_ERR "rdma_ucm: couldn't create abi_version attr\n");		goto err;	}	return 0;err:	misc_deregister(&ucma_misc);	return ret;}static void __exit ucma_cleanup(void){	device_remove_file(ucma_misc.this_device, &dev_attr_abi_version);	misc_deregister(&ucma_misc);	idr_destroy(&ctx_idr);}module_init(ucma_init);module_exit(ucma_cleanup);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?