mirror of https://github.com/torvalds/linux.git
After migrating my laptop from 4.19-LTS to 5.4-LTS a while ago I noticed
that my Ethernet port to which a bond and a VLAN interface are attached
appeared to remain up after resuming from suspend with the cable unplugged
(and that problem still persists with 5.10-LTS).
It happens that the following happens:
- the network driver (e1000e here) prepares to suspend, calls e1000e_down()
which calls netif_carrier_off() to signal that the link is going down.
- netif_carrier_off() adds a link_watch event to the list of events for
this device
- the device is completely stopped.
- the machine suspends
- the cable is unplugged and the machine brought to another location
- the machine is resumed
- the queued linkwatch events are processed for the device
- the device doesn't yet have the __LINK_STATE_PRESENT bit and its events
are silently dropped
- the device is resumed with its link down
- the upper VLAN and bond interfaces are never notified that the link had
been turned down and remain up
- the only way to provoke a change is to physically connect the machine
to a port and possibly unplug it.
The state after resume looks like this:
$ ip -br li | egrep 'bond|eth'
bond0 UP e8:6a:64:64:64:64 <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP>
eth0 DOWN e8:6a:64:64:64:64 <NO-CARRIER,BROADCAST,MULTICAST,SLAVE,UP>
eth0.2@eth0 UP e8:6a:64:64:64:64 <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP>
Placing an explicit call to netdev_state_change() either in the suspend
or the resume code in the NIC driver worked around this but the solution
is not satisfying.
The issue in fact really is in link_watch that loses events while it
ought not to. It happens that the test for the device being present was
added by commit
|
||
|---|---|---|
| .. | ||
| Makefile | ||
| bpf_sk_storage.c | ||
| datagram.c | ||
| datagram.h | ||
| dev.c | ||
| dev_addr_lists.c | ||
| dev_ioctl.c | ||
| devlink.c | ||
| drop_monitor.c | ||
| dst.c | ||
| dst_cache.c | ||
| failover.c | ||
| fib_notifier.c | ||
| fib_rules.c | ||
| filter.c | ||
| flow_dissector.c | ||
| flow_offload.c | ||
| gen_estimator.c | ||
| gen_stats.c | ||
| gro_cells.c | ||
| hwbm.c | ||
| link_watch.c | ||
| lwt_bpf.c | ||
| lwtunnel.c | ||
| neighbour.c | ||
| net-procfs.c | ||
| net-sysfs.c | ||
| net-sysfs.h | ||
| net-traces.c | ||
| net_namespace.c | ||
| netclassid_cgroup.c | ||
| netevent.c | ||
| netpoll.c | ||
| netprio_cgroup.c | ||
| page_pool.c | ||
| pktgen.c | ||
| ptp_classifier.c | ||
| request_sock.c | ||
| rtnetlink.c | ||
| scm.c | ||
| secure_seq.c | ||
| selftests.c | ||
| skbuff.c | ||
| skmsg.c | ||
| sock.c | ||
| sock_diag.c | ||
| sock_map.c | ||
| sock_reuseport.c | ||
| stream.c | ||
| sysctl_net_core.c | ||
| timestamping.c | ||
| tso.c | ||
| utils.c | ||
| xdp.c | ||