## Automatically generated incremental diff
## From:   linux-2.2.27-pre1
## To:     linux-2.2.27-pre2
## Robot:  $Id: make-incremental-diff,v 1.12 2004/01/06 07:19:36 hpa Exp $

diff -urN linux-2.2.27-pre1/ChangeLog-2.2.27 linux-2.2.27-pre2/ChangeLog-2.2.27
--- linux-2.2.27-pre1/ChangeLog-2.2.27	2004-04-20 12:28:51.000000000 -0700
+++ linux-2.2.27-pre2/ChangeLog-2.2.27	2004-04-20 12:28:53.000000000 -0700
@@ -11,13 +11,22 @@
     Thanks to Alan Cox 8-)
 
 
--------------------------------------------------------------------------
+----------------------------------------------------------------------------
 If you need a more secured, more stable, even faster, better SMP support,
-IDE LBA48 support, IPSec support, HTB support, IPVS support etc. enabled
-kernel with many more features and important fixes, please use my
-2.2-secure tree.
+LFS support, Highmem support, IDE LBA48 support, IPSec support, HTB support,
+IPVS support etc. enabled kernel with many more features and important
+fixes, please use my 2.2-secure tree.
 You may find more informations about it at http://www.wolk-project.de/
--------------------------------------------------------------------------
+----------------------------------------------------------------------------
+
+
+
+2.2.27-pre2
+-----------
+o	A more correct fix to last mremap (2) bug		(Dan Yefimov/Solar Designer)
+o	renamed imho *bogus* _vsnprintf to vsnprintf		(me)
+o	fixed 'noexec' behaviour (2.4 backport)			(me)
+	  from Ulrich Drepper
 
 
 
diff -urN linux-2.2.27-pre1/Makefile linux-2.2.27-pre2/Makefile
--- linux-2.2.27-pre1/Makefile	2004-04-20 12:28:51.000000000 -0700
+++ linux-2.2.27-pre2/Makefile	2004-04-20 12:28:53.000000000 -0700
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 27
-EXTRAVERSION = -pre1
+EXTRAVERSION = -pre2
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
diff -urN linux-2.2.27-pre1/include/linux/kernel.h linux-2.2.27-pre2/include/linux/kernel.h
--- linux-2.2.27-pre1/include/linux/kernel.h	2004-02-23 03:37:04.000000000 -0800
+++ linux-2.2.27-pre2/include/linux/kernel.h	2004-04-20 12:28:53.000000000 -0700
@@ -53,7 +53,7 @@
 	__attribute__ ((format (printf, 2, 3)));
 extern int vsprintf(char *buf, const char *, va_list)
 	__attribute__ ((format (printf, 2, 0)));
-extern int _vsnprintf(char *buf, int n, const char *, va_list)
+extern int vsnprintf(char *buf, int n, const char *, va_list)
 	__attribute__ ((format (printf, 3, 0)));
 
 extern int session_of_pgrp(int pgrp);
diff -urN linux-2.2.27-pre1/kernel/ksyms.c linux-2.2.27-pre2/kernel/ksyms.c
--- linux-2.2.27-pre1/kernel/ksyms.c	2001-11-02 08:39:16.000000000 -0800
+++ linux-2.2.27-pre2/kernel/ksyms.c	2004-04-20 12:28:53.000000000 -0700
@@ -362,6 +362,7 @@
 EXPORT_SYMBOL(printk);
 EXPORT_SYMBOL(sprintf);
 EXPORT_SYMBOL(vsprintf);
+EXPORT_SYMBOL(vsnprintf);
 EXPORT_SYMBOL(kdevname);
 EXPORT_SYMBOL(bdevname);
 EXPORT_SYMBOL(cdevname);
diff -urN linux-2.2.27-pre1/kernel/printk.c linux-2.2.27-pre2/kernel/printk.c
--- linux-2.2.27-pre1/kernel/printk.c	2002-09-16 09:26:33.000000000 -0700
+++ linux-2.2.27-pre2/kernel/printk.c	2004-04-20 12:28:53.000000000 -0700
@@ -260,7 +260,7 @@
 
 	spin_lock_irqsave(&console_lock, flags);
 	va_start(args, fmt);
-	i = _vsnprintf(buf + 3, sizeof(buf) - sizeof(buf) / 8 - 3, fmt, args);
+	i = vsnprintf(buf + 3, sizeof(buf) - sizeof(buf) / 8 - 3, fmt, args);
 	buf_end = buf + 3 + i;
 	va_end(args);
 	for (p = buf + 3; p < buf_end; p++) {
diff -urN linux-2.2.27-pre1/lib/vsprintf.c linux-2.2.27-pre2/lib/vsprintf.c
--- linux-2.2.27-pre1/lib/vsprintf.c	2002-09-16 09:26:33.000000000 -0700
+++ linux-2.2.27-pre2/lib/vsprintf.c	2004-04-20 12:28:53.000000000 -0700
@@ -142,7 +142,7 @@
 /* Forward decl. needed for IP address printing stuff... */
 int sprintf(char * buf, const char *fmt, ...);
 
-int _vsnprintf(char *buf, int n, const char *fmt, va_list args)
+int vsnprintf(char *buf, int n, const char *fmt, va_list args)
 {
 	int len;
 	unsigned long num;
@@ -314,7 +314,7 @@
 
 int vsprintf(char *buf, const char *fmt, va_list args)
 {
-	return _vsnprintf(buf, -1, fmt, args);
+	return vsnprintf(buf, -1, fmt, args);
 }
 
 int sprintf(char * buf, const char *fmt, ...)
diff -urN linux-2.2.27-pre1/mm/mmap.c linux-2.2.27-pre2/mm/mmap.c
--- linux-2.2.27-pre1/mm/mmap.c	2004-02-24 05:48:05.000000000 -0800
+++ linux-2.2.27-pre2/mm/mmap.c	2004-04-20 12:28:53.000000000 -0700
@@ -176,8 +176,13 @@
 	struct vm_area_struct * vma;
 	int error;
 
-	if (file && (!file->f_op || !file->f_op->mmap))
-		return -ENODEV;
+	if (file) {
+		if (!file->f_op || !file->f_op->mmap)
+			return -ENODEV;
+
+		if ((prot & PROT_EXEC) && IS_NOEXEC(file->f_dentry->d_inode))
+			return -EPERM;
+	}
 
 	if ((len = PAGE_ALIGN(len)) == 0)
 		return addr;
diff -urN linux-2.2.27-pre1/mm/mremap.c linux-2.2.27-pre2/mm/mremap.c
--- linux-2.2.27-pre1/mm/mremap.c	2004-02-24 05:48:05.000000000 -0800
+++ linux-2.2.27-pre2/mm/mremap.c	2004-04-20 12:28:53.000000000 -0700
@@ -9,115 +9,119 @@
 #include <linux/shm.h>
 #include <linux/mman.h>
 #include <linux/swap.h>
+#include <linux/file.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
 extern int vm_enough_memory(long pages);
 
-static inline pte_t *get_one_pte(struct mm_struct *mm, unsigned long addr)
-{
-	pgd_t * pgd;
-	pmd_t * pmd;
-	pte_t * pte = NULL;
-
-	pgd = pgd_offset(mm, addr);
-	if (pgd_none(*pgd))
-		goto end;
-	if (pgd_bad(*pgd)) {
-		printk("move_one_page: bad source pgd (%08lx)\n", pgd_val(*pgd));
-		pgd_clear(pgd);
-		goto end;
-	}
-
-	pmd = pmd_offset(pgd, addr);
-	if (pmd_none(*pmd))
-		goto end;
-	if (pmd_bad(*pmd)) {
-		printk("move_one_page: bad source pmd (%08lx)\n", pmd_val(*pmd));
-		pmd_clear(pmd);
-		goto end;
-	}
-
-	pte = pte_offset(pmd, addr);
-	if (pte_none(*pte))
-		pte = NULL;
-end:
-	return pte;
-}
-
-static inline pte_t *alloc_one_pte(struct mm_struct *mm, unsigned long addr)
-{
-	pmd_t * pmd;
-	pte_t * pte = NULL;
-
-	pmd = pmd_alloc(pgd_offset(mm, addr), addr);
-	if (pmd)
-		pte = pte_alloc(pmd, addr);
-	return pte;
-}
-
-static inline int copy_one_pte(pte_t * src, pte_t * dst)
-{
-	int error = 0;
-	pte_t pte = *src;
+#define PTE_TABLE_MASK ((PTRS_PER_PTE - 1) * sizeof(pte_t))
+#define PMD_TABLE_MASK ((PTRS_PER_PMD - 1) * sizeof(pmd_t))
 
-	if (!pte_none(pte)) {
-		error++;
-		if (dst) {
-			pte_clear(src);
-			set_pte(dst, pte);
-			error--;
-		}
-	}
-	return error;
-}
-
-static int move_one_page(struct mm_struct *mm, unsigned long old_addr, unsigned long new_addr)
-{
-	int error = 0;
-	pte_t * src;
-
-	src = get_one_pte(mm, old_addr);
-	if (src)
-		error = copy_one_pte(src, alloc_one_pte(mm, new_addr));
-	return error;
-}
+/* Idea borrowed from copy_page_range(), see mm/memory.c */
 
-static int move_page_tables(struct mm_struct * mm,
+static int copy_page_tables(struct mm_struct * mm,
 	unsigned long new_addr, unsigned long old_addr, unsigned long len)
 {
-	unsigned long offset = len;
-
-	flush_cache_range(mm, old_addr, old_addr + len);
-
-	/*
-	 * This is not the clever way to do this, but we're taking the
-	 * easy way out on the assumption that most remappings will be
-	 * only a few pages.. This also makes error recovery easier.
-	 */
-	while (offset) {
-		offset -= PAGE_SIZE;
-		if (move_one_page(mm, old_addr + offset, new_addr + offset))
-			goto oops_we_failed;
+	pgd_t * src_pgd, * dst_pgd;
+	pmd_t * dst_pmd;
+	register pte_t * dst_pte;
+	unsigned long src_addr, dst_addr, end;
+
+	dst_addr = (new_addr &= PAGE_MASK);
+	end = (src_addr = (old_addr &= PAGE_MASK)) + len;
+	src_pgd = pgd_offset(mm, src_addr);
+	dst_pgd = pgd_offset(mm, dst_addr);
+	if (!(dst_pmd = pmd_alloc(dst_pgd, dst_addr)) ||
+	    !(dst_pte = pte_alloc(dst_pmd, dst_addr)))
+		goto oops_we_failed;
+
+	for (;; src_pgd++) {
+		pmd_t * src_pmd;
+
+		if (pgd_none(*src_pgd))
+			goto skip_copy_pmd_range;
+		if (pgd_bad(*src_pgd)) {
+			printk(KERN_ERR "copy_page_tables: bad source pgd (%08lx)\n", pgd_val(*src_pgd));
+			pgd_clear(src_pgd);
+skip_copy_pmd_range:
+			src_addr = (src_addr + PGDIR_SIZE) & PGDIR_MASK;
+			if (src_addr >= end)
+				return 0;
+			dst_addr = new_addr + (src_addr - old_addr);
+			dst_pgd = pgd_offset(mm, dst_addr);
+			if (!(dst_pmd = pmd_alloc(dst_pgd, dst_addr)) ||
+			    !(dst_pte = pte_alloc(dst_pmd, dst_addr)))
+				goto oops_we_failed;
+			continue;
+		}
+		src_pmd = pmd_offset(src_pgd, src_addr);
+		do {
+			register pte_t * src_pte;
+
+			if (pmd_none(*src_pmd))
+				goto skip_copy_pte_range;
+			if (pmd_bad(*src_pmd)) {
+				printk(KERN_ERR "copy_page_tables: bad source pmd (%08lx)\n", pmd_val(*src_pmd));
+				pmd_clear(src_pmd);
+skip_copy_pte_range:
+				src_addr = (src_addr + PMD_SIZE) & PMD_MASK;
+				if (src_addr >= end)
+					return 0;
+				dst_addr = new_addr + (src_addr - old_addr);
+				dst_pgd = pgd_offset(mm, dst_addr);
+				if (!(dst_pmd = pmd_alloc(dst_pgd, dst_addr)) ||
+				    !(dst_pte = pte_alloc(dst_pmd, dst_addr)))
+					goto oops_we_failed;
+				continue;
+			}
+			src_pte = pte_offset(src_pmd, src_addr);
+			do {
+				register pte_t pte = *src_pte;
+
+				if (!pte_none(pte)) {
+					if (!pte_present(pte))
+						swap_duplicate(pte_val(pte));
+					else {
+						register unsigned long page_nr =
+						    (pte_val(pte) >> PAGE_SHIFT);
+
+						if (!(page_nr >= max_mapnr || 
+						    PageReserved(mem_map+page_nr)))
+							atomic_inc(&mem_map[page_nr].count);
+					}
+					set_pte(dst_pte, pte);
+				}
+				if ((src_addr += PAGE_SIZE) >= end)
+					return 0;
+				dst_addr += PAGE_SIZE;
+				if (!((unsigned long) ++dst_pte & PTE_TABLE_MASK)) {
+					if (!((unsigned long) ++dst_pmd
+					      & PMD_TABLE_MASK) &&
+					    !(dst_pmd = pmd_alloc(++dst_pgd,
+								  dst_addr)))
+						goto oops_we_failed;
+					if (!(dst_pte = pte_alloc(dst_pmd,
+								  dst_addr)))
+						goto oops_we_failed;
+				}
+			} while ((unsigned long) ++src_pte & PTE_TABLE_MASK);
+		} while ((unsigned long) ++src_pmd & PMD_TABLE_MASK);
 	}
-	flush_tlb_range(mm, old_addr, old_addr + len);
 	return 0;
 
 	/*
-	 * Ok, the move failed because we didn't have enough pages for
+	 * Ok, the copy failed because we didn't have enough pages for
 	 * the new page table tree. This is unlikely, but we have to
-	 * take the possibility into account. In that case we just move
-	 * all the pages back (this will work, because we still have
-	 * the old page tables)
+	 * take the possibility into account. In that case we just remove
+	 * all the fresh copies of pages.
 	 */
 oops_we_failed:
 	flush_cache_range(mm, new_addr, new_addr + len);
-	while ((offset += PAGE_SIZE) < len)
-		move_one_page(mm, new_addr + offset, old_addr + offset);
 	zap_page_range(mm, new_addr, len);
 	flush_tlb_range(mm, new_addr, new_addr + len);
-	return -1;
+	return -ENOMEM;
 }
 
 static inline unsigned long move_vma(struct vm_area_struct * vma,
@@ -127,9 +131,11 @@
 
 	new_vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 	if (new_vma) {
-		unsigned long new_addr = get_unmapped_area(addr, new_len);
+		unsigned long new_addr = get_unmapped_area(0, new_len);
+
+		if (new_addr && !copy_page_tables(current->mm, new_addr, addr, old_len)) {
+			unsigned long ret;
 
-		if (new_addr && !move_page_tables(current->mm, new_addr, addr, old_len)) {
 			*new_vma = *vma;
 			new_vma->vm_start = new_addr;
 			new_vma->vm_end = new_addr+new_len;
@@ -138,10 +144,19 @@
 				new_vma->vm_file->f_count++;
 			if (new_vma->vm_ops && new_vma->vm_ops->open)
 				new_vma->vm_ops->open(new_vma);
+			if ((ret = do_munmap(addr, old_len))) {
+				if (new_vma->vm_ops && new_vma->vm_ops->close)
+					new_vma->vm_ops->close(new_vma);
+				if (new_vma->vm_file)
+					fput(new_vma->vm_file);
+				flush_cache_range(current->mm, new_addr, new_addr + old_len);
+				zap_page_range(current->mm, new_addr, old_len);
+				flush_tlb_range(current->mm, new_addr, new_addr + old_len);
+				kmem_cache_free(vm_area_cachep, new_vma);
+				return ret;
+			}
 			insert_vm_struct(current->mm, new_vma);
 			merge_segments(current->mm, new_vma->vm_start, new_vma->vm_end);
-			/* XXX: possible errors masked, mapping might remain */
-			do_munmap(addr, old_len);
 			current->mm->total_vm += new_len >> PAGE_SHIFT;
 			if (new_vma->vm_flags & VM_LOCKED) {
 				current->mm->locked_vm += new_len >> PAGE_SHIFT;
@@ -168,30 +183,25 @@
 
 	down(&current->mm->mmap_sem);
 	lock_kernel();
-	if (addr & ~PAGE_MASK)
-		goto out;
-	old_len = PAGE_ALIGN(old_len);
-	new_len = PAGE_ALIGN(new_len);
-
-	if (old_len > TASK_SIZE || addr > TASK_SIZE - old_len)
-		goto out;
-
-	if (addr >= TASK_SIZE)
+	if ((addr & ~PAGE_MASK) || !(old_len = PAGE_ALIGN(old_len)) ||
+	    old_len > TASK_SIZE || addr > TASK_SIZE - old_len ||
+	    (new_len = PAGE_ALIGN(new_len)) > TASK_SIZE)
 		goto out;
 
 	/*
 	 * Always allow a shrinking remap: that just unmaps
 	 * the unnecessary pages..
 	 */
-	if (old_len >= new_len) {
-		ret = do_munmap(addr+new_len, old_len - new_len);
-		if (!ret || old_len == new_len)
+	if (old_len > new_len) {
+		if (!(ret = do_munmap(addr + new_len, old_len - new_len)))
 			ret = addr;
 		goto out;
 	}
 
-	if (new_len > TASK_SIZE || addr > TASK_SIZE - new_len)
+	if (old_len == new_len) {
+		ret = addr;
 		goto out;
+	}
 
 	/*
 	 * Ok, we need to grow..
