Skip to content

Commit 5112457

Browse files
committed
net: add netdev->up protected by netdev_lock()
Some uAPI (netdev netlink) hide net_device's sub-objects while the interface is down to ensure uniform behavior across drivers. To remove the rtnl_lock dependency from those uAPIs we need a way to safely tell if the device is down or up. Add an indication of whether device is open or closed, protected by netdev->lock. The semantics are the same as IFF_UP, but taking netdev_lock around every write to ->flags would be a lot of code churn. We don't want to blanket the entire open / close path by netdev_lock, because it will prevent us from applying it to specific structures - core helpers won't be able to take that lock from any function called by the drivers on open/close paths. So the state of the flag is "pessimistic", as in it may report false negatives, but never false positives. Reviewed-by: Joe Damato <[email protected]> Reviewed-by: Eric Dumazet <[email protected]> Reviewed-by: Kuniyuki Iwashima <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 2628f49 commit 5112457

File tree

3 files changed

+27
-3
lines changed

3 files changed

+27
-3
lines changed

include/linux/netdevice.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2443,12 +2443,24 @@ struct net_device {
24432443
unsigned long gro_flush_timeout;
24442444
u32 napi_defer_hard_irqs;
24452445

2446+
/**
2447+
* @up: copy of @state's IFF_UP, but safe to read with just @lock.
2448+
* May report false negatives while the device is being opened
2449+
* or closed (@lock does not protect .ndo_open, or .ndo_close).
2450+
*/
2451+
bool up;
2452+
24462453
/**
24472454
* @lock: netdev-scope lock, protects a small selection of fields.
24482455
* Should always be taken using netdev_lock() / netdev_unlock() helpers.
24492456
* Drivers are free to use it for other protection.
24502457
*
2451-
* Protects: @reg_state, @net_shaper_hierarchy.
2458+
* Protects:
2459+
* @net_shaper_hierarchy, @reg_state
2460+
*
2461+
* Partially protects (writers must hold both @lock and rtnl_lock):
2462+
* @up
2463+
*
24522464
* Ordering: take after rtnl_lock.
24532465
*/
24542466
struct mutex lock;

net/core/dev.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1619,7 +1619,7 @@ static int __dev_open(struct net_device *dev, struct netlink_ext_ack *extack)
16191619
if (ret)
16201620
clear_bit(__LINK_STATE_START, &dev->state);
16211621
else {
1622-
dev->flags |= IFF_UP;
1622+
netif_set_up(dev, true);
16231623
dev_set_rx_mode(dev);
16241624
dev_activate(dev);
16251625
add_device_randomness(dev->dev_addr, dev->addr_len);
@@ -1698,7 +1698,7 @@ static void __dev_close_many(struct list_head *head)
16981698
if (ops->ndo_stop)
16991699
ops->ndo_stop(dev);
17001700

1701-
dev->flags &= ~IFF_UP;
1701+
netif_set_up(dev, false);
17021702
netpoll_poll_enable(dev);
17031703
}
17041704
}

net/core/dev.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,18 @@ void __dev_notify_flags(struct net_device *dev, unsigned int old_flags,
128128
void unregister_netdevice_many_notify(struct list_head *head,
129129
u32 portid, const struct nlmsghdr *nlh);
130130

131+
static inline void netif_set_up(struct net_device *dev, bool value)
132+
{
133+
if (value)
134+
dev->flags |= IFF_UP;
135+
else
136+
dev->flags &= ~IFF_UP;
137+
138+
netdev_lock(dev);
139+
dev->up = value;
140+
netdev_unlock(dev);
141+
}
142+
131143
static inline void netif_set_gso_max_size(struct net_device *dev,
132144
unsigned int size)
133145
{

0 commit comments

Comments
 (0)