Commit 6890ab31 authored by Eric Dumazet's avatar Eric Dumazet Committed by Paolo Abeni

rtnetlink: do not depend on RTNL in rtnl_fill_proto_down()

Change dev_change_proto_down() and dev_change_proto_down_reason()
to write once on dev->proto_down and dev->proto_down_reason.

Then rtnl_fill_proto_down() can use READ_ONCE() annotations
and run locklessly.

rtnl_proto_down_size() should assume worst case,
because readng dev->proto_down_reason multiple
times would be racy without RTNL in the future.
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 6747a5d4
...@@ -9223,7 +9223,7 @@ int dev_change_proto_down(struct net_device *dev, bool proto_down) ...@@ -9223,7 +9223,7 @@ int dev_change_proto_down(struct net_device *dev, bool proto_down)
netif_carrier_off(dev); netif_carrier_off(dev);
else else
netif_carrier_on(dev); netif_carrier_on(dev);
dev->proto_down = proto_down; WRITE_ONCE(dev->proto_down, proto_down);
return 0; return 0;
} }
...@@ -9237,18 +9237,21 @@ int dev_change_proto_down(struct net_device *dev, bool proto_down) ...@@ -9237,18 +9237,21 @@ int dev_change_proto_down(struct net_device *dev, bool proto_down)
void dev_change_proto_down_reason(struct net_device *dev, unsigned long mask, void dev_change_proto_down_reason(struct net_device *dev, unsigned long mask,
u32 value) u32 value)
{ {
u32 proto_down_reason;
int b; int b;
if (!mask) { if (!mask) {
dev->proto_down_reason = value; proto_down_reason = value;
} else { } else {
proto_down_reason = dev->proto_down_reason;
for_each_set_bit(b, &mask, 32) { for_each_set_bit(b, &mask, 32) {
if (value & (1 << b)) if (value & (1 << b))
dev->proto_down_reason |= BIT(b); proto_down_reason |= BIT(b);
else else
dev->proto_down_reason &= ~BIT(b); proto_down_reason &= ~BIT(b);
} }
} }
WRITE_ONCE(dev->proto_down_reason, proto_down_reason);
} }
struct bpf_xdp_link { struct bpf_xdp_link {
......
...@@ -1036,7 +1036,7 @@ static size_t rtnl_proto_down_size(const struct net_device *dev) ...@@ -1036,7 +1036,7 @@ static size_t rtnl_proto_down_size(const struct net_device *dev)
{ {
size_t size = nla_total_size(1); size_t size = nla_total_size(1);
if (dev->proto_down_reason) /* Assume dev->proto_down_reason is not zero. */
size += nla_total_size(0) + nla_total_size(4); size += nla_total_size(0) + nla_total_size(4);
return size; return size;
...@@ -1737,10 +1737,10 @@ static int rtnl_fill_proto_down(struct sk_buff *skb, ...@@ -1737,10 +1737,10 @@ static int rtnl_fill_proto_down(struct sk_buff *skb,
struct nlattr *pr; struct nlattr *pr;
u32 preason; u32 preason;
if (nla_put_u8(skb, IFLA_PROTO_DOWN, dev->proto_down)) if (nla_put_u8(skb, IFLA_PROTO_DOWN, READ_ONCE(dev->proto_down)))
goto nla_put_failure; goto nla_put_failure;
preason = dev->proto_down_reason; preason = READ_ONCE(dev->proto_down_reason);
if (!preason) if (!preason)
return 0; return 0;
......
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