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/