Stefan Rompf <[EMAIL PROTECTED]> writes:

> as described in net/core/dev.c:
>
>  * The @dev_base list is protected by @dev_base_lock and the rtln
>  * semaphore.
>  *
>  * Pure readers hold dev_base_lock for reading.
>  *
>  * Writers must hold the rtnl semaphore while they loop through the
>  * dev_base list, and hold dev_base_lock for writing when they do the
>  * actual updates.  This allows pure readers to access the list even
>  * while a writer is preparing to update it.

You are _not_ protected with dev_base_lock, only the line:
                dev->operstate_useroverride = OPERU_DORMANT;
is protected. Why don't you do atomic write instead?

dev->operstate_kernel can change (using netif_set_kernel_operstate())
at any moment, including from within IRQ handler. I assume you already
do atomic access. Still, this is racy as a whole. To see what I mean,
could you please outline (fill the empty functions) how would you use
netif_[gs]et_kernel_operstate():

// MODULE 1
// hardware driver changes carrier (called from IRQ handler)
hardware_driver_carrier_changed(int carrier_state)
{
}

// MODULE 2
// protocol driver changes protocol status based on negotations with peer
proto_driver_protocol_state_changed(int protocol_state)
{
}

// protocol driver listens to device status changes:
proto_driver_device_event(int state)
{
}

> rtnl is held by caller during linkwatch_run_queue(),
> operstate_useroverride is 
> only updated in process context, so this works.

What does calling from process context change here? That would be true
with BKL and, say, Linux 2.0 but it's no longer the case. rtnl lock
protects you from userland, though.

> This doesn't guarantee yet that no other netif_set_kernel_operstate() has 
> taken place before linkwatch_work runs - therefore, the change would need to 
> be written in an event queue what I don't do [yet]. But it guarantees that 
> there will be another event if that happens.

Event - yes. But the change will have already been lost.

Look, you can even have this:

CPU1:                                   CPU2:
                                netif_set_kernel_operstate(newstate) {
                                    oldstate = dev->operstate_kernel;
netif_set_kernel_operstate(newstate) {
    oldstate = dev->operstate_kernel;
        if (oldstate != newstate) {
[1]         dev->operstate_kernel = newstate;
                                        if (oldstate != newstate) {
[2]                                          dev->operstate_kernel = newstate;

            smp_wmb();
            linkwatch_fire_event(dev);
                                            smp_wmb();
                                                linkwatch_fire_event(dev);

How do you protect [1] and [2] from overwriting each other? You have to
use a lock, and this lock have to protect not only
netif_set_kernel_operstate() but the whole logic above it.

I don't say it's unacceptable, though I'd ask Jeff or David first (still
hope they'll say something co I'm ccing them).

You don't currently need such lock only because there is just one
module allowed to change a particular flag (__LINK_STATE_NOCARRIER etc.),
and this module is required to serialize all changes (which is usually
done naturally from device IRQ handler which is already serialized).
-- 
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