Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 24 Oct 2025 10:17:24 -0500
From:      Kyle Evans <kevans@FreeBSD.org>
To:        FreeBSD CURRENT <freebsd-current@freebsd.org>
Subject:   Re: evdev-induced panic (devfs / destroy_dev race?)
Message-ID:  <f42f8932-b4fa-47a6-845e-9e8f9d873100@FreeBSD.org>
In-Reply-To: <bfdfb864-c8e0-4487-a414-d6dd45ffce9a@FreeBSD.org>

index | next in thread | previous in thread | raw e-mail

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


help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?f42f8932-b4fa-47a6-845e-9e8f9d873100>