⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ucm.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (c) 2005 Topspin Communications.  All rights reserved. * Copyright (c) 2005 Intel Corporation.  All rights reserved. * * This software is available to you under a choice of one of two * licenses.  You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * *     Redistribution and use in source and binary forms, with or *     without modification, are permitted provided that the following *     conditions are met: * *      - Redistributions of source code must retain the above *	copyright notice, this list of conditions and the following *	disclaimer. * *      - Redistributions in binary form must reproduce the above *	copyright notice, this list of conditions and the following *	disclaimer in the documentation and/or other materials *	provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * $Id: ucm.c 2594 2005-06-13 19:46:02Z libor $ */#include <linux/init.h>#include <linux/fs.h>#include <linux/module.h>#include <linux/device.h>#include <linux/err.h>#include <linux/poll.h>#include <linux/file.h>#include <linux/mount.h>#include <linux/cdev.h>#include <linux/idr.h>#include <asm/uaccess.h>#include <rdma/ib_cm.h>#include <rdma/ib_user_cm.h>MODULE_AUTHOR("Libor Michalek");MODULE_DESCRIPTION("InfiniBand userspace Connection Manager access");MODULE_LICENSE("Dual BSD/GPL");struct ib_ucm_device {	int			devnum;	struct cdev		dev;	struct class_device	class_dev;	struct ib_device	*ib_dev;};struct ib_ucm_file {	struct semaphore mutex;	struct file *filp;	struct ib_ucm_device *device;	struct list_head  ctxs;	struct list_head  events;	wait_queue_head_t poll_wait;};struct ib_ucm_context {	int                 id;	wait_queue_head_t   wait;	atomic_t            ref;	int		    events_reported;	struct ib_ucm_file *file;	struct ib_cm_id    *cm_id;	__u64		   uid;	struct list_head    events;    /* list of pending events. */	struct list_head    file_list; /* member in file ctx list */};struct ib_ucm_event {	struct ib_ucm_context *ctx;	struct list_head file_list; /* member in file event list */	struct list_head ctx_list;  /* member in ctx event list */	struct ib_cm_id *cm_id;	struct ib_ucm_event_resp resp;	void *data;	void *info;	int data_len;	int info_len;};enum {	IB_UCM_MAJOR = 231,	IB_UCM_BASE_MINOR = 224,	IB_UCM_MAX_DEVICES = 32};#define IB_UCM_BASE_DEV MKDEV(IB_UCM_MAJOR, IB_UCM_BASE_MINOR)static void ib_ucm_add_one(struct ib_device *device);static void ib_ucm_remove_one(struct ib_device *device);static struct ib_client ucm_client = {	.name   = "ucm",	.add    = ib_ucm_add_one,	.remove = ib_ucm_remove_one};static DECLARE_MUTEX(ctx_id_mutex);static DEFINE_IDR(ctx_id_table);static DECLARE_BITMAP(dev_map, IB_UCM_MAX_DEVICES);static struct ib_ucm_context *ib_ucm_ctx_get(struct ib_ucm_file *file, int id){	struct ib_ucm_context *ctx;	down(&ctx_id_mutex);	ctx = idr_find(&ctx_id_table, id);	if (!ctx)		ctx = ERR_PTR(-ENOENT);	else if (ctx->file != file)		ctx = ERR_PTR(-EINVAL);	else		atomic_inc(&ctx->ref);	up(&ctx_id_mutex);	return ctx;}static void ib_ucm_ctx_put(struct ib_ucm_context *ctx){	if (atomic_dec_and_test(&ctx->ref))		wake_up(&ctx->wait);}static inline int ib_ucm_new_cm_id(int event){	return event == IB_CM_REQ_RECEIVED || event == IB_CM_SIDR_REQ_RECEIVED;}static void ib_ucm_cleanup_events(struct ib_ucm_context *ctx){	struct ib_ucm_event *uevent;	down(&ctx->file->mutex);	list_del(&ctx->file_list);	while (!list_empty(&ctx->events)) {		uevent = list_entry(ctx->events.next,				    struct ib_ucm_event, ctx_list);		list_del(&uevent->file_list);		list_del(&uevent->ctx_list);		/* clear incoming connections. */		if (ib_ucm_new_cm_id(uevent->resp.event))			ib_destroy_cm_id(uevent->cm_id);		kfree(uevent);	}	up(&ctx->file->mutex);}static struct ib_ucm_context *ib_ucm_ctx_alloc(struct ib_ucm_file *file){	struct ib_ucm_context *ctx;	int result;	ctx = kzalloc(sizeof *ctx, GFP_KERNEL);	if (!ctx)		return NULL;	atomic_set(&ctx->ref, 1);	init_waitqueue_head(&ctx->wait);	ctx->file = file;	INIT_LIST_HEAD(&ctx->events);	do {		result = idr_pre_get(&ctx_id_table, GFP_KERNEL);		if (!result)			goto error;		down(&ctx_id_mutex);		result = idr_get_new(&ctx_id_table, ctx, &ctx->id);		up(&ctx_id_mutex);	} while (result == -EAGAIN);	if (result)		goto error;	list_add_tail(&ctx->file_list, &file->ctxs);	return ctx;error:	kfree(ctx);	return NULL;}static void ib_ucm_event_path_get(struct ib_ucm_path_rec *upath,				  struct ib_sa_path_rec	 *kpath){	if (!kpath || !upath)		return;	memcpy(upath->dgid, kpath->dgid.raw, sizeof *upath->dgid);	memcpy(upath->sgid, kpath->sgid.raw, sizeof *upath->sgid);	upath->dlid             = kpath->dlid;	upath->slid             = kpath->slid;	upath->raw_traffic      = kpath->raw_traffic;	upath->flow_label       = kpath->flow_label;	upath->hop_limit        = kpath->hop_limit;	upath->traffic_class    = kpath->traffic_class;	upath->reversible       = kpath->reversible;	upath->numb_path        = kpath->numb_path;	upath->pkey             = kpath->pkey;	upath->sl	        = kpath->sl;	upath->mtu_selector     = kpath->mtu_selector;	upath->mtu              = kpath->mtu;	upath->rate_selector    = kpath->rate_selector;	upath->rate             = kpath->rate;	upath->packet_life_time = kpath->packet_life_time;	upath->preference       = kpath->preference;	upath->packet_life_time_selector =		kpath->packet_life_time_selector;}static void ib_ucm_event_req_get(struct ib_ucm_req_event_resp *ureq,				 struct ib_cm_req_event_param *kreq){	ureq->remote_ca_guid             = kreq->remote_ca_guid;	ureq->remote_qkey                = kreq->remote_qkey;	ureq->remote_qpn                 = kreq->remote_qpn;	ureq->qp_type                    = kreq->qp_type;	ureq->starting_psn               = kreq->starting_psn;	ureq->responder_resources        = kreq->responder_resources;	ureq->initiator_depth            = kreq->initiator_depth;	ureq->local_cm_response_timeout  = kreq->local_cm_response_timeout;	ureq->flow_control               = kreq->flow_control;	ureq->remote_cm_response_timeout = kreq->remote_cm_response_timeout;	ureq->retry_count                = kreq->retry_count;	ureq->rnr_retry_count            = kreq->rnr_retry_count;	ureq->srq                        = kreq->srq;	ureq->port			 = kreq->port;	ib_ucm_event_path_get(&ureq->primary_path, kreq->primary_path);	ib_ucm_event_path_get(&ureq->alternate_path, kreq->alternate_path);}static void ib_ucm_event_rep_get(struct ib_ucm_rep_event_resp *urep,				 struct ib_cm_rep_event_param *krep){	urep->remote_ca_guid      = krep->remote_ca_guid;	urep->remote_qkey         = krep->remote_qkey;	urep->remote_qpn          = krep->remote_qpn;	urep->starting_psn        = krep->starting_psn;	urep->responder_resources = krep->responder_resources;	urep->initiator_depth     = krep->initiator_depth;	urep->target_ack_delay    = krep->target_ack_delay;	urep->failover_accepted   = krep->failover_accepted;	urep->flow_control        = krep->flow_control;	urep->rnr_retry_count     = krep->rnr_retry_count;	urep->srq                 = krep->srq;}static void ib_ucm_event_sidr_rep_get(struct ib_ucm_sidr_rep_event_resp *urep,				      struct ib_cm_sidr_rep_event_param *krep){	urep->status = krep->status;	urep->qkey   = krep->qkey;	urep->qpn    = krep->qpn;};static int ib_ucm_event_process(struct ib_cm_event *evt,				struct ib_ucm_event *uvt){	void *info = NULL;	switch (evt->event) {	case IB_CM_REQ_RECEIVED:		ib_ucm_event_req_get(&uvt->resp.u.req_resp,				     &evt->param.req_rcvd);		uvt->data_len      = IB_CM_REQ_PRIVATE_DATA_SIZE;		uvt->resp.present  = IB_UCM_PRES_PRIMARY;		uvt->resp.present |= (evt->param.req_rcvd.alternate_path ?				      IB_UCM_PRES_ALTERNATE : 0);		break;	case IB_CM_REP_RECEIVED:		ib_ucm_event_rep_get(&uvt->resp.u.rep_resp,				     &evt->param.rep_rcvd);		uvt->data_len = IB_CM_REP_PRIVATE_DATA_SIZE;		break;	case IB_CM_RTU_RECEIVED:		uvt->data_len = IB_CM_RTU_PRIVATE_DATA_SIZE;		uvt->resp.u.send_status = evt->param.send_status;		break;	case IB_CM_DREQ_RECEIVED:		uvt->data_len = IB_CM_DREQ_PRIVATE_DATA_SIZE;		uvt->resp.u.send_status = evt->param.send_status;		break;	case IB_CM_DREP_RECEIVED:		uvt->data_len = IB_CM_DREP_PRIVATE_DATA_SIZE;		uvt->resp.u.send_status = evt->param.send_status;		break;	case IB_CM_MRA_RECEIVED:		uvt->resp.u.mra_resp.timeout =					evt->param.mra_rcvd.service_timeout;		uvt->data_len = IB_CM_MRA_PRIVATE_DATA_SIZE;		break;	case IB_CM_REJ_RECEIVED:		uvt->resp.u.rej_resp.reason = evt->param.rej_rcvd.reason;		uvt->data_len = IB_CM_REJ_PRIVATE_DATA_SIZE;		uvt->info_len = evt->param.rej_rcvd.ari_length;		info	      = evt->param.rej_rcvd.ari;		break;	case IB_CM_LAP_RECEIVED:		ib_ucm_event_path_get(&uvt->resp.u.lap_resp.path,				      evt->param.lap_rcvd.alternate_path);		uvt->data_len = IB_CM_LAP_PRIVATE_DATA_SIZE;		uvt->resp.present = IB_UCM_PRES_ALTERNATE;		break;	case IB_CM_APR_RECEIVED:		uvt->resp.u.apr_resp.status = evt->param.apr_rcvd.ap_status;		uvt->data_len = IB_CM_APR_PRIVATE_DATA_SIZE;		uvt->info_len = evt->param.apr_rcvd.info_len;		info	      = evt->param.apr_rcvd.apr_info;		break;	case IB_CM_SIDR_REQ_RECEIVED:		uvt->resp.u.sidr_req_resp.pkey = 					evt->param.sidr_req_rcvd.pkey;		uvt->resp.u.sidr_req_resp.port = 					evt->param.sidr_req_rcvd.port;		uvt->data_len = IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE;		break;	case IB_CM_SIDR_REP_RECEIVED:		ib_ucm_event_sidr_rep_get(&uvt->resp.u.sidr_rep_resp,					  &evt->param.sidr_rep_rcvd);		uvt->data_len = IB_CM_SIDR_REP_PRIVATE_DATA_SIZE;		uvt->info_len = evt->param.sidr_rep_rcvd.info_len;		info	      = evt->param.sidr_rep_rcvd.info;		break;	default:		uvt->resp.u.send_status = evt->param.send_status;		break;	}	if (uvt->data_len) {		uvt->data = kmalloc(uvt->data_len, GFP_KERNEL);		if (!uvt->data)			goto err1;		memcpy(uvt->data, evt->private_data, uvt->data_len);		uvt->resp.present |= IB_UCM_PRES_DATA;	}	if (uvt->info_len) {		uvt->info = kmalloc(uvt->info_len, GFP_KERNEL);		if (!uvt->info)			goto err2;		memcpy(uvt->info, info, uvt->info_len);		uvt->resp.present |= IB_UCM_PRES_INFO;	}	return 0;err2:	kfree(uvt->data);err1:	return -ENOMEM;}static int ib_ucm_event_handler(struct ib_cm_id *cm_id,				struct ib_cm_event *event){	struct ib_ucm_event *uevent;	struct ib_ucm_context *ctx;	int result = 0;	ctx = cm_id->context;	uevent = kzalloc(sizeof *uevent, GFP_KERNEL);	if (!uevent)		goto err1;	uevent->ctx = ctx;	uevent->cm_id = cm_id;	uevent->resp.uid = ctx->uid;	uevent->resp.id = ctx->id;	uevent->resp.event = event->event;	result = ib_ucm_event_process(event, uevent);	if (result)		goto err2;	down(&ctx->file->mutex);	list_add_tail(&uevent->file_list, &ctx->file->events);	list_add_tail(&uevent->ctx_list, &ctx->events);	wake_up_interruptible(&ctx->file->poll_wait);	up(&ctx->file->mutex);	return 0;err2:	kfree(uevent);err1:	/* Destroy new cm_id's */	return ib_ucm_new_cm_id(event->event);}static ssize_t ib_ucm_event(struct ib_ucm_file *file,			    const char __user *inbuf,			    int in_len, int out_len){	struct ib_ucm_context *ctx;	struct ib_ucm_event_get cmd;	struct ib_ucm_event *uevent;	int result = 0;	DEFINE_WAIT(wait);	if (out_len < sizeof(struct ib_ucm_event_resp))		return -ENOSPC;	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))		return -EFAULT;	down(&file->mutex);	while (list_empty(&file->events)) {		if (file->filp->f_flags & O_NONBLOCK) {			result = -EAGAIN;			break;		}		if (signal_pending(current)) {			result = -ERESTARTSYS;			break;		}		prepare_to_wait(&file->poll_wait, &wait, TASK_INTERRUPTIBLE);		up(&file->mutex);		schedule();		down(&file->mutex);		finish_wait(&file->poll_wait, &wait);	}	if (result)		goto done;	uevent = list_entry(file->events.next, struct ib_ucm_event, file_list);	if (ib_ucm_new_cm_id(uevent->resp.event)) {		ctx = ib_ucm_ctx_alloc(file);		if (!ctx) {			result = -ENOMEM;			goto done;		}		ctx->cm_id = uevent->cm_id;		ctx->cm_id->context = ctx;		uevent->resp.id = ctx->id;	}	if (copy_to_user((void __user *)(unsigned long)cmd.response,			 &uevent->resp, sizeof(uevent->resp))) {		result = -EFAULT;		goto done;	}	if (uevent->data) {		if (cmd.data_len < uevent->data_len) {			result = -ENOMEM;			goto done;		}		if (copy_to_user((void __user *)(unsigned long)cmd.data,				 uevent->data, uevent->data_len)) {			result = -EFAULT;			goto done;

⌨️ 快捷键说明

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