diff -urN v2.4.2-pre3/arch/alpha/mm/init.c work-v2.4.2-pre3/arch/alpha/mm/init.c
--- v2.4.2-pre3/arch/alpha/mm/init.c	Wed Nov 29 01:43:39 2000
+++ work-v2.4.2-pre3/arch/alpha/mm/init.c	Mon Feb 12 16:35:09 2001
@@ -32,6 +32,9 @@
 #include <asm/dma.h>
 #include <asm/mmu_context.h>
 #include <asm/console.h>
+#include <asm/tlb.h>
+
+mmu_gather_t mmu_gathers[NR_CPUS];
 
 static unsigned long totalram_pages;
 
diff -urN v2.4.2-pre3/arch/arm/mm/init.c work-v2.4.2-pre3/arch/arm/mm/init.c
--- v2.4.2-pre3/arch/arm/mm/init.c	Mon Feb 12 12:18:54 2001
+++ work-v2.4.2-pre3/arch/arm/mm/init.c	Mon Feb 12 16:35:33 2001
@@ -33,6 +33,9 @@
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <asm/tlb.h>
+
+mmu_gather_t mmu_gathers[NR_CPUS];
 
 #ifndef CONFIG_DISCONTIGMEM
 #define NR_NODES	1
diff -urN v2.4.2-pre3/arch/cris/mm/init.c work-v2.4.2-pre3/arch/cris/mm/init.c
--- v2.4.2-pre3/arch/cris/mm/init.c	Mon Feb 12 12:18:54 2001
+++ work-v2.4.2-pre3/arch/cris/mm/init.c	Mon Feb 12 16:35:59 2001
@@ -57,6 +57,9 @@
 #include <asm/pgtable.h>
 #include <asm/dma.h>
 #include <asm/svinto.h>
+#include <asm/tlb.h>
+
+mmu_gather_t mmu_gathers[NR_CPUS];
 
 static unsigned long totalram_pages;
 
diff -urN v2.4.2-pre3/arch/i386/boot/install.sh work-v2.4.2-pre3/arch/i386/boot/install.sh
--- v2.4.2-pre3/arch/i386/boot/install.sh	Tue Jan  3 06:57:26 1995
+++ work-v2.4.2-pre3/arch/i386/boot/install.sh	Mon Feb 12 16:32:48 2001
@@ -21,6 +21,7 @@
 
 # User may have a custom install script
 
+if [ -x ~/bin/installkernel ]; then exec ~/bin/installkernel "$@"; fi
 if [ -x /sbin/installkernel ]; then exec /sbin/installkernel "$@"; fi
 
 # Default install - same as make zlilo
diff -urN v2.4.2-pre3/arch/i386/mm/init.c work-v2.4.2-pre3/arch/i386/mm/init.c
--- v2.4.2-pre3/arch/i386/mm/init.c	Tue Jan 30 14:38:49 2001
+++ work-v2.4.2-pre3/arch/i386/mm/init.c	Mon Feb 12 16:32:48 2001
@@ -35,7 +35,9 @@
 #include <asm/fixmap.h>
 #include <asm/e820.h>
 #include <asm/apic.h>
+#include <asm/tlb.h>
 
+mmu_gather_t mmu_gathers[NR_CPUS];
 unsigned long highstart_pfn, highend_pfn;
 static unsigned long totalram_pages;
 static unsigned long totalhigh_pages;
diff -urN v2.4.2-pre3/arch/ia64/mm/init.c work-v2.4.2-pre3/arch/ia64/mm/init.c
--- v2.4.2-pre3/arch/ia64/mm/init.c	Thu Jan  4 15:50:17 2001
+++ work-v2.4.2-pre3/arch/ia64/mm/init.c	Mon Feb 12 16:36:33 2001
@@ -23,6 +23,9 @@
 #include <asm/pgalloc.h>
 #include <asm/sal.h>
 #include <asm/system.h>
+#include <asm/tlb.h>
+
+mmu_gather_t mmu_gathers[NR_CPUS];
 
 /* References to section boundaries: */
 extern char _stext, _etext, _edata, __init_begin, __init_end;
diff -urN v2.4.2-pre3/arch/m68k/mm/init.c work-v2.4.2-pre3/arch/m68k/mm/init.c
--- v2.4.2-pre3/arch/m68k/mm/init.c	Mon Oct 16 15:58:51 2000
+++ work-v2.4.2-pre3/arch/m68k/mm/init.c	Mon Feb 12 16:36:52 2001
@@ -31,6 +31,9 @@
 #ifdef CONFIG_ATARI
 #include <asm/atari_stram.h>
 #endif
+#include <asm/tlb.h>
+
+mmu_gather_t mmu_gathers[NR_CPUS];
 
 static unsigned long totalram_pages;
 
diff -urN v2.4.2-pre3/arch/mips/mm/init.c work-v2.4.2-pre3/arch/mips/mm/init.c
--- v2.4.2-pre3/arch/mips/mm/init.c	Mon Oct 16 15:58:51 2000
+++ work-v2.4.2-pre3/arch/mips/mm/init.c	Mon Feb 12 16:37:33 2001
@@ -38,6 +38,9 @@
 #include <asm/sgialib.h>
 #endif
 #include <asm/mmu_context.h>
+#include <asm/tlb.h>
+
+mmu_gather_t mmu_gathers[NR_CPUS];
 
 static unsigned long totalram_pages;
 
diff -urN v2.4.2-pre3/arch/mips64/mm/init.c work-v2.4.2-pre3/arch/mips64/mm/init.c
--- v2.4.2-pre3/arch/mips64/mm/init.c	Mon Oct 16 15:58:51 2000
+++ work-v2.4.2-pre3/arch/mips64/mm/init.c	Mon Feb 12 16:37:18 2001
@@ -37,6 +37,9 @@
 #include <asm/sgialib.h>
 #endif
 #include <asm/mmu_context.h>
+#include <asm/tlb.h>
+
+mmu_gather_t mmu_gathers[NR_CPUS];
 
 unsigned long totalram_pages;
 
diff -urN v2.4.2-pre3/arch/parisc/mm/init.c work-v2.4.2-pre3/arch/parisc/mm/init.c
--- v2.4.2-pre3/arch/parisc/mm/init.c	Tue Dec  5 15:29:39 2000
+++ work-v2.4.2-pre3/arch/parisc/mm/init.c	Mon Feb 12 16:37:56 2001
@@ -19,6 +19,9 @@
 #include <linux/unistd.h>
 
 #include <asm/pgalloc.h>
+#include <asm/tlb.h>
+
+mmu_gather_t mmu_gathers[NR_CPUS];
 
 static unsigned long totalram_pages;
 extern unsigned long max_pfn, mem_max;
diff -urN v2.4.2-pre3/arch/ppc/mm/init.c work-v2.4.2-pre3/arch/ppc/mm/init.c
--- v2.4.2-pre3/arch/ppc/mm/init.c	Tue Jan 30 14:38:50 2001
+++ work-v2.4.2-pre3/arch/ppc/mm/init.c	Mon Feb 12 16:38:26 2001
@@ -67,6 +67,9 @@
 #if defined(CONFIG_4xx)
 #include "4xx_tlb.h"
 #endif
+#include <asm/tlb.h>
+
+mmu_gather_t mmu_gathers[NR_CPUS];
 
 #define MAX_LOW_MEM	(512 << 20)
 
diff -urN v2.4.2-pre3/arch/s390/mm/init.c work-v2.4.2-pre3/arch/s390/mm/init.c
--- v2.4.2-pre3/arch/s390/mm/init.c	Wed Nov 29 01:43:39 2000
+++ work-v2.4.2-pre3/arch/s390/mm/init.c	Mon Feb 12 16:38:43 2001
@@ -35,6 +35,9 @@
 #include <asm/pgalloc.h>
 #include <asm/dma.h>
 #include <asm/lowcore.h>
+#include <asm/tlb.h>
+
+mmu_gather_t mmu_gathers[NR_CPUS];
 
 static unsigned long totalram_pages;
 
diff -urN v2.4.2-pre3/arch/sh/mm/init.c work-v2.4.2-pre3/arch/sh/mm/init.c
--- v2.4.2-pre3/arch/sh/mm/init.c	Wed Nov 29 01:43:39 2000
+++ work-v2.4.2-pre3/arch/sh/mm/init.c	Mon Feb 12 16:38:59 2001
@@ -34,6 +34,9 @@
 #include <asm/pgalloc.h>
 #include <asm/mmu_context.h>
 #include <asm/io.h>
+#include <asm/tlb.h>
+
+mmu_gather_t mmu_gathers[NR_CPUS];
 
 /*
  * Cache of MMU context last used.
diff -urN v2.4.2-pre3/arch/sparc/mm/init.c work-v2.4.2-pre3/arch/sparc/mm/init.c
--- v2.4.2-pre3/arch/sparc/mm/init.c	Mon Dec 11 15:37:03 2000
+++ work-v2.4.2-pre3/arch/sparc/mm/init.c	Mon Feb 12 16:39:31 2001
@@ -32,6 +32,9 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/vaddrs.h>
+#include <asm/tlb.h>
+
+mmu_gather_t mmu_gathers[NR_CPUS];
 
 unsigned long *sparc_valid_addr_bitmap;
 
diff -urN v2.4.2-pre3/arch/sparc64/mm/init.c work-v2.4.2-pre3/arch/sparc64/mm/init.c
--- v2.4.2-pre3/arch/sparc64/mm/init.c	Mon Feb 12 12:18:55 2001
+++ work-v2.4.2-pre3/arch/sparc64/mm/init.c	Mon Feb 12 16:39:16 2001
@@ -30,6 +30,9 @@
 #include <asm/vaddrs.h>
 #include <asm/dma.h>
 #include <asm/starfire.h>
+#include <asm/tlb.h>
+
+mmu_gather_t mmu_gathers[NR_CPUS];
 
 extern void device_scan(void);
 
diff -urN v2.4.2-pre3/drivers/net/hamradio/soundmodem/gentbl.c work-v2.4.2-pre3/drivers/net/hamradio/soundmodem/gentbl.c
--- v2.4.2-pre3/drivers/net/hamradio/soundmodem/gentbl.c	Thu Jun 25 15:25:16 1998
+++ work-v2.4.2-pre3/drivers/net/hamradio/soundmodem/gentbl.c	Mon Feb 12 16:32:48 2001
@@ -26,6 +26,7 @@
  */
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <math.h>
 #include <string.h>
 
diff -urN v2.4.2-pre3/include/asm-alpha/tlb.h work-v2.4.2-pre3/include/asm-alpha/tlb.h
--- v2.4.2-pre3/include/asm-alpha/tlb.h	Wed Dec 31 19:00:00 1969
+++ work-v2.4.2-pre3/include/asm-alpha/tlb.h	Mon Feb 12 16:33:44 2001
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -urN v2.4.2-pre3/include/asm-arm/tlb.h work-v2.4.2-pre3/include/asm-arm/tlb.h
--- v2.4.2-pre3/include/asm-arm/tlb.h	Wed Dec 31 19:00:00 1969
+++ work-v2.4.2-pre3/include/asm-arm/tlb.h	Mon Feb 12 16:33:44 2001
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -urN v2.4.2-pre3/include/asm-cris/tlb.h work-v2.4.2-pre3/include/asm-cris/tlb.h
--- v2.4.2-pre3/include/asm-cris/tlb.h	Wed Dec 31 19:00:00 1969
+++ work-v2.4.2-pre3/include/asm-cris/tlb.h	Mon Feb 12 16:33:44 2001
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -urN v2.4.2-pre3/include/asm-generic/tlb.h work-v2.4.2-pre3/include/asm-generic/tlb.h
--- v2.4.2-pre3/include/asm-generic/tlb.h	Wed Dec 31 19:00:00 1969
+++ work-v2.4.2-pre3/include/asm-generic/tlb.h	Mon Feb 12 16:32:48 2001
@@ -0,0 +1,111 @@
+/* asm-generic/tlb.h
+ *
+ *	Generic TLB shootdown code
+ *
+ * Copyright 2001 Red Hat, Inc.
+ * Based on code from mm/memory.c Copyright Linus Torvalds and others.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _ASM_GENERIC__TLB_H
+#define _ASM_GENERIC__TLB_H
+
+#ifdef CONFIG_SMP
+/* aim for something that fits in the L1 cache */
+#define FREE_PTE_NR	508
+
+/* mmu_gather_t is an opaque type used by the mm code for passing around any
+ * data needed by arch specific code for tlb_remove_page.  This structure can
+ * be per-CPU or per-MM as the page table lock is held for the duration of TLB
+ * shootdown.
+ */
+typedef struct free_pte_ctx {
+	struct mm_struct	*mm;
+	unsigned long		nr;	/* set to ~0UL means fast mode */
+	unsigned long	start_addr, end_addr;
+	pte_t	ptes[FREE_PTE_NR];
+} mmu_gather_t;
+
+/* Users of the generic TLB shootdown code must declare this storage space. */
+extern mmu_gather_t	mmu_gathers[NR_CPUS];
+
+/* tlb_gather_mmu
+ *	Return a pointer to an initialized mmu_gather_t.
+ */
+static inline mmu_gather_t *tlb_gather_mmu(struct mm_struct *mm)
+{
+	mmu_gather_t *tlb = &mmu_gathers[smp_processor_id()];
+
+	tlb->mm = mm;
+	/* Use fast mode if there is only one user of this mm (this process) */
+	tlb->nr = (atomic_read(&(mm)->mm_users) == 1) ? ~0UL : 0UL;
+	return tlb;
+}
+
+/* void tlb_remove_page(mmu_gather_t *tlb, pte_t *ptep, unsigned long addr)
+ *	Must perform the equivalent to __free_pte(pte_get_and_clear(ptep)), while
+ *	handling the additional races in SMP caused by other CPUs caching valid
+ *	mappings in their TLBs.
+ */
+#define tlb_remove_page(ctxp, pte, addr) do {\
+		/* Handle the common case fast, first. */\
+		if ((ctxp)->nr == ~0UL) {\
+			__free_pte(*(pte));\
+			pte_clear((pte));\
+			break;\
+		}\
+		if (!(ctxp)->nr) \
+			(ctxp)->start_addr = (addr);\
+		(ctxp)->ptes[(ctxp)->nr++] = ptep_get_and_clear(pte);\
+		(ctxp)->end_addr = (addr) + PAGE_SIZE;\
+		if ((ctxp)->nr >= FREE_PTE_NR)\
+			tlb_finish_mmu((ctxp), 0, 0);\
+	} while (0)
+
+/* tlb_finish_mmu
+ *	Called at the end of the shootdown operation to free up any resources
+ *	that were required.  The page talbe lock is still held at this point.
+ */
+static inline void tlb_finish_mmu(struct free_pte_ctx *ctx, unsigned long start, unsigned long end)
+{
+	unsigned long i, nr;
+
+	/* Handle the fast case first. */
+	if (ctx->nr == ~0UL) {
+		flush_tlb_range(ctx->mm, start, end);
+		return;
+	}
+	nr = ctx->nr;
+	ctx->nr = 0;
+	if (nr)
+		flush_tlb_range(ctx->mm, ctx->start_addr, ctx->end_addr);
+	for (i=0; i < nr; i++) {
+		pte_t pte = ctx->ptes[i];
+		__free_pte(pte);
+	}
+}
+
+#else
+
+/* The uniprocessor functions are quite simple and are inline macros in an
+ * attempt to get gcc to generate optimal code since this code is run on each
+ * page in a process at exit.
+ */
+typedef struct mm_struct mmu_gather_t;
+
+#define tlb_gather_mmu(mm)	(mm)
+#define tlb_finish_mmu(tlb, start, end)	flush_tlb_range(tlb, start, end)
+#define tlb_remove_page(tlb, ptep, addr)	do {\
+		pte_t __pte = *(ptep);\
+		pte_clear(ptep);\
+		__free_pte(__pte);\
+	} while (0)
+
+#endif
+
+
+#endif /* _ASM_GENERIC__TLB_H */
+
diff -urN v2.4.2-pre3/include/asm-i386/tlb.h work-v2.4.2-pre3/include/asm-i386/tlb.h
--- v2.4.2-pre3/include/asm-i386/tlb.h	Wed Dec 31 19:00:00 1969
+++ work-v2.4.2-pre3/include/asm-i386/tlb.h	Mon Feb 12 16:32:48 2001
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -urN v2.4.2-pre3/include/asm-ia64/tlb.h work-v2.4.2-pre3/include/asm-ia64/tlb.h
--- v2.4.2-pre3/include/asm-ia64/tlb.h	Wed Dec 31 19:00:00 1969
+++ work-v2.4.2-pre3/include/asm-ia64/tlb.h	Mon Feb 12 16:33:45 2001
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -urN v2.4.2-pre3/include/asm-m68k/tlb.h work-v2.4.2-pre3/include/asm-m68k/tlb.h
--- v2.4.2-pre3/include/asm-m68k/tlb.h	Wed Dec 31 19:00:00 1969
+++ work-v2.4.2-pre3/include/asm-m68k/tlb.h	Mon Feb 12 16:33:45 2001
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -urN v2.4.2-pre3/include/asm-mips/tlb.h work-v2.4.2-pre3/include/asm-mips/tlb.h
--- v2.4.2-pre3/include/asm-mips/tlb.h	Wed Dec 31 19:00:00 1969
+++ work-v2.4.2-pre3/include/asm-mips/tlb.h	Mon Feb 12 16:33:45 2001
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -urN v2.4.2-pre3/include/asm-mips64/tlb.h work-v2.4.2-pre3/include/asm-mips64/tlb.h
--- v2.4.2-pre3/include/asm-mips64/tlb.h	Wed Dec 31 19:00:00 1969
+++ work-v2.4.2-pre3/include/asm-mips64/tlb.h	Mon Feb 12 16:33:45 2001
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -urN v2.4.2-pre3/include/asm-parisc/tlb.h work-v2.4.2-pre3/include/asm-parisc/tlb.h
--- v2.4.2-pre3/include/asm-parisc/tlb.h	Wed Dec 31 19:00:00 1969
+++ work-v2.4.2-pre3/include/asm-parisc/tlb.h	Mon Feb 12 16:33:45 2001
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -urN v2.4.2-pre3/include/asm-ppc/tlb.h work-v2.4.2-pre3/include/asm-ppc/tlb.h
--- v2.4.2-pre3/include/asm-ppc/tlb.h	Wed Dec 31 19:00:00 1969
+++ work-v2.4.2-pre3/include/asm-ppc/tlb.h	Mon Feb 12 16:33:45 2001
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -urN v2.4.2-pre3/include/asm-s390/tlb.h work-v2.4.2-pre3/include/asm-s390/tlb.h
--- v2.4.2-pre3/include/asm-s390/tlb.h	Wed Dec 31 19:00:00 1969
+++ work-v2.4.2-pre3/include/asm-s390/tlb.h	Mon Feb 12 16:33:45 2001
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -urN v2.4.2-pre3/include/asm-sh/tlb.h work-v2.4.2-pre3/include/asm-sh/tlb.h
--- v2.4.2-pre3/include/asm-sh/tlb.h	Wed Dec 31 19:00:00 1969
+++ work-v2.4.2-pre3/include/asm-sh/tlb.h	Mon Feb 12 16:33:45 2001
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -urN v2.4.2-pre3/include/asm-sparc/tlb.h work-v2.4.2-pre3/include/asm-sparc/tlb.h
--- v2.4.2-pre3/include/asm-sparc/tlb.h	Wed Dec 31 19:00:00 1969
+++ work-v2.4.2-pre3/include/asm-sparc/tlb.h	Mon Feb 12 16:33:45 2001
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -urN v2.4.2-pre3/include/asm-sparc64/tlb.h work-v2.4.2-pre3/include/asm-sparc64/tlb.h
--- v2.4.2-pre3/include/asm-sparc64/tlb.h	Wed Dec 31 19:00:00 1969
+++ work-v2.4.2-pre3/include/asm-sparc64/tlb.h	Mon Feb 12 16:33:45 2001
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -urN v2.4.2-pre3/include/linux/swap.h work-v2.4.2-pre3/include/linux/swap.h
--- v2.4.2-pre3/include/linux/swap.h	Tue Feb  6 18:02:45 2001
+++ work-v2.4.2-pre3/include/linux/swap.h	Mon Feb 12 16:32:48 2001
@@ -293,6 +293,22 @@
 
 extern void shmem_unuse(swp_entry_t entry, struct page *page);
 
+/* Helper function for TLB shootdown that frees a present pte.
+ */
+static inline void __free_pte(pte_t pte)
+{
+	struct page *page = pte_page(pte);
+	if ((!VALID_PAGE(page)) || PageReserved(page))
+		return;
+	/* 
+	 * free_page() used to be able to clear swap cache
+	 * entries.  We may now have to do it manually.  
+	 */
+	if (pte_dirty(pte) && page->mapping)
+		set_page_dirty(page);
+	free_page_and_swap_cache(page);
+}
+
 #endif /* __KERNEL__*/
 
 #endif /* _LINUX_SWAP_H */
diff -urN v2.4.2-pre3/include/linux/tlb.h work-v2.4.2-pre3/include/linux/tlb.h
--- v2.4.2-pre3/include/linux/tlb.h	Wed Dec 31 19:00:00 1969
+++ work-v2.4.2-pre3/include/linux/tlb.h	Mon Feb 12 16:33:45 2001
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -urN v2.4.2-pre3/include/math-emu/tlb.h work-v2.4.2-pre3/include/math-emu/tlb.h
--- v2.4.2-pre3/include/math-emu/tlb.h	Wed Dec 31 19:00:00 1969
+++ work-v2.4.2-pre3/include/math-emu/tlb.h	Mon Feb 12 16:33:45 2001
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -urN v2.4.2-pre3/include/net/tlb.h work-v2.4.2-pre3/include/net/tlb.h
--- v2.4.2-pre3/include/net/tlb.h	Wed Dec 31 19:00:00 1969
+++ work-v2.4.2-pre3/include/net/tlb.h	Mon Feb 12 16:33:45 2001
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -urN v2.4.2-pre3/include/pcmcia/tlb.h work-v2.4.2-pre3/include/pcmcia/tlb.h
--- v2.4.2-pre3/include/pcmcia/tlb.h	Wed Dec 31 19:00:00 1969
+++ work-v2.4.2-pre3/include/pcmcia/tlb.h	Mon Feb 12 16:33:45 2001
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -urN v2.4.2-pre3/include/scsi/tlb.h work-v2.4.2-pre3/include/scsi/tlb.h
--- v2.4.2-pre3/include/scsi/tlb.h	Wed Dec 31 19:00:00 1969
+++ work-v2.4.2-pre3/include/scsi/tlb.h	Mon Feb 12 16:33:45 2001
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -urN v2.4.2-pre3/include/video/tlb.h work-v2.4.2-pre3/include/video/tlb.h
--- v2.4.2-pre3/include/video/tlb.h	Wed Dec 31 19:00:00 1969
+++ work-v2.4.2-pre3/include/video/tlb.h	Mon Feb 12 16:33:45 2001
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -urN v2.4.2-pre3/mm/filemap.c work-v2.4.2-pre3/mm/filemap.c
--- v2.4.2-pre3/mm/filemap.c	Mon Feb 12 12:19:03 2001
+++ work-v2.4.2-pre3/mm/filemap.c	Mon Feb 12 16:32:48 2001
@@ -2023,9 +2023,7 @@
 	if (vma->vm_flags & VM_LOCKED)
 		return -EINVAL;
 
-	flush_cache_range(vma->vm_mm, start, end);
 	zap_page_range(vma->vm_mm, start, end - start);
-	flush_tlb_range(vma->vm_mm, start, end);
 	return 0;
 }
 
diff -urN v2.4.2-pre3/mm/memory.c work-v2.4.2-pre3/mm/memory.c
--- v2.4.2-pre3/mm/memory.c	Mon Feb 12 12:19:03 2001
+++ work-v2.4.2-pre3/mm/memory.c	Mon Feb 12 16:32:48 2001
@@ -46,7 +46,7 @@
 #include <asm/pgalloc.h>
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
-
+#include <asm/tlb.h>
 
 unsigned long max_mapnr;
 unsigned long num_physpages;
@@ -265,37 +265,19 @@
 /*
  * Return indicates whether a page was freed so caller can adjust rss
  */
-static inline int free_pte(pte_t pte)
-{
-	if (pte_present(pte)) {
-		struct page *page = pte_page(pte);
-		if ((!VALID_PAGE(page)) || PageReserved(page))
-			return 0;
-		/* 
-		 * free_page() used to be able to clear swap cache
-		 * entries.  We may now have to do it manually.  
-		 */
-		if (pte_dirty(pte) && page->mapping)
-			set_page_dirty(page);
-		free_page_and_swap_cache(page);
-		return 1;
-	}
-	swap_free(pte_to_swp_entry(pte));
-	return 0;
-}
-
 static inline void forget_pte(pte_t page)
 {
 	if (!pte_none(page)) {
 		printk("forget_pte: old mapping existed!\n");
-		free_pte(page);
+		BUG();
 	}
 }
 
-static inline int zap_pte_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size)
+static inline int zap_pte_range(mmu_gather_t *tlb, pmd_t * pmd, unsigned long address, unsigned long size)
 {
-	pte_t * pte;
-	int freed;
+	unsigned long offset;
+	pte_t * ptep;
+	int freed = 0;
 
 	if (pmd_none(*pmd))
 		return 0;
@@ -304,27 +286,27 @@
 		pmd_clear(pmd);
 		return 0;
 	}
-	pte = pte_offset(pmd, address);
+	ptep = pte_offset(pmd, address);
 	address &= ~PMD_MASK;
 	if (address + size > PMD_SIZE)
 		size = PMD_SIZE - address;
-	size >>= PAGE_SHIFT;
-	freed = 0;
-	for (;;) {
-		pte_t page;
-		if (!size)
-			break;
-		page = ptep_get_and_clear(pte);
-		pte++;
-		size--;
-		if (pte_none(page))
+	size &= PAGE_MASK;
+	for (offset=0; offset < size; ptep++, offset += PAGE_SIZE) {
+		pte_t pte = *ptep;
+		if (pte_none(pte))
 			continue;
-		freed += free_pte(page);
+		if (pte_present(pte)) {
+			freed ++;
+			/* This will eventually call __free_pte on the pte. */
+			tlb_remove_page(tlb, ptep, address + offset);
+		} else
+			swap_free(pte_to_swp_entry(pte));
 	}
+
 	return freed;
 }
 
-static inline int zap_pmd_range(struct mm_struct *mm, pgd_t * dir, unsigned long address, unsigned long size)
+static inline int zap_pmd_range(mmu_gather_t *tlb, pgd_t * dir, unsigned long address, unsigned long size)
 {
 	pmd_t * pmd;
 	unsigned long end;
@@ -344,7 +326,7 @@
 		end = PGDIR_SIZE;
 	freed = 0;
 	do {
-		freed += zap_pte_range(mm, pmd, address, end - address);
+		freed += zap_pte_range(tlb, pmd, address, end - address);
 		address = (address + PMD_SIZE) & PMD_MASK; 
 		pmd++;
 	} while (address < end);
@@ -356,8 +338,9 @@
  */
 void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size)
 {
+	mmu_gather_t *tlb;
 	pgd_t * dir;
-	unsigned long end = address + size;
+	unsigned long start = address, end = address + size;
 	int freed = 0;
 
 	dir = pgd_offset(mm, address);
@@ -372,12 +355,18 @@
 	if (address >= end)
 		BUG();
 	spin_lock(&mm->page_table_lock);
+	flush_cache_range(mm, address, end);
+	tlb = tlb_gather_mmu(mm);
+
 	do {
-		freed += zap_pmd_range(mm, dir, address, end - address);
+		freed += zap_pmd_range(tlb, dir, address, end - address);
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	} while (address && (address < end));
-	spin_unlock(&mm->page_table_lock);
+
+	/* this will flush any remaining tlb entries */
+	tlb_finish_mmu(tlb, start, end);
+
 	/*
 	 * Update rss for the mm_struct (not necessarily current->mm)
 	 * Notice that rss is an unsigned long.
@@ -386,6 +375,7 @@
 		mm->rss -= freed;
 	else
 		mm->rss = 0;
+	spin_unlock(&mm->page_table_lock);
 }
 
 
@@ -908,9 +898,7 @@
 
 		/* mapping wholly truncated? */
 		if (mpnt->vm_pgoff >= pgoff) {
-			flush_cache_range(mm, start, end);
 			zap_page_range(mm, start, len);
-			flush_tlb_range(mm, start, end);
 			continue;
 		}
 
@@ -923,9 +911,7 @@
 		/* Ok, partially affected.. */
 		start += diff << PAGE_SHIFT;
 		len = (len - diff) << PAGE_SHIFT;
-		flush_cache_range(mm, start, end);
 		zap_page_range(mm, start, len);
-		flush_tlb_range(mm, start, end);
 	} while ((mpnt = mpnt->vm_next_share) != NULL);
 }
 			      
diff -urN v2.4.2-pre3/mm/mmap.c work-v2.4.2-pre3/mm/mmap.c
--- v2.4.2-pre3/mm/mmap.c	Mon Feb 12 12:19:03 2001
+++ work-v2.4.2-pre3/mm/mmap.c	Mon Feb 12 16:32:48 2001
@@ -373,9 +373,7 @@
 	vma->vm_file = NULL;
 	fput(file);
 	/* Undo any partial mapping done by a device driver. */
-	flush_cache_range(mm, vma->vm_start, vma->vm_end);
 	zap_page_range(mm, vma->vm_start, vma->vm_end - vma->vm_start);
-	flush_tlb_range(mm, vma->vm_start, vma->vm_end);
 free_vma:
 	kmem_cache_free(vm_area_cachep, vma);
 	return error;
@@ -750,9 +748,7 @@
 		remove_shared_vm_struct(mpnt);
 		mm->map_count--;
 
-		flush_cache_range(mm, st, end);
 		zap_page_range(mm, st, size);
-		flush_tlb_range(mm, st, end);
 
 		/*
 		 * Fix the mapping, and free the old area if it wasn't reused.
diff -urN v2.4.2-pre3/mm/mremap.c work-v2.4.2-pre3/mm/mremap.c
--- v2.4.2-pre3/mm/mremap.c	Fri Dec 29 17:07:24 2000
+++ work-v2.4.2-pre3/mm/mremap.c	Mon Feb 12 16:32:48 2001
@@ -119,7 +119,6 @@
 	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;
 }
 
