Commit 547af765 authored by Sean Hefty's avatar Sean Hefty Committed by Roland Dreier

IB/multicast: Report errors on multicast groups if P_key changes

P_key changes can invalidate multicast groups.  Report errors on all
multicast groups affected by a pkey change.
Signed-off-by: default avatarSean Hefty <sean.hefty@intel.com>
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent 94545e8c
...@@ -73,11 +73,20 @@ struct mcast_device { ...@@ -73,11 +73,20 @@ struct mcast_device {
}; };
enum mcast_state { enum mcast_state {
MCAST_IDLE,
MCAST_JOINING, MCAST_JOINING,
MCAST_MEMBER, MCAST_MEMBER,
MCAST_ERROR,
};
enum mcast_group_state {
MCAST_IDLE,
MCAST_BUSY, MCAST_BUSY,
MCAST_ERROR MCAST_GROUP_ERROR,
MCAST_PKEY_EVENT
};
enum {
MCAST_INVALID_PKEY_INDEX = 0xFFFF
}; };
struct mcast_member; struct mcast_member;
...@@ -93,9 +102,10 @@ struct mcast_group { ...@@ -93,9 +102,10 @@ struct mcast_group {
struct mcast_member *last_join; struct mcast_member *last_join;
int members[3]; int members[3];
atomic_t refcount; atomic_t refcount;
enum mcast_state state; enum mcast_group_state state;
struct ib_sa_query *query; struct ib_sa_query *query;
int query_id; int query_id;
u16 pkey_index;
}; };
struct mcast_member { struct mcast_member {
...@@ -378,9 +388,19 @@ static int fail_join(struct mcast_group *group, struct mcast_member *member, ...@@ -378,9 +388,19 @@ static int fail_join(struct mcast_group *group, struct mcast_member *member,
static void process_group_error(struct mcast_group *group) static void process_group_error(struct mcast_group *group)
{ {
struct mcast_member *member; struct mcast_member *member;
int ret; int ret = 0;
u16 pkey_index;
if (group->state == MCAST_PKEY_EVENT)
ret = ib_find_pkey(group->port->dev->device,
group->port->port_num,
be16_to_cpu(group->rec.pkey), &pkey_index);
spin_lock_irq(&group->lock); spin_lock_irq(&group->lock);
if (group->state == MCAST_PKEY_EVENT && !ret &&
group->pkey_index == pkey_index)
goto out;
while (!list_empty(&group->active_list)) { while (!list_empty(&group->active_list)) {
member = list_entry(group->active_list.next, member = list_entry(group->active_list.next,
struct mcast_member, list); struct mcast_member, list);
...@@ -399,6 +419,7 @@ static void process_group_error(struct mcast_group *group) ...@@ -399,6 +419,7 @@ static void process_group_error(struct mcast_group *group)
} }
group->rec.join_state = 0; group->rec.join_state = 0;
out:
group->state = MCAST_BUSY; group->state = MCAST_BUSY;
spin_unlock_irq(&group->lock); spin_unlock_irq(&group->lock);
} }
...@@ -415,9 +436,9 @@ static void mcast_work_handler(struct work_struct *work) ...@@ -415,9 +436,9 @@ static void mcast_work_handler(struct work_struct *work)
retest: retest:
spin_lock_irq(&group->lock); spin_lock_irq(&group->lock);
while (!list_empty(&group->pending_list) || while (!list_empty(&group->pending_list) ||
(group->state == MCAST_ERROR)) { (group->state != MCAST_BUSY)) {
if (group->state == MCAST_ERROR) { if (group->state != MCAST_BUSY) {
spin_unlock_irq(&group->lock); spin_unlock_irq(&group->lock);
process_group_error(group); process_group_error(group);
goto retest; goto retest;
...@@ -494,12 +515,19 @@ static void join_handler(int status, struct ib_sa_mcmember_rec *rec, ...@@ -494,12 +515,19 @@ static void join_handler(int status, struct ib_sa_mcmember_rec *rec,
void *context) void *context)
{ {
struct mcast_group *group = context; struct mcast_group *group = context;
u16 pkey_index = MCAST_INVALID_PKEY_INDEX;
if (status) if (status)
process_join_error(group, status); process_join_error(group, status);
else { else {
ib_find_pkey(group->port->dev->device, group->port->port_num,
be16_to_cpu(rec->pkey), &pkey_index);
spin_lock_irq(&group->port->lock); spin_lock_irq(&group->port->lock);
group->rec = *rec; group->rec = *rec;
if (group->state == MCAST_BUSY &&
group->pkey_index == MCAST_INVALID_PKEY_INDEX)
group->pkey_index = pkey_index;
if (!memcmp(&mgid0, &group->rec.mgid, sizeof mgid0)) { if (!memcmp(&mgid0, &group->rec.mgid, sizeof mgid0)) {
rb_erase(&group->node, &group->port->table); rb_erase(&group->node, &group->port->table);
mcast_insert(group->port, group, 1); mcast_insert(group->port, group, 1);
...@@ -539,6 +567,7 @@ static struct mcast_group *acquire_group(struct mcast_port *port, ...@@ -539,6 +567,7 @@ static struct mcast_group *acquire_group(struct mcast_port *port,
group->port = port; group->port = port;
group->rec.mgid = *mgid; group->rec.mgid = *mgid;
group->pkey_index = MCAST_INVALID_PKEY_INDEX;
INIT_LIST_HEAD(&group->pending_list); INIT_LIST_HEAD(&group->pending_list);
INIT_LIST_HEAD(&group->active_list); INIT_LIST_HEAD(&group->active_list);
INIT_WORK(&group->work, mcast_work_handler); INIT_WORK(&group->work, mcast_work_handler);
...@@ -707,7 +736,8 @@ int ib_init_ah_from_mcmember(struct ib_device *device, u8 port_num, ...@@ -707,7 +736,8 @@ int ib_init_ah_from_mcmember(struct ib_device *device, u8 port_num,
} }
EXPORT_SYMBOL(ib_init_ah_from_mcmember); EXPORT_SYMBOL(ib_init_ah_from_mcmember);
static void mcast_groups_lost(struct mcast_port *port) static void mcast_groups_event(struct mcast_port *port,
enum mcast_group_state state)
{ {
struct mcast_group *group; struct mcast_group *group;
struct rb_node *node; struct rb_node *node;
...@@ -721,7 +751,8 @@ static void mcast_groups_lost(struct mcast_port *port) ...@@ -721,7 +751,8 @@ static void mcast_groups_lost(struct mcast_port *port)
atomic_inc(&group->refcount); atomic_inc(&group->refcount);
queue_work(mcast_wq, &group->work); queue_work(mcast_wq, &group->work);
} }
group->state = MCAST_ERROR; if (group->state != MCAST_GROUP_ERROR)
group->state = state;
spin_unlock(&group->lock); spin_unlock(&group->lock);
} }
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
...@@ -731,16 +762,20 @@ static void mcast_event_handler(struct ib_event_handler *handler, ...@@ -731,16 +762,20 @@ static void mcast_event_handler(struct ib_event_handler *handler,
struct ib_event *event) struct ib_event *event)
{ {
struct mcast_device *dev; struct mcast_device *dev;
int index;
dev = container_of(handler, struct mcast_device, event_handler); dev = container_of(handler, struct mcast_device, event_handler);
index = event->element.port_num - dev->start_port;
switch (event->event) { switch (event->event) {
case IB_EVENT_PORT_ERR: case IB_EVENT_PORT_ERR:
case IB_EVENT_LID_CHANGE: case IB_EVENT_LID_CHANGE:
case IB_EVENT_SM_CHANGE: case IB_EVENT_SM_CHANGE:
case IB_EVENT_CLIENT_REREGISTER: case IB_EVENT_CLIENT_REREGISTER:
mcast_groups_lost(&dev->port[event->element.port_num - mcast_groups_event(&dev->port[index], MCAST_GROUP_ERROR);
dev->start_port]); break;
case IB_EVENT_PKEY_CHANGE:
mcast_groups_event(&dev->port[index], MCAST_PKEY_EVENT);
break; break;
default: default:
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment