ucm.c

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

C
1,349
字号
		}	}	if (uevent->info) {		if (cmd.info_len < uevent->info_len) {			result = -ENOMEM;			goto done;		}		if (copy_to_user((void __user *)(unsigned long)cmd.info,				 uevent->info, uevent->info_len)) {			result = -EFAULT;			goto done;		}	}	list_del(&uevent->file_list);	list_del(&uevent->ctx_list);	uevent->ctx->events_reported++;	kfree(uevent->data);	kfree(uevent->info);	kfree(uevent);done:	mutex_unlock(&file->file_mutex);	return result;}static ssize_t ib_ucm_create_id(struct ib_ucm_file *file,				const char __user *inbuf,				int in_len, int out_len){	struct ib_ucm_create_id cmd;	struct ib_ucm_create_id_resp resp;	struct ib_ucm_context *ctx;	int result;	if (out_len < sizeof(resp))		return -ENOSPC;	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))		return -EFAULT;	mutex_lock(&file->file_mutex);	ctx = ib_ucm_ctx_alloc(file);	mutex_unlock(&file->file_mutex);	if (!ctx)		return -ENOMEM;	ctx->uid = cmd.uid;	ctx->cm_id = ib_create_cm_id(file->device->ib_dev,				     ib_ucm_event_handler, ctx);	if (IS_ERR(ctx->cm_id)) {		result = PTR_ERR(ctx->cm_id);		goto err1;	}	resp.id = ctx->id;	if (copy_to_user((void __user *)(unsigned long)cmd.response,			 &resp, sizeof(resp))) {		result = -EFAULT;		goto err2;	}	return 0;err2:	ib_destroy_cm_id(ctx->cm_id);err1:	mutex_lock(&ctx_id_mutex);	idr_remove(&ctx_id_table, ctx->id);	mutex_unlock(&ctx_id_mutex);	kfree(ctx);	return result;}static ssize_t ib_ucm_destroy_id(struct ib_ucm_file *file,				 const char __user *inbuf,				 int in_len, int out_len){	struct ib_ucm_destroy_id cmd;	struct ib_ucm_destroy_id_resp resp;	struct ib_ucm_context *ctx;	int result = 0;	if (out_len < sizeof(resp))		return -ENOSPC;	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))		return -EFAULT;	mutex_lock(&ctx_id_mutex);	ctx = idr_find(&ctx_id_table, cmd.id);	if (!ctx)		ctx = ERR_PTR(-ENOENT);	else if (ctx->file != file)		ctx = ERR_PTR(-EINVAL);	else		idr_remove(&ctx_id_table, ctx->id);	mutex_unlock(&ctx_id_mutex);	if (IS_ERR(ctx))		return PTR_ERR(ctx);	ib_ucm_ctx_put(ctx);	wait_for_completion(&ctx->comp);	/* No new events will be generated after destroying the cm_id. */	ib_destroy_cm_id(ctx->cm_id);	/* Cleanup events not yet reported to the user. */	ib_ucm_cleanup_events(ctx);	resp.events_reported = ctx->events_reported;	if (copy_to_user((void __user *)(unsigned long)cmd.response,			 &resp, sizeof(resp)))		result = -EFAULT;	kfree(ctx);	return result;}static ssize_t ib_ucm_attr_id(struct ib_ucm_file *file,			      const char __user *inbuf,			      int in_len, int out_len){	struct ib_ucm_attr_id_resp resp;	struct ib_ucm_attr_id cmd;	struct ib_ucm_context *ctx;	int result = 0;	if (out_len < sizeof(resp))		return -ENOSPC;	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))		return -EFAULT;	ctx = ib_ucm_ctx_get(file, cmd.id);	if (IS_ERR(ctx))		return PTR_ERR(ctx);	resp.service_id   = ctx->cm_id->service_id;	resp.service_mask = ctx->cm_id->service_mask;	resp.local_id     = ctx->cm_id->local_id;	resp.remote_id    = ctx->cm_id->remote_id;	if (copy_to_user((void __user *)(unsigned long)cmd.response,			 &resp, sizeof(resp)))		result = -EFAULT;	ib_ucm_ctx_put(ctx);	return result;}static ssize_t ib_ucm_init_qp_attr(struct ib_ucm_file *file,				   const char __user *inbuf,				   int in_len, int out_len){	struct ib_uverbs_qp_attr resp;	struct ib_ucm_init_qp_attr cmd;	struct ib_ucm_context *ctx;	struct ib_qp_attr qp_attr;	int result = 0;	if (out_len < sizeof(resp))		return -ENOSPC;	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))		return -EFAULT;	ctx = ib_ucm_ctx_get(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;	result = ib_cm_init_qp_attr(ctx->cm_id, &qp_attr, &resp.qp_attr_mask);	if (result)		goto out;	ib_copy_qp_attr_to_user(&resp, &qp_attr);	if (copy_to_user((void __user *)(unsigned long)cmd.response,			 &resp, sizeof(resp)))		result = -EFAULT;out:	ib_ucm_ctx_put(ctx);	return result;}static int ucm_validate_listen(__be64 service_id, __be64 service_mask){	service_id &= service_mask;	if (((service_id & IB_CMA_SERVICE_ID_MASK) == IB_CMA_SERVICE_ID) ||	    ((service_id & IB_SDP_SERVICE_ID_MASK) == IB_SDP_SERVICE_ID))		return -EINVAL;	return 0;}static ssize_t ib_ucm_listen(struct ib_ucm_file *file,			     const char __user *inbuf,			     int in_len, int out_len){	struct ib_ucm_listen cmd;	struct ib_ucm_context *ctx;	int result;	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))		return -EFAULT;	ctx = ib_ucm_ctx_get(file, cmd.id);	if (IS_ERR(ctx))		return PTR_ERR(ctx);	result = ucm_validate_listen(cmd.service_id, cmd.service_mask);	if (result)		goto out;	result = ib_cm_listen(ctx->cm_id, cmd.service_id, cmd.service_mask,			      NULL);out:	ib_ucm_ctx_put(ctx);	return result;}static ssize_t ib_ucm_notify(struct ib_ucm_file *file,			     const char __user *inbuf,			     int in_len, int out_len){	struct ib_ucm_notify cmd;	struct ib_ucm_context *ctx;	int result;	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))		return -EFAULT;	ctx = ib_ucm_ctx_get(file, cmd.id);	if (IS_ERR(ctx))		return PTR_ERR(ctx);	result = ib_cm_notify(ctx->cm_id, (enum ib_event_type) cmd.event);	ib_ucm_ctx_put(ctx);	return result;}static int ib_ucm_alloc_data(const void **dest, u64 src, u32 len){	void *data;	*dest = NULL;	if (!len)		return 0;	data = kmalloc(len, GFP_KERNEL);	if (!data)		return -ENOMEM;	if (copy_from_user(data, (void __user *)(unsigned long)src, len)) {		kfree(data);		return -EFAULT;	}	*dest = data;	return 0;}static int ib_ucm_path_get(struct ib_sa_path_rec **path, u64 src){	struct ib_user_path_rec upath;	struct ib_sa_path_rec  *sa_path;	*path = NULL;	if (!src)		return 0;	sa_path = kmalloc(sizeof(*sa_path), GFP_KERNEL);	if (!sa_path)		return -ENOMEM;	if (copy_from_user(&upath, (void __user *)(unsigned long)src,			   sizeof(upath))) {		kfree(sa_path);		return -EFAULT;	}	ib_copy_path_rec_from_user(sa_path, &upath);	*path = sa_path;	return 0;}static ssize_t ib_ucm_send_req(struct ib_ucm_file *file,			       const char __user *inbuf,			       int in_len, int out_len){	struct ib_cm_req_param param;	struct ib_ucm_context *ctx;	struct ib_ucm_req cmd;	int result;	param.private_data   = NULL;	param.primary_path   = NULL;	param.alternate_path = NULL;	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))		return -EFAULT;	result = ib_ucm_alloc_data(&param.private_data, cmd.data, cmd.len);	if (result)		goto done;	result = ib_ucm_path_get(&param.primary_path, cmd.primary_path);	if (result)		goto done;	result = ib_ucm_path_get(&param.alternate_path, cmd.alternate_path);	if (result)		goto done;	param.private_data_len           = cmd.len;	param.service_id                 = cmd.sid;	param.qp_num                     = cmd.qpn;	param.qp_type                    = cmd.qp_type;	param.starting_psn               = cmd.psn;	param.peer_to_peer               = cmd.peer_to_peer;	param.responder_resources        = cmd.responder_resources;	param.initiator_depth            = cmd.initiator_depth;	param.remote_cm_response_timeout = cmd.remote_cm_response_timeout;	param.flow_control               = cmd.flow_control;	param.local_cm_response_timeout  = cmd.local_cm_response_timeout;	param.retry_count                = cmd.retry_count;	param.rnr_retry_count            = cmd.rnr_retry_count;	param.max_cm_retries             = cmd.max_cm_retries;	param.srq                        = cmd.srq;	ctx = ib_ucm_ctx_get(file, cmd.id);	if (!IS_ERR(ctx)) {		result = ib_send_cm_req(ctx->cm_id, &param);		ib_ucm_ctx_put(ctx);	} else		result = PTR_ERR(ctx);done:	kfree(param.private_data);	kfree(param.primary_path);	kfree(param.alternate_path);	return result;}static ssize_t ib_ucm_send_rep(struct ib_ucm_file *file,			       const char __user *inbuf,			       int in_len, int out_len){	struct ib_cm_rep_param param;	struct ib_ucm_context *ctx;	struct ib_ucm_rep cmd;	int result;	param.private_data = NULL;	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))		return -EFAULT;	result = ib_ucm_alloc_data(&param.private_data, cmd.data, cmd.len);	if (result)		return result;	param.qp_num              = cmd.qpn;	param.starting_psn        = cmd.psn;	param.private_data_len    = cmd.len;	param.responder_resources = cmd.responder_resources;	param.initiator_depth     = cmd.initiator_depth;	param.failover_accepted   = cmd.failover_accepted;	param.flow_control        = cmd.flow_control;	param.rnr_retry_count     = cmd.rnr_retry_count;	param.srq                 = cmd.srq;	ctx = ib_ucm_ctx_get(file, cmd.id);	if (!IS_ERR(ctx)) {		ctx->uid = cmd.uid;		result = ib_send_cm_rep(ctx->cm_id, &param);		ib_ucm_ctx_put(ctx);	} else		result = PTR_ERR(ctx);	kfree(param.private_data);	return result;}static ssize_t ib_ucm_send_private_data(struct ib_ucm_file *file,					const char __user *inbuf, int in_len,					int (*func)(struct ib_cm_id *cm_id,						    const void *private_data,						    u8 private_data_len)){	struct ib_ucm_private_data cmd;	struct ib_ucm_context *ctx;	const void *private_data = NULL;	int result;	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))		return -EFAULT;	result = ib_ucm_alloc_data(&private_data, cmd.data, cmd.len);	if (result)		return result;	ctx = ib_ucm_ctx_get(file, cmd.id);	if (!IS_ERR(ctx)) {		result = func(ctx->cm_id, private_data, cmd.len);		ib_ucm_ctx_put(ctx);	} else		result = PTR_ERR(ctx);	kfree(private_data);	return result;}static ssize_t ib_ucm_send_rtu(struct ib_ucm_file *file,			       const char __user *inbuf,			       int in_len, int out_len){	return ib_ucm_send_private_data(file, inbuf, in_len, ib_send_cm_rtu);}static ssize_t ib_ucm_send_dreq(struct ib_ucm_file *file,				const char __user *inbuf,				int in_len, int out_len){	return ib_ucm_send_private_data(file, inbuf, in_len, ib_send_cm_dreq);}static ssize_t ib_ucm_send_drep(struct ib_ucm_file *file,				const char __user *inbuf,				int in_len, int out_len){	return ib_ucm_send_private_data(file, inbuf, in_len, ib_send_cm_drep);}static ssize_t ib_ucm_send_info(struct ib_ucm_file *file,				const char __user *inbuf, int in_len,				int (*func)(struct ib_cm_id *cm_id,					    int status,					    const void *info,					    u8 info_len,					    const void *data,					    u8 data_len))

⌨️ 快捷键说明

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