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
This commit is contained in:
Konstantin Belousov 2021-11-12 21:45:06 +02:00
parent dad71022bd
commit 4f924a786a

View File

@ -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);
}