Skip to content

Commit 9d40c84

Browse files
edumazetpaulmckrcu
authored andcommitted
net: devinet: Reduce refcount before grace period
Currently, the inetdev_destroy() function waits for an RCU grace period before decrementing the refcount and freeing memory. This causes a delay with a new RCU configuration that tries to save power, which results in the network interface disappearing later than expected. The resulting delay causes test failures on ChromeOS. Refactor the code such that the refcount is freed before the grace period and memory is freed after. With this a ChromeOS network test passes that does 'ip netns del' and polls for an interface disappearing, now passes. Reported-by: Joel Fernandes (Google) <[email protected]> Signed-off-by: Eric Dumazet <[email protected]> Signed-off-by: Joel Fernandes (Google) <[email protected]> Cc: David Ahern <[email protected]> Cc: "David S. Miller" <[email protected]> Cc: Hideaki YOSHIFUJI <[email protected]> Cc: Jakub Kicinski <[email protected]> Cc: Paolo Abeni <[email protected]> Cc: <[email protected]> Signed-off-by: Paul E. McKenney <[email protected]>
1 parent 483c26f commit 9d40c84

File tree

1 file changed

+10
-9
lines changed

1 file changed

+10
-9
lines changed

net/ipv4/devinet.c

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -234,21 +234,28 @@ static void inet_free_ifa(struct in_ifaddr *ifa)
234234
call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
235235
}
236236

237+
static void in_dev_free_rcu(struct rcu_head *head)
238+
{
239+
struct in_device *idev = container_of(head, struct in_device, rcu_head);
240+
241+
kfree(rcu_dereference_protected(idev->mc_hash, 1));
242+
kfree(idev);
243+
}
244+
237245
void in_dev_finish_destroy(struct in_device *idev)
238246
{
239247
struct net_device *dev = idev->dev;
240248

241249
WARN_ON(idev->ifa_list);
242250
WARN_ON(idev->mc_list);
243-
kfree(rcu_dereference_protected(idev->mc_hash, 1));
244251
#ifdef NET_REFCNT_DEBUG
245252
pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL");
246253
#endif
247254
netdev_put(dev, &idev->dev_tracker);
248255
if (!idev->dead)
249256
pr_err("Freeing alive in_device %p\n", idev);
250257
else
251-
kfree(idev);
258+
call_rcu(&idev->rcu_head, in_dev_free_rcu);
252259
}
253260
EXPORT_SYMBOL(in_dev_finish_destroy);
254261

@@ -298,12 +305,6 @@ static struct in_device *inetdev_init(struct net_device *dev)
298305
goto out;
299306
}
300307

301-
static void in_dev_rcu_put(struct rcu_head *head)
302-
{
303-
struct in_device *idev = container_of(head, struct in_device, rcu_head);
304-
in_dev_put(idev);
305-
}
306-
307308
static void inetdev_destroy(struct in_device *in_dev)
308309
{
309310
struct net_device *dev;
@@ -328,7 +329,7 @@ static void inetdev_destroy(struct in_device *in_dev)
328329
neigh_parms_release(&arp_tbl, in_dev->arp_parms);
329330
arp_ifdown(dev);
330331

331-
call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
332+
in_dev_put(in_dev);
332333
}
333334

334335
int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)

0 commit comments

Comments
 (0)