Skip to content

Commit

Permalink
dcbnl : Disable software interrupts before taking dcb_lock
Browse files Browse the repository at this point in the history
Solves possible lockup issues that can be seen from firmware DCB agents calling
into the DCB app api.

DCB firmware event queues can be tied in with NAPI so that dcb events are
generated in softIRQ context. This can results in calls to dcb_*app()
functions which try to take the dcb_lock.

If the the event triggers while we also have the dcb_lock because lldpad or
some other agent happened to be issuing a  get/set command we could see a cpu
lockup.

This code was not originally written with firmware agents in mind, hence
grabbing dcb_lock from softIRQ context was not considered.

Signed-off-by: Anish Bhatt <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
anish authored and davem330 committed Nov 16, 2014
1 parent 8c2dd54 commit 52cff74
Showing 1 changed file with 18 additions and 18 deletions.
36 changes: 18 additions & 18 deletions net/dcb/dcbnl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1080,13 +1080,13 @@ static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
if (!app)
return -EMSGSIZE;

spin_lock(&dcb_lock);
spin_lock_bh(&dcb_lock);
list_for_each_entry(itr, &dcb_app_list, list) {
if (itr->ifindex == netdev->ifindex) {
err = nla_put(skb, DCB_ATTR_IEEE_APP, sizeof(itr->app),
&itr->app);
if (err) {
spin_unlock(&dcb_lock);
spin_unlock_bh(&dcb_lock);
return -EMSGSIZE;
}
}
Expand All @@ -1097,7 +1097,7 @@ static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
else
dcbx = -EOPNOTSUPP;

spin_unlock(&dcb_lock);
spin_unlock_bh(&dcb_lock);
nla_nest_end(skb, app);

/* get peer info if available */
Expand Down Expand Up @@ -1234,7 +1234,7 @@ static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev)
}

/* local app */
spin_lock(&dcb_lock);
spin_lock_bh(&dcb_lock);
app = nla_nest_start(skb, DCB_ATTR_CEE_APP_TABLE);
if (!app)
goto dcb_unlock;
Expand Down Expand Up @@ -1271,7 +1271,7 @@ static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev)
else
dcbx = -EOPNOTSUPP;

spin_unlock(&dcb_lock);
spin_unlock_bh(&dcb_lock);

/* features flags */
if (ops->getfeatcfg) {
Expand Down Expand Up @@ -1326,7 +1326,7 @@ static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev)
return 0;

dcb_unlock:
spin_unlock(&dcb_lock);
spin_unlock_bh(&dcb_lock);
nla_put_failure:
return err;
}
Expand Down Expand Up @@ -1762,10 +1762,10 @@ u8 dcb_getapp(struct net_device *dev, struct dcb_app *app)
struct dcb_app_type *itr;
u8 prio = 0;

spin_lock(&dcb_lock);
spin_lock_bh(&dcb_lock);
if ((itr = dcb_app_lookup(app, dev->ifindex, 0)))
prio = itr->app.priority;
spin_unlock(&dcb_lock);
spin_unlock_bh(&dcb_lock);

return prio;
}
Expand All @@ -1789,7 +1789,7 @@ int dcb_setapp(struct net_device *dev, struct dcb_app *new)
if (dev->dcbnl_ops->getdcbx)
event.dcbx = dev->dcbnl_ops->getdcbx(dev);

spin_lock(&dcb_lock);
spin_lock_bh(&dcb_lock);
/* Search for existing match and replace */
if ((itr = dcb_app_lookup(new, dev->ifindex, 0))) {
if (new->priority)
Expand All @@ -1804,7 +1804,7 @@ int dcb_setapp(struct net_device *dev, struct dcb_app *new)
if (new->priority)
err = dcb_app_add(new, dev->ifindex);
out:
spin_unlock(&dcb_lock);
spin_unlock_bh(&dcb_lock);
if (!err)
call_dcbevent_notifiers(DCB_APP_EVENT, &event);
return err;
Expand All @@ -1823,10 +1823,10 @@ u8 dcb_ieee_getapp_mask(struct net_device *dev, struct dcb_app *app)
struct dcb_app_type *itr;
u8 prio = 0;

spin_lock(&dcb_lock);
spin_lock_bh(&dcb_lock);
if ((itr = dcb_app_lookup(app, dev->ifindex, 0)))
prio |= 1 << itr->app.priority;
spin_unlock(&dcb_lock);
spin_unlock_bh(&dcb_lock);

return prio;
}
Expand All @@ -1850,7 +1850,7 @@ int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new)
if (dev->dcbnl_ops->getdcbx)
event.dcbx = dev->dcbnl_ops->getdcbx(dev);

spin_lock(&dcb_lock);
spin_lock_bh(&dcb_lock);
/* Search for existing match and abort if found */
if (dcb_app_lookup(new, dev->ifindex, new->priority)) {
err = -EEXIST;
Expand All @@ -1859,7 +1859,7 @@ int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new)

err = dcb_app_add(new, dev->ifindex);
out:
spin_unlock(&dcb_lock);
spin_unlock_bh(&dcb_lock);
if (!err)
call_dcbevent_notifiers(DCB_APP_EVENT, &event);
return err;
Expand All @@ -1882,15 +1882,15 @@ int dcb_ieee_delapp(struct net_device *dev, struct dcb_app *del)
if (dev->dcbnl_ops->getdcbx)
event.dcbx = dev->dcbnl_ops->getdcbx(dev);

spin_lock(&dcb_lock);
spin_lock_bh(&dcb_lock);
/* Search for existing match and remove it. */
if ((itr = dcb_app_lookup(del, dev->ifindex, del->priority))) {
list_del(&itr->list);
kfree(itr);
err = 0;
}

spin_unlock(&dcb_lock);
spin_unlock_bh(&dcb_lock);
if (!err)
call_dcbevent_notifiers(DCB_APP_EVENT, &event);
return err;
Expand All @@ -1902,12 +1902,12 @@ static void dcb_flushapp(void)
struct dcb_app_type *app;
struct dcb_app_type *tmp;

spin_lock(&dcb_lock);
spin_lock_bh(&dcb_lock);
list_for_each_entry_safe(app, tmp, &dcb_app_list, list) {
list_del(&app->list);
kfree(app);
}
spin_unlock(&dcb_lock);
spin_unlock_bh(&dcb_lock);
}

static int __init dcbnl_init(void)
Expand Down

0 comments on commit 52cff74

Please sign in to comment.