git: 613723bac219 - main - linuxkpi: Allow ida_destroy and idr_destroy to be called multiple times
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 06 Jun 2024 20:42:56 UTC
The branch main has been updated by wulf: URL: https://cgit.FreeBSD.org/src/commit/?id=613723bac219cb08ac1ad0afd3e07850d7fccc10 commit 613723bac219cb08ac1ad0afd3e07850d7fccc10 Author: Austin Shafer <ashafer@badland.io> AuthorDate: 2024-06-06 20:42:06 +0000 Commit: Vladimir Kondratyev <wulf@FreeBSD.org> CommitDate: 2024-06-06 20:42:06 +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 --- 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 583e2c237198..59c375194689 100644 --- a/sys/compat/linuxkpi/common/src/linux_idr.c +++ b/sys/compat/linuxkpi/common/src/linux_idr.c @@ -178,6 +178,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) { @@ -802,4 +810,5 @@ ida_destroy(struct ida *ida) { idr_destroy(&ida->idr); free(ida->free_bitmap, M_IDR); + ida->free_bitmap = NULL; }