The transition from synchronize_rcu() to call_rcu() in the CAN bcm driver introduced a structural race that the RX_NO_AUTOTIMER flag was never capable of closing. The original synchronize_rcu() was expensive precisely because it enforced the guarantee that no RCU reader could be active while the bcm_op was destroyed. The call_rcu() replacement broke that guarantee by definition — it defers the callback to some point after current readers exit, but the hrtimer fast-path isn't a traditional RCU reader. It can re-arm itself after the callback is scheduled but before it executes, creating a TOCTOU window that no flag check can close.

The three-part fix — workqueue deferral for timer cancellation, a dedicated workqueue to avoid system-wide saturation, and socket reference counting — is a significant architectural escalation from the original performance optimization. The socket reference count addition is the most telling detail: it acknowledges that deferred work can now outlive the original calling context by an unbounded amount, requiring protection against a socket being freed while a still-armed timer holds a dangling pointer. This wasn't a subtle bug; it was a fundamental mismatch between the API's concurrency model and the caller's execution topology.

This pattern — call_rcu() breaking hrtimer-coupled cleanup — may be endemic in code where hrtimers run in softirq context with fast-paths that can re-arm them. The RX_NO_AUTOTIMER flag introduced in the same commit as the refactor was an attempt to serve as a synchronization barrier, but a flag check in a concurrent fast-path is not a memory fence. The fix admits what the original design failed to model: the hrtimer can revive the object after the RCU callback is scheduled, breaking the temporal assumptions that call_rcu() relies on.