Thirumalai Srinivasan wrote:

Garrett,

To prevent deadlocks and recursive locks, we need to have a strict lock ordering across layers. Currently the vast majority seem to be use top -> bottom ordering while holding locks across layers, since most of the control paths go top down.
A simple rule set would be

* Each layer is free to decide on the locking hierarchy used with respect to locks
  it owns, i.e. the locks in its own layer

* There is a single global order for holding locks across layers, i.e. top to bottom.
  So layer A can hold a lock and call into layer B, only if A is above B.

Trying to fine grain the above, and defining the order on a per entry point basis makes the permutations unmanageable. Note that the problem you see is not driver specific. Every
layer has to handle the problem in the upcall direction.

With the above rules, no layer (including the driver) may hold any lock in the upcall direction.

But if the calling context is broken (by use of a taskq for instance), then the risks you describe go away. Since that calling context is already broken, I just would like a guarantee that it will *remain* so. Then I can get away with this kind of approach. Otherwise I add a lot of complexity or an additional context switch (taskq) into my drivers. (Multiple drivers suffer this problem.)

And yes, my suggestion does add a small amount of complexity to the *rules* for drivers (an exception for a few mac_xxx_update entry points), but the gain is the removal of significant complexity or additional context switches in the device drivers.

I'll trade complexity in the framework for elimination of that complexity in drivers (repeated across multiple drivers.)

   -- Garrett

Thirumalai


Garrett D'Amore wrote:

Eric Cheng wrote:

Garrett D'Amore wrote:

So, given this, it is it safe for me to just call mac_{link,tx_notify() while holding driver locks?


I would recommend that you not do this even though the code appears to be safe for now. the reason is that you do not know what the notify callback is going to do. it may somehow loopback down to the driver to acquire the same lock you're holding.


I realize that is a concern, which is why I'm asking here. If all the notify does (and ever will do) is fire off a taskq, then its going to be safe. But if it loops back (or ever will), then its not.



Or must I go to contortions (such as adding my own driver taskq, or a soft interrupt) to ensure that I never call this while holding a driver specific lock?


what's the problem with releasing the lock, then call mac_link_notify()?


You cant just "release" the lock in the middle of your code, always. There are often considerations that have to be made about whether it is actually _safe_ to drop the lock. Assumptions that you made and were protected by the lock, are no longer true after the lock is dropped. (Of course, if you're doing the notify at nearly the same place as you drop the lock anyway, its easy. But if the notify is deep inside nested code, its much harder to do safely.)

For example, on the tx hot path, I might find that I'm out of descriptors. If that happens, I need to attempt to reclaim them. If I do reclaim some, and if the mac layer was previously suspended due to flow control, then I need to notify the mac layer.

All this happens in the hot path, and dropping and reacquiring the lock here would be a significant pain in the butt.

I can try to track whether I've reclaimed resources or not, and do the notify later after the lock is reclaimed, but that significantly complicates the code, separates the action of notification far from the point when I've discovered that I should do the notification, and is thus likely to be a source of errors, particularly when the code is maintained by someone else who may not see the bigger picture.

Its much simpler if I have just one call to mac_tx_update, at the point at which I've discovered that I need to do it, rather than deferring it to some other point after I've dropped the lock.


Will this guarantee hold true going forward? Obviously, since it does a lot to simplify driver design, and eliminate extra context switches, I'd really prefer to be able to rely on this behavior.


we're redesigning nemo's locking as part of the crossbow project. you will hear more about this in several weeks time. for now, I'd suggest that you try not to hold locks across any mac_* interface. if there are issues with doing this, let us know and we'll take your needs into account in our new design.


See the above. I'd really, really like to have mac_xxx_update() continue to use the asynchronous taskq notification and therefore be safe to call with locks held, if at all possible. Obviously the other mac functions (e.g. mac_rx, etc.) really do need to be called without any locks held.


   -- Garrett

_______________________________________________
networking-discuss mailing list
[email protected]



_______________________________________________
networking-discuss mailing list
[email protected]

Reply via email to