Add a netdevice_tracker inside struct net_device, to track the self reference when a device has an active watchdog timer.
Unified · Split
| @@ -1951,6 +1951,7 @@ enum netdev_ml_priv_type { · 1950 unmodified lines | |||
| 1951 | * | 1951 | * |
| 1952 | * @dev_addr_shadow: Copy of @dev_addr to catch direct writes. | 1952 | * @dev_addr_shadow: Copy of @dev_addr to catch direct writes. |
| 1953 | * @linkwatch_dev_tracker: refcount tracker used by linkwatch. | 1953 | * @linkwatch_dev_tracker: refcount tracker used by linkwatch. |
| 1954 | * @watchdog_dev_tracker: refcount tracker used by watchdog. | ||
| 1954 | * | 1955 | * |
| 1955 | * FIXME: cleanup struct net_device such that network protocol info | 1956 | * FIXME: cleanup struct net_device such that network protocol info |
| 1956 | * moves out. | 1957 | * moves out. |
| @@ -2282,6 +2283,7 @@ struct net_device { · 325 unmodified lines | |||
| 2282 | 2283 | ||
| 2283 | u8 dev_addr_shadow[MAX_ADDR_LEN]; | 2284 | u8 dev_addr_shadow[MAX_ADDR_LEN]; |
| 2284 | netdevice_tracker linkwatch_dev_tracker; | 2285 | netdevice_tracker linkwatch_dev_tracker; |
| 2286 | netdevice_tracker watchdog_dev_tracker; | ||
| 2285 | }; | 2287 | }; |
| 2286 | #define to_net_dev(d) container_of(d, struct net_device, dev) | 2288 | #define to_net_dev(d) container_of(d, struct net_device, dev) |
| 2287 | 2289 | ||
| @@ -499,6 +499,7 @@ EXPORT_SYMBOL(netif_tx_unlock); · 498 unmodified lines | |||
| 499 | static void dev_watchdog(struct timer_list *t) | 499 | static void dev_watchdog(struct timer_list *t) |
| 500 | { | 500 | { |
| 501 | struct net_device *dev = from_timer(dev, t, watchdog_timer); | 501 | struct net_device *dev = from_timer(dev, t, watchdog_timer); |
| 502 | bool release = true; | ||
| 502 | 503 | ||
| 503 | spin_lock(&dev->tx_global_lock); | 504 | spin_lock(&dev->tx_global_lock); |
| 504 | if (!qdisc_tx_is_noop(dev)) { | 505 | if (!qdisc_tx_is_noop(dev)) { |
| @@ -534,12 +535,13 @@ static void dev_watchdog(struct timer_list *t) · 29 unmodified lines | |||
| 534 | if (!mod_timer(&dev->watchdog_timer, | 535 | if (!mod_timer(&dev->watchdog_timer, |
| 535 | round_jiffies(jiffies + | 536 | round_jiffies(jiffies + |
| 536 | dev->watchdog_timeo))) | 537 | dev->watchdog_timeo))) |
| 537 | dev_hold(dev); | 538 | release = false; |
| 538 | } | 539 | } |
| 539 | } | 540 | } |
| 540 | spin_unlock(&dev->tx_global_lock); | 541 | spin_unlock(&dev->tx_global_lock); |
| 541 | 542 | ||
| 542 | dev_put(dev); | 543 | if (release) |
| 544 | dev_put_track(dev, &dev->watchdog_dev_tracker); | ||
| 543 | } | 545 | } |
| 544 | 546 | ||
| 545 | void __netdev_watchdog_up(struct net_device *dev) | 547 | void __netdev_watchdog_up(struct net_device *dev) |
| @@ -549,7 +551,7 @@ void __netdev_watchdog_up(struct net_device *dev) · 3 unmodified lines | |||
| 549 | dev->watchdog_timeo = 5*HZ; | 551 | dev->watchdog_timeo = 5*HZ; |
| 550 | if (!mod_timer(&dev->watchdog_timer, | 552 | if (!mod_timer(&dev->watchdog_timer, |
| 551 | round_jiffies(jiffies + dev->watchdog_timeo))) | 553 | round_jiffies(jiffies + dev->watchdog_timeo))) |
| 552 | dev_hold(dev); | 554 | dev_hold_track(dev, &dev->watchdog_dev_tracker, GFP_ATOMIC); |
| 553 | } | 555 | } |
| 554 | } | 556 | } |
| 555 | EXPORT_SYMBOL_GPL(__netdev_watchdog_up); | 557 | EXPORT_SYMBOL_GPL(__netdev_watchdog_up); |
| @@ -563,7 +565,7 @@ static void dev_watchdog_down(struct net_device *dev) · 7 unmodified lines | |||
| 563 | { | 565 | { |
| 564 | netif_tx_lock_bh(dev); | 566 | netif_tx_lock_bh(dev); |
| 565 | if (del_timer(&dev->watchdog_timer)) | 567 | if (del_timer(&dev->watchdog_timer)) |
| 566 | dev_put(dev); | 568 | dev_put_track(dev, &dev->watchdog_dev_tracker); |
| 567 | netif_tx_unlock_bh(dev); | 569 | netif_tx_unlock_bh(dev); |
| 568 | } | 570 | } |
| 569 | 571 | ||