5
votes

I have a device driver I am working with that has a shared resource between the ISR (more specifically the bottom half of the ISR) and the read() call.

The ISR does nothing more than call schedule_work() to get the bottom half to do the heavy lifting. The resource is shared between read() (i.e., user context) and the function that implements the bottom half, which is why I am locking with spin_lock_bh().

What I don't understand is the mechanics of the locking. Say someone currently holds the lock, what happens when the ISR hits schedule_work() (i.e., a hardware interrupt fired while we were holding the lock)? Does the work still get scheduled and then ran at a later time or does it get dropped to the floor? Stated differently... what is actually "locked" or prevented (i.e., the work queue or the execution of the work)? Does the work queue get updated?

To contrast my question, I understand that if I were using spin_lock_irqsave(), the ISR would be disabled while holding the lock, so I wouldn't get to schedule_work() in the first place, but given how the resource is shared, I don't think I need to or want to disable hardware interrupts when holding the lock.

2

2 Answers

6
votes

An ISR can't wait for a lock if it might be held by code that does not disable interrupts. That would result in a deadlock. spin_lock_irqsave first disables interrupts, saving the previous state, then takes the lock. The restore undoes this in reverse order.

A bottom half is still an interrupt. spin_lock_bh does the equivalent by disabling bottom half execution, then taking the lock. This prevents bottom half execution from stepping on our read code.

A lock prevents multiple threads from executing the locked code. The work queue is protected by only being operated on while holding the lock.

2
votes

spin_lock_bh disables softirqs (bh is an ancient term that actually refers to softirqs). However, work_queues triggered with schedule_work don't actually run in a softirq but in a dedicated thread, thus process context.

Therefore your driver needs just the simple spin_lock() to protect against concurrent read() calls.

It may need to disable interrupts when accessing resources shared with the "top-half" but that was not the scope of your question.