Recursive spinlocks for Network Recursion Bugs in 2.6.18

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 





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 [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux