patch-2.2.0-pre8 linux/mm/memory.c

Next file: linux/mm/mmap.c
Previous file: linux/mm/filemap.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.0-pre7/linux/mm/memory.c linux/mm/memory.c
@@ -126,48 +126,36 @@
  * This function clears all user-level page tables of a process - this
  * is needed by execve(), so that old pages aren't in the way.
  */
-void clear_page_tables(struct task_struct * tsk)
+void clear_page_tables(struct mm_struct *mm, unsigned long first, int nr)
 {
-	pgd_t * page_dir = tsk->mm->pgd;
-	int i;
-
-	if (!page_dir || page_dir == swapper_pg_dir)
-		goto out_bad;
-	for (i = 0 ; i < USER_PTRS_PER_PGD ; i++)
-		free_one_pgd(page_dir + i);
-
-	/* keep the page table cache within bounds */
-	check_pgt_cache();
-	return;
+	pgd_t * page_dir = mm->pgd;
 
-out_bad:
-	printk(KERN_ERR 
-		"clear_page_tables: %s trying to clear kernel pgd\n",
-		tsk->comm);
-	return;
+	if (page_dir && page_dir != swapper_pg_dir) {
+		page_dir += first;
+		do {
+			free_one_pgd(page_dir);
+			page_dir++;
+		} while (--nr);
+
+		/* keep the page table cache within bounds */
+		check_pgt_cache();
+	}
 }
 
 /*
- * This function frees up all page tables of a process when it exits. It
- * is the same as "clear_page_tables()", except it also frees the old
- * page table directory.
+ * This function just free's the page directory - the
+ * pages tables themselves have been freed earlier by 
+ * clear_page_tables().
  */
 void free_page_tables(struct mm_struct * mm)
 {
 	pgd_t * page_dir = mm->pgd;
-	int i;
 
-	if (!page_dir)
-		goto out;
-	if (page_dir == swapper_pg_dir)
-		goto out_bad;
-	for (i = 0 ; i < USER_PTRS_PER_PGD ; i++)
-		free_one_pgd(page_dir + i);
-	pgd_free(page_dir);
-
-	/* keep the page table cache within bounds */
-	check_pgt_cache();
-out:
+	if (page_dir) {
+		if (page_dir == swapper_pg_dir)
+			goto out_bad;
+		pgd_free(page_dir);
+	}
 	return;
 
 out_bad:
@@ -204,7 +192,7 @@
 	pgd_t * src_pgd, * dst_pgd;
 	unsigned long address = vma->vm_start;
 	unsigned long end = vma->vm_end;
-	unsigned long cow = (vma->vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE;
+	unsigned long cow = (vma->vm_flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE;
 	
 	src_pgd = pgd_offset(src, address)-1;
 	dst_pgd = pgd_offset(dst, address)-1;
@@ -277,10 +265,15 @@
 					set_pte(dst_pte, pte);
 					goto cont_copy_pte_range;
 				}
-				if (cow)
+				/* If it's a COW mapping, write protect it both in the parent and the child */
+				if (cow) {
 					pte = pte_wrprotect(pte);
+					set_pte(src_pte, pte);
+				}
+				/* If it's a shared mapping, mark it clean in the child */
+				if (vma->vm_flags & VM_SHARED)
+					pte = pte_mkclean(pte);
 				set_pte(dst_pte, pte_mkold(pte));
-				set_pte(src_pte, pte);
 				atomic_inc(&mem_map[page_nr].count);
 			
 cont_copy_pte_range:		address += PAGE_SIZE;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov