/* * Copyright (c) 2006 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.
*/
/* * A multicast group has four types of members: full member, non member, * sendonly non member and sendonly full member. * We need to keep track of the number of members of each * type based on their join state. Adjust the number of members the belong to * the specified join states.
*/ staticvoid adjust_membership(struct mcast_group *group, u8 join_state, int inc)
{ int i;
for (i = 0; i < NUM_JOIN_MEMBERSHIP_TYPES; i++, join_state >>= 1) if (join_state & 0x1)
group->members[i] += inc;
}
/* * If a multicast group has zero members left for a particular join state, but * the group is still a member with the SA, we need to leave that join state. * Determine which join states we still belong to, but that do not have any * active members.
*/ static u8 get_leave_state(struct mcast_group *group)
{
u8 leave_state = 0; int i;
for (i = 0; i < NUM_JOIN_MEMBERSHIP_TYPES; i++) if (!group->members[i])
leave_state |= (0x1 << i);
while (!list_empty(&group->active_list)) {
member = list_entry(group->active_list.next, struct mcast_member, list);
refcount_inc(&member->refcount);
list_del_init(&member->list);
adjust_membership(group, member->multicast.rec.join_state, -1);
member->state = MCAST_ERROR;
spin_unlock_irq(&group->lock);
ret = member->multicast.callback(-ENETRESET,
&member->multicast);
deref_member(member); if (ret)
ib_sa_free_multicast(&member->multicast);
spin_lock_irq(&group->lock);
}
/* * Fail a join request if it is still active - at the head of the pending queue.
*/ staticvoid process_join_error(struct mcast_group *group, int status)
{ struct mcast_member *member; int ret;
spin_lock_irq(&group->lock);
member = list_entry(group->pending_list.next, struct mcast_member, list); if (group->last_join == member) {
refcount_inc(&member->refcount);
list_del_init(&member->list);
spin_unlock_irq(&group->lock);
ret = member->multicast.callback(status, &member->multicast);
deref_member(member); if (ret)
ib_sa_free_multicast(&member->multicast);
} else
spin_unlock_irq(&group->lock);
}
/* * We serialize all join requests to a single group to make our lives much * easier. Otherwise, two users could try to join the same group * simultaneously, with different configurations, one could leave while the * join is in progress, etc., which makes locking around error recovery * difficult.
*/ struct ib_sa_multicast *
ib_sa_join_multicast(struct ib_sa_client *client, struct ib_device *device, u32 port_num, struct ib_sa_mcmember_rec *rec,
ib_sa_comp_mask comp_mask, gfp_t gfp_mask, int (*callback)(int status, struct ib_sa_multicast *multicast), void *context)
{ struct mcast_device *dev; struct mcast_member *member; struct ib_sa_multicast *multicast; int ret;
dev = ib_get_client_data(device, &mcast_client); if (!dev) return ERR_PTR(-ENODEV);
member = kmalloc(sizeof *member, gfp_mask); if (!member) return ERR_PTR(-ENOMEM);
member->group = acquire_group(&dev->port[port_num - dev->start_port],
&rec->mgid, gfp_mask); if (!member->group) {
ret = -ENOMEM; goto err;
}
/* * The user will get the multicast structure in their callback. They * could then free the multicast structure before we can return from * this routine. So we save the pointer to return before queuing * any callback.
*/
multicast = &member->multicast;
queue_join(member); return multicast;
member = container_of(multicast, struct mcast_member, multicast);
group = member->group;
spin_lock_irq(&group->lock); if (member->state == MCAST_MEMBER)
adjust_membership(group, multicast->rec.join_state, -1);
list_del_init(&member->list);
if (group->state == MCAST_IDLE) {
group->state = MCAST_BUSY;
spin_unlock_irq(&group->lock); /* Continue to hold reference on group until callback */
queue_work(mcast_wq, &group->work);
} else {
spin_unlock_irq(&group->lock);
release_group(group);
}
/** * ib_init_ah_from_mcmember - Initialize AH attribute from multicast * member record and gid of the device. * @device: RDMA device * @port_num: Port of the rdma device to consider * @rec: Multicast member record to use * @ndev: Optional netdevice, applicable only for RoCE * @gid_type: GID type to consider * @ah_attr: AH attribute to fillup on successful completion * * ib_init_ah_from_mcmember() initializes AH attribute based on multicast * member record and other device properties. On success the caller is * responsible to call rdma_destroy_ah_attr on the ah_attr. Returns 0 on * success or appropriate error code. *
*/ int ib_init_ah_from_mcmember(struct ib_device *device, u32 port_num, struct ib_sa_mcmember_rec *rec, struct net_device *ndev, enum ib_gid_type gid_type, struct rdma_ah_attr *ah_attr)
{ conststruct ib_gid_attr *sgid_attr;
/* GID table is not based on the netdevice for IB link layer, * so ignore ndev during search.
*/ if (rdma_protocol_ib(device, port_num))
ndev = NULL; elseif (!rdma_protocol_roce(device, port_num)) return -EINVAL;
for (i = 0; i <= dev->end_port - dev->start_port; i++) { if (rdma_cap_ib_mcast(device, dev->start_port + i)) {
port = &dev->port[i];
deref_port(port);
wait_for_completion(&port->comp);
}
}
kfree(dev);
}
int mcast_init(void)
{ int ret;
mcast_wq = alloc_ordered_workqueue("ib_mcast", WQ_MEM_RECLAIM); if (!mcast_wq) return -ENOMEM;
ib_sa_register_client(&sa_client);
ret = ib_register_client(&mcast_client); if (ret) goto err; return 0;
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.15Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.