mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Martin Karsten <mkarsten@uwaterloo.ca>
To: Eric Dumazet <edumazet@kernel.org>, mt4022@columbia.edu
Cc: "David S. Miller" <davem@davemloft.net>,
	Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
	Simon Horman <horms@kernel.org>,
	Andrew Lunn <andrew+netdev@lunn.ch>, Joe Damato <joe@dama.to>,
	Dragos Tatulea <dtatulea@nvidia.com>,
	Kuniyuki Iwashima <kuniyu@google.com>,
	Stanislav Fomichev <sdf.kernel@gmail.com>,
	Sridhar Samudrala <sridhar.samudrala@intel.com>,
	Cosmin Ratiu <cratiu@nvidia.com>,
	Tariq Toukan <tariqt@nvidia.com>,
	Wang Zhan <wang.zhan@smartx.com>,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	tz2294@columbia.edu
Subject: Re: [PATCH net] net: cancel napi->timer after the grace period in netif_napi_del()
Date: Tue, 3 Nov 2026 19:55:43 -0500	[thread overview]
Message-ID: <ae3e5838-6985-48be-bd99-fa5a21143942@uwaterloo.ca> (raw)
In-Reply-To: <CAL4WiioJuY1L5ji7tVXggp=FDm3eidwekpxqAMdnxWUyiTR3fg@mail.gmail.com>

On 2026-11-03 13:37, Eric Dumazet wrote:
> Le mar. 3 nov. 2026 à 19:19, Mani Tofigh via B4 Relay
> <devnull+mt4022.columbia.edu@kernel.org> a écrit :
>>
>> From: Mani Tofigh <mt4022@columbia.edu>
>>
>> A napi can be freed with its timer still queued.  napi_disable()
>> cancels napi->timer, but napi_complete_done(), busy_poll_stop() and
>> napi_suspend_irqs() start it without owning the napi and can do so
>> right after the cancel.  netif_napi_del() only waits for that start to
>> finish:
>>
>>    Task A (epoll_wait)                  Task B (queue reset)
>>    napi_suspend_irqs()
>>      rcu_read_lock()
>>      napi = napi_by_id(id)
>>                                         napi_disable_locked(napi)
>>                                           hrtimer_cancel(&napi->timer)
>>                                           napi_hash_del(napi)
>>                                         netif_napi_del_locked(napi)
>>                                           synchronize_net()
>>                                           /* waits for Task A */
>>      hrtimer_start(&napi->timer)
>>      rcu_read_unlock()
>>                                         kfree(rq)
>>                                           /* timer still queued */
>>
>> With netdevsim and debug objects:
>>
>>    [    3.073483] ODEBUG: free active (active state 0) object: 000000001504358f object type: hrtimer hint: napi_watchdog+0x0/0xa0
>>    [    3.073515] WARNING: lib/debugobjects.c:629 at debug_print_object+0x1a4/0x3b0, CPU#0: napitimer/66
>>    [    3.079603] CPU: 0 UID: 0 PID: 66 Comm: napitimer Tainted: G        W            7.3.0-17087-gd865f2677c44 #1 PREEMPT
>>    [    3.084822] RIP: 0010:debug_print_object+0x1ae/0x3b0
>>    ...
>>    [    3.103822] Call Trace:
>>    [    3.104408]  <TASK>
>>    [    3.105933]  debug_check_no_obj_freed+0x496/0x5f0
>>    [    3.109988]  kfree+0x33a/0x510
>>    [    3.110715]  netdev_rx_queue_reconfig+0x357/0x580
>>    [    3.111780]  netdev_rx_queue_restart+0x8f/0xc0
>>    [    3.113924]  nsim_qreset_write+0x24d/0x350
>>    [    3.117832]  full_proxy_write+0x109/0x1d0
>>    [    3.118741]  vfs_write+0x1e3/0x1250
>>    [    3.124758]  __x64_sys_pwrite64+0x18c/0x250
>>    [    3.129645]  do_syscall_64+0xfb/0x590
>>    [    3.131385]  entry_SYSCALL_64_after_hwframe+0x77/0x7f
>>
>> Without debug objects, napi_watchdog() later runs on freed memory.
>>
>> After napi_disable() and a grace period none of the three can reach the
>> napi anymore.  Two need SCHED, which napi_disable() keeps, and
>> napi_suspend_irqs() needs the napi hash, which napi_disable() removed it
>> from.  So cancel the timer again after the grace period that
>> netif_napi_del() already waits for, and in free_netdev(), where
>> unregister has already waited for one.  With the fix, debug objects
>> don't report a freed active timer anymore.
>>
>> This bug was identified and confirmed with the help of a deterministic
>> hypervisor currently under development.  The C reproducer below however
>> hits it within about 1s.
>>
>> Fixes: 6f8b12d661d0 ("net: napi: add hard irqs deferral feature")
>> Fixes: 3fcbecbdeb04 ("net: Add control functions for irq suspension")
>> Fixes: 58e2330bd455 ("net: napi: Avoid gro timer misfiring at end of busypoll")
>> Signed-off-by: Mani Tofigh <mt4022@columbia.edu>
>> ---

Thanks for reporting this. I'm very impressed by the reproducer!

> Bug seems real, but could we prepare something generic (in the core).

I agree and I believe Sashiko has found this bug earlier [1]. I didn't 
have a reproducer at the time and maintainers didn't flag it, so I 
didn't speak up.

I thought this could be addressed more easily, by adding to each of the 
3 calls to hrtimer_start (maybe via subroutine as Eric suggests):

> static void napi_timer_start(struct napi_struct *n, unsigned long timeout)
> {
>          hrtimer_start(&n->timer, ns_to_ktime(timeout),
>                        HRTIMER_MODE_REL_PINNED);
>          smp_mb();
>          if (unlikely(!test_bit(NAPI_STATE_LISTED, &n->state)))
>                  hrtimer_try_to_cancel(&n->timer);
> }

     hrtimer_start(&n->timer, ns_to_ktime(timeout),
             HRTIMER_MODE_REL_PINNED);
     if (unlikely(napi_is_scheduled(n)))
       hrtimer_cancel(&n->timer);

> And in __netif_napi_del_locked() :

This change is not needed then.

My reasoning is as follows: SCHED is being set in napi_disable_locked() 
before hrtimer_cancel() is called. hrtimer_start() and hrtimer_cancel() 
are atomic to each other and impose strict memory ordering via the timer 
lock (I assume?), so the SCHED bit is propagated, if hrtimer_cancel() in 
napi_disable() happens first. Memory is not yet released due to RCU. If 
the napi might be scheduled for some other reason, I believe it is still 
fine to cancel the timer.

I am not sure about hrtimer_try_to_cancel() vs hrtimer_cancel(). If 
hrtimer_try_to_cancel() fails, the timer callback might "running", but 
could it be on a different core and slow enough, so napi_disable() might 
complete and memory be freed before napi_watchdog() is done?

In my tests, including the reproducer, this works, but this stuff is 
always dicey...

Thanks,
Martin

[1] 
https://sashiko.dev/#/patchset/20260523012247.1574691-1-mkarsten%40uwaterloo.ca


      reply	other threads:[~2026-11-04  0:55 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-03 18:19 Mani Tofigh via B4 Relay
2026-11-03 18:37 ` Eric Dumazet
2026-11-04  0:55   ` Martin Karsten [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ae3e5838-6985-48be-bd99-fa5a21143942@uwaterloo.ca \
    --to=mkarsten@uwaterloo.ca \
    --cc=andrew+netdev@lunn.ch \
    --cc=cratiu@nvidia.com \
    --cc=davem@davemloft.net \
    --cc=dtatulea@nvidia.com \
    --cc=edumazet@kernel.org \
    --cc=horms@kernel.org \
    --cc=joe@dama.to \
    --cc=kuba@kernel.org \
    --cc=kuniyu@google.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mt4022@columbia.edu \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=sdf.kernel@gmail.com \
    --cc=sridhar.samudrala@intel.com \
    --cc=tariqt@nvidia.com \
    --cc=tz2294@columbia.edu \
    --cc=wang.zhan@smartx.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®