lib: allow idr to be used in irq context
Subsystems (3)
PATCH 1/2 lib: allow idr to be used in irq context
Hi,
This patch allows idr to be used in irq context.
idr_pre_get() is necessary to be called before idr_get_new() is called. No locking is necessary when calling idr_pre_get().
But idr_get_new(), idr_find() and idr_remove() must be serialized with respect to each other.
All of the aforementioned, may end up in alloc_layer() or free_layer() which grabs the idp lock using spin_lock.
If idr_get_new() or idr_remove() is used in IRQ context, then we may get a lockup when idr_pre_get was called in process context and an IRQ interrupted while it held the idp lock.
This patch changes the spin_lock to spin_lock_irqsave, and spin_unlock to spin_unlock_irqrestore, to allow idr_get_new(), idr_find() and idr_remove() to be called from IRQ context, while idr_pre_get() to be called in process context.
lib/idr.c renamed from lib/idr.c.old +6 -4
@@ -37,27 +37,29 @@static struct idr_layer *alloc_layer (struct idr *idp) {struct idr_layer *p; +unsigned long flags; -spin_lock (&idp->lock); +spin_lock_irqsave (&idp->lock, flags);if ((p = idp->id_free)) { idp->id_free = p->ary[0 ]; idp->id_free_cnt--; p->ary[0 ] =NULL ; } -spin_unlock (&idp->lock); +spin_unlock_irqrestore (&idp->lock, flags);return (p); }static void free_layer (struct idr *idp,struct idr_layer *p) { +unsigned long flags;/* * Depends on the return element being zeroed. */ -spin_lock (&idp->lock); +spin_lock_irqsave (&idp->lock, flags); p->ary[0 ] = idp->id_free; idp->id_free = p; idp->id_free_cnt++; -spin_unlock (&idp->lock); +spin_unlock_irqrestore (&idp->lock, flags); }/**