linux_kernel_portfolio

GFP CONTEXT BUG EXERCISE

Axiomatic Derivation | Linux Kernel 6.14.0-37-generic | x86_64


MACHINE DATA (AXIOMS)

Kernel: 6.14.0-37-generic
PAGE_SIZE: 4096
GFP_KERNEL: 0xCC0
GFP_ATOMIC: 0x0 (simplified, actually has other bits)

PART 1: PREEMPT_COUNT BITS (DO BY HAND)

  1. AXIOM: preempt_count() returns 32-bit integer.
  2. AXIOM: Bits 0-7 = preemption depth. Range: 0-255.
  3. AXIOM: Bits 8-15 = softirq count.
  4. AXIOM: Bits 16-19 = hardirq count.
  5. AXIOM: Bit 20 = NMI.
  6. CALCULATE: Softirq mask = bits 8-15 = 0x___ (fill hex).
  7. CALCULATE: Hardirq mask = bits 16-19 = 0x___ (fill hex).
  8. CALCULATE: Interrupt mask = softirq hardirq NMI = 0x___ (fill hex).
  9. FORMULA: in_interrupt() = (preempt_count() & interrupt_mask) != 0.

PART 2: CONTEXT DETERMINATION (DO BY HAND)

  1. SCENARIO A: preempt_count() = 0x00000000.
  2. CALCULATE: 0x00000000 & 0x1FFF00 = ___.
  3. RESULT: in_interrupt() = ___ (true/false).
  4. CONTEXT: ___ context (process/interrupt).
  5. GFP: Can use GFP_KERNEL? ___ (yes/no).

  6. SCENARIO B: preempt_count() = 0x00000100.
  7. CALCULATE: 0x00000100 & 0x1FFF00 = ___.
  8. RESULT: in_interrupt() = ___ (true/false).
  9. CONTEXT: ___ context (process/interrupt/softirq).
  10. GFP: Can use GFP_KERNEL? ___ (yes/no).

  11. SCENARIO C: preempt_count() = 0x00010000.
  12. CALCULATE: 0x00010000 & 0x1FFF00 = ___.
  13. RESULT: in_interrupt() = ___ (true/false).
  14. CONTEXT: ___ context (hardirq).
  15. GFP: Can use GFP_KERNEL? ___ (yes/no).

PART 3: GFP FLAGS BITS (DO BY HAND)

  1. AXIOM: ___GFP_IO_BIT = 6.
  2. AXIOM: ___GFP_FS_BIT = 7.
  3. AXIOM: ___GFP_DIRECT_RECLAIM_BIT = 10.
  4. AXIOM: ___GFP_KSWAPD_RECLAIM_BIT = 11.
  5. CALCULATE: _GFP_IO = 1 « 6 = __.
  6. CALCULATE: _GFP_FS = 1 « 7 = __.
  7. CALCULATE: _GFP_DIRECT_RECLAIM = 1 « 10 = __.
  8. CALCULATE: _GFP_KSWAPD_RECLAIM = 1 « 11 = __.
  9. CALCULATE: __GFP_RECLAIM = __GFP_DIRECT_RECLAIM _GFP_KSWAPD_RECLAIM = __ __ = __.
  10. CALCULATE: GFP_KERNEL = __GFP_RECLAIM __GFP_IO _GFP_FS = __ ___ __ = __.
  11. VERIFY: GFP_KERNEL = 0xCC0? ___ (✓/✗).

PART 4: WHY GFP_KERNEL FAILS IN INTERRUPT

  1. PROBLEM: alloc_page(GFP_KERNEL) in softirq.
  2. GFP_KERNEL contains _GFP_DIRECT_RECLAIM = bit 10 = __.
  3. __GFP_DIRECT_RECLAIM means: kernel MAY call schedule() to wait for pages.
  4. schedule() checks: in_atomic()?
  5. If in_atomic() = true AND schedule() called → BUG_ON(“scheduling while atomic”).
  6. Timer callback runs in softirq → preempt_count() has bits 8-15 set.
  7. in_interrupt() = true → atomic context.
  8. schedule() called → BUG.

PART 5: TRACE TIMER FLOW

  1. module_init() runs in process context.
  2. preempt_count() = 0x00000000 → in_interrupt() = false.
  3. GFP_KERNEL safe here.
  4. timer_setup() arms timer for 100ms later.
  5. 100ms passes…
  6. Timer fires → timer_callback() runs.
  7. Now in softirq context → preempt_count() = 0x00000100 (example).
  8. alloc_page(GFP_KERNEL) → checks if can reclaim.
  9. __GFP_DIRECT_RECLAIM set → tries to sleep.
  10. schedule() → BUG_ON(in_atomic()).

PART 6: VERIFICATION COMMANDS

  1. BEFORE: sudo insmod gfp_context_bug.ko
  2. WAIT: 100ms for timer to fire.
  3. CHECK: sudo dmesg grep GFP_CONTEXT
  4. EXPECTED OUTPUT:
    • init: in_interrupt()=0, preempt_count()=0x0
    • timer_callback: in_interrupt()=1, preempt_count()=0x??? (non-zero)
    • alloc_SUCCESS or alloc_FAILED (depending on memory pressure)
  5. IF BUG LINE UNCOMMENTED: dmesg shows “BUG: scheduling while atomic” or similar.
  6. sudo rmmod gfp_context_bug

PART 7: FAILURE PREDICTIONS

F1. User uses GFP_KERNEL everywhere → works in init, crashes in timer. F2. User confuses preempt_count bits → wrong mask calculation. F3. User forgets timer runs async → expects sequential execution. F4. User doesn’t check alloc return → NULL dereference in interrupt = hard crash. F5. User uses GFP_ATOMIC in process context → works but wastes emergency reserves.


ANSWERS (FILL AFTER TRYING)

06. 0xFF00 (bits 8-15)
07. 0xF0000 (bits 16-19)
08. 0x1FFF00 (all interrupt bits)
11. 0x00000000
12. false
13. process
14. yes
16. 0x00000100
17. true
18. softirq
19. no
21. 0x00010000
22. true
23. hardirq
24. no
29. 64 = 0x40
30. 128 = 0x80
31. 1024 = 0x400
32. 2048 = 0x800
33. 0x400 | 0x800 = 0xC00
34. 0xC00 | 0x40 | 0x80 = 0xCC0
35. ✓
37. 0x400