You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
70 lines
2.6 KiB
70 lines
2.6 KiB
6 years ago
|
From dd7590a3ab3f0804ed5e930295e2caa5979e3958 Mon Sep 17 00:00:00 2001
|
||
|
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||
|
Date: Thu, 28 Feb 2019 22:57:33 +0100
|
||
|
Subject: [PATCH] leds: trigger: netdev: fix refcnt leak on interface rename
|
||
|
MIME-Version: 1.0
|
||
|
Content-Type: text/plain; charset=UTF-8
|
||
|
Content-Transfer-Encoding: 8bit
|
||
|
|
||
|
Renaming a netdev-trigger-tracked interface was resulting in an
|
||
|
unbalanced dev_hold().
|
||
|
|
||
|
Example:
|
||
|
> iw phy phy0 interface add foo type __ap
|
||
|
> echo netdev > trigger
|
||
|
> echo foo > device_name
|
||
|
> ip link set foo name bar
|
||
|
> iw dev bar del
|
||
|
[ 237.355366] unregister_netdevice: waiting for bar to become free. Usage count = 1
|
||
|
[ 247.435362] unregister_netdevice: waiting for bar to become free. Usage count = 1
|
||
|
[ 257.545366] unregister_netdevice: waiting for bar to become free. Usage count = 1
|
||
|
|
||
|
Above problem was caused by trigger checking a dev->name which obviously
|
||
|
changes after renaming an interface. It meant missing all further events
|
||
|
including the NETDEV_UNREGISTER which is required for calling dev_put().
|
||
|
|
||
|
This change fixes that by:
|
||
|
1) Comparing device struct *address* for notification-filtering purposes
|
||
|
2) Dropping unneeded NETDEV_CHANGENAME code (no behavior change)
|
||
|
|
||
|
Fixes: 06f502f57d0d ("leds: trigger: Introduce a NETDEV trigger")
|
||
|
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||
|
Acked-by: Pavel Machek <pavel@ucw.cz>
|
||
|
Signed-off-by: Jacek Anaszewski <jacek.anaszewski@gmail.com>
|
||
|
---
|
||
|
drivers/leds/trigger/ledtrig-netdev.c | 13 +++++--------
|
||
|
1 file changed, 5 insertions(+), 8 deletions(-)
|
||
|
|
||
|
--- a/drivers/leds/trigger/ledtrig-netdev.c
|
||
|
+++ b/drivers/leds/trigger/ledtrig-netdev.c
|
||
|
@@ -299,11 +299,11 @@ static int netdev_trig_notify(struct not
|
||
|
notifier);
|
||
|
|
||
|
if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE
|
||
|
- && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER
|
||
|
- && evt != NETDEV_CHANGENAME)
|
||
|
+ && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER)
|
||
|
return NOTIFY_DONE;
|
||
|
|
||
|
- if (strcmp(dev->name, trigger_data->device_name))
|
||
|
+ if (!(dev == trigger_data->net_dev ||
|
||
|
+ (evt == NETDEV_REGISTER && !strcmp(dev->name, trigger_data->device_name))))
|
||
|
return NOTIFY_DONE;
|
||
|
|
||
|
cancel_delayed_work_sync(&trigger_data->work);
|
||
|
@@ -318,12 +318,9 @@ static int netdev_trig_notify(struct not
|
||
|
dev_hold(dev);
|
||
|
trigger_data->net_dev = dev;
|
||
|
break;
|
||
|
- case NETDEV_CHANGENAME:
|
||
|
case NETDEV_UNREGISTER:
|
||
|
- if (trigger_data->net_dev) {
|
||
|
- dev_put(trigger_data->net_dev);
|
||
|
- trigger_data->net_dev = NULL;
|
||
|
- }
|
||
|
+ dev_put(trigger_data->net_dev);
|
||
|
+ trigger_data->net_dev = NULL;
|
||
|
break;
|
||
|
case NETDEV_UP:
|
||
|
case NETDEV_CHANGE:
|