why spin_lock_irqsave needs to disable preemption on multiprocessor

1.1k views Asked by At

Just curious why spin_lock_irqsave needs to disable the preemption after disabling local interrupt.

static inline unsigned long __raw_spin_lock_irqsave(raw_spinlock_t *lock)
{
    unsigned long flags;

    local_irq_save(flags);
    preempt_disable(); ===> can preemption happen with interrupt disabled?
    spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
    ...
}

Preemption should only be possible with interrupt enabled, thus there should be no need to worry about preemption after disabling interrupt.

1

There are 1 answers

0
Matviy Kotoniy On

Because there exist functions which cause preemption unless preemption is explicitly disabled, regardless of the state of interrupts. The assumption being that if preemption was not allowed, it would be explicitly disabled and the function would not preempt. Using interrupts to do preemption disabling instead violates this assumption.

One such function is cond_resched(), which calls _cond_resched() in core.c (https://elixir.bootlin.com/linux/v5.9-rc5/source/kernel/sched/core.c#L6116)

It checks for preemption being enabled and invokes the scheduler. This function is called from a number of places in the kernel and it's possible to accidentally trigger one of them, breaking your spin-lock protected critical section.

Furthermore, the interrupt disabling spin lock implies that your critical section may be accessed from an interrupt handler. If you accidentally trigger preemption using cond_resched(), once your process gets scheduled back interrupts will be re-enabled. If an interrupt occurs which attempts to acquire the lock, you will have a deadlock.