M2 data path: BSD netisr workqueue + lock reentrancy fixes + diagnostics

- hooks: packets are queued to pfk_netisr ordered wq (process context) and
  re-injected with an skb->mark guard (PFK_MARK_PASSED); softirq-safe,
  documented divergence vs OpenBSD in-place ip_input continuation
- pfk_rwlock: per-task writer recursion (NET/PF lock nesting like OpenBSD)
- pfk_net: holder-task+depth reentrancy (pid-based hack removed)
- ifnet events deferred to ordered workqueue (rtnl AB-BA fix)
- idr iteration start index fix (kifs were never attached -> kif==NULL drop)
- pfk_lock_trace module param for lock diagnostics
- tests/vm: 01-state 02-block 03-tables 04-anchors + lib; vm-run-tests.sh
- docs/en/install.md: apply/build guide (core patch set currently EMPTY)
This commit is contained in:
lgcosta committed 2026-11-11 17:05:53 -03:00
1 parent 5323ee2c71
commit a0941b77fe
12 files changed
+413 -108

No files matched your search

+44 -10
View File
@@ -100,27 +100,61 @@ taskq_create(const char *name, unsigned int nthreads, int ipl,
/* ---------------- NET_LOCK ---------------- */
static DECLARE_RWSEM(pfk_net_sem);
static atomic_t pfk_net_readers = ATOMIC_INIT(0);
static atomic_t pfk_net_owner = ATOMIC_INIT(0); /* task pid holding write */
/*
* PFLINUX: OpenBSD's NET_LOCK nesting is friendly for the holder (e.g.
* pfioctl takes NET_LOCK and pf_status_read() does too). Linux rw_semaphores
* are not recursive, so track the holder task + depth: nested lock/unlock by
* the same task balance without touching the rwsem. (Tracking was by task
* pointer on purpose: pids can be recycled.)
*/
static DEFINE_RAW_SPINLOCK(pfk_net_owner_lock);
static struct task_struct *pfk_net_owner;
static int pfk_net_depth;
void pfk_net_lock_init(void) { }
void
pfk_net_lock(void)
{
/* Re-entrant for the holder: OpenBSD's NET_LOCK is friendly with
* nested calls in the same path (e.g. our netdev notifier firing
* while pfioctl holds the lock). */
if (atomic_read(&pfk_net_owner) == current->pid)
unsigned long flags;
bool nested;
raw_spin_lock_irqsave(&pfk_net_owner_lock, flags);
nested = (pfk_net_owner == current);
if (nested)
pfk_net_depth++;
raw_spin_unlock_irqrestore(&pfk_net_owner_lock, flags);
if (nested)
return;
down_write(&pfk_net_sem);
atomic_set(&pfk_net_owner, current->pid);
raw_spin_lock_irqsave(&pfk_net_owner_lock, flags);
pfk_net_owner = current;
pfk_net_depth = 1;
raw_spin_unlock_irqrestore(&pfk_net_owner_lock, flags);
}
void
pfk_net_unlock(void)
{
if (atomic_read(&pfk_net_owner) != current->pid)
return; /* nested no-op for non-holders */
atomic_set(&pfk_net_owner, 0);
up_write(&pfk_net_sem);
unsigned long flags;
int depth;
raw_spin_lock_irqsave(&pfk_net_owner_lock, flags);
if (pfk_net_owner != current) {
/* not the holder: unbalanced unlock — ignore loudly */
raw_spin_unlock_irqrestore(&pfk_net_owner_lock, flags);
WARN_ON_ONCE(1);
return;
}
depth = --pfk_net_depth;
raw_spin_unlock_irqrestore(&pfk_net_owner_lock, flags);
if (depth == 0) {
raw_spin_lock_irqsave(&pfk_net_owner_lock, flags);
pfk_net_owner = NULL;
raw_spin_unlock_irqrestore(&pfk_net_owner_lock, flags);
up_write(&pfk_net_sem);
}
}
void pfk_net_read_enter(void) { down_read(&pfk_net_sem);
atomic_inc(&pfk_net_readers); }