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

📄 cm.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
			node = node->rb_left;		else if (service_id > cm_id_priv->id.service_id)			node = node->rb_right;		else if (data_cmp < 0)			node = node->rb_left;		else			node = node->rb_right;	}	return NULL;}static struct cm_timewait_info * cm_insert_remote_id(struct cm_timewait_info						     *timewait_info){	struct rb_node **link = &cm.remote_id_table.rb_node;	struct rb_node *parent = NULL;	struct cm_timewait_info *cur_timewait_info;	__be64 remote_ca_guid = timewait_info->remote_ca_guid;	__be32 remote_id = timewait_info->work.remote_id;	while (*link) {		parent = *link;		cur_timewait_info = rb_entry(parent, struct cm_timewait_info,					     remote_id_node);		if (remote_id < cur_timewait_info->work.remote_id)			link = &(*link)->rb_left;		else if (remote_id > cur_timewait_info->work.remote_id)			link = &(*link)->rb_right;		else if (remote_ca_guid < cur_timewait_info->remote_ca_guid)			link = &(*link)->rb_left;		else if (remote_ca_guid > cur_timewait_info->remote_ca_guid)			link = &(*link)->rb_right;		else			return cur_timewait_info;	}	timewait_info->inserted_remote_id = 1;	rb_link_node(&timewait_info->remote_id_node, parent, link);	rb_insert_color(&timewait_info->remote_id_node, &cm.remote_id_table);	return NULL;}static struct cm_timewait_info * cm_find_remote_id(__be64 remote_ca_guid,						   __be32 remote_id){	struct rb_node *node = cm.remote_id_table.rb_node;	struct cm_timewait_info *timewait_info;	while (node) {		timewait_info = rb_entry(node, struct cm_timewait_info,					 remote_id_node);		if (remote_id < timewait_info->work.remote_id)			node = node->rb_left;		else if (remote_id > timewait_info->work.remote_id)			node = node->rb_right;		else if (remote_ca_guid < timewait_info->remote_ca_guid)			node = node->rb_left;		else if (remote_ca_guid > timewait_info->remote_ca_guid)			node = node->rb_right;		else			return timewait_info;	}	return NULL;}static struct cm_timewait_info * cm_insert_remote_qpn(struct cm_timewait_info						      *timewait_info){	struct rb_node **link = &cm.remote_qp_table.rb_node;	struct rb_node *parent = NULL;	struct cm_timewait_info *cur_timewait_info;	__be64 remote_ca_guid = timewait_info->remote_ca_guid;	__be32 remote_qpn = timewait_info->remote_qpn;	while (*link) {		parent = *link;		cur_timewait_info = rb_entry(parent, struct cm_timewait_info,					     remote_qp_node);		if (remote_qpn < cur_timewait_info->remote_qpn)			link = &(*link)->rb_left;		else if (remote_qpn > cur_timewait_info->remote_qpn)			link = &(*link)->rb_right;		else if (remote_ca_guid < cur_timewait_info->remote_ca_guid)			link = &(*link)->rb_left;		else if (remote_ca_guid > cur_timewait_info->remote_ca_guid)			link = &(*link)->rb_right;		else			return cur_timewait_info;	}	timewait_info->inserted_remote_qp = 1;	rb_link_node(&timewait_info->remote_qp_node, parent, link);	rb_insert_color(&timewait_info->remote_qp_node, &cm.remote_qp_table);	return NULL;}static struct cm_id_private * cm_insert_remote_sidr(struct cm_id_private						    *cm_id_priv){	struct rb_node **link = &cm.remote_sidr_table.rb_node;	struct rb_node *parent = NULL;	struct cm_id_private *cur_cm_id_priv;	union ib_gid *port_gid = &cm_id_priv->av.dgid;	__be32 remote_id = cm_id_priv->id.remote_id;	while (*link) {		parent = *link;		cur_cm_id_priv = rb_entry(parent, struct cm_id_private,					  sidr_id_node);		if (remote_id < cur_cm_id_priv->id.remote_id)			link = &(*link)->rb_left;		else if (remote_id > cur_cm_id_priv->id.remote_id)			link = &(*link)->rb_right;		else {			int cmp;			cmp = memcmp(port_gid, &cur_cm_id_priv->av.dgid,				     sizeof *port_gid);			if (cmp < 0)				link = &(*link)->rb_left;			else if (cmp > 0)				link = &(*link)->rb_right;			else				return cur_cm_id_priv;		}	}	rb_link_node(&cm_id_priv->sidr_id_node, parent, link);	rb_insert_color(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table);	return NULL;}static void cm_reject_sidr_req(struct cm_id_private *cm_id_priv,			       enum ib_cm_sidr_status status){	struct ib_cm_sidr_rep_param param;	memset(&param, 0, sizeof param);	param.status = status;	ib_send_cm_sidr_rep(&cm_id_priv->id, &param);}struct ib_cm_id *ib_create_cm_id(struct ib_device *device,				 ib_cm_handler cm_handler,				 void *context){	struct cm_id_private *cm_id_priv;	int ret;	cm_id_priv = kzalloc(sizeof *cm_id_priv, GFP_KERNEL);	if (!cm_id_priv)		return ERR_PTR(-ENOMEM);	cm_id_priv->id.state = IB_CM_IDLE;	cm_id_priv->id.device = device;	cm_id_priv->id.cm_handler = cm_handler;	cm_id_priv->id.context = context;	cm_id_priv->id.remote_cm_qpn = 1;	ret = cm_alloc_id(cm_id_priv);	if (ret)		goto error;	spin_lock_init(&cm_id_priv->lock);	init_completion(&cm_id_priv->comp);	INIT_LIST_HEAD(&cm_id_priv->work_list);	atomic_set(&cm_id_priv->work_count, -1);	atomic_set(&cm_id_priv->refcount, 1);	return &cm_id_priv->id;error:	kfree(cm_id_priv);	return ERR_PTR(-ENOMEM);}EXPORT_SYMBOL(ib_create_cm_id);static struct cm_work * cm_dequeue_work(struct cm_id_private *cm_id_priv){	struct cm_work *work;	if (list_empty(&cm_id_priv->work_list))		return NULL;	work = list_entry(cm_id_priv->work_list.next, struct cm_work, list);	list_del(&work->list);	return work;}static void cm_free_work(struct cm_work *work){	if (work->mad_recv_wc)		ib_free_recv_mad(work->mad_recv_wc);	kfree(work);}static inline int cm_convert_to_ms(int iba_time){	/* approximate conversion to ms from 4.096us x 2^iba_time */	return 1 << max(iba_time - 8, 0);}/* * calculate: 4.096x2^ack_timeout = 4.096x2^ack_delay + 2x4.096x2^life_time * Because of how ack_timeout is stored, adding one doubles the timeout. * To avoid large timeouts, select the max(ack_delay, life_time + 1), and * increment it (round up) only if the other is within 50%. */static u8 cm_ack_timeout(u8 ca_ack_delay, u8 packet_life_time){	int ack_timeout = packet_life_time + 1;	if (ack_timeout >= ca_ack_delay)		ack_timeout += (ca_ack_delay >= (ack_timeout - 1));	else		ack_timeout = ca_ack_delay +			      (ack_timeout >= (ca_ack_delay - 1));	return min(31, ack_timeout);}static void cm_cleanup_timewait(struct cm_timewait_info *timewait_info){	if (timewait_info->inserted_remote_id) {		rb_erase(&timewait_info->remote_id_node, &cm.remote_id_table);		timewait_info->inserted_remote_id = 0;	}	if (timewait_info->inserted_remote_qp) {		rb_erase(&timewait_info->remote_qp_node, &cm.remote_qp_table);		timewait_info->inserted_remote_qp = 0;	}}static struct cm_timewait_info * cm_create_timewait_info(__be32 local_id){	struct cm_timewait_info *timewait_info;	timewait_info = kzalloc(sizeof *timewait_info, GFP_KERNEL);	if (!timewait_info)		return ERR_PTR(-ENOMEM);	timewait_info->work.local_id = local_id;	INIT_DELAYED_WORK(&timewait_info->work.work, cm_work_handler);	timewait_info->work.cm_event.event = IB_CM_TIMEWAIT_EXIT;	return timewait_info;}static void cm_enter_timewait(struct cm_id_private *cm_id_priv){	int wait_time;	unsigned long flags;	spin_lock_irqsave(&cm.lock, flags);	cm_cleanup_timewait(cm_id_priv->timewait_info);	list_add_tail(&cm_id_priv->timewait_info->list, &cm.timewait_list);	spin_unlock_irqrestore(&cm.lock, flags);	/*	 * The cm_id could be destroyed by the user before we exit timewait.	 * To protect against this, we search for the cm_id after exiting	 * timewait before notifying the user that we've exited timewait.	 */	cm_id_priv->id.state = IB_CM_TIMEWAIT;	wait_time = cm_convert_to_ms(cm_id_priv->av.timeout);	queue_delayed_work(cm.wq, &cm_id_priv->timewait_info->work.work,			   msecs_to_jiffies(wait_time));	cm_id_priv->timewait_info = NULL;}static void cm_reset_to_idle(struct cm_id_private *cm_id_priv){	unsigned long flags;	cm_id_priv->id.state = IB_CM_IDLE;	if (cm_id_priv->timewait_info) {		spin_lock_irqsave(&cm.lock, flags);		cm_cleanup_timewait(cm_id_priv->timewait_info);		spin_unlock_irqrestore(&cm.lock, flags);		kfree(cm_id_priv->timewait_info);		cm_id_priv->timewait_info = NULL;	}}static void cm_destroy_id(struct ib_cm_id *cm_id, int err){	struct cm_id_private *cm_id_priv;	struct cm_work *work;	cm_id_priv = container_of(cm_id, struct cm_id_private, id);retest:	spin_lock_irq(&cm_id_priv->lock);	switch (cm_id->state) {	case IB_CM_LISTEN:		cm_id->state = IB_CM_IDLE;		spin_unlock_irq(&cm_id_priv->lock);		spin_lock_irq(&cm.lock);		rb_erase(&cm_id_priv->service_node, &cm.listen_service_table);		spin_unlock_irq(&cm.lock);		break;	case IB_CM_SIDR_REQ_SENT:		cm_id->state = IB_CM_IDLE;		ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);		spin_unlock_irq(&cm_id_priv->lock);		break;	case IB_CM_SIDR_REQ_RCVD:		spin_unlock_irq(&cm_id_priv->lock);		cm_reject_sidr_req(cm_id_priv, IB_SIDR_REJECT);		break;	case IB_CM_REQ_SENT:		ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);		spin_unlock_irq(&cm_id_priv->lock);		ib_send_cm_rej(cm_id, IB_CM_REJ_TIMEOUT,			       &cm_id_priv->id.device->node_guid,			       sizeof cm_id_priv->id.device->node_guid,			       NULL, 0);		break;	case IB_CM_REQ_RCVD:		if (err == -ENOMEM) {			/* Do not reject to allow future retries. */			cm_reset_to_idle(cm_id_priv);			spin_unlock_irq(&cm_id_priv->lock);		} else {			spin_unlock_irq(&cm_id_priv->lock);			ib_send_cm_rej(cm_id, IB_CM_REJ_CONSUMER_DEFINED,				       NULL, 0, NULL, 0);		}		break;	case IB_CM_MRA_REQ_RCVD:	case IB_CM_REP_SENT:	case IB_CM_MRA_REP_RCVD:		ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);		/* Fall through */	case IB_CM_MRA_REQ_SENT:	case IB_CM_REP_RCVD:	case IB_CM_MRA_REP_SENT:		spin_unlock_irq(&cm_id_priv->lock);		ib_send_cm_rej(cm_id, IB_CM_REJ_CONSUMER_DEFINED,			       NULL, 0, NULL, 0);		break;	case IB_CM_ESTABLISHED:		spin_unlock_irq(&cm_id_priv->lock);		ib_send_cm_dreq(cm_id, NULL, 0);		goto retest;	case IB_CM_DREQ_SENT:		ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);		cm_enter_timewait(cm_id_priv);		spin_unlock_irq(&cm_id_priv->lock);		break;	case IB_CM_DREQ_RCVD:		spin_unlock_irq(&cm_id_priv->lock);		ib_send_cm_drep(cm_id, NULL, 0);		break;	default:		spin_unlock_irq(&cm_id_priv->lock);		break;	}	cm_free_id(cm_id->local_id);	cm_deref_id(cm_id_priv);	wait_for_completion(&cm_id_priv->comp);	while ((work = cm_dequeue_work(cm_id_priv)) != NULL)		cm_free_work(work);	kfree(cm_id_priv->compare_data);	kfree(cm_id_priv->private_data);	kfree(cm_id_priv);}void ib_destroy_cm_id(struct ib_cm_id *cm_id){	cm_destroy_id(cm_id, 0);}EXPORT_SYMBOL(ib_destroy_cm_id);int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask,		 struct ib_cm_compare_data *compare_data){	struct cm_id_private *cm_id_priv, *cur_cm_id_priv;	unsigned long flags;	int ret = 0;	service_mask = service_mask ? service_mask :		       __constant_cpu_to_be64(~0ULL);	service_id &= service_mask;	if ((service_id & IB_SERVICE_ID_AGN_MASK) == IB_CM_ASSIGN_SERVICE_ID &&	    (service_id != IB_CM_ASSIGN_SERVICE_ID))		return -EINVAL;	cm_id_priv = container_of(cm_id, struct cm_id_private, id);	if (cm_id->state != IB_CM_IDLE)		return -EINVAL;	if (compare_data) {		cm_id_priv->compare_data = kzalloc(sizeof *compare_data,						   GFP_KERNEL);		if (!cm_id_priv->compare_data)			return -ENOMEM;		cm_mask_copy(cm_id_priv->compare_data->data,			     compare_data->data, compare_data->mask);		memcpy(cm_id_priv->compare_data->mask, compare_data->mask,		       IB_CM_COMPARE_SIZE);	}	cm_id->state = IB_CM_LISTEN;	spin_lock_irqsave(&cm.lock, flags);	if (service_id == IB_CM_ASSIGN_SERVICE_ID) {		cm_id->service_id = cpu_to_be64(cm.listen_service_id++);		cm_id->service_mask = __constant_cpu_to_be64(~0ULL);	} else {		cm_id->service_id = service_id;		cm_id->service_mask = service_mask;	}	cur_cm_id_priv = cm_insert_listen(cm_id_priv);	spin_unlock_irqrestore(&cm.lock, flags);	if (cur_cm_id_priv) {		cm_id->state = IB_CM_IDLE;		kfree(cm_id_priv->compare_data);		cm_id_priv->compare_data = NULL;		ret = -EBUSY;	}	return ret;}EXPORT_SYMBOL(ib_cm_listen);static __be64 cm_form_tid(struct cm_id_private *cm_id_priv,			  enum cm_msg_sequence msg_seq){	u64 hi_tid, low_tid;	hi_tid   = ((u64) cm_id_priv->av.port->mad_agent->hi_tid) << 32;	low_tid  = (u64) ((__force u32)cm_id_priv->id.local_id |			  (msg_seq << 30));	return cpu_to_be64(hi_tid | low_tid);}static void cm_format_mad_hdr(struct ib_mad_hdr *hdr,			      __be16 attr_id, __be64 tid){	hdr->base_version  = IB_MGMT_BASE_VERSION;	hdr->mgmt_class	   = IB_MGMT_CLASS_CM;	hdr->class_version = IB_CM_CLASS_VERSION;	hdr->method	   = IB_MGMT_METHOD_SEND;	hdr->attr_id	   = attr_id;	hdr->tid	   = tid;}static void cm_format_req(struct cm_req_msg *req_msg,			  struct cm_id_private *cm_id_priv,			  struct ib_cm_req_param *param){	cm_format_mad_hdr(&req_msg->hdr, CM_REQ_ATTR_ID,			  cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_REQ));	req_msg->local_comm_id = cm_id_priv->id.local_id;	req_msg->service_id = param->service_id;

⌨️ 快捷键说明

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