Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/x86/x86 LDT handling fixes:
details: https://anonhg.NetBSD.org/src/rev/a942efa684a2
branches: trunk
changeset: 818088:a942efa684a2
user: dholland <dholland%NetBSD.org@localhost>
date: Sat Sep 24 21:13:44 2016 +0000
description:
LDT handling fixes:
- add missing membar_store_store ("membar_producer") when setting a
new ldt;
- use UVM_KMF_WAITVA when allocating space for a new ldt instead of
crashing if uvm_km_alloc fails;
- if uvm_km_alloc fails in pmap_fork, bail instead of crashing;
- clarify what else is going on in pmap_fork;
- don't uvm_km_free while holding a mutex.
diffstat:
sys/arch/x86/x86/pmap.c | 33 ++++++++++++++++++++++++++++-----
sys/arch/x86/x86/sys_machdep.c | 15 ++++++++++-----
2 files changed, 38 insertions(+), 10 deletions(-)
diffs (149 lines):
diff -r 8c9cc53f1391 -r a942efa684a2 sys/arch/x86/x86/pmap.c
--- a/sys/arch/x86/x86/pmap.c Sat Sep 24 21:00:54 2016 +0000
+++ b/sys/arch/x86/x86/pmap.c Sat Sep 24 21:13:44 2016 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.c,v 1.221 2016/08/27 16:07:26 maxv Exp $ */
+/* $NetBSD: pmap.c,v 1.222 2016/09/24 21:13:44 dholland Exp $ */
/*-
* Copyright (c) 2008, 2010, 2016 The NetBSD Foundation, Inc.
@@ -171,7 +171,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.221 2016/08/27 16:07:26 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.222 2016/09/24 21:13:44 dholland Exp $");
#include "opt_user_ldt.h"
#include "opt_lockdebug.h"
@@ -2443,30 +2443,49 @@
return;
}
+ /*
+ * Copy the LDT into the new process.
+ *
+ * Read pmap1's ldt pointer and length unlocked; if it changes
+ * behind our back we'll retry. This will starve if there's a
+ * stream of LDT changes in another thread but that should not
+ * happen.
+ */
+
retry:
if (pmap1->pm_ldt != NULL) {
len = pmap1->pm_ldt_len;
+ /* Allocate space for the new process's LDT */
new_ldt = (union descriptor *)uvm_km_alloc(kernel_map, len, 0,
UVM_KMF_WIRED);
+ if (new_ldt == NULL) {
+ printf("WARNING: pmap_fork: "
+ "unable to allocate LDT space\n");
+ return;
+ }
mutex_enter(&cpu_lock);
+ /* Get a GDT slot for it */
sel = ldt_alloc(new_ldt, len);
if (sel == -1) {
mutex_exit(&cpu_lock);
uvm_km_free(kernel_map, (vaddr_t)new_ldt, len,
UVM_KMF_WIRED);
- printf("WARNING: pmap_fork: unable to allocate LDT\n");
+ printf("WARNING: pmap_fork: "
+ "unable to allocate LDT selector\n");
return;
}
} else {
+ /* Wasn't anything there after all. */
len = -1;
new_ldt = NULL;
sel = -1;
mutex_enter(&cpu_lock);
}
- /* Copy the LDT, if necessary. */
+ /* If there's still something there now that we have cpu_lock... */
if (pmap1->pm_ldt != NULL) {
if (len != pmap1->pm_ldt_len) {
+ /* Oops, it changed. Drop what we did and try again */
if (len != -1) {
ldt_free(sel);
uvm_km_free(kernel_map, (vaddr_t)new_ldt,
@@ -2476,6 +2495,7 @@
goto retry;
}
+ /* Copy the LDT data and install it in pmap2 */
memcpy(new_ldt, pmap1->pm_ldt, len);
pmap2->pm_ldt = new_ldt;
pmap2->pm_ldt_len = pmap1->pm_ldt_len;
@@ -2484,11 +2504,14 @@
}
if (len != -1) {
+ /* There wasn't still something there, so mop up */
ldt_free(sel);
+ mutex_exit(&cpu_lock);
uvm_km_free(kernel_map, (vaddr_t)new_ldt, len,
UVM_KMF_WIRED);
+ } else {
+ mutex_exit(&cpu_lock);
}
- mutex_exit(&cpu_lock);
#endif /* USER_LDT */
}
#endif /* PMAP_FORK */
diff -r 8c9cc53f1391 -r a942efa684a2 sys/arch/x86/x86/sys_machdep.c
--- a/sys/arch/x86/x86/sys_machdep.c Sat Sep 24 21:00:54 2016 +0000
+++ b/sys/arch/x86/x86/sys_machdep.c Sat Sep 24 21:13:44 2016 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: sys_machdep.c,v 1.29 2015/10/23 18:53:26 christos Exp $ */
+/* $NetBSD: sys_machdep.c,v 1.30 2016/09/24 21:13:44 dholland Exp $ */
/*-
* Copyright (c) 1998, 2007, 2009 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sys_machdep.c,v 1.29 2015/10/23 18:53:26 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_machdep.c,v 1.30 2016/09/24 21:13:44 dholland Exp $");
#include "opt_mtrr.h"
#include "opt_perfctrs.h"
@@ -327,7 +327,7 @@
new_len = max(new_len, NLDT * sizeof(union descriptor));
new_len = round_page(new_len);
new_ldt = (union descriptor *)uvm_km_alloc(kernel_map,
- new_len, 0, UVM_KMF_WIRED | UVM_KMF_ZERO);
+ new_len, 0, UVM_KMF_WIRED | UVM_KMF_ZERO | UVM_KMF_WAITVA);
mutex_enter(&cpu_lock);
if (pmap->pm_ldt_len <= new_len) {
break;
@@ -365,9 +365,11 @@
}
/* All changes are now globally visible. Swap in the new LDT. */
- pmap->pm_ldt = new_ldt;
pmap->pm_ldt_len = new_len;
pmap->pm_ldt_sel = new_sel;
+ /* membar_store_store for pmap_fork() to read these unlocked safely */
+ membar_producer();
+ pmap->pm_ldt = new_ldt;
/* Switch existing users onto new LDT. */
pmap_ldt_sync(pmap);
@@ -375,10 +377,13 @@
/* Free existing LDT (if any). */
if (old_ldt != NULL) {
ldt_free(old_sel);
+ /* exit the mutex before free */
+ mutex_exit(&cpu_lock);
uvm_km_free(kernel_map, (vaddr_t)old_ldt, old_len,
UVM_KMF_WIRED);
+ } else {
+ mutex_exit(&cpu_lock);
}
- mutex_exit(&cpu_lock);
return error;
#endif
Home |
Main Index |
Thread Index |
Old Index