summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/vm
diff options
context:
space:
mode:
authorMichael Corcoran <Michael.Corcoran@Sun.COM>2009-02-23 16:16:02 -0800
committerMichael Corcoran <Michael.Corcoran@Sun.COM>2009-02-23 16:16:02 -0800
commit2af6eb52b537fd75202964edd660905fb4fa601d (patch)
tree9877e0e6e516005ccdc0f6c1196d00efcb6eb842 /usr/src/uts/common/vm
parentc3a96863fc7054253767fc2de22e9e9f3a3b36fa (diff)
downloadillumos-joyent-2af6eb52b537fd75202964edd660905fb4fa601d.tar.gz
6657218 page_numtopp_nolock cpu_vm_data_destroy race condition causes panic
6696311 kmem_cache_alloc's use of CPU macro is not preemption friendly, causes panic
Diffstat (limited to 'usr/src/uts/common/vm')
-rw-r--r--usr/src/uts/common/vm/vm_page.c34
1 files changed, 30 insertions, 4 deletions
diff --git a/usr/src/uts/common/vm/vm_page.c b/usr/src/uts/common/vm/vm_page.c
index 37f59cf206..836881f6d2 100644
--- a/usr/src/uts/common/vm/vm_page.c
+++ b/usr/src/uts/common/vm/vm_page.c
@@ -5787,8 +5787,17 @@ page_numtopp_nolock(pfn_t pfnum)
{
struct memseg *seg;
page_t *pp;
- vm_cpu_data_t *vc = CPU->cpu_vm_data;
+ vm_cpu_data_t *vc;
+ /*
+ * We need to disable kernel preemption while referencing the
+ * cpu_vm_data field in order to prevent us from being switched to
+ * another cpu and trying to reference it after it has been freed.
+ * This will keep us on cpu and prevent it from being removed while
+ * we are still on it.
+ */
+ kpreempt_disable();
+ vc = CPU->cpu_vm_data;
ASSERT(vc != NULL);
MEMSEG_STAT_INCR(nsearch);
@@ -5798,8 +5807,10 @@ page_numtopp_nolock(pfn_t pfnum)
(pfnum >= seg->pages_base) && (pfnum < seg->pages_end)) {
MEMSEG_STAT_INCR(nlastwon);
pp = seg->pages + (pfnum - seg->pages_base);
- if (pp->p_pagenum == pfnum)
+ if (pp->p_pagenum == pfnum) {
+ kpreempt_enable();
return ((page_t *)pp);
+ }
}
/* Else Try hash */
@@ -5808,8 +5819,10 @@ page_numtopp_nolock(pfn_t pfnum)
MEMSEG_STAT_INCR(nhashwon);
vc->vc_pnum_memseg = seg;
pp = seg->pages + (pfnum - seg->pages_base);
- if (pp->p_pagenum == pfnum)
+ if (pp->p_pagenum == pfnum) {
+ kpreempt_enable();
return ((page_t *)pp);
+ }
}
/* Else Brute force */
@@ -5817,10 +5830,12 @@ page_numtopp_nolock(pfn_t pfnum)
if (pfnum >= seg->pages_base && pfnum < seg->pages_end) {
vc->vc_pnum_memseg = seg;
pp = seg->pages + (pfnum - seg->pages_base);
+ kpreempt_enable();
return ((page_t *)pp);
}
}
vc->vc_pnum_memseg = NULL;
+ kpreempt_enable();
MEMSEG_STAT_INCR(nnotfound);
return ((page_t *)NULL);
@@ -5862,7 +5877,17 @@ page_nextn(page_t *pp, ulong_t n)
{
struct memseg *seg;
page_t *ppn;
- vm_cpu_data_t *vc = (vm_cpu_data_t *)CPU->cpu_vm_data;
+ vm_cpu_data_t *vc;
+
+ /*
+ * We need to disable kernel preemption while referencing the
+ * cpu_vm_data field in order to prevent us from being switched to
+ * another cpu and trying to reference it after it has been freed.
+ * This will keep us on cpu and prevent it from being removed while
+ * we are still on it.
+ */
+ kpreempt_disable();
+ vc = (vm_cpu_data_t *)CPU->cpu_vm_data;
ASSERT(vc != NULL);
@@ -5892,6 +5917,7 @@ page_nextn(page_t *pp, ulong_t n)
pp = seg->pages;
}
vc->vc_pnext_memseg = seg;
+ kpreempt_enable();
return (ppn);
}