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

Reply via email to