aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/kern_linker.c
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2021-11-12 19:45:06 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2021-11-28 08:36:09 +0000
commit4f924a786ae08af496dfe55230f8fe1e2ca16150 (patch)
tree55c38d56baee3491229d9e30b961063a0fd81c2e /sys/kern/kern_linker.c
parentdad71022bd7a8f95ab2ba656bec61e2424a1c3c5 (diff)
downloadsrc-4f924a786ae08af496dfe55230f8fe1e2ca16150.tar.gz
src-4f924a786ae08af496dfe55230f8fe1e2ca16150.zip
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
Diffstat (limited to 'sys/kern/kern_linker.c')
-rw-r--r--sys/kern/kern_linker.c22
1 files 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);
}