## Near-Term — Completed

- [x] MMU notifier implementation for DKMS mode (stock kernel compatibility)
  - Created minimem_mmu.c/h with MMU notifier release callback
  - On process exit: walks page tables, clears MiniMem PTE markers, frees zsmalloc
  - Eliminates "unrecognized swap entry" warnings on stock kernels
  - Deferred registration via workqueue (mmu_notifier_get takes mmap_write_lock internally)
  - Uses down_write_trylock on mmap_lock in work handler to avoid blocking
  - Two-phase minimem_zap_range: collect+clear PTEs under PTL, then free zsmalloc outside PTL
  - pte_clear in release callback prevents kernel from seeing stale swap entries
- [x] Fix mmap_lock deadlock: scanner holds mmap_read_lock, MMU notifier registration
    takes mmap_write_lock internally
  - Root cause: mmu_notifier_get() calls mmap_write_lock(mm) internally
  - Fix: minimem_mmu_register_deferred() queues mm for later registration in workqueue
  - Work handler uses down_write_trylock(&mm->mmap_lock) to avoid blocking
  - Scanner uses mmap_read_trylock instead of mmap_read_lock to avoid deadlock
  - drain_and_restore also uses mmap_read_trylock
- [x] Fix rwsem deadlock in parallel decompression
  - Root cause: minimem_map rwsem write lock held by scanner, read lock held by
    parallel decompression across wait_for_completion
  - Fix: kept rwsem in minimem_map (removing it caused init SIGBUS crash)
- [x] Fix VMA iteration API: vma_next(mm, vma) → VMA_ITERATOR/for_each_vma
- [x] Added mmu_release_count and mmu_release_pages sysfs attributes
- [x] Added compress_pid sysfs attribute for opt-in per-process compression
- [x] Both stock and custom kernel VM tests pass (no panics, no hangs, no leaks)
- [x] No "unrecognized swap entry" messages on stock kernel (MMU notifier handles cleanup)
- [x] Scanner sweep enabled on stock kernels via kretprobe
  - Root cause: pte_unmap_same() is no-op on x86-64, so do_swap_page() doesn't bail out
    after kprobe handler installs present PTE; handle_pte_marker() returns SIGBUS
  - Fix: replaced struct kprobe with struct kretprobe on do_swap_page()
  - Entry handler decompresses and installs present PTE, sets data->handled
  - Return handler changes VM_FAULT_SIGBUS to VM_FAULT_NOPAGE for MiniMem faults
  - p99 decompress latency: 0.4µs (stock/kretprobe) vs 0.3µs (custom/patched)
- [x] MMU notifier cleanup on module unload
  - Root cause: dangling ops pointers in live processes' notifier lists
  - Fix: track notifiers via list_head in minimem_mmu_sub, release all refs (users count)
    in minimem_mmu_exit(), then mmu_notifier_synchronize()
  - Added minimem_mmu_exiting flag to make release callback no-op during exit

## Near-Term — Open Issues

- [x] Scanner mark pass has no batch limit
  - Added scanner_mark_budget_pages (default 65536, range 4096-524288)
  - Caps pages examined per mark phase to prevent CPU spikes on large-memory systems
  - Cursor-based resumption: mark pass saves (pid, addr) position across cycles
  - Mark pass yields when budget exhausted or CPU time budget exceeded

- [x] No CPU budget mechanism for scanner
  - Added scanner_cpu_budget_ms (default 50ms, range 1-1000)
  - Each mark/sweep phase measures wall-clock time and yields when budget exceeded
  - Cursor-based resumption for sweep phase too (saves pid + addr)
  - New sysfs stats: scanner_mark_yielded, scanner_sweep_yielded
  - On 16GB system: mark phase processes ~256MB (64K pages) per 50ms cycle
  - Feels like a tiny trickle of CPU, not a flood

- [ ] Munmap cleanup not handled on stock kernels
  - invalidate_range_start is a no-op
  - PTE markers remain after munmap, cleaned up on process exit via release callback
  - Minor gap — zsmalloc allocations are freed eventually

- [ ] CPU overhead test threshold too strict for VMs
  - Scanner rate 132-133 pages/s in QEMU VM (4 vCPU, 8GB)
  - Test threshold: 1000 pages/s for "OK", 10000 for "PASS"
  - Need to either: lower VM test threshold, or adjust test for virtualized env
  - Real hardware likely performs much better (10-100x faster page scanning)

- [ ] kretprobe overhead on non-MiniMem page faults
  - kretprobe fires on every do_swap_page() call, not just MiniMem faults
  - Entry handler does a quick is_minimem_pte() check and returns early for non-MiniMem
  - Return handler only fires when data->handled is true (MiniMem faults only)
  - Overhead for non-MiniMem faults is one PTE comparison in entry handler — negligible

- [ ] Architecture portability of kretprobe approach
  - regs_set_return_value()/regs_return_value() may need arch-specific implementations
  - pte_unmap_same() works on non-x86-64 (ARM64, etc.) so original kprobe approach may work there
  - Need testing on ARM64 and other architectures

## Near-Term — Kernel Module (Critical)

- [ ] Test on real hardware (not QEMU) — NUMA, large memory, different CPU arches
- [ ] Verify shrinker under real memory pressure
- [ ] THP + KSM compatibility testing (kernel upstreaming prerequisite)
- [ ] OOM behavior verification (kernel upstreaming prerequisite)
- [ ] zram coexistence load testing (kernel upstreaming prerequisite)

## Near-Term — VM Testing

- [ ] E2E test: large memory VM (4GB+)