Skip to content

Commit 547af76

Browse files
Sean HeftyRoland Dreier
authored andcommitted
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: Sean Hefty <[email protected]> Signed-off-by: Roland Dreier <[email protected]>
1 parent 94545e8 commit 547af76

File tree

1 file changed

+45
-10
lines changed

1 file changed

+45
-10
lines changed

drivers/infiniband/core/multicast.c

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,20 @@ struct mcast_device {
7373
};
7474

7575
enum mcast_state {
76-
MCAST_IDLE,
7776
MCAST_JOINING,
7877
MCAST_MEMBER,
78+
MCAST_ERROR,
79+
};
80+
81+
enum mcast_group_state {
82+
MCAST_IDLE,
7983
MCAST_BUSY,
80-
MCAST_ERROR
84+
MCAST_GROUP_ERROR,
85+
MCAST_PKEY_EVENT
86+
};
87+
88+
enum {
89+
MCAST_INVALID_PKEY_INDEX = 0xFFFF
8190
};
8291

8392
struct mcast_member;
@@ -93,9 +102,10 @@ struct mcast_group {
93102
struct mcast_member *last_join;
94103
int members[3];
95104
atomic_t refcount;
96-
enum mcast_state state;
105+
enum mcast_group_state state;
97106
struct ib_sa_query *query;
98107
int query_id;
108+
u16 pkey_index;
99109
};
100110

101111
struct mcast_member {
@@ -378,9 +388,19 @@ static int fail_join(struct mcast_group *group, struct mcast_member *member,
378388
static void process_group_error(struct mcast_group *group)
379389
{
380390
struct mcast_member *member;
381-
int ret;
391+
int ret = 0;
392+
u16 pkey_index;
393+
394+
if (group->state == MCAST_PKEY_EVENT)
395+
ret = ib_find_pkey(group->port->dev->device,
396+
group->port->port_num,
397+
be16_to_cpu(group->rec.pkey), &pkey_index);
382398

383399
spin_lock_irq(&group->lock);
400+
if (group->state == MCAST_PKEY_EVENT && !ret &&
401+
group->pkey_index == pkey_index)
402+
goto out;
403+
384404
while (!list_empty(&group->active_list)) {
385405
member = list_entry(group->active_list.next,
386406
struct mcast_member, list);
@@ -399,6 +419,7 @@ static void process_group_error(struct mcast_group *group)
399419
}
400420

401421
group->rec.join_state = 0;
422+
out:
402423
group->state = MCAST_BUSY;
403424
spin_unlock_irq(&group->lock);
404425
}
@@ -415,9 +436,9 @@ static void mcast_work_handler(struct work_struct *work)
415436
retest:
416437
spin_lock_irq(&group->lock);
417438
while (!list_empty(&group->pending_list) ||
418-
(group->state == MCAST_ERROR)) {
439+
(group->state != MCAST_BUSY)) {
419440

420-
if (group->state == MCAST_ERROR) {
441+
if (group->state != MCAST_BUSY) {
421442
spin_unlock_irq(&group->lock);
422443
process_group_error(group);
423444
goto retest;
@@ -494,12 +515,19 @@ static void join_handler(int status, struct ib_sa_mcmember_rec *rec,
494515
void *context)
495516
{
496517
struct mcast_group *group = context;
518+
u16 pkey_index = MCAST_INVALID_PKEY_INDEX;
497519

498520
if (status)
499521
process_join_error(group, status);
500522
else {
523+
ib_find_pkey(group->port->dev->device, group->port->port_num,
524+
be16_to_cpu(rec->pkey), &pkey_index);
525+
501526
spin_lock_irq(&group->port->lock);
502527
group->rec = *rec;
528+
if (group->state == MCAST_BUSY &&
529+
group->pkey_index == MCAST_INVALID_PKEY_INDEX)
530+
group->pkey_index = pkey_index;
503531
if (!memcmp(&mgid0, &group->rec.mgid, sizeof mgid0)) {
504532
rb_erase(&group->node, &group->port->table);
505533
mcast_insert(group->port, group, 1);
@@ -539,6 +567,7 @@ static struct mcast_group *acquire_group(struct mcast_port *port,
539567

540568
group->port = port;
541569
group->rec.mgid = *mgid;
570+
group->pkey_index = MCAST_INVALID_PKEY_INDEX;
542571
INIT_LIST_HEAD(&group->pending_list);
543572
INIT_LIST_HEAD(&group->active_list);
544573
INIT_WORK(&group->work, mcast_work_handler);
@@ -707,7 +736,8 @@ int ib_init_ah_from_mcmember(struct ib_device *device, u8 port_num,
707736
}
708737
EXPORT_SYMBOL(ib_init_ah_from_mcmember);
709738

710-
static void mcast_groups_lost(struct mcast_port *port)
739+
static void mcast_groups_event(struct mcast_port *port,
740+
enum mcast_group_state state)
711741
{
712742
struct mcast_group *group;
713743
struct rb_node *node;
@@ -721,7 +751,8 @@ static void mcast_groups_lost(struct mcast_port *port)
721751
atomic_inc(&group->refcount);
722752
queue_work(mcast_wq, &group->work);
723753
}
724-
group->state = MCAST_ERROR;
754+
if (group->state != MCAST_GROUP_ERROR)
755+
group->state = state;
725756
spin_unlock(&group->lock);
726757
}
727758
spin_unlock_irqrestore(&port->lock, flags);
@@ -731,16 +762,20 @@ static void mcast_event_handler(struct ib_event_handler *handler,
731762
struct ib_event *event)
732763
{
733764
struct mcast_device *dev;
765+
int index;
734766

735767
dev = container_of(handler, struct mcast_device, event_handler);
768+
index = event->element.port_num - dev->start_port;
736769

737770
switch (event->event) {
738771
case IB_EVENT_PORT_ERR:
739772
case IB_EVENT_LID_CHANGE:
740773
case IB_EVENT_SM_CHANGE:
741774
case IB_EVENT_CLIENT_REREGISTER:
742-
mcast_groups_lost(&dev->port[event->element.port_num -
743-
dev->start_port]);
775+
mcast_groups_event(&dev->port[index], MCAST_GROUP_ERROR);
776+
break;
777+
case IB_EVENT_PKEY_CHANGE:
778+
mcast_groups_event(&dev->port[index], MCAST_PKEY_EVENT);
744779
break;
745780
default:
746781
break;

0 commit comments

Comments
 (0)