Subject: Possible VM fix(s) for 2.4 PPC port

From: Mike Beede <[email-masked]>
Date: Mon, 08 Jan 2001 11:18:30 -0600

We've been working with 2.4.0-test10 on 750 and found a couple of
things that might be useful to others.  If this isn't the place to
send these, can someone let me know?

First, we had some kernel panics loading modules.  Turns out that the
module list is half-baked during part of sys_module_install.  If we
take a memory fault copying in the module contents, the fault handler
can't search the kernel exception list because the module list is
temporarily corrupted.  So instead of __copy_tofrom_user just failing,
the kernel takes a fault.  The patch to module.c fixs this.

The second problem is that if you vmalloc memory requiring a new entry
in the
kernel pgd, it isn't visible when in a user context (if that's the
current
right term....).  Turned out, that was why we were having our memory
fault
in the first place, but now we failed the syscall instead of panicking.

We added some code modeled on the i386 version that copies the pgd
entry from the kernel pgd and it seems to work.  I assume that the PPC
version doesn't fault in pages in the kernel, since vmalloc seems to
allocate pages when called.  If that assumption is wrong, then this
isn't a sufficient solution, but it shouldn't be any worse than what
was there in test10.

	Mike Beede

--
Mike Beede, [email-masked]
Cisco Systems
612-398-1009

--- kernel/module.c.orig	Mon Jan  8 10:56:30 2001
+++ kernel/module.c	Mon Jan  8 10:59:22 2001
@@ -201,6 +201,7 @@
 		error = -EFAULT;
 		goto err2;
 	}
+	mod->next = mod_tmp.next;

 	/* Sanity check the size of the module.  */
 	error = -EINVAL;
@@ -292,7 +293,6 @@
 	flush_icache_range((unsigned long)mod, (unsigned long)mod +
mod->size);

 	/* Update module references.  */
-	mod->next = mod_tmp.next;
 	mod->refs = NULL;
 	for (i = 0, dep = mod->deps; i < mod->ndeps; ++i, ++dep) {
 		struct module *o, *d = dep->dep;
--- arch/ppc/mm/fault.c.orig	Mon Jan  8 10:49:14 2001
+++ arch/ppc/mm/fault.c	Mon Jan  8 10:54:19 2001
@@ -95,6 +95,14 @@
 #endif /* !CONFIG_4xx */
 #endif /* CONFIG_XMON || CONFIG_KGDB */

+        /*
+         * Handle a fault in kernel space.
+         */
+
+        if ( address > TASK_SIZE ) {
+           goto vmalloc_fault;
+        }
+
 	if (in_interrupt() || mm == NULL) {
 		bad_page_fault(regs, address);
 		return;
@@ -168,8 +176,35 @@
 	pte_misses++;
 	return;

+  vmalloc_fault:
+        {
+           /*
+            * Synchronize this task's top level page table with the
+            * reference page table.  Modeled on the i386 code with
+            * the difference that there are no pmds in the PPC port.
+            */
+           int offset = pgd_index(address);
+           pgd_t *pgd, *pgd_k;
+           pmd_t *pmd, *pmd_k;
+
+           pgd = current->active_mm->pgd + offset; /* address of pgd
entry in current */
+           pgd_k = init_mm.pgd + offset; /* address of pgd entry in
reference table */
+
+           if ( !pgd_val(*pgd) ) { /* if there isn't a pgd entry
already */
+              if (!pgd_val(*pgd_k)) {/* if there isn't a pgd entry in
the reference table */
+                 goto bad_area_nosemaphore;
+              }
+              *pgd = *pgd_k;
+              return;
+           }
+           goto bad_area_nosemaphore;
+        }
+
+#endif
+
 bad_area:
 	up(&mm->mmap_sem);
+  bad_area_nosemaphore:
 	pte_errors++;

 	/* User mode accesses cause a SIGSEGV */

** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/