ipath_verbs_mcast.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 334 行

C
334
字号
/* * Copyright (c) 2005, 2006 PathScale, Inc. 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. */#include <linux/list.h>#include <linux/rcupdate.h>#include "ipath_verbs.h"/* * Global table of GID to attached QPs. * The table is global to all ipath devices since a send from one QP/device * needs to be locally routed to any locally attached QPs on the same * or different device. */static struct rb_root mcast_tree;static DEFINE_SPINLOCK(mcast_lock);/** * ipath_mcast_qp_alloc - alloc a struct to link a QP to mcast GID struct * @qp: the QP to link */static struct ipath_mcast_qp *ipath_mcast_qp_alloc(struct ipath_qp *qp){	struct ipath_mcast_qp *mqp;	mqp = kmalloc(sizeof *mqp, GFP_KERNEL);	if (!mqp)		goto bail;	mqp->qp = qp;	atomic_inc(&qp->refcount);bail:	return mqp;}static void ipath_mcast_qp_free(struct ipath_mcast_qp *mqp){	struct ipath_qp *qp = mqp->qp;	/* Notify ipath_destroy_qp() if it is waiting. */	if (atomic_dec_and_test(&qp->refcount))		wake_up(&qp->wait);	kfree(mqp);}/** * ipath_mcast_alloc - allocate the multicast GID structure * @mgid: the multicast GID * * A list of QPs will be attached to this structure. */static struct ipath_mcast *ipath_mcast_alloc(union ib_gid *mgid){	struct ipath_mcast *mcast;	mcast = kmalloc(sizeof *mcast, GFP_KERNEL);	if (!mcast)		goto bail;	mcast->mgid = *mgid;	INIT_LIST_HEAD(&mcast->qp_list);	init_waitqueue_head(&mcast->wait);	atomic_set(&mcast->refcount, 0);bail:	return mcast;}static void ipath_mcast_free(struct ipath_mcast *mcast){	struct ipath_mcast_qp *p, *tmp;	list_for_each_entry_safe(p, tmp, &mcast->qp_list, list)		ipath_mcast_qp_free(p);	kfree(mcast);}/** * ipath_mcast_find - search the global table for the given multicast GID * @mgid: the multicast GID to search for * * Returns NULL if not found. * * The caller is responsible for decrementing the reference count if found. */struct ipath_mcast *ipath_mcast_find(union ib_gid *mgid){	struct rb_node *n;	unsigned long flags;	struct ipath_mcast *mcast;	spin_lock_irqsave(&mcast_lock, flags);	n = mcast_tree.rb_node;	while (n) {		int ret;		mcast = rb_entry(n, struct ipath_mcast, rb_node);		ret = memcmp(mgid->raw, mcast->mgid.raw,			     sizeof(union ib_gid));		if (ret < 0)			n = n->rb_left;		else if (ret > 0)			n = n->rb_right;		else {			atomic_inc(&mcast->refcount);			spin_unlock_irqrestore(&mcast_lock, flags);			goto bail;		}	}	spin_unlock_irqrestore(&mcast_lock, flags);	mcast = NULL;bail:	return mcast;}/** * ipath_mcast_add - insert mcast GID into table and attach QP struct * @mcast: the mcast GID table * @mqp: the QP to attach * * Return zero if both were added.  Return EEXIST if the GID was already in * the table but the QP was added.  Return ESRCH if the QP was already * attached and neither structure was added. */static int ipath_mcast_add(struct ipath_mcast *mcast,			   struct ipath_mcast_qp *mqp){	struct rb_node **n = &mcast_tree.rb_node;	struct rb_node *pn = NULL;	unsigned long flags;	int ret;	spin_lock_irqsave(&mcast_lock, flags);	while (*n) {		struct ipath_mcast *tmcast;		struct ipath_mcast_qp *p;		pn = *n;		tmcast = rb_entry(pn, struct ipath_mcast, rb_node);		ret = memcmp(mcast->mgid.raw, tmcast->mgid.raw,			     sizeof(union ib_gid));		if (ret < 0) {			n = &pn->rb_left;			continue;		}		if (ret > 0) {			n = &pn->rb_right;			continue;		}		/* Search the QP list to see if this is already there. */		list_for_each_entry_rcu(p, &tmcast->qp_list, list) {			if (p->qp == mqp->qp) {				spin_unlock_irqrestore(&mcast_lock, flags);				ret = ESRCH;				goto bail;			}		}		list_add_tail_rcu(&mqp->list, &tmcast->qp_list);		spin_unlock_irqrestore(&mcast_lock, flags);		ret = EEXIST;		goto bail;	}	list_add_tail_rcu(&mqp->list, &mcast->qp_list);	atomic_inc(&mcast->refcount);	rb_link_node(&mcast->rb_node, pn, n);	rb_insert_color(&mcast->rb_node, &mcast_tree);	spin_unlock_irqrestore(&mcast_lock, flags);	ret = 0;bail:	return ret;}int ipath_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid){	struct ipath_qp *qp = to_iqp(ibqp);	struct ipath_mcast *mcast;	struct ipath_mcast_qp *mqp;	int ret;	/*	 * Allocate data structures since its better to do this outside of	 * spin locks and it will most likely be needed.	 */	mcast = ipath_mcast_alloc(gid);	if (mcast == NULL) {		ret = -ENOMEM;		goto bail;	}	mqp = ipath_mcast_qp_alloc(qp);	if (mqp == NULL) {		ipath_mcast_free(mcast);		ret = -ENOMEM;		goto bail;	}	switch (ipath_mcast_add(mcast, mqp)) {	case ESRCH:		/* Neither was used: can't attach the same QP twice. */		ipath_mcast_qp_free(mqp);		ipath_mcast_free(mcast);		ret = -EINVAL;		goto bail;	case EEXIST:		/* The mcast wasn't used */		ipath_mcast_free(mcast);		break;	default:		break;	}	ret = 0;bail:	return ret;}int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid){	struct ipath_qp *qp = to_iqp(ibqp);	struct ipath_mcast *mcast = NULL;	struct ipath_mcast_qp *p, *tmp;	struct rb_node *n;	unsigned long flags;	int last = 0;	int ret;	spin_lock_irqsave(&mcast_lock, flags);	/* Find the GID in the mcast table. */	n = mcast_tree.rb_node;	while (1) {		if (n == NULL) {			spin_unlock_irqrestore(&mcast_lock, flags);			ret = 0;			goto bail;		}		mcast = rb_entry(n, struct ipath_mcast, rb_node);		ret = memcmp(gid->raw, mcast->mgid.raw,			     sizeof(union ib_gid));		if (ret < 0)			n = n->rb_left;		else if (ret > 0)			n = n->rb_right;		else			break;	}	/* Search the QP list. */	list_for_each_entry_safe(p, tmp, &mcast->qp_list, list) {		if (p->qp != qp)			continue;		/*		 * We found it, so remove it, but don't poison the forward		 * link until we are sure there are no list walkers.		 */		list_del_rcu(&p->list);		/* If this was the last attached QP, remove the GID too. */		if (list_empty(&mcast->qp_list)) {			rb_erase(&mcast->rb_node, &mcast_tree);			last = 1;		}		break;	}	spin_unlock_irqrestore(&mcast_lock, flags);	if (p) {		/*		 * Wait for any list walkers to finish before freeing the		 * list element.		 */		wait_event(mcast->wait, atomic_read(&mcast->refcount) <= 1);		ipath_mcast_qp_free(p);	}	if (last) {		atomic_dec(&mcast->refcount);		wait_event(mcast->wait, !atomic_read(&mcast->refcount));		ipath_mcast_free(mcast);	}	ret = 0;bail:	return ret;}int ipath_mcast_tree_empty(void){	return mcast_tree.rb_node == NULL;}

⌨️ 快捷键说明

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