git: 89e485e04d54 - stable/14 - linuxkpi: Allow ida_destroy and idr_destroy to be called multiple times

From: Vladimir Kondratyev <wulf_at_FreeBSD.org>
Date: Thu, 01 Aug 2024 22:27:34 UTC
The branch stable/14 has been updated by wulf:

URL: https://cgit.FreeBSD.org/src/commit/?id=89e485e04d547b236f32e3d4eb9ece0684ef01e0

commit 89e485e04d547b236f32e3d4eb9ece0684ef01e0
Author:     Austin Shafer <ashafer@badland.io>
AuthorDate: 2024-06-06 20:42:06 +0000
Commit:     Vladimir Kondratyev <wulf@FreeBSD.org>
CommitDate: 2024-08-01 21:09:39 +0000

    linuxkpi: Allow ida_destroy and idr_destroy to be called multiple times
    
    This fixes some weird behavior triggered by nvidia-drm.ko: some DRM
    cleanup functions will be called multiple times, leading to a double
    free. drm_mode_config_cleanup will be called twice, causing ida_destroy
    to be called twice. Although calling the cleanup twice doesn't seem
    very clean, on Linux this seems to be permissable as it handles it
    just fine. Not doing these checks causes mutex panics and double frees.
    
    In order to preserve this behavior this change checks if the objects
    have already been destroyed and bails if so. This fixes the panic seen
    when unloading the nvidia-drm driver.
    
    MFC after:      1 week
    Reviewed by:    bz, manu
    Differential revision:  https://reviews.freebsd.org/D44865
    
    (cherry picked from commit 613723bac219cb08ac1ad0afd3e07850d7fccc10)
---
 sys/compat/linuxkpi/common/src/linux_idr.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/sys/compat/linuxkpi/common/src/linux_idr.c b/sys/compat/linuxkpi/common/src/linux_idr.c
index b80f8c168d45..8d7f76c7964b 100644
--- a/sys/compat/linuxkpi/common/src/linux_idr.c
+++ b/sys/compat/linuxkpi/common/src/linux_idr.c
@@ -179,6 +179,14 @@ idr_destroy(struct idr *idr)
 {
 	struct idr_layer *il, *iln;
 
+	/*
+	 * This idr can be reused, and this function might be called multiple times
+	 * without a idr_init(). Check if this is the case.  If we do not do this
+	 * then the mutex will panic while asserting that it is valid.
+	 */
+	if (mtx_initialized(&idr->lock) == 0)
+		return;
+
 	idr_remove_all(idr);
 	mtx_lock(&idr->lock);
 	for (il = idr->free; il != NULL; il = iln) {
@@ -803,4 +811,5 @@ ida_destroy(struct ida *ida)
 {
 	idr_destroy(&ida->idr);
 	free(ida->free_bitmap, M_IDR);
+	ida->free_bitmap = NULL;
 }