Recursive spinlocks for Network Recursion Bugs in 2.6.18

From: Jeffrey V. Merkey
Date: Sat Dec 09 2006 - 01:21:10 EST




This code segment in /net/core/dev.c is a prime example of the need for recursive spin locks.

if (dev->flags & IFF_UP) {
int cpu = smp_processor_id(); /* ok because BHs are off */

if (dev->xmit_lock_owner != cpu) {

HARD_TX_LOCK(dev, cpu);

if (!netif_queue_stopped(dev)) {
rc = 0;
if (!dev_hard_start_xmit(skb, dev)) {
HARD_TX_UNLOCK(dev);
goto out;
}
}
HARD_TX_UNLOCK(dev);
if (net_ratelimit())
printk(KERN_CRIT "Virtual device %s asks to "
"queue packet!\n", dev->name);
} else {
/* Recursion is detected! It is possible,
* unfortunately */
if (net_ratelimit())
printk(KERN_CRIT "Dead loop on virtual device "
"%s, fix it urgently!\n", dev->name);
}
}

Recursive spinlocks perform the logic

rspin_lock(spin_lock)
{
if (spin_lock->lock->cpu_owner = cpu I am on) && (spin_lock->lock)
{
spin_lock->use_count++;
}
else
{
spin_lock(lock)
lock->cpu_owner = cpu I am on;
lock->use_count++;
}
}

rspin_unlock(spin_lock)
{
if (spin_lock->lock->cpu_owner = cpu I am on) && (spin_lock->use_count)
{
spin_lock->use_count--;
}
else
{ lock->use_count++; lock->cpu_owner = cpu I am on;
spin_unlock(lock)
}
}

One implementation of this is:

LONG rspin_lock(rlock_t *rlock)
{
register LONG proc = get_processor_id();
register LONG retCode;

if (rlock->lockValue && rlock->processor == (proc + 1))
{
rlock->count++;
retCode = 1;
}
else
{
dspin_lock(&rlock->lockValue);
rlock->processor = (proc + 1);
retCode = 0;
}

return retCode;

}
LONG rspin_unlock(rlock_t *rlock)
{

register LONG retCode;

if (rlock->count)
{
rlock->count--;
retCode = 1;
}
else
{
rlock->processor = 0;
dspin_unlock(&rlock->lockValue);
retCode = 0;
}

return retCode;
}

Just a suggestion. Would be a useful primitive for a lot of context implementations where users turn on interrupts inside of nested spin lock code.

Jeff




-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/