Stefan Rompf <[EMAIL PROTECTED]> writes: > +++ linux-2.6.14/net/core/link_watch.c > @@ -75,7 +75,14 @@ void linkwatch_run_queue(void) > clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state); > > if (dev->flags & IFF_UP) { > - if (netif_carrier_ok(dev)) { > + if (netif_get_kernel_operstate(dev) < OPER_UP && > + dev->operstate_useroverride == > OPERU_UP_UNTIL_DORMANT) { > + write_lock_bh(&dev_base_lock); > + dev->operstate_useroverride = OPERU_DORMANT; > + write_unlock_bh(&dev_base_lock);
Why do you do that instead of atomic write? The locking works differently - you don't need to protect a single write (because it can be done atomically), you need to protect fragments of code that read the value and then change it depending on the value and/or on other factors (probably not the best description, you may want to seek a better one). Such as (example only, probably not exactly correct here): *lock(xx); if (netif_get_kernel_operstate(dev) < OPER_UP && dev->operstate_useroverride == OPERU_UP_UNTIL_DORMANT) { dev->operstate_useroverride = OPERU_DORMANT; } ... *unlock(xx); If you don't protect the "critical section" with a lock, the kernel may change the value in different place (with another CPU, preempt etc.) before you subsequently alter it again here and the first change (event) could be lost. > +void netif_set_kernel_operstate(struct net_device *dev, unsigned char > newstate) { > + char oldstate = dev->operstate_kernel; > + if (oldstate != newstate) { > + dev->operstate_kernel = newstate; > + smp_wmb(); > + linkwatch_fire_event(dev); > + } > +} Still not sure any wmb() is needed. Unless I'm mistaken that's for synchronizing I/O mainly (and to prevent gcc reordering but don't see any possible here). atomic_set() maybe? But it doesn't make all real locking issues go away. > @@ -561,6 +561,9 @@ static int vlan_device_event(struct noti > struct vlan_group *grp = __vlan_find_group(dev->ifindex); > int i, flgs; > struct net_device *vlandev; > + unsigned char ostate = netif_get_operstate(dev); > + > + if (ostate == OPER_DOWN) ostate = OPER_LOWERLAYERDOWN; > > if (!grp) > goto out; > @@ -578,13 +581,7 @@ static int vlan_device_event(struct noti > if (!vlandev) > continue; > > - if (netif_carrier_ok(dev)) { > - if (!netif_carrier_ok(vlandev)) > - netif_carrier_on(vlandev); > - } else { > - if (netif_carrier_ok(vlandev)) > - netif_carrier_off(vlandev); > - } > + netif_set_kernel_operstate(vlandev, ostate); This probably isn't a problem as that's the only writer and calls are serialized (you don't want admin status - contrary to what SNMP says - in the operstate, and nothing changes carrier state). But real world (WLAN, WAN) is different, there are at least 2 writers even without admin status here. But if we do that, we should move admin status here as well I think (and probably get rid of __LIST_STATE_* completely). Nothing more to lose and at least SNMP consistency to gain (not only that). -- Krzysztof Halasa - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html