Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is in_irq() reliable?

Unreliable Guide To Hacking The Linux Kernel states that

You can tell you are in a hardware interrupt, because in_irq() returns true.
Caution. Beware that this will return a false positive if interrupts are disabled (see below).

Is it really the case that in_irq() may return non-zero not in hardirq context in the Linux kernels 2.6.32 or newer on x86?

In my experiments with the kernel 2.6.32 (Debian 6) and 3.4 (OpenSUSE 12.1), in_irq() always returned 0 when called from a process context even if it was called between local_irq_disable() and local_irq_enable(). The results were the same when I used spinlock functions that disable interrupts instead of local_irq*.

From the source code of the kernel, I currently cannot see how in_irq() can return a false positive. Could anyone clarify this?

EDIT: I have also tried both *_irqsave() and *_irq() spinlock API as well as local_irq_save() / local_irq_restore(), the results were the same, that is, in_irq() returned 0 when the interrupts were disabled. Disabling the interrupts explicitly via cli machine instruction on x86 also did not force in_irq() to return non-zero.

like image 907
Eugene Avatar asked Oct 21 '22 18:10

Eugene


1 Answers

in_irq() is a wrapper that looks at some bits in preempt_count, which is an int in the thread_info struct and a value of 0 means it's not pre-empted so it's not in an irq.

local_irq_disable() by itself does not affect that count, but spin_lock_irqsave() does, so that could lead to the false positive. You say you used the spinlock functions, did you use this one? If so, look to see if the value of preempt_count is changing.

EDIT: Just to cover all the bases, check to make sure kernel pre-emption is enabled.

like image 154
engineerC Avatar answered Oct 27 '22 15:10

engineerC