Re: [RFC PATCH net-next 2/2] net: napi: Skip poll when arming GRO timer in busy poll
From: Martin Karsten
Date: Tue Apr 28 2026 - 21:03:18 EST
On 2026-04-28 20:37, Jakub Kicinski wrote:
On Tue, 28 Apr 2026 17:51:31 +0000 Dragos Tatulea wrote:
From: Martin Karsten <mkarsten@xxxxxxxxxxxx>
As referenced in the previous patch, having the GRO timer scheduled
while poll is running can lead to issues.
Skip the extra call to napi->poll() when the GRO timer is armed. This
removes the need for having a separate __busy_poll_stop routine and its
code is moved directly into the relevant places in busy_poll_stop.
This needs to go in separately, the previous patch should be a Fix,
this is net-next material.
Ok, thanks for the recommendation!
@@ -6918,13 +6898,28 @@ static void busy_poll_stop(struct napi_struct *napi, void *have_poll_lock,
if (flags & NAPI_F_PREFER_BUSY_POLL) {
napi->defer_hard_irqs_count = napi_get_defer_hard_irqs(napi);
- if (napi->defer_hard_irqs_count) {
- /* Timer will be scheduled after napi poll to avoid
- * firing during a slow poll which could cause the
- * queue to get stuck with interrupts disabled and no
- * scheduled timer.
+ timeout = napi_get_gro_flush_timeout(napi);
+ if (napi->defer_hard_irqs_count && timeout) {
+ unsigned long flags;
Feels like either timeout should also be declared in closest scope or
flags at function level
Good point, thanks. I also just realize there's two flags - I somehow missed that before. Maybe the 2nd flags isn't necessary after all.
+ /* Drop prefer-busy state as in napi_complete_done(). */
sloppy comment
Ok, will improve.
+ clear_bit(NAPI_STATE_PREFER_BUSY_POLL, &napi->state);
+ netpoll_poll_unlock(have_poll_lock);
+
+ /* Flush too old packets. If HZ < 1000, flush all
+ * packets.
+ */
sloppy comment
This one was just copied over from __busy_poll_stop. TBH, I don't know exactly what's happening in the 'gro_flush_normal' call.
+ gro_flush_normal(&napi->gro, HZ >= 1000);
+ local_irq_save(flags);
+ hrtimer_start(&napi->timer, ns_to_ktime(timeout),
+ HRTIMER_MODE_REL_PINNED);
+ clear_bit(NAPI_STATE_SCHED, &napi->state);
+ local_irq_restore(flags);
+
+ /* Timer started, so need for another call to
+ * napi->poll().
*/
- timeout = napi_get_gro_flush_timeout(napi);
+ goto out;
I think an else branch would do here? Let's not abuse goto
Ok, will rewrite. Among other things, I thought a goto avoids indentation of the unchanged code and thus makes the patch smaller, but I have no strong preference.
Thanks,
Martin