[LWN Logo]
[LWN.net]
===== kernel/fork.c 1.5 vs edited =====
--- 1.5/kernel/fork.c	Sat Feb 10 20:54:34 2001
+++ edited/kernel/fork.c	Thu Mar  8 13:50:44 2001
@@ -203,7 +203,9 @@
 	atomic_set(&mm->mm_count, 1);
 	init_MUTEX(&mm->mmap_sem);
 	mm->page_table_lock = SPIN_LOCK_UNLOCKED;
+	lock_kernel();
 	mm->pgd = pgd_alloc();
+	unlock_kernel();
 	if (mm->pgd)
 		return mm;
 	free_mm(mm);
@@ -234,7 +236,9 @@
 inline void __mmdrop(struct mm_struct *mm)
 {
 	if (mm == &init_mm) BUG();
+	lock_kernel();
 	pgd_free(mm->pgd);
+	unlock_kernel();
 	destroy_context(mm);
 	free_mm(mm);
 }
===== mm/vmalloc.c 1.3 vs edited =====
--- 1.3/mm/vmalloc.c	Sat Feb 10 20:54:34 2001
+++ edited/mm/vmalloc.c	Thu Mar  8 12:55:42 2001
@@ -146,6 +146,7 @@
 	lock_kernel();
 	do {
 		pmd_t *pmd;
+		pgd_t olddir = *dir;
 		
 		pmd = pmd_alloc_kernel(dir, address);
 		ret = -ENOMEM;
@@ -155,6 +156,8 @@
 		ret = -ENOMEM;
 		if (alloc_area_pmd(pmd, address, end - address, gfp_mask, prot))
 			break;
+		if (pgd_val(olddir) != pgd_val(*dir))
+			set_pgdir(address, *dir);
 
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
===== include/asm-i386/pgalloc.h 1.1 vs edited =====
--- 1.1/include/asm-i386/pgalloc.h	Sat Jan  6 10:26:31 2001
+++ edited/include/asm-i386/pgalloc.h	Thu Mar  8 12:50:47 2001
@@ -152,6 +152,33 @@
 
 extern int do_check_pgt_cache(int, int);
 
+extern inline void set_pgdir(unsigned long address, pgd_t entry)
+{
+	struct task_struct * p;
+	pgd_t *pgd;
+#ifdef CONFIG_SMP
+	int i;
+#endif	
+
+	read_lock(&tasklist_lock);
+	for_each_task(p) {
+		if (!p->mm)
+			continue;
+		*pgd_offset(p->mm,address) = entry;
+	}
+	read_unlock(&tasklist_lock);
+#ifndef CONFIG_SMP
+	for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
+		pgd[address >> PGDIR_SHIFT] = entry;
+#else
+	/* To pgd_alloc/pgd_free, one holds master kernel lock and so does our callee, so we can
+	   modify pgd caches of other CPUs as well. -jj */
+	for (i = 0; i < NR_CPUS; i++)
+		for (pgd = (pgd_t *)cpu_data[i].pgd_quick; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
+			pgd[address >> PGDIR_SHIFT] = entry;
+#endif
+}
+
 /*
  * TLB flushing:
  *
===== arch/i386/mm/ioremap.c 1.1 vs edited =====
--- 1.1/arch/i386/mm/ioremap.c	Sat Jan  6 10:29:43 2001
+++ edited/arch/i386/mm/ioremap.c	Thu Mar  8 12:50:47 2001
@@ -78,6 +78,7 @@
 		if (remap_area_pmd(pmd, address, end - address,
 					 phys_addr + address, flags))
 			return -ENOMEM;
+		set_pgdir(address, *dir);
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	} while (address && (address < end));