ucm.c
来自「底层驱动开发」· C语言 代码 · 共 1,327 行 · 第 1/3 页
C
1,327 行
/* * 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 <asm/uaccess.h>#include "ucm.h"MODULE_AUTHOR("Libor Michalek");MODULE_DESCRIPTION("InfiniBand userspace Connection Manager access");MODULE_LICENSE("Dual BSD/GPL");static int ucm_debug_level;module_param_named(debug_level, ucm_debug_level, int, 0644);MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0");enum { IB_UCM_MAJOR = 231, IB_UCM_MINOR = 255};#define IB_UCM_DEV MKDEV(IB_UCM_MAJOR, IB_UCM_MINOR)#define PFX "UCM: "#define ucm_dbg(format, arg...) \ do { \ if (ucm_debug_level > 0) \ printk(KERN_DEBUG PFX format, ## arg); \ } while (0)static struct semaphore ctx_id_mutex;static struct idr ctx_id_table;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 = kmalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return NULL; memset(ctx, 0, sizeof *ctx); 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); ucm_dbg("Allocated CM ID <%d>\n", ctx->id); return ctx;error: kfree(ctx); return NULL;}/* * Event portion of the API, handle CM events * and allow event polling. */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; 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->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 = kmalloc(sizeof(*uevent), GFP_KERNEL); if (!uevent) goto err1; memset(uevent, 0, sizeof(*uevent)); 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; /* * wait */ 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,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?