diff -u --recursive v1.1.32/linux/Makefile linux/Makefile
--- v1.1.32/linux/Makefile	Thu Jul 21 08:18:00 1994
+++ linux/Makefile	Thu Jul 21 10:37:39 1994
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 32
+SUBLEVEL = 33
 
 all:	Version zImage
 
diff -u --recursive v1.1.32/linux/drivers/block/cdu31a.c linux/drivers/block/cdu31a.c
--- v1.1.32/linux/drivers/block/cdu31a.c	Thu Jul 14 00:48:20 1994
+++ linux/drivers/block/cdu31a.c	Wed Jul 20 23:13:28 1994
@@ -1772,6 +1772,9 @@
    int num_spin_ups;
 
 
+   if (filp->f_mode & 2)
+      return -EACCES;
+
    if (!sony_spun_up)
    {
       num_spin_ups = 0;
diff -u --recursive v1.1.32/linux/drivers/block/hd.c linux/drivers/block/hd.c
--- v1.1.32/linux/drivers/block/hd.c	Thu Jul 21 08:18:02 1994
+++ linux/drivers/block/hd.c	Thu Jul 21 07:38:40 1994
@@ -218,12 +218,12 @@
 }
 
 static void hd_request (void);
-unsigned int identified  [MAX_HD] = {0,}; /* 1 = drive ID already displayed   */
-unsigned int unmask_intr [MAX_HD] = {0,}; /* 1 = unmask IRQs during I/O       */
-unsigned int max_mult    [MAX_HD] = {0,}; /* max sectors for MultMode         */
-unsigned int mult_req    [MAX_HD] = {0,}; /* requested MultMode count         */
-unsigned int mult_count  [MAX_HD] = {0,}; /* currently enabled MultMode count */
-struct request WCURRENT;
+static unsigned int identified  [MAX_HD] = {0,}; /* 1 = drive ID already displayed   */
+static unsigned int unmask_intr [MAX_HD] = {0,}; /* 1 = unmask IRQs during I/O       */
+static unsigned int max_mult    [MAX_HD] = {0,}; /* max sectors for MultMode         */
+static unsigned int mult_req    [MAX_HD] = {0,}; /* requested MultMode count         */
+static unsigned int mult_count  [MAX_HD] = {0,}; /* currently enabled MultMode count */
+static struct request WCURRENT;
 
 static void rawstring (char *prefix, char *s, int n)
 {
diff -u --recursive v1.1.32/linux/drivers/block/mcd.c linux/drivers/block/mcd.c
--- v1.1.32/linux/drivers/block/mcd.c	Sat Jul  9 16:30:45 1994
+++ linux/drivers/block/mcd.c	Wed Jul 20 23:13:28 1994
@@ -1029,6 +1029,9 @@
 
 	if (mcdPresent == 0)
 		return -ENXIO;			/* no hardware */
+	
+	if (fp->f_mode & 2)			/* write access? */
+		return -EACCES;
 
 	if (!mcd_open_count && mcd_state == MCD_S_IDLE) {
 
diff -u --recursive v1.1.32/linux/drivers/block/sbpcd.c linux/drivers/block/sbpcd.c
--- v1.1.32/linux/drivers/block/sbpcd.c	Sat Jul 16 19:51:21 1994
+++ linux/drivers/block/sbpcd.c	Wed Jul 20 23:13:28 1994
@@ -3211,6 +3211,9 @@
 
   if (ndrives==0) return (-ENXIO);             /* no hardware */
 
+  if (fp->f_mode & 2)
+	  return -EACCES;
+
   i = MINOR(ip->i_rdev);
   if ( (i<0) || (i>=NR_SBPCD) )
     {
diff -u --recursive v1.1.32/linux/drivers/char/console.c linux/drivers/char/console.c
--- v1.1.32/linux/drivers/char/console.c	Thu Jul 21 08:18:04 1994
+++ linux/drivers/char/console.c	Thu Jul 21 14:06:28 1994
@@ -35,6 +35,9 @@
  * Code to check for different video-cards mostly by Galen Hunt,
  * <g-hunt@ee.utah.edu>
  *
+ * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94
+ * <poe@daimi.aau.dk>
+ *
  */
 
 #define CAN_LOAD_EGA_FONTS    /* undefine if the user must not do this */
@@ -80,7 +83,7 @@
 #include <linux/ctype.h>
 
 /* Routines for selection control. */
-int set_selection(const int arg);
+int set_selection(const int arg, struct tty_struct *tty);
 int paste_selection(struct tty_struct *tty);
 static void clear_selection(void);
 static void highlight_pointer(const int currcons, const int where);
@@ -153,6 +156,7 @@
 	/* misc */
 	unsigned long	vc_ques		: 1;
 	unsigned long	vc_need_wrap	: 1;
+	unsigned long	vc_report_mouse : 1;
 	unsigned long	vc_tab_stop[5];		/* Tab stops. 160 columns. */
 	unsigned char * vc_translate;
 	unsigned char *	vc_G0_charset;
@@ -196,6 +200,7 @@
 #define deccm		(vc_cons[currcons].vc_deccm)
 #define decim		(vc_cons[currcons].vc_decim)
 #define need_wrap	(vc_cons[currcons].vc_need_wrap)
+#define report_mouse	(vc_cons[currcons].vc_report_mouse)
 #define color		(vc_cons[currcons].vc_color)
 #define s_color		(vc_cons[currcons].vc_s_color)
 #define def_color	(vc_cons[currcons].vc_def_color)
@@ -775,6 +780,16 @@
 	respond_string(buf, tty);
 }
 
+static void mouse_report(int currcons, struct tty_struct * tty,
+			 int butt, int mrx, int mry)
+{
+	char buf[8];
+
+	sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
+		(char)('!' + mry));
+	respond_string(buf, tty);
+}
+
 static inline void status_report(int currcons, struct tty_struct * tty)
 {
 	respond_string("\033[0n", tty);	/* Terminal ok */
@@ -832,6 +847,9 @@
 				else
 					clr_kbd(decarm);
 				break;
+			case 9:
+				report_mouse = on_off;
+				break;
 			case 25:		/* Cursor on/off */
 				deccm = on_off;
 				set_cursor(currcons);
@@ -1001,6 +1019,7 @@
 	G1_charset	= GRAF_TRANS;
 	charset		= 0;
 	need_wrap	= 0;
+	report_mouse	= 0;
 
 	disp_ctrl	= 0;
 	toggle_meta	= 0;
@@ -1838,8 +1857,16 @@
 	return (v < l) ? l : ((v > u) ? u : v);
 }
 
+/* invoked via ioctl(TIOCLINUX) */
+int mouse_reporting_p(void)
+{
+	int currcons = fg_console;
+
+	return ((report_mouse) ? 0 : -EINVAL);
+}
+
 /* set the current selection. Invoked by ioctl(). */
-int set_selection(const int arg)
+int set_selection(const int arg, struct tty_struct *tty)
 {
 	unsigned short *args, xs, ys, xe, ye;
 	int currcons = fg_console;
@@ -1862,6 +1889,11 @@
 	ye = limit(ye, 0, video_num_lines - 1);
 	ps = ys * video_size_row + (xs << 1);
 	pe = ye * video_size_row + (xe << 1);
+
+	if (report_mouse && (sel_mode & 16)) {
+		mouse_report(currcons, tty, sel_mode & 15, xs, ys);
+		return 0;
+	}
 
 	if (ps > pe)	/* make sel_start <= sel_end */
 	{
diff -u --recursive v1.1.32/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v1.1.32/linux/drivers/char/tty_io.c	Thu Jul 21 08:18:07 1994
+++ linux/drivers/char/tty_io.c	Thu Jul 21 12:38:29 1994
@@ -66,9 +66,10 @@
 #undef TTY_DEBUG_HANGUP
 
 #ifdef CONFIG_SELECTION
-extern int set_selection(const int arg);
+extern int set_selection(const int arg, struct tty_struct *tty);
 extern int paste_selection(struct tty_struct *tty);
 extern int sel_loadlut(const int arg);
+extern int mouse_reporting_p(void);
 extern int shift_state;
 #endif /* CONFIG_SELECTION */
 extern int do_screendump(int arg);
@@ -1381,7 +1382,7 @@
 					return do_get_ps_info(arg);
 #ifdef CONFIG_SELECTION
 				case 2:
-					return set_selection(arg);
+					return set_selection(arg, tty);
 				case 3:
 					return paste_selection(tty);
 				case 4:
@@ -1392,6 +1393,8 @@
 				case 6:
 					put_fs_byte(shift_state,arg);
 					return 0;
+				case 7:
+					return mouse_reporting_p();
 #endif /* CONFIG_SELECTION */
 				default: 
 					return -EINVAL;
diff -u --recursive v1.1.32/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v1.1.32/linux/drivers/scsi/sr.c	Tue Jul 19 10:18:54 1994
+++ linux/drivers/scsi/sr.c	Wed Jul 20 23:13:27 1994
@@ -268,6 +268,9 @@
 	if(MINOR(inode->i_rdev) >= NR_SR || 
 	   !scsi_CDs[MINOR(inode->i_rdev)].device) return -ENXIO;   /* No such device */
 
+	if (filp->f_mode & 2)  
+	    return -EACCES;
+
         check_disk_change(inode->i_rdev);
 
 	if(!scsi_CDs[MINOR(inode->i_rdev)].device->access_count++)
diff -u --recursive v1.1.32/linux/fs/exec.c linux/fs/exec.c
--- v1.1.32/linux/fs/exec.c	Tue Jun 28 22:30:27 1994
+++ linux/fs/exec.c	Thu Jul 21 10:51:35 1994
@@ -537,6 +537,8 @@
 		mpnt1 = mpnt->vm_next;
 		if (mpnt->vm_ops && mpnt->vm_ops->close)
 			mpnt->vm_ops->close(mpnt);
+		if (mpnt->vm_inode)
+			iput(mpnt->vm_inode);
 		kfree(mpnt);
 		mpnt = mpnt1;
 	}
diff -u --recursive v1.1.32/linux/fs/nfs/mmap.c linux/fs/nfs/mmap.c
--- v1.1.32/linux/fs/nfs/mmap.c	Tue Jul 19 10:19:13 1994
+++ linux/fs/nfs/mmap.c	Thu Jul 21 10:11:39 1994
@@ -23,63 +23,11 @@
 #include <asm/segment.h>
 #include <asm/system.h>
 
+/*
+ * Fill in the supplied page for mmap
+ */
 static unsigned long nfs_file_mmap_nopage(struct vm_area_struct * area,
-	unsigned long address, unsigned long page, int error_code);
-
-extern void file_mmap_free(struct vm_area_struct * area);
-extern int file_mmap_share(struct vm_area_struct * from, struct vm_area_struct * to,
-				unsigned long address);
-
-struct vm_operations_struct nfs_file_mmap = {
-	NULL,			/* open */
-	file_mmap_free,		/* close */
-	nfs_file_mmap_nopage,	/* nopage */
-	NULL,			/* wppage */
-	file_mmap_share,	/* share */
-	NULL,			/* unmap */
-};
-
-
-/* This is used for a general mmap of a nfs file */
-int nfs_mmap(struct inode * inode, struct file * file,
-	unsigned long addr, size_t len, int prot, unsigned long off)
-{
-	struct vm_area_struct * mpnt;
-
-	if (prot & PAGE_RW)	/* only PAGE_COW or read-only supported now */
-		return -EINVAL;
-	if (off & (inode->i_sb->s_blocksize - 1))
-		return -EINVAL;
-	if (!inode->i_sb || !S_ISREG(inode->i_mode))
-		return -EACCES;
-	if (!IS_RDONLY(inode)) {
-		inode->i_atime = CURRENT_TIME;
-		inode->i_dirt = 1;
-	}
-
-	mpnt = (struct vm_area_struct * ) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
-	if (!mpnt)
-		return -ENOMEM;
-
-	unmap_page_range(addr, len);
-	mpnt->vm_task = current;
-	mpnt->vm_start = addr;
-	mpnt->vm_end = addr + len;
-	mpnt->vm_page_prot = prot;
-	mpnt->vm_flags = 0;
-	mpnt->vm_share = NULL;
-	mpnt->vm_inode = inode;
-	inode->i_count++;
-	mpnt->vm_offset = off;
-	mpnt->vm_ops = &nfs_file_mmap;
-	insert_vm_struct(current, mpnt);
-	merge_segments(current->mm->mmap, NULL, NULL);
-	return 0;
-}
-
-
-static unsigned long nfs_file_mmap_nopage(struct vm_area_struct * area, unsigned long address,
-	unsigned long page, int error_code)
+	unsigned long address, unsigned long page, int error_code)
 {
 	struct inode * inode = area->vm_inode;
 	unsigned int clear;
@@ -125,4 +73,50 @@
 		*(char *)--tmp = 0;
 	}
 	return page;
+}
+struct vm_operations_struct nfs_file_mmap = {
+	NULL,			/* open */
+	NULL,			/* close */
+	nfs_file_mmap_nopage,	/* nopage */
+	NULL,			/* wppage */
+	NULL,			/* share */
+	NULL,			/* unmap */
+};
+
+
+/* This is used for a general mmap of a nfs file */
+int nfs_mmap(struct inode * inode, struct file * file,
+	unsigned long addr, size_t len, int prot, unsigned long off)
+{
+	struct vm_area_struct * mpnt;
+
+	if (prot & PAGE_RW)	/* only PAGE_COW or read-only supported now */
+		return -EINVAL;
+	if (off & (inode->i_sb->s_blocksize - 1))
+		return -EINVAL;
+	if (!inode->i_sb || !S_ISREG(inode->i_mode))
+		return -EACCES;
+	if (!IS_RDONLY(inode)) {
+		inode->i_atime = CURRENT_TIME;
+		inode->i_dirt = 1;
+	}
+
+	mpnt = (struct vm_area_struct * ) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
+	if (!mpnt)
+		return -ENOMEM;
+
+	unmap_page_range(addr, len);
+	mpnt->vm_task = current;
+	mpnt->vm_start = addr;
+	mpnt->vm_end = addr + len;
+	mpnt->vm_page_prot = prot;
+	mpnt->vm_flags = 0;
+	mpnt->vm_share = NULL;
+	mpnt->vm_inode = inode;
+	inode->i_count++;
+	mpnt->vm_offset = off;
+	mpnt->vm_ops = &nfs_file_mmap;
+	insert_vm_struct(current, mpnt);
+	merge_segments(current->mm->mmap, NULL, NULL);
+	return 0;
 }
diff -u --recursive v1.1.32/linux/include/linux/mm.h linux/include/linux/mm.h
--- v1.1.32/linux/include/linux/mm.h	Thu Jul 21 08:18:19 1994
+++ linux/include/linux/mm.h	Thu Jul 21 13:56:31 1994
@@ -61,6 +61,8 @@
 		unsigned long page);
 	int (*share)(struct vm_area_struct * from, struct vm_area_struct * to, unsigned long address);
 	int (*unmap)(struct vm_area_struct *area, unsigned long, size_t);
+	void (*swapout)(struct vm_area_struct *,  unsigned long *);
+	unsigned long (*swapin)(struct vm_area_struct *,  unsigned long);
 };
 
 extern unsigned long __bad_page(void);
@@ -167,7 +169,7 @@
 
 extern void swap_free(unsigned long page_nr);
 extern unsigned long swap_duplicate(unsigned long page_nr);
-extern void swap_in(unsigned long *table_ptr);
+extern unsigned long swap_in(unsigned long entry);
 extern void si_swapinfo(struct sysinfo * val);
 extern void rw_swap_page(int rw, unsigned long nr, char * buf);
 
@@ -222,5 +224,13 @@
 /* vm_ops not present page codes */
 #define SHM_SWP_TYPE 0x41
 extern void shm_no_page (ulong *);
+
+/* swap cache stuff (in swap.c) */
+extern unsigned long * swap_cache;
+
+extern inline unsigned long in_swap_cache (unsigned long addr)
+{
+	return swap_cache[addr >> PAGE_SHIFT]; 
+}
 
 #endif
diff -u --recursive v1.1.32/linux/include/linux/unistd.h linux/include/linux/unistd.h
--- v1.1.32/linux/include/linux/unistd.h	Tue Jun 21 14:16:25 1994
+++ linux/include/linux/unistd.h	Thu Jul 21 08:24:30 1994
@@ -143,6 +143,7 @@
 #define __NR_bdflush		134
 #define __NR_sysfs		135
 #define __NR_personality	136
+#define __NR_afs_syscall	137 /* Syscall for Andrew File System */
 
 extern int errno;
 
diff -u --recursive v1.1.32/linux/ipc/shm.c linux/ipc/shm.c
--- v1.1.32/linux/ipc/shm.c	Thu Jul 21 13:54:37 1994
+++ linux/ipc/shm.c	Thu Jul 21 13:54:37 1994
@@ -19,6 +19,7 @@
 static int newseg (key_t key, int shmflg, int size);
 static int shm_map (struct shm_desc *shmd, int remap);
 static void killseg (int id);
+static unsigned long shm_swap_in(struct vm_area_struct *, unsigned long);
 
 static int shm_tot = 0;  /* total number of shared memory pages */
 static int shm_rss = 0; /* number of shared memory pages that are in memory */
@@ -375,13 +376,24 @@
 	return 0;
 }
 
+static struct vm_operations_struct shm_vm_ops = {
+	NULL,			/* open */
+	NULL,			/* close */
+	NULL,			/* nopage (done with swapin) */
+	NULL,			/* wppage */
+	NULL,			/* share */
+	NULL,			/* unmap */
+	NULL,			/* swapout (hardcoded right now) */
+	shm_swap_in		/* swapin */
+};
+
 /*
  * This is really minimal support to make the shared mem stuff
  * ve known by the general VM manager. It should add the vm_ops
  * field so that 'munmap()' and friends work correctly on shared
  * memory areas..
  */
-static int add_vm_area(unsigned long addr, unsigned long len)
+static int add_vm_area(unsigned long addr, unsigned long len, int readonly)
 {
 	struct vm_area_struct * vma;
 
@@ -392,12 +404,15 @@
 	vma->vm_task = current;
 	vma->vm_start = addr;
 	vma->vm_end = addr + len;
-	vma->vm_page_prot = PAGE_SHARED;
+	if (readonly)
+		vma->vm_page_prot = PAGE_READONLY;
+	else
+		vma->vm_page_prot = PAGE_SHARED;
 	vma->vm_flags = VM_SHM;
 	vma->vm_share = NULL;
 	vma->vm_inode = NULL;
 	vma->vm_offset = 0;
-	vma->vm_ops = NULL;
+	vma->vm_ops = &shm_vm_ops;
 	insert_vm_struct(current, vma);
 	merge_segments(current->mm->mmap, NULL, NULL);
 	return 0;
@@ -476,7 +491,7 @@
 	shmd->end = addr + shp->shm_npages * PAGE_SIZE;
 	shmd->task = current;
 
-	if ((err = add_vm_area(shmd->start, shmd->end - shmd->start))) {
+	if ((err = add_vm_area(shmd->start, shmd->end - shmd->start, shmflg & SHM_RDONLY))) {
 		kfree(shmd);
 		return err;
 	}
@@ -614,36 +629,34 @@
 }
 
 /*
- * page not present ... go through shm_pages .. called from swap_in()
+ * page not present ... go through shm_pages
  */
-void shm_no_page (unsigned long *ptent)
+static unsigned long shm_swap_in(struct vm_area_struct * vma, unsigned long code)
 {
 	unsigned long page;
-	unsigned long code = *ptent;
 	struct shmid_ds *shp;
 	unsigned int id, idx;
 
 	id = (code >> SHM_ID_SHIFT) & SHM_ID_MASK;
 	if (id > max_shmid) {
 		printk ("shm_no_page: id=%d too big. proc mem corruptedn", id);
-		return;
+		return BAD_PAGE | PAGE_SHARED;
 	}
 	shp = shm_segs[id];
 	if (shp == IPC_UNUSED || shp == IPC_NOID) {
 		printk ("shm_no_page: id=%d invalid. Race.\n", id);
-		return;
+		return BAD_PAGE | PAGE_SHARED;
 	}
 	idx = (code >> SHM_IDX_SHIFT) & SHM_IDX_MASK;
 	if (idx >= shp->shm_npages) {
 		printk ("shm_no_page : too large page index. id=%d\n", id);
-		return;
+		return BAD_PAGE | PAGE_SHARED;
 	}
 
 	if (!(shp->shm_pages[idx] & PAGE_PRESENT)) {
 		if(!(page = get_free_page(GFP_KERNEL))) {
 			oom(current);
-			*ptent = BAD_PAGE | PAGE_ACCESSED | 7;
-			return;
+			return BAD_PAGE | PAGE_SHARED;
 		}
 		if (shp->shm_pages[idx] & PAGE_PRESENT) {
 			free_page (page);
@@ -667,10 +680,9 @@
 	current->mm->min_flt++;
 	page = shp->shm_pages[idx];
 	if (code & SHM_READ_ONLY)           /* write-protect */
-		page &= ~2;
+		page &= ~PAGE_RW;
 	mem_map[MAP_NR(page)]++;
-	*ptent = page;
-	return;
+	return page;
 }
 
 /*
diff -u --recursive v1.1.32/linux/kernel/exit.c linux/kernel/exit.c
--- v1.1.32/linux/kernel/exit.c	Tue Jun 21 14:16:26 1994
+++ linux/kernel/exit.c	Thu Jul 21 10:23:45 1994
@@ -365,6 +365,8 @@
 		struct vm_area_struct * next = mpnt->vm_next;
 		if (mpnt->vm_ops && mpnt->vm_ops->close)
 			mpnt->vm_ops->close(mpnt);
+		if (mpnt->vm_inode)
+			iput(mpnt->vm_inode);
 		kfree(mpnt);
 		mpnt = next;
 	}
diff -u --recursive v1.1.32/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v1.1.32/linux/kernel/ksyms.c	Fri Jul  8 13:26:41 1994
+++ linux/kernel/ksyms.c	Thu Jul 21 08:25:01 1994
@@ -79,6 +79,8 @@
 	X(do_munmap),
 	X(insert_vm_struct),
 	X(zeromap_page_range),
+	X(unmap_page_range),
+	X(merge_segments),
 
 	/* internal kernel memory management */
 	X(__get_free_pages),
@@ -95,6 +97,7 @@
 	X(iput),
 	X(namei),
 	X(lnamei),
+	X(open_namei),
 
 	/* device registration */
 	X(register_chrdev),
@@ -133,6 +136,8 @@
 	/* process management */
 	X(wake_up),
 	X(wake_up_interruptible),
+	X(sleep_on),
+	X(interruptible_sleep_on),
 	X(schedule),
 	X(current),
 	X(jiffies),
diff -u --recursive v1.1.32/linux/kernel/sched.c linux/kernel/sched.c
--- v1.1.32/linux/kernel/sched.c	Thu Jul 21 08:18:21 1994
+++ linux/kernel/sched.c	Thu Jul 21 00:00:52 1994
@@ -412,8 +412,9 @@
 			return 1;
 		}
 	}
-	if (p->next || p->prev)
-		printk("del_timer() called with timer not initialized\n");
+	if (timer->next || timer->prev)
+		printk("del_timer() called from %08lx with timer not initialized\n",
+			((unsigned long *) &timer)[-1]);
 	restore_flags(flags);
 	return 0;
 #else	
diff -u --recursive v1.1.32/linux/kernel/sys_call.S linux/kernel/sys_call.S
--- v1.1.32/linux/kernel/sys_call.S	Tue Jun 21 14:16:26 1994
+++ linux/kernel/sys_call.S	Thu Jul 21 08:24:30 1994
@@ -537,5 +537,6 @@
 	.long _sys_bdflush
 	.long _sys_sysfs		/* 135 */
 	.long _sys_personality
+	.long 0				/* for afs_syscall */
 
-	.space (NR_syscalls-136)*4
+	.space (NR_syscalls-137)*4
diff -u --recursive v1.1.32/linux/mm/memory.c linux/mm/memory.c
--- v1.1.32/linux/mm/memory.c	Thu Jul 21 08:18:22 1994
+++ linux/mm/memory.c	Thu Jul 21 15:06:57 1994
@@ -724,9 +724,16 @@
 	from &= PAGE_MASK;
 	from_page = from + PAGE_PTR(from_address);
 	from = *(unsigned long *) from_page;
-/* is the page clean and present? */
-	if ((from & (PAGE_PRESENT | PAGE_DIRTY)) != PAGE_PRESENT)
+/* is the page present? */
+	if (!(from & PAGE_PRESENT))
 		return 0;
+/* if it is private, it must be clean to be shared */
+	if ((from_area->vm_page_prot & PAGE_COW) && (from & PAGE_DIRTY))
+		return 0;
+/* the swap caching doesn't really handle shared pages.. */
+	if (in_swap_cache(from))
+		return 0;
+/* is the page reasonable at all? */
 	if (from >= high_memory)
 		return 0;
 	if (mem_map[MAP_NR(from)] & MAP_PAGE_RESERVED)
@@ -856,6 +863,28 @@
 	return 0;
 }
 
+static inline void do_swap_page(struct vm_area_struct * vma,
+	unsigned long address, unsigned long * pge, unsigned long entry)
+{
+	unsigned long page;
+
+	if (vma->vm_ops && vma->vm_ops->swapin)
+		page = vma->vm_ops->swapin(vma, entry);
+	else
+		page = swap_in(entry);
+	if (*pge != entry) {
+		free_page(page);
+		return;
+	}
+	page = page | vma->vm_page_prot;
+	if (mem_map[MAP_NR(page)] > 1 && (page & PAGE_COW))
+		page &= ~PAGE_RW;
+	++vma->vm_task->mm->rss;
+	++vma->vm_task->mm->maj_flt;
+	*pge = page;
+	return;
+}
+
 void do_no_page(struct vm_area_struct * vma, unsigned long address,
 	unsigned long error_code)
 {
@@ -870,9 +899,7 @@
 	if (entry & PAGE_PRESENT)
 		return;
 	if (entry) {
-		++vma->vm_task->mm->rss;
-		++vma->vm_task->mm->maj_flt;
-		swap_in((unsigned long *) page);
+		do_swap_page(vma, address, (unsigned long *) page, entry);
 		return;
 	}
 	address &= PAGE_MASK;
@@ -886,6 +913,7 @@
 	page = get_free_page(GFP_KERNEL);
 	if (share_page(vma, address, error_code, page)) {
 		++vma->vm_task->mm->min_flt;
+		++vma->vm_task->mm->rss;
 		return;
 	}
 	if (!page) {
@@ -1224,7 +1252,7 @@
 
 
 /* This handles a generic mmap of a disk file */
-unsigned long file_mmap_nopage(struct vm_area_struct * area, unsigned long address,
+static unsigned long file_mmap_nopage(struct vm_area_struct * area, unsigned long address,
 	unsigned long page, int error_code)
 {
 	struct inode * inode = area->vm_inode;
@@ -1244,33 +1272,11 @@
 	return bread_page(page, inode->i_dev, nr, inode->i_sb->s_blocksize, !(error_code & PAGE_RW));
 }
 
-void file_mmap_free(struct vm_area_struct * area)
-{
-	if (area->vm_inode)
-		iput(area->vm_inode);
-#if 0
-	if (area->vm_inode)
-		printk("Free inode %x:%d (%d)\n",area->vm_inode->i_dev, 
-				 area->vm_inode->i_ino, area->vm_inode->i_count);
-#endif
-}
-
-/*
- * Compare the contents of the mmap entries, and decide if we are allowed to
- * share the pages
- */
-int file_mmap_share(struct vm_area_struct * area1, 
-		    struct vm_area_struct * area2, 
-		    unsigned long address)
-{
-	return 1;
-}
-
 struct vm_operations_struct file_mmap = {
 	NULL,			/* open */
-	file_mmap_free,		/* close */
+	NULL,			/* close */
 	file_mmap_nopage,	/* nopage */
 	NULL,			/* wppage */
-	file_mmap_share,	/* share */
+	NULL,			/* share */
 	NULL,			/* unmap */
 };
diff -u --recursive v1.1.32/linux/mm/mmap.c linux/mm/mmap.c
--- v1.1.32/linux/mm/mmap.c	Sat Jul  9 16:30:47 1994
+++ linux/mm/mmap.c	Thu Jul 21 10:23:45 1994
@@ -194,6 +194,8 @@
 	if (addr == area->vm_start && end == area->vm_end) {
 		if (area->vm_ops && area->vm_ops->close)
 			area->vm_ops->close(area);
+		if (area->vm_inode)
+			iput(area->vm_inode);
 		return;
 	}
 
@@ -216,8 +218,8 @@
 		mpnt->vm_start = end;
 		if (mpnt->vm_inode)
 			mpnt->vm_inode->i_count++;
-		insert_vm_struct(current, mpnt);
 		area->vm_end = addr;	/* Truncate area */
+		insert_vm_struct(current, mpnt);
 	}
 
 	/* construct whatever mapping is needed */
diff -u --recursive v1.1.32/linux/mm/swap.c linux/mm/swap.c
--- v1.1.32/linux/mm/swap.c	Tue Jul 19 10:19:15 1994
+++ linux/mm/swap.c	Thu Jul 21 15:10:42 1994
@@ -8,6 +8,7 @@
  * This file should contain most things doing the swapping from/to disk.
  * Started 18.12.91
  */
+#define SWAP_CACHE_INFO
 
 #include <linux/mm.h>
 #include <linux/sched.h>
@@ -47,13 +48,115 @@
 
 extern int shm_swap (int);
 
-/*
- * The following are used to make sure we don't thrash too much...
- * NOTE!! NR_LAST_FREE_PAGES must be a power of 2...
- */
-#define NR_LAST_FREE_PAGES 32
-static unsigned long last_free_pages[NR_LAST_FREE_PAGES] = {0,};
+unsigned long *swap_cache;
+static unsigned long swap_cache_size;
+
+#ifdef SWAP_CACHE_INFO
+static unsigned long add_calls_total = 0;
+static unsigned long add_calls_success = 0;
+static unsigned long del_calls_total = 0;
+static unsigned long del_calls_success = 0;
+static unsigned long find_calls_total = 0;
+static unsigned long find_calls_success = 0;
+
+extern inline void show_swap_cache_info (void)
+{
+	printk("Swap cache: add %ld/%ld, delete %ld/%ld, find %ld/%ld\n",
+	       add_calls_total, add_calls_success, 
+	       del_calls_total, del_calls_success,
+	       find_calls_total, find_calls_success);
+}
+#endif
+
+extern inline unsigned long init_swap_cache (unsigned long mem_start,
+					    unsigned long mem_end)
+{
+	mem_start = (mem_start + 15) & ~15;
+	swap_cache = (unsigned long *) mem_start;
+	swap_cache_size = mem_end >> PAGE_SHIFT;
+	memset(swap_cache, 0, swap_cache_size * sizeof (unsigned long));
+#ifdef SWAP_CACHE_INFO
+	printk("%ld bytes for swap cache allocated\n",
+	       swap_cache_size * sizeof(unsigned long));
+#endif	
+	
+	return (unsigned long) (swap_cache + swap_cache_size);
+}
+
+extern inline long find_in_swap_cache (unsigned long addr)
+{
+	unsigned long entry;
+
+#ifdef SWAP_CACHE_INFO
+	find_calls_total++;
+#endif
+	__asm__ __volatile__ (
+			      "xchgl %0,%1\n"
+			      : "=m" (swap_cache[addr >> PAGE_SHIFT]),
+			        "=r" (entry)
+			      : "0" (swap_cache[addr >> PAGE_SHIFT]),
+			        "1" (0)
+			      );
+#ifdef SWAP_CACHE_INFO
+	if (entry)
+		find_calls_success++;
+#endif	
+	
+	return entry;
+}
+
+extern  inline int add_to_swap_cache (unsigned long addr, unsigned long entry)
+{
+	struct swap_info_struct * p = &swap_info[SWP_TYPE(entry)];
+	
+#ifdef SWAP_CACHE_INFO
+	add_calls_total++;
+#endif
+	if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) { 
+		__asm__ __volatile__ (
+				      "xchgl %0,%1\n"
+				      : "=m" (swap_cache[addr >> PAGE_SHIFT]),
+				       "=r" (entry)
+				      : "0" (swap_cache[addr >> PAGE_SHIFT]),
+				       "1" (entry)
+				      );
+		if (entry)  {
+			printk("swap_cache: replacing non-NULL entry\n");
+		}
+#ifdef SWAP_CACHE_INFO
+		add_calls_success++;
+#endif
+		return 1;
+	}
+	return 0;
+}
+
+
+extern inline int delete_from_swap_cache(unsigned long addr)
+{
+	unsigned long entry;
+	
+#ifdef SWAP_CACHE_INFO
+	del_calls_total++;
+#endif	
+	__asm__ __volatile__ (
+			      "xchgl %0,%1\n"
+			      : "=m" (swap_cache[addr >> PAGE_SHIFT]),
+			        "=r" (entry)
+			      : "0" (swap_cache[addr >> PAGE_SHIFT]),
+			        "1" (0)
+			      );
+	if (entry)  {
+#ifdef SWAP_CACHE_INFO
+		del_calls_success++;
+#endif
+		swap_free(entry);
+		return 1;
+	}
+	return 0;
+}
 
+
 void rw_swap_page(int rw, unsigned long entry, char * buf)
 {
 	unsigned long type, offset;
@@ -142,7 +245,7 @@
 	}
 	p = type + swap_info;
 	if (offset >= p->max) {
-		printk("swap_free: weirdness\n");
+		printk("swap_duplicate: weirdness\n");
 		return 0;
 	}
 	if (!p->swap_map[offset]) {
@@ -193,42 +296,24 @@
 	wake_up(&lock_queue);
 }
 
-void swap_in(unsigned long *table_ptr)
+unsigned long swap_in(unsigned long entry)
 {
-	unsigned long entry;
 	unsigned long page;
 
-	entry = *table_ptr;
-	if (PAGE_PRESENT & entry) {
-		printk("trying to swap in present page\n");
-		return;
-	}
-	if (!entry) {
-		printk("No swap page in swap_in\n");
-		return;
-	}
-	if (SWP_TYPE(entry) == SHM_SWP_TYPE) {
-		shm_no_page ((unsigned long *) table_ptr);
-		return;
-	}
 	if (!(page = get_free_page(GFP_KERNEL))) {
 		oom(current);
-		page = BAD_PAGE;
-	} else	
-		read_swap_page(entry, (char *) page);
-	if (*table_ptr != entry) {
-		free_page(page);
-		return;
+		return BAD_PAGE;
 	}
-	*table_ptr = page | (PAGE_DIRTY | PAGE_PRIVATE);
-	swap_free(entry);
+	read_swap_page(entry, (char *) page);
+	if (add_to_swap_cache(page, entry))
+		return page | PAGE_PRIVATE;
+  	swap_free(entry);
+	return page | PAGE_DIRTY | PAGE_PRIVATE;
 }
 
 static inline int try_to_swap_out(unsigned long * table_ptr)
 {
-	int i;
-	unsigned long page;
-	unsigned long entry;
+	unsigned long page, entry;
 
 	page = *table_ptr;
 	if (!(PAGE_PRESENT & page))
@@ -237,13 +322,14 @@
 		return 0;
 	if (mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED)
 		return 0;
+	
+	if ((PAGE_DIRTY & page) && delete_from_swap_cache(page))  {
+		return 0;
+	}
 	if (PAGE_ACCESSED & page) {
 		*table_ptr &= ~PAGE_ACCESSED;
 		return 0;
 	}
-	for (i = 0; i < NR_LAST_FREE_PAGES; i++)
-		if (last_free_pages[i] == (page & PAGE_MASK))
-			return 0;
 	if (PAGE_DIRTY & page) {
 		page &= PAGE_MASK;
 		if (mem_map[MAP_NR(page)] != 1)
@@ -256,6 +342,26 @@
 		free_page(page);
 		return 1;
 	}
+
+        if ((entry = find_in_swap_cache(page)))  {
+		*table_ptr |= PAGE_DIRTY;
+		if (mem_map[MAP_NR(page)] != 1) {
+			return 0;
+		}
+		if (!entry)  {
+			if (!(entry = get_swap_page()))  {
+				return 0;
+			}
+			*table_ptr = entry;
+			invalidate();
+			write_swap_page(entry, (char *) (page & PAGE_MASK));
+		} else  {
+			*table_ptr = entry;
+			invalidate();
+		}
+		free_page(page & PAGE_MASK);
+		return 1;
+	} 
 	page &= PAGE_MASK;
 	*table_ptr = 0;
 	invalidate();
@@ -531,8 +637,10 @@
 			if (!(*map & MAP_PAGE_RESERVED)) {
 				save_flags(flag);
 				cli();
-				if (!--*map)
+				if (!--*map)  {
 					free_pages_ok(addr, order);
+					delete_from_swap_cache(addr);
+				}
 				restore_flags(flag);
 				if(*map == 1) {
 				  int j;
@@ -639,6 +747,9 @@
 	}
 	restore_flags(flags);
 	printk("= %lukB)\n", total);
+#ifdef SWAP_CACHE_INFO
+	show_swap_cache_info();
+#endif	
 }
 
 /*
@@ -654,6 +765,7 @@
 	struct task_struct *p;
 
 	nr = 0;
+	
 /*
  * When we have to sleep, we restart the whole algorithm from the same
  * task we stopped in. That at least rids us of all races.
@@ -677,8 +789,15 @@
 				page = *ppage;
 				if (!page)
 					continue;
-				if (page & PAGE_PRESENT)
+				if (page & PAGE_PRESENT) {
+					if (!(page = in_swap_cache(page)))
+						continue;
+					if (SWP_TYPE(page) != type)
+						continue;
+					*ppage |= PAGE_DIRTY;
+					delete_from_swap_cache(*ppage);
 					continue;
+				}
 				if (SWP_TYPE(page) != type)
 					continue;
 				if (!tmp) {
@@ -898,6 +1017,7 @@
 	unsigned long mask = PAGE_MASK;
 	int i;
 
+	start_mem = init_swap_cache(start_mem, end_mem);
 	mem_map = (unsigned short *) start_mem;
 	p = mem_map + MAP_NR(end_mem);
 	start_mem = (unsigned long) p;
diff -u --recursive v1.1.32/linux/net/inet/arp.c linux/net/inet/arp.c
--- v1.1.32/linux/net/inet/arp.c	Thu Jul 21 08:18:23 1994
+++ linux/net/inet/arp.c	Wed Jul 20 23:51:46 1994
@@ -746,13 +746,13 @@
 		entry->hlen = hlen;
 		entry->htype = htype;
 		entry->flags = ATF_COM;
+		entry->timer.next = entry->timer.prev = NULL;
 		memcpy(entry->ha, sha, hlen);
 		entry->last_used = jiffies;
 		entry->dev = skb->dev;
 		skb_queue_head_init(&entry->skb);
 		entry->next = arp_tables[hash];
 		arp_tables[hash] = entry;
-		entry->timer.next = entry->timer.prev = NULL;
 		sti();
 	}
 
@@ -837,14 +837,14 @@
 		entry->htype = dev->type;
 		entry->flags = 0;
 		memset(entry->ha, 0, dev->addr_len);
-		entry->last_used = jiffies;
-		entry->next = arp_tables[hash];
 		entry->dev = dev;
-		arp_tables[hash] = entry;
+		entry->last_used = jiffies;
 		entry->timer.next = entry->timer.prev = NULL;
 		entry->timer.function = arp_expire_request;
 		entry->timer.data = (unsigned long)entry;
 		entry->timer.expires = ARP_RES_TIME;
+		entry->next = arp_tables[hash];
+		arp_tables[hash] = entry;
 		add_timer(&entry->timer);
 		entry->retries = ARP_MAX_TRIES;
 		skb_queue_head_init(&entry->skb);
@@ -1048,8 +1048,8 @@
 		entry->ip = ip;
 		entry->hlen = hlen;
 		entry->htype = htype;
-		entry->next = arp_tables[hash];
 		entry->timer.next = entry->timer.prev = NULL;
+		entry->next = arp_tables[hash];
 		arp_tables[hash] = entry;
 		skb_queue_head_init(&entry->skb);
 	}
