Re: spin_lock and spin_lock_irqsave usage?

David S. Miller (davem@dm.cobaltmicro.com)
Wed, 3 Dec 1997 20:16:49 -0800


From: Peeter Joot <peeter@joot.com>
Date: Wed, 3 Dec 1997 22:58:12 -0500 (EST)

I was wondering what the differences were between
spin_lock_irq(save|restore) and spin_lock.

I have a rough idea of what they do, although I cannot profess to
really understand how the interrupt code works. What I really want
to know is where one should use the irqsave/restore version of
spin_lock and where this is not needed or wanted.

I thought at first this may be on longer sorts of operations where
it is more likely to have an interrupt happen, but this doesn't
seem to be the case as places like REMOVE_LINKS use the irq spin
locks, but only hold the locks for a few operations.

Consider data structure my_thing:

struct my_thing {
struct my_thing *next;
int data;
};

These things are maintained in a global list, used by some subsystem.
Let's say a system call uses this thing, and access to it must be SMP
safe, thus:

spinlock_t my_list_spinlock = SPIN_LOCK_INIT;
static struct my_thing *my_list_of_things = NULL;

asmlinkage int sys_mysys(void)
{
struct my_thing *p;
int ret = -ENOENT;

spin_lock(&my_list_spinlock);
p = list_remove(my_list_of_things);
spin_unlock(&my_list_spinlock);

if(p != NULL) {
ret = p->data;
kfree(p);
}
return ret;
}

Ok, fine enough. HOWEVER if code run from within an interrupt handler
can try to access this list as well you must use the
spin_{lock,unlock}_irq() variants. For example is an interrupt has to
walk my_list_of_things (note this includes things like bh_handler's as
well) you need to clear interrupts else you'd end up with something
like:

spin_lock(&my_list_spinlock);
p = list_remove(...);
....
(interrupt comes in, calls some code which goes)

spin_lock(&my_list_spinlock);

whoops, that'll deadlock forever.

When to use the save/restore variants of the IRQ blocking spinlock
routines is a bit more complicated. The following rule should suffice
though. If you know that your caller will always run with interrupts
on, you can just use spin_lock_irq() and spin_unlock_irq(), however if
you cannot be certain of this you should always use the
spin_lock_irqsave() and spin_lock_irqrestore() routines.

Even more fun scenerio's wrt. interrupts arise when using the
rwlock_t's because if only read_lock()'s occur in the interrupt
handlers then only write_lock()'s need also block irq's...

Later,
David S. Miller
davem@dm.cobaltmicro.com