Page MenuHomeFreeBSD

D30456.id89904.diff
No OneTemporary

D30456.id89904.diff

diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c
--- a/sys/kern/kern_linker.c
+++ b/sys/kern/kern_linker.c
@@ -106,6 +106,7 @@
linker_file_t linker_kernel_file;
static struct sx kld_sx; /* kernel linker lock */
+static bool kld_busy;
/*
* Load counter used by clients to determine if a linker file has been
@@ -1050,6 +1051,40 @@
M_WAITOK));
}
+int
+linker_set_busy(bool unlock, bool interruptible)
+{
+ int error;
+
+ sx_xlock(&kld_sx);
+ while (kld_busy) {
+ error = sx_sleep(&kld_busy, &kld_sx, interruptible ? PCATCH :
+ 0, "kldser1", 0);
+ if (error != 0) {
+ if (unlock)
+ sx_xunlock(&kld_sx);
+ return (error);
+ }
+ }
+ kld_busy = true;
+ if (unlock)
+ sx_xunlock(&kld_sx);
+ return (0);
+}
+
+void
+linker_set_unbusy(bool locked)
+{
+ if (locked)
+ sx_assert(&kld_sx, SA_XLOCKED);
+ else
+ sx_xlock(&kld_sx);
+ MPASS(kld_busy);
+ kld_busy = false;
+ wakeup(&kld_busy);
+ sx_xunlock(&kld_sx);
+}
+
/*
* Syscalls.
*/
@@ -1066,12 +1101,6 @@
if ((error = priv_check(td, PRIV_KLD_LOAD)) != 0)
return (error);
- /*
- * It is possible that kldloaded module will attach a new ifnet,
- * so vnet context must be set when this ocurs.
- */
- CURVNET_SET(TD_TO_VNET(td));
-
/*
* If file does not contain a qualified name or any dot in it
* (kldname.ko, or kldname.ver.ko) treat it as an interface
@@ -1085,19 +1114,27 @@
modname = file;
}
- sx_xlock(&kld_sx);
- error = linker_load_module(kldname, modname, NULL, NULL, &lf);
- if (error) {
+ error = linker_set_busy(false, true);
+ if (error != 0) {
sx_xunlock(&kld_sx);
- goto done;
+ return (error);
}
- lf->userrefs++;
- if (fileid != NULL)
- *fileid = lf->id;
- sx_xunlock(&kld_sx);
-done:
+ /*
+ * It is possible that kldloaded module will attach a new ifnet,
+ * so vnet context must be set when this ocurs.
+ */
+ CURVNET_SET(TD_TO_VNET(td));
+
+ error = linker_load_module(kldname, modname, NULL, NULL, &lf);
CURVNET_RESTORE();
+
+ if (error == 0) {
+ lf->userrefs++;
+ if (fileid != NULL)
+ *fileid = lf->id;
+ }
+ linker_set_unbusy(true);
return (error);
}
@@ -1132,8 +1169,13 @@
if ((error = priv_check(td, PRIV_KLD_UNLOAD)) != 0)
return (error);
+ error = linker_set_busy(false, true);
+ if (error != 0) {
+ sx_xunlock(&kld_sx);
+ return (error);
+ }
+
CURVNET_SET(TD_TO_VNET(td));
- sx_xlock(&kld_sx);
lf = linker_find_file_by_id(fileid);
if (lf) {
KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs));
@@ -1153,9 +1195,8 @@
}
} else
error = ENOENT;
- sx_xunlock(&kld_sx);
-
CURVNET_RESTORE();
+ linker_set_unbusy(true);
return (error);
}
diff --git a/sys/kern/subr_firmware.c b/sys/kern/subr_firmware.c
--- a/sys/kern/subr_firmware.c
+++ b/sys/kern/subr_firmware.c
@@ -251,6 +251,8 @@
linker_file_t result;
int error;
+ error = linker_set_busy(true, false);
+ MPASS(error == 0);
error = linker_reference_module(fwli->imagename, NULL, &result);
if (error != 0) {
if (bootverbose || (fwli->flags & FIRMWARE_GET_NOWARN) == 0)
@@ -275,6 +277,7 @@
done:
wakeup_one(arg);
mtx_unlock(&firmware_mtx);
+ linker_set_unbusy(false);
}
/*
diff --git a/sys/sys/linker.h b/sys/sys/linker.h
--- a/sys/sys/linker.h
+++ b/sys/sys/linker.h
@@ -196,6 +196,10 @@
/* HWPMC helper */
void *linker_hwpmc_list_objects(void);
+/* kldload/kldunload syscalls blocking */
+int linker_set_busy(bool unlock, bool interruptible);
+void linker_set_unbusy(bool locked);
+
#endif /* _KERNEL */
/*

File Metadata

Mime Type
text/plain
Expires
Tue, Apr 28, 7:58 PM (49 m, 48 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
32302493
Default Alt Text
D30456.id89904.diff (3 KB)

Event Timeline