Hi, I am writing a USB driver for Linux 2.4 and Linux 2.6, and I am currently using a single spin lock exclusively with spin_lock_irqsave() and spin_unlock_irqrestore(). However, I am wondering if it is possible to optimise this approach to locking, please? I am currently using my lock in the following places: - user context - timer functions - tasklets - USB URB callback functions There are also a lot of utility functions which can be called from any of the above. I understand that these utility functions *must* use the irqsave/irqrestore variants because they can have no idea whether interrupts are enabled or not. Therefore my question is really about the timer, tasklet and URB callback functions *themselves*. E.g. tasklet_init(&tasklet, do_task, context); void do_task(unsigned long data) { unsigned long flags; spin_lock_irqsave("lock", flags); ... // do stuff ... spin_unlock_irqrestore("lock", flags); } Is this overkill? Or can I get away with using spin_lock_irq() and spin_unlock_irq()? Similarly for timers: can I use spin_lock_irq() and spin_unlock_irq() in the top-level timer function? I understand that the URB callback function is called in hard IRQ context. Does this mean that I only need spin_lock() and spin_unlock()? E.g. void urb_callback(struct urb *urb, struct pt_regs *regs) { spin_lock("lock"); ... // do stuff ... spin_unlock("lock"); } Finally, I recently tripped over an "interesting" bug in my driver. I was using spin_lock_irqsave and spin_unlock_irqrestore exclusively throughout my driver, and decided to move one of my tasklets onto a work-queue instead. This was fine for a short time, but suddenly my PS2 keyboard stopped responding! My PS2 mouse kept on working, so interrupts were obviously still enabled. (This was on a UP machine, BTW.) Turning the task back into a tasklet fixed the problem immediately. However, the function wasn't exactly rocket-science: void do_task(unsigned long data) { unsigned long flags; spin_lock_irqsave("lock", flags); for each entry in list { if (entry->callback != NULL) { // Just use spin_unlock() and // spin_lock() here instead? spin_unlock_irqrestore("lock", flags); entry->callback(entry->context); spin_lock_irqsave("lock", flags); entry->callback = NULL; } ... // do other things ... entry->wake_me_up = 1; } spin_unlock_irqrestore(); // Wake everyone up! wake_event_interruptible("queue"); if (task_flag) tasklet_schedule(another task); } Isn't the only difference between a tasklet and a work-queue that one runs in interrupt context and the other runs in user context? Can anyone think why this function might have had such an effect on my keyboard, please? Thanks for any advice here, Cheers, Chris ___________________________________________________________ ALL-NEW Yahoo! Messenger - all new features - even more fun! http://uk.messenger.yahoo.com -- Kernelnewbies: Help each other learn about the Linux kernel. Archive: http://mail.nl.linux.org/kernelnewbies/ FAQ: http://kernelnewbies.org/faq/