git: 4f924a786ae0 - main - linker_kldload_busy(): allow recursion

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sun, 28 Nov 2021 08:36:22 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=4f924a786ae08af496dfe55230f8fe1e2ca16150

commit 4f924a786ae08af496dfe55230f8fe1e2ca16150
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2021-11-12 19:45:06 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2021-11-28 08:36:09 +0000

    linker_kldload_busy(): allow recursion
    
    Some drivers recursively loads modules by explicit calls to kldload
    during initialization, which might occur during kldload.
    
    PR:     259748
    Reported and tested by: thj
    Reviewed by:    markj
    Sponsored by:   Nvidia networking
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D32972
---
 sys/kern/kern_linker.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c
index bcdbb467e84e..1337d2c0b278 100644
--- a/sys/kern/kern_linker.c
+++ b/sys/kern/kern_linker.c
@@ -106,7 +106,8 @@ MALLOC_DEFINE(M_LINKER, "linker", "kernel linker");
 linker_file_t linker_kernel_file;
 
 static struct sx kld_sx;	/* kernel linker lock */
-static bool kld_busy;
+static u_int kld_busy;
+static struct thread *kld_busy_owner;
 
 /*
  * Load counter used by clients to determine if a linker file has been
@@ -1065,7 +1066,9 @@ linker_kldload_busy(int flags)
 
 	if ((flags & LINKER_UB_LOCKED) == 0)
 		sx_xlock(&kld_sx);
-	while (kld_busy) {
+	while (kld_busy > 0) {
+		if (kld_busy_owner == curthread)
+			break;
 		error = sx_sleep(&kld_busy, &kld_sx,
 		    (flags & LINKER_UB_PCATCH) != 0 ? PCATCH : 0,
 		    "kldbusy", 0);
@@ -1075,7 +1078,8 @@ linker_kldload_busy(int flags)
 			return (error);
 		}
 	}
-	kld_busy = true;
+	kld_busy++;
+	kld_busy_owner = curthread;
 	if ((flags & LINKER_UB_UNLOCK) != 0)
 		sx_xunlock(&kld_sx);
 	return (0);
@@ -1090,9 +1094,15 @@ linker_kldload_unbusy(int flags)
 
 	if ((flags & LINKER_UB_LOCKED) == 0)
 		sx_xlock(&kld_sx);
-	MPASS(kld_busy);
-	kld_busy = false;
-	wakeup(&kld_busy);
+	MPASS(kld_busy > 0);
+	if (kld_busy_owner != curthread)
+		panic("linker_kldload_unbusy done by not owning thread %p",
+		    kld_busy_owner);
+	kld_busy--;
+	if (kld_busy == 0) {
+		kld_busy_owner = NULL;
+		wakeup(&kld_busy);
+	}
 	sx_xunlock(&kld_sx);
 }