Re: evdev-induced panic (devfs / destroy_dev race?)

From: Kyle Evans <kevans_at_FreeBSD.org>
Date: Fri, 24 Oct 2025 15:17:24 UTC
On 10/23/25 07:41, Kyle Evans wrote:
> Hi,
> 
> Not sure if anyone else has noticed this, but I seem to have scared up an evdev panic:
>
> [...]
>> This was seemingly the result of removing my mouse's USB dongle.  Presumably detach revoked the client and
> woke it up, which then triggered the above close() from moused to race with destroy_dev() for invoking the
> cdevpriv dtor.
> 
> I spent a few minutes thinking about it and didn't really come to a good idea of what the fix might be,
> though I suspect there's nothing evdev can really do about it at the moment and we might need to somehow
> coordinate this in destroy_dev().
> 
> Kyle Evans

This thread ended up going largely off-list because I was traveling, but to kind of summarize the
remainder of the discussion: cdevpriv bits are properly protected by the cdevpriv_mtx, but I
pitched the following scenario:

Consider threads (U)ser and (D)river:

  - (U) has called close(2) and is in the middle of devfs_close_f, maybe has bumped the thread refcount
  - (D) has initiated destroy_dev, waiting for the thread refcount to drop

Let's assume now that (U) releases the thread ref. What stops (D) and (U) from subsequently racing to
grab the cdevpriv_mtx?

I couldn't immediately see anything that might, so let's pretend that (U) wins and peels the cdevpriv off,
so now the cdevpriv list is empty. (D) is free to return from destroy_dev while (U) is in the middle of
executing the dtor, where we destroy the sx that (U) is trying to acquire.

kib created D53303[0] to have destroy_dev() provide a release barrier for cdevpriv destructors so that
callers can safely release state as all destructors have run, either by destroy_dev() itself or a
concurrent close(2), which I think is the right balance.

Thanks,

Kyle Evans

[0] https://reviews.freebsd.org/D53303