Commit fd888e85 authored by Sebastian Andrzej Siewior's avatar Sebastian Andrzej Siewior Committed by David S. Miller

net: Write lock dev_base_lock without disabling bottom halves.

The writer acquires dev_base_lock with disabled bottom halves.
The reader can acquire dev_base_lock without disabling bottom halves
because there is no writer in softirq context.

On PREEMPT_RT the softirqs are preemptible and local_bh_disable() acts
as a lock to ensure that resources, that are protected by disabling
bottom halves, remain protected.
This leads to a circular locking dependency if the lock acquired with
disabled bottom halves (as in write_lock_bh()) and somewhere else with
enabled bottom halves (as by read_lock() in netstat_show()) followed by
disabling bottom halves (cxgb_get_stats() -> t4_wr_mbox_meat_timeout()
-> spin_lock_bh()). This is the reverse locking order.

All read_lock() invocation are from sysfs callback which are not invoked
from softirq context. Therefore there is no need to disable bottom
halves while acquiring a write lock.

Acquire the write lock of dev_base_lock without disabling bottom halves.
Reported-by: default avatarPei Zhang <pezhang@redhat.com>
Reported-by: default avatarLuis Claudio R. Goncalves <lgoncalv@redhat.com>
Signed-off-by: default avatarSebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 07b8ca37
...@@ -365,12 +365,12 @@ static void list_netdevice(struct net_device *dev) ...@@ -365,12 +365,12 @@ static void list_netdevice(struct net_device *dev)
ASSERT_RTNL(); ASSERT_RTNL();
write_lock_bh(&dev_base_lock); write_lock(&dev_base_lock);
list_add_tail_rcu(&dev->dev_list, &net->dev_base_head); list_add_tail_rcu(&dev->dev_list, &net->dev_base_head);
netdev_name_node_add(net, dev->name_node); netdev_name_node_add(net, dev->name_node);
hlist_add_head_rcu(&dev->index_hlist, hlist_add_head_rcu(&dev->index_hlist,
dev_index_hash(net, dev->ifindex)); dev_index_hash(net, dev->ifindex));
write_unlock_bh(&dev_base_lock); write_unlock(&dev_base_lock);
dev_base_seq_inc(net); dev_base_seq_inc(net);
} }
...@@ -383,11 +383,11 @@ static void unlist_netdevice(struct net_device *dev) ...@@ -383,11 +383,11 @@ static void unlist_netdevice(struct net_device *dev)
ASSERT_RTNL(); ASSERT_RTNL();
/* Unlink dev from the device chain */ /* Unlink dev from the device chain */
write_lock_bh(&dev_base_lock); write_lock(&dev_base_lock);
list_del_rcu(&dev->dev_list); list_del_rcu(&dev->dev_list);
netdev_name_node_del(dev->name_node); netdev_name_node_del(dev->name_node);
hlist_del_rcu(&dev->index_hlist); hlist_del_rcu(&dev->index_hlist);
write_unlock_bh(&dev_base_lock); write_unlock(&dev_base_lock);
dev_base_seq_inc(dev_net(dev)); dev_base_seq_inc(dev_net(dev));
} }
...@@ -1188,15 +1188,15 @@ int dev_change_name(struct net_device *dev, const char *newname) ...@@ -1188,15 +1188,15 @@ int dev_change_name(struct net_device *dev, const char *newname)
netdev_adjacent_rename_links(dev, oldname); netdev_adjacent_rename_links(dev, oldname);
write_lock_bh(&dev_base_lock); write_lock(&dev_base_lock);
netdev_name_node_del(dev->name_node); netdev_name_node_del(dev->name_node);
write_unlock_bh(&dev_base_lock); write_unlock(&dev_base_lock);
synchronize_rcu(); synchronize_rcu();
write_lock_bh(&dev_base_lock); write_lock(&dev_base_lock);
netdev_name_node_add(net, dev->name_node); netdev_name_node_add(net, dev->name_node);
write_unlock_bh(&dev_base_lock); write_unlock(&dev_base_lock);
ret = call_netdevice_notifiers(NETDEV_CHANGENAME, dev); ret = call_netdevice_notifiers(NETDEV_CHANGENAME, dev);
ret = notifier_to_errno(ret); ret = notifier_to_errno(ret);
......
...@@ -55,7 +55,7 @@ static void rfc2863_policy(struct net_device *dev) ...@@ -55,7 +55,7 @@ static void rfc2863_policy(struct net_device *dev)
if (operstate == dev->operstate) if (operstate == dev->operstate)
return; return;
write_lock_bh(&dev_base_lock); write_lock(&dev_base_lock);
switch(dev->link_mode) { switch(dev->link_mode) {
case IF_LINK_MODE_TESTING: case IF_LINK_MODE_TESTING:
...@@ -74,7 +74,7 @@ static void rfc2863_policy(struct net_device *dev) ...@@ -74,7 +74,7 @@ static void rfc2863_policy(struct net_device *dev)
dev->operstate = operstate; dev->operstate = operstate;
write_unlock_bh(&dev_base_lock); write_unlock(&dev_base_lock);
} }
......
...@@ -842,9 +842,9 @@ static void set_operstate(struct net_device *dev, unsigned char transition) ...@@ -842,9 +842,9 @@ static void set_operstate(struct net_device *dev, unsigned char transition)
} }
if (dev->operstate != operstate) { if (dev->operstate != operstate) {
write_lock_bh(&dev_base_lock); write_lock(&dev_base_lock);
dev->operstate = operstate; dev->operstate = operstate;
write_unlock_bh(&dev_base_lock); write_unlock(&dev_base_lock);
netdev_state_change(dev); netdev_state_change(dev);
} }
} }
...@@ -2778,11 +2778,11 @@ static int do_setlink(const struct sk_buff *skb, ...@@ -2778,11 +2778,11 @@ static int do_setlink(const struct sk_buff *skb,
if (tb[IFLA_LINKMODE]) { if (tb[IFLA_LINKMODE]) {
unsigned char value = nla_get_u8(tb[IFLA_LINKMODE]); unsigned char value = nla_get_u8(tb[IFLA_LINKMODE]);
write_lock_bh(&dev_base_lock); write_lock(&dev_base_lock);
if (dev->link_mode ^ value) if (dev->link_mode ^ value)
status |= DO_SETLINK_NOTIFY; status |= DO_SETLINK_NOTIFY;
dev->link_mode = value; dev->link_mode = value;
write_unlock_bh(&dev_base_lock); write_unlock(&dev_base_lock);
} }
if (tb[IFLA_VFINFO_LIST]) { if (tb[IFLA_VFINFO_LIST]) {
......
...@@ -30,13 +30,13 @@ static bool is_slave_up(struct net_device *dev) ...@@ -30,13 +30,13 @@ static bool is_slave_up(struct net_device *dev)
static void __hsr_set_operstate(struct net_device *dev, int transition) static void __hsr_set_operstate(struct net_device *dev, int transition)
{ {
write_lock_bh(&dev_base_lock); write_lock(&dev_base_lock);
if (dev->operstate != transition) { if (dev->operstate != transition) {
dev->operstate = transition; dev->operstate = transition;
write_unlock_bh(&dev_base_lock); write_unlock(&dev_base_lock);
netdev_state_change(dev); netdev_state_change(dev);
} else { } else {
write_unlock_bh(&dev_base_lock); write_unlock(&dev_base_lock);
} }
} }
......
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