Pete Zaitcev gives the following summary:
          If you are in a process context (any syscall) and want to
	lock other process out, use a semaphore.  You can take a semaphore
	and sleep (copy_from_user*( or
	kmalloc(x,GFP_KERNEL)).
      
	Otherwise (== data can be touched in an interrupt), use
	spin_lock_irqsave() and
	spin_unlock_irqrestore().
	
	Avoid holding spinlock for more than 5 lines of code and
	across any function call (except accessors like
	readb).
	
The following table lists the minimum locking requirements between various contexts. In some cases, the same context can only be running on one CPU at a time, so no locking is required for that context (eg. a particular thread can only run on one CPU at a time, but if it needs shares data with another thread, locking is required).
	Remember the advice above: you can always use
	spin_lock_irqsave(), which is a superset
	of all other spinlock primitives.
   
Table 5-1. Table of Locking Requirements
| IRQ Handler A | IRQ Handler B | Softirq A | Softirq B | Tasklet A | Tasklet B | Timer A | Timer B | User Context A | User Context B | |
| IRQ Handler A | None | |||||||||
| IRQ Handler B | spin_lock_irqsave() | None | ||||||||
| Softirq A | spin_lock_irq() | spin_lock_irq() | spin_lock() | |||||||
| Softirq B | spin_lock_irq() | spin_lock_irq() | spin_lock() | spin_lock() | ||||||
| Tasklet A | spin_lock_irq() | spin_lock_irq() | spin_lock() | spin_lock() | None | |||||
| Tasklet B | spin_lock_irq() | spin_lock_irq() | spin_lock() | spin_lock() | spin_lock() | None | ||||
| Timer A | spin_lock_irq() | spin_lock_irq() | spin_lock() | spin_lock() | spin_lock() | spin_lock() | None | |||
| Timer B | spin_lock_irq() | spin_lock_irq() | spin_lock() | spin_lock() | spin_lock() | spin_lock() | spin_lock() | None | ||
| User Context A | spin_lock_irq() | spin_lock_irq() | spin_lock_bh() | spin_lock_bh() | spin_lock_bh() | spin_lock_bh() | spin_lock_bh() | spin_lock_bh() | None | |
| User Context B | spin_lock_irq() | spin_lock_irq() | spin_lock_bh() | spin_lock_bh() | spin_lock_bh() | spin_lock_bh() | spin_lock_bh() | spin_lock_bh() | down_interruptible | None |