diff -u --recursive --new-file v1.3.66/linux/CREDITS linux/CREDITS
--- v1.3.66/linux/CREDITS	Sat Feb 17 16:02:43 1996
+++ linux/CREDITS	Mon Feb 19 13:29:07 1996
@@ -324,6 +324,11 @@
 N: Ralf Flaxa
 E: rfflaxa@immd4.informatik.uni-erlangen.de
 D: The Linux Support Team Erlangen
+D: Creator of LST distribution
+D: Author of installation tool LISA
+S: Pfitznerweg 6
+S: 74523 Schwaebisch Hall
+S: Germany
 
 N: Lawrence Foard
 E: entropy@world.std.com
@@ -407,6 +412,14 @@
 D: DOSemu
 S: Muehlenweg 19
 S: 34266 Niestetal
+S: Germany
+
+N: Sebastian Hetze
+E: she@lunetix.de
+D: German Linux Documentation,
+D: Organization of German Linux Conferences
+S: Danckelmannstr. 48
+S: 14059 Berlin
 S: Germany
 
 N: Michael Hipp
diff -u --recursive --new-file v1.3.66/linux/Documentation/devices.tex linux/Documentation/devices.tex
--- v1.3.66/linux/Documentation/devices.tex	Wed Feb  7 15:11:18 1996
+++ linux/Documentation/devices.tex	Sun Feb 18 10:43:17 1996
@@ -42,14 +42,14 @@
 %
 \title{{\bf Linux Allocated Devices}}
 \author{Maintained by H. Peter Anvin $<$hpa@storm.net$>$}
-\date{Last revised: February 3, 1996}
+\date{Last revised: February 17, 1996}
 \maketitle
 %
 \noindent
 This list is the successor to Rick Miller's Linux Device List, which
-he stopped maintaining when he lost network access in 1993.  It is a
-registry of allocated major device numbers, as well as the recommended
-{\file /dev} directory nodes for these devices.
+he stopped maintaining when he got busy with other things in 1993.  It
+is a registry of allocated major device numbers, as well as the
+recommended {\file /dev} directory nodes for these devices.
 
 The latest version of this list is included with the Linux kernel
 sources in \LaTeX\ and ASCII form.  In case of discrepancy, the
@@ -145,6 +145,7 @@
 \major{36}{}{char }{Netlink support}
 \major{  }{}{block}{MCA ESDI hard disk}
 \major{37}{}{char }{IDE tape}
+\major{  }{}{block}{Zorro II ramdisk}
 \major{38}{}{char }{Myricom PCI Myrinet board}
 \major{39}{--40}{}{Unallocated}
 \major{41}{}{char}{Yet Another Micro Monitor}
@@ -183,9 +184,14 @@
 	\minor{9}{/dev/urandom}{Less secure, but faster random number generator}
 \\
 \major{}{}{block}{RAM disk}
-	\minor{1}{/dev/ramdisk}{RAM disk}
+	\minor{0}{/dev/ram0}{First RAM disk}
+	\minordots
+	\minor{7}{/dev/ram7}{Eighth RAM disk}
 \end{devicelist}
 
+\noindent
+Earlier kernels had /dev/ramdisk (1, 1) here.
+
 \begin{devicelist}
 \major{2}{}{char}{Pseudo-TTY masters}
 	\minor{0}{/dev/ptyp0}{First PTY master}
@@ -307,7 +313,7 @@
 \noindent
 For compatibility with previous versions of Linux, the first 64 PTYs
 are replicated under this device number.  This use will be obsolescent
-with the release of Linux 1.4 and may be removed in a future version
+with the release of Linux 2.0 and may be removed in a future version
 of Linux.
 
 \begin{devicelist}
@@ -815,12 +821,13 @@
 	\minor{131}{/dev/smpte3}{Fourth MIDI port, SMPTE timed}
 \\
 \major{  }{}{block}{Modular RAM disk}
-	\minor{0}{/dev/ram0}{First modular RAM disk}
-	\minor{1}{/dev/ram1}{Second modular RAM disk}
-	\minordots
-	\minor{255}{/dev/ram255}{256th modular RAM disk}
 \end{devicelist}
 
+\noindent
+This device number is provided for older kernels which did not have
+the modular RAM disk in the standard distribution.  See major number
+1.  This assignment will be removed when the 2.0 kernel is released.
+
 \begin{devicelist}
 \major{36}{}{char }{Netlink support}
 	\minor{0}{/dev/route}{Routing, device updates (kernel to user)}
@@ -846,6 +853,11 @@
 Currently, only one IDE tape drive is supported.
 
 \begin{devicelist}
+\major{  }{}{block}{Zorro II ramdisk}
+	\minor{0}{/dev/z2ram}{Zorro II ramdisk}
+\end{devicelist}
+
+\begin{devicelist}
 \major{38}{}{char }{Myricom PCI Myrinet board}
 	\minor{0}{/dev/mlanai0}{First Myrinet board}
 	\minor{1}{/dev/mlanai1}{Second Myrinet board}
@@ -961,16 +973,20 @@
 \link{/dev/stdin}{fd/0}{symbolic}{Standard input file descriptor}
 \link{/dev/stdout}{fd/1}{symbolic}{Standard output file descriptor}
 \link{/dev/stderr}{fd/2}{symbolic}{Standard error file descriptor}
+\link{/dev/nfsd}{socksys}{symbolic}{Required by iBCS-2}
+\link{/dev/X0R}{null}{symbolic}{Required by iBCS-2}
 \end{nodelist}
 
+\noindent
+Note: The last device is: letter {\tt X}-digit {\tt 0}-letter {\tt R}.
+
 \subsection{Recommended links}
 
 It is recommended that these links exist on all systems:
 
 \begin{nodelist}
-\link{/dev/X0R}{null}{symbolic}{Used by iBCS-2}
-\link{/dev/nfsd}{socksys}{symbolic}{Used by iBCS-2}
 \link{/dev/core}{/proc/kcore}{symbolic}{Backward compatibility}
+\link{/dev/ramdisk}{ram1}{symbolic}{Backward compatibility}
 \link{/dev/scd?}{sr?}{hard}{Alternate name for CD-ROMs}
 %\link{/dev/fd?H*}{fd?D*}{hard}{Compatible floppy formats}
 %\link{/dev/fd?E*}{fd?D*}{hard}{Compatible floppy formats}
diff -u --recursive --new-file v1.3.66/linux/Documentation/devices.txt linux/Documentation/devices.txt
--- v1.3.66/linux/Documentation/devices.txt	Wed Feb  7 15:11:19 1996
+++ linux/Documentation/devices.txt	Sun Feb 18 10:43:25 1996
@@ -2,12 +2,12 @@
 
 	     Maintained by H. Peter Anvin <hpa@storm.net>
 
-		    Last revised: February 3, 1996
+		   Last revised: February 17, 1996
 
 This list is the successor to Rick Miller's Linux Device List, which
-he stopped maintaining when he lost network access in 1993.  It is a
-registry of allocated major device numbers, as well as the recommended
-/dev directory nodes for these devices.
+he stopped maintaining when he got busy with other things in 1993.  It
+is a registry of allocated major device numbers, as well as the
+recommended /dev directory nodes for these devices.
 
 The lastest version of this list is included with the Linux kernel
 sources in LaTeX and ASCII form.  In case of discrepancy, the LaTeX
@@ -45,7 +45,11 @@
 		  8 = /dev/random	Nondeterministic random number gen.
 		  9 = /dev/urandom	Faster, less secure random number gen.
     block	RAM disk
-		  1 = /dev/ramdisk	RAM disk
+		  0 = /dev/ram0		First RAM disk
+		    ...
+		  7 = /dev/ram7		Eighth RAM disk
+
+		Older kernels had /dev/ramdisk (1, 1) here.
 		    
   2 char	Pseudo-TTY masters
 		  0 = /dev/ptyp0	First PTY master
@@ -550,10 +554,11 @@
 		130 = /dev/smpte2	Third MIDI port, SMPTE timed
 		131 = /dev/smpte3	Fourth MIDI port, SMPTE timed
     block	Modular RAM disk device
-		  0 = /dev/ram0		First modular RAM disk
-		  1 = /dev/ram1		Second modular RAM disk
-		      ...
-		255 = /dev/ram255	256th modular RAM disk
+
+		This device number is provided for older kernels which
+		did not have the modular RAM disk in the standard
+		distribution.  See major number 1.  This assignment
+		will be removed when the 2.0 kernel is released.
 
  36 char	Netlink support
 		  0 = /dev/route	Routing, device updates, kernel to user
@@ -572,6 +577,9 @@
 
 		Currently, only one IDE tape drive is supported.
 
+    block	Zorro II ramdisk
+		  0 = /dev/z2ram	Zorro II ramdisk
+
  38 char	Myricom PCI Myrinet board
 		  0 = /dev/mlanai0	First Myrinet board
 		  1 = /dev/mlanai1	Second Myrinet board
@@ -657,16 +665,18 @@
 /dev/stdin	fd/0		symbolic	stdin file descriptor
 /dev/stdout	fd/1		symbolic	stdout file descriptor
 /dev/stderr	fd/2		symbolic	stderr file descriptor
+/dev/nfsd	socksys		symbolic	Required by iBCS-2
+/dev/X0R	null		symbolic	Required by iBCS-2
 
+Note: the last device is letter X-digit 0-letter R.
 
 	Recommended links
 
 It is recommended that these links exist on all systems:
 
-/dev/X0R	null		symbolic	Used by iBCS-2
-/dev/nfsd	socksys		symbolic	Used by iBCS-2
 /dev/core	/proc/kcore	symbolic	Backward compatibility
-/dev/scd?	/dev/sr?	hard		Alternate SCSI CD-ROM name
+/dev/ramdisk	ram1		symbolic	Backward compatibility
+/dev/scd?	sr?		hard		Alternate SCSI CD-ROM name
 
 
 	Locally defined links
diff -u --recursive --new-file v1.3.66/linux/Makefile linux/Makefile
--- v1.3.66/linux/Makefile	Sat Feb 17 18:14:28 1996
+++ linux/Makefile	Mon Feb 19 13:30:20 1996
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 66
+SUBLEVEL = 67
 
 ARCH = i386
 
diff -u --recursive --new-file v1.3.66/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c
--- v1.3.66/linux/arch/alpha/kernel/traps.c	Sat Feb 17 16:02:45 1996
+++ linux/arch/alpha/kernel/traps.c	Mon Feb 19 10:59:52 1996
@@ -8,6 +8,7 @@
  * This file initializes the trap entry points
  */
 
+#include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/tty.h>
diff -u --recursive --new-file v1.3.66/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- v1.3.66/linux/arch/i386/kernel/entry.S	Wed Feb  7 15:11:20 1996
+++ linux/arch/i386/kernel/entry.S	Mon Feb 19 07:55:24 1996
@@ -684,4 +684,5 @@
 	.long SYMBOL_NAME(sys_sched_get_priority_max)
 	.long SYMBOL_NAME(sys_sched_get_priority_min)  /* 160 */
 	.long SYMBOL_NAME(sys_sched_rr_get_interval)
-	.space (NR_syscalls-162)*4
+	.long SYMBOL_NAME(sys_nanosleep)
+	.space (NR_syscalls-163)*4
diff -u --recursive --new-file v1.3.66/linux/drivers/net/depca.c linux/drivers/net/depca.c
--- v1.3.66/linux/drivers/net/depca.c	Sat Feb 17 16:02:49 1996
+++ linux/drivers/net/depca.c	Mon Feb 19 13:32:59 1996
@@ -943,13 +943,16 @@
 	    }
 	  }
 	  if (buf[0] & 0x01) {              /* Multicast/Broadcast */
-	    if ((*(s16 *)&buf[0] == -1) && (*(s32 *)&buf[2] == -1)) {
+	    if ((*(s16 *)&buf[0] == -1) &&
+		(*(s16 *)&buf[2] == -1) &&
+		(*(s16 *)&buf[4] == -1)) {
 	      lp->pktStats.broadcast++;
 	    } else {
 	      lp->pktStats.multicast++;
 	    }
 	  } else if ((*(s16 *)&buf[0] == *(s16 *)&dev->dev_addr[0]) &&
-		     (*(s32 *)&buf[2] == *(s32 *)&dev->dev_addr[2])) {
+		     (*(s16 *)&buf[2] == *(s16 *)&dev->dev_addr[2]) &&
+		     (*(s16 *)&buf[4] == *(s16 *)&dev->dev_addr[4])) {
 	    lp->pktStats.unicast++;
 	  }
 	  
diff -u --recursive --new-file v1.3.66/linux/drivers/net/slip.h linux/drivers/net/slip.h
--- v1.3.66/linux/drivers/net/slip.h	Fri Feb  9 17:53:02 1996
+++ linux/drivers/net/slip.h	Sun Feb 18 10:13:05 1996
@@ -14,6 +14,8 @@
  *	Dmitry Gorodchanin	:	Added CSLIP statistics.
  *	Stanislav Voronyi	:	Make line checking as created by
  *					Igor Chechik, RELCOM Corp.
+ *	Craig Schlenter		:	Fixed #define bug that caused
+ *					CSLIP telnets to hang in 1.3.61-6
  *
  * Author:	Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  */
@@ -89,8 +91,8 @@
 #define SLF_INUSE	0		/* Channel in use               */
 #define SLF_ESCAPE	1               /* ESC received                 */
 #define SLF_ERROR	2               /* Parity, etc. error           */
-#define SLF_KEEPTEST	4		/* Keepalive test flag		*/
-#define SLF_OUTWAIT	8		/* is outpacket was flag	*/
+#define SLF_KEEPTEST	3		/* Keepalive test flag		*/
+#define SLF_OUTWAIT	4		/* is outpacket was flag	*/
 
   unsigned char		mode;		/* SLIP mode			*/
 #define SL_MODE_SLIP	0
diff -u --recursive --new-file v1.3.66/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c
--- v1.3.66/linux/drivers/scsi/aha152x.c	Fri Jan 26 01:37:06 1996
+++ linux/drivers/scsi/aha152x.c	Mon Feb 19 13:29:08 1996
@@ -2958,8 +2958,13 @@
     scd = scd->next;
   }
   
-  *start=buffer;
-  return (pos-buffer < length ? pos-buffer : length);     
+  *start=buffer+offset;
+  if (pos - buffer < offset)
+    return 0;
+  else if (pos - buffer - offset < length)
+    return pos - buffer - offset;
+  else
+    return length;
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v1.3.66/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v1.3.66/linux/drivers/scsi/scsi.c	Sat Feb 17 16:02:52 1996
+++ linux/drivers/scsi/scsi.c	Mon Feb 19 08:33:37 1996
@@ -564,7 +564,7 @@
         ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) {
       if (((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) &&
           ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION) &&
-          ((SCpnt->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST))
+          ((SCpnt->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST || lun > 0))
         return 1;
     }
     else
diff -u --recursive --new-file v1.3.66/linux/fs/buffer.c linux/fs/buffer.c
--- v1.3.66/linux/fs/buffer.c	Sat Feb 17 16:02:53 1996
+++ linux/fs/buffer.c	Mon Feb 19 15:31:37 1996
@@ -56,6 +56,7 @@
    buffers to discard when more memory is needed */
 static struct buffer_head * next_to_age[NR_LIST] = {NULL, };
 static struct buffer_head * free_list[NR_SIZES] = {NULL, };
+
 static struct buffer_head * unused_list = NULL;
 struct buffer_head * reuse_list = NULL;
 static struct wait_queue * buffer_wait = NULL;
@@ -846,8 +847,7 @@
 	refile_buffer(buf);
 
 	if (buf->b_count) {
-		if (!--buf->b_count)
-			wake_up(&buffer_wait);
+		buf->b_count--;
 		return;
 	}
 	printk("VFS: brelse: Trying to free free buffer\n");
@@ -867,7 +867,6 @@
 	remove_from_hash_queue(buf);
 	buf->b_dev = NODEV;
 	refile_buffer(buf);
-	wake_up(&buffer_wait);
 }
 
 /*
@@ -966,6 +965,7 @@
 	((volatile struct buffer_head *) bh)->b_wait = wait;
 	bh->b_next_free = unused_list;
 	unused_list = bh;
+	wake_up(&buffer_wait);
 }
 
 static void get_more_buffer_heads(void)
@@ -973,11 +973,26 @@
 	int i;
 	struct buffer_head * bh;
 
-	if (unused_list)
-		return;
+	for (;;) {
+		if (unused_list)
+			return;
 
-	if (!(bh = (struct buffer_head*) get_free_page(GFP_KERNEL)))
-		return;
+		/*
+		 * This is critical.  We can't swap out pages to get
+		 * more buffer heads, because the swap-out may need
+		 * more buffer-heads itself.  Thus GFP_ATOMIC.
+		 */
+		bh = (struct buffer_head *) get_free_page(GFP_ATOMIC);
+		if (bh)
+			break;
+
+		/*
+		 * Uhhuh. We're _really_ low on memory. Now we just
+		 * wait for old buffer heads to become free due to
+		 * finishing IO..
+		 */
+		sleep_on(&buffer_wait);
+	}
 
 	for (nr_buffer_heads+=i=PAGE_SIZE/sizeof*bh ; i>0; i--) {
 		bh->b_next_free = unused_list;	/* only make link */
@@ -1217,6 +1232,7 @@
 		page->free_after = 0;
 		free_page(page_address(page));
 	}
+	wake_up(&buffer_wait);
 }
 
 /*
@@ -1307,7 +1323,6 @@
 	free_list[isize] = bh;
 	buffer_pages[MAP_NR(page)] = bh;
 	tmp->b_this_page = bh;
-	wake_up(&buffer_wait);
 	buffermem += PAGE_SIZE;
 	return 1;
 }
diff -u --recursive --new-file v1.3.66/linux/fs/exec.c linux/fs/exec.c
--- v1.3.66/linux/fs/exec.c	Fri Feb  9 17:53:06 1996
+++ linux/fs/exec.c	Mon Feb 19 13:29:08 1996
@@ -167,7 +167,7 @@
 		for (fmt = formats ; fmt ; fmt = fmt->next) {
 			int (*fn)(int) = fmt->load_shlib;
 			if (!fn)
-				break;
+				continue;
 			retval = fn(fd);
 			if (retval != -ENOEXEC)
 				break;
@@ -658,7 +658,7 @@
 		for (fmt = formats ; fmt ; fmt = fmt->next) {
 			int (*fn)(struct linux_binprm *, struct pt_regs *) = fmt->load_binary;
 			if (!fn)
-				break;
+				continue;
 			retval = fn(&bprm, regs);
 			if (retval >= 0) {
 				iput(bprm.inode);
diff -u --recursive --new-file v1.3.66/linux/fs/ext/file.c linux/fs/ext/file.c
--- v1.3.66/linux/fs/ext/file.c	Thu Jan  4 21:54:56 1996
+++ linux/fs/ext/file.c	Tue Feb 20 10:28:13 1996
@@ -45,7 +45,7 @@
 	NULL,			/* readdir - bad */
 	NULL,			/* select - default */
 	NULL,			/* ioctl - default */
-	generic_mmap,  		/* mmap */
+	generic_file_mmap,	/* mmap */
 	NULL,			/* no special open is needed */
 	NULL,			/* release */
 	ext_sync_file			/* fsync */
diff -u --recursive --new-file v1.3.66/linux/fs/ext2/file.c linux/fs/ext2/file.c
--- v1.3.66/linux/fs/ext2/file.c	Thu Jan  4 21:54:56 1996
+++ linux/fs/ext2/file.c	Tue Feb 20 10:28:13 1996
@@ -50,7 +50,7 @@
 	NULL,			/* readdir - bad */
 	NULL,			/* select - default */
 	ext2_ioctl,		/* ioctl */
-	generic_mmap,  		/* mmap */
+	generic_file_mmap,	/* mmap */
 	NULL,			/* no special open is needed */
 	ext2_release_file,	/* release */
 	ext2_sync_file,		/* fsync */
diff -u --recursive --new-file v1.3.66/linux/fs/fat/file.c linux/fs/fat/file.c
--- v1.3.66/linux/fs/fat/file.c	Fri Feb  9 17:53:06 1996
+++ linux/fs/fat/file.c	Tue Feb 20 10:28:13 1996
@@ -33,7 +33,7 @@
 	NULL,			/* readdir - bad */
 	NULL,			/* select - default */
 	NULL,			/* ioctl - default */
-	generic_mmap,		/* mmap */
+	generic_file_mmap,	/* mmap */
 	NULL,			/* no special open is needed */
 	NULL,			/* release */
 	file_fsync		/* fsync */
@@ -61,8 +61,8 @@
 };
 /* #Specification: msdos / special devices / mmap	
 	Mmapping does work because a special mmap is provide in that case.
-	Note that it is much less efficient than the generic_mmap normally
-	used since it allocate extra buffer. generic_mmap is used for
+	Note that it is much less efficient than the generic_file_mmap normally
+	used since it allocate extra buffer. generic_file_mmap is used for
 	normal device (512 bytes hardware sectors).
 */
 static struct file_operations fat_file_operations_1024 = {
diff -u --recursive --new-file v1.3.66/linux/fs/fat/inode.c linux/fs/fat/inode.c
--- v1.3.66/linux/fs/fat/inode.c	Sun Feb 11 15:32:46 1996
+++ linux/fs/fat/inode.c	Mon Feb 19 13:29:08 1996
@@ -358,6 +358,15 @@
 	return (cluster-2)*sb->cluster_size+sb->data_start+offset;
 }
 
+static int is_exec(char *extension)
+{
+	char *exe_extensions = "EXECOMBAT", *walk;
+
+	for (walk = exe_extensions; *walk; walk += 3)
+		if (!strncmp(extension, walk, 3))
+			return 1;
+	return 0;
+}
 
 void fat_read_inode(struct inode *inode, struct inode_operations *fs_dir_inode_ops)
 {
@@ -424,7 +433,8 @@
 			}
 	} else { /* not a directory */
 		inode->i_mode = MSDOS_MKMODE(raw_entry->attr,
-		    (IS_NOEXEC(inode) ? S_IRUGO|S_IWUGO : S_IRWXUGO)
+		    ((IS_NOEXEC(inode) || !is_exec(raw_entry->ext))
+		    	? S_IRUGO|S_IWUGO : S_IRWXUGO)
 		    & ~MSDOS_SB(inode->i_sb)->fs_umask) | S_IFREG;
 		inode->i_op = (sb->s_blocksize == 1024)
 			? &fat_file_inode_operations_1024
diff -u --recursive --new-file v1.3.66/linux/fs/hpfs/hpfs_fs.c linux/fs/hpfs/hpfs_fs.c
--- v1.3.66/linux/fs/hpfs/hpfs_fs.c	Tue Jan 23 21:15:50 1996
+++ linux/fs/hpfs/hpfs_fs.c	Tue Feb 20 10:28:13 1996
@@ -155,7 +155,7 @@
 	NULL,				/* readdir - bad */
 	NULL,				/* select - default */
 	NULL,				/* ioctl - default */
-	generic_mmap,			/* mmap */
+	generic_file_mmap,		/* mmap */
 	NULL,				/* no special open is needed */
 	NULL,				/* release */
 	file_fsync,			/* fsync */
diff -u --recursive --new-file v1.3.66/linux/fs/isofs/file.c linux/fs/isofs/file.c
--- v1.3.66/linux/fs/isofs/file.c	Thu Jan  4 21:54:56 1996
+++ linux/fs/isofs/file.c	Tue Feb 20 10:28:13 1996
@@ -29,7 +29,7 @@
 	NULL,			/* readdir - bad */
 	NULL,			/* select - default */
 	NULL,			/* ioctl - default */
-	generic_mmap,		/* mmap */
+	generic_file_mmap,	/* mmap */
 	NULL,			/* no special open is needed */
 	NULL,			/* release */
 	NULL			/* fsync */
diff -u --recursive --new-file v1.3.66/linux/fs/minix/file.c linux/fs/minix/file.c
--- v1.3.66/linux/fs/minix/file.c	Sat Jan  6 19:10:40 1996
+++ linux/fs/minix/file.c	Tue Feb 20 10:28:13 1996
@@ -40,7 +40,7 @@
 	NULL,			/* readdir - bad */
 	NULL,			/* select - default */
 	NULL,			/* ioctl - default */
-	generic_mmap,  		/* mmap */
+	generic_file_mmap,	/* mmap */
 	NULL,			/* no special open is needed */
 	NULL,			/* release */
 	minix_sync_file		/* fsync */
diff -u --recursive --new-file v1.3.66/linux/fs/nfs/Makefile linux/fs/nfs/Makefile
--- v1.3.66/linux/fs/nfs/Makefile	Fri Nov 17 08:42:27 1995
+++ linux/fs/nfs/Makefile	Tue Feb 20 09:51:05 1996
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 O_TARGET := nfs.o
-O_OBJS   := proc.o sock.o rpcsock.o inode.o file.o dir.o symlink.o mmap.o
+O_OBJS   := proc.o sock.o rpcsock.o inode.o file.o dir.o symlink.o
 
 ifdef CONFIG_ROOT_NFS
 O_OBJS += nfsroot.o
diff -u --recursive --new-file v1.3.66/linux/fs/nfs/file.c linux/fs/nfs/file.c
--- v1.3.66/linux/fs/nfs/file.c	Sat Feb 17 16:02:53 1996
+++ linux/fs/nfs/file.c	Tue Feb 20 10:01:35 1996
@@ -11,6 +11,8 @@
  *
  *  Expire cache on write to a file by Wai S Kok (Oct 1994).
  *
+ *  Total rewrite of read side for new NFS buffer cache.. Linus.
+ *
  *  nfs regular file handling functions
  */
 
@@ -22,13 +24,16 @@
 #include <linux/mm.h>
 #include <linux/nfs_fs.h>
 #include <linux/malloc.h>
+#include <linux/pagemap.h>
 
 #include <asm/segment.h>
 #include <asm/system.h>
 
+static int nfs_file_mmap(struct inode *, struct file *, struct vm_area_struct *);
 static int nfs_file_read(struct inode *, struct file *, char *, int);
 static int nfs_file_write(struct inode *, struct file *, const char *, int);
 static int nfs_fsync(struct inode *, struct file *);
+static int nfs_readpage(struct inode * inode, struct page * page);
 
 static struct file_operations nfs_file_operations = {
 	NULL,			/* lseek - default */
@@ -37,7 +42,7 @@
 	NULL,			/* readdir - bad */
 	NULL,			/* select - default */
 	NULL,			/* ioctl - default */
-	nfs_mmap,		/* mmap */
+	nfs_file_mmap,		/* mmap */
 	NULL,			/* no special open is needed */
 	NULL,			/* release */
 	nfs_fsync,		/* fsync */
@@ -56,136 +61,98 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	NULL,			/* readpage */
+	nfs_readpage,		/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
 	NULL			/* truncate */
 };
 
-/* Once data is inserted, it can only be deleted, if (in_use==0). */
-struct read_cache {
-	int		in_use;		/* currently in use? */
-	unsigned long	inode_num;	/* inode number */
-	off_t		file_pos;	/* file position */
-	int		len;		/* size of data */
-	unsigned long	time;		/* time, this entry was inserted */
-	char *		buf;		/* data */
-	int		buf_size;	/* size of buffer */
-};
+static inline void revalidate_inode(struct nfs_server * server, struct inode * inode)
+{
+	struct nfs_fattr fattr;
 
-#define READ_CACHE_SIZE 5
-#define EXPIRE_CACHE (HZ * 3)		/* keep no longer than 3 seconds */
+	if (jiffies - NFS_READTIME(inode) < server->acregmax)
+		return;
+
+	NFS_READTIME(inode) = jiffies;
+	if (nfs_proc_getattr(server, NFS_FH(inode), &fattr) == 0) {
+		nfs_refresh_inode(inode, &fattr);
+		if (fattr.mtime.seconds == NFS_OLDMTIME(inode))
+			return;
+		NFS_OLDMTIME(inode) = fattr.mtime.seconds;
+	}
+	invalidate_inode_pages(inode, 0);
+}
 
-unsigned long num_requests = 0;
-unsigned long num_cache_hits = 0;
 
-static int tail = 0;	/* next cache slot to replace */
+static int nfs_file_read(struct inode * inode, struct file * file,
+	char * buf, int count)
+{
+	revalidate_inode(NFS_SERVER(inode), inode);
+	return generic_file_read(inode, file, buf, count);
+}
 
-static struct read_cache cache[READ_CACHE_SIZE] = {
-	{ 0, 0, -1, 0, 0, NULL, 0 },
-	{ 0, 0, -1, 0, 0, NULL, 0 },
-	{ 0, 0, -1, 0, 0, NULL, 0 },
-	{ 0, 0, -1, 0, 0, NULL, 0 },
-	{ 0, 0, -1, 0, 0, NULL, 0 } };
+static int nfs_file_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
+{
+	revalidate_inode(NFS_SERVER(inode), inode);
+	return generic_file_mmap(inode, file, vma);
+}
 
 static int nfs_fsync(struct inode *inode, struct file *file)
 {
 	return 0;
 }
 
-static int nfs_file_read(struct inode *inode, struct file *file, char *buf,
-			 int count)
+static inline void do_read_nfs(struct inode * inode, char * buf, unsigned long pos)
 {
-	int result, hunk, i, n, fs;
+	int refresh = 0;
+	int count = PAGE_SIZE;
+	int rsize = NFS_SERVER(inode)->rsize;
 	struct nfs_fattr fattr;
-	char *data;
-	off_t pos;
 
-	if (!inode) {
-		printk("nfs_file_read: inode = NULL\n");
-		return -EINVAL;
-	}
-	if (!S_ISREG(inode->i_mode)) {
-		printk("nfs_file_read: read from non-file, mode %07o\n",
-			inode->i_mode);
-		return -EINVAL;
-	}
-	pos = file->f_pos;
-	if (pos + count > inode->i_size)
-		count = inode->i_size - pos;
-	if (count <= 0)
-		return 0;
-	++num_requests;
-	cli();
-	for (i = 0; i < READ_CACHE_SIZE; i++)
-		if ((cache[i].inode_num == inode->i_ino)
-			&& (cache[i].file_pos <= pos)
-			&& (cache[i].file_pos + cache[i].len >= pos + count)
-			&& (jiffies - cache[i].time < EXPIRE_CACHE))
-			break;
-	if (i < READ_CACHE_SIZE) {
-		++cache[i].in_use;
-		sti();
-		++num_cache_hits;
-		memcpy_tofs(buf, cache[i].buf + pos - cache[i].file_pos, count);
-		--cache[i].in_use;
-		file->f_pos += count;
-		return count;
-	}
-	sti();
-	n = NFS_SERVER(inode)->rsize;
-	for (i = 0; i < count - n; i += n) {
+	do {
+		int result;
+
+		if (count < rsize)
+			rsize = count;
 		result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode), 
-			pos, n, buf, &fattr, 1);
+			pos, rsize, buf, &fattr);
 		if (result < 0)
-			return result;
-		pos += result;
-		buf += result;
-		if (result < n) {
-			file->f_pos = pos;
-			nfs_refresh_inode(inode, &fattr);
-			return i + result;
-		}
-	}
-	fs = 0;
-	if (!(data = (char *)kmalloc(n, GFP_KERNEL))) {
-		data = buf;
-		fs = 1;
-	}
-	result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode),
-		pos, n, data, &fattr, fs);
-	if (result < 0) {
-		if (!fs)
-			kfree_s(data, n);
-		return result;
-	}
-	hunk = count - i;
-	if (result < hunk)
-		hunk = result;
-	if (fs) {
-		file->f_pos = pos + hunk;
+			goto partial;
+		refresh = 1;
+		count -= rsize;
+		pos += rsize;
+		buf += rsize;
+		if (result < rsize)
+			goto partial;
+	} while (count);
+	nfs_refresh_inode(inode, &fattr);
+	return;
+
+partial:
+	memset(buf, 0, count);
+	if (refresh)
 		nfs_refresh_inode(inode, &fattr);
-		return i + hunk;
+}
+
+static int nfs_readpage(struct inode * inode, struct page * page)
+{
+	unsigned long address;
+
+	address = page_address(page);
+	page->count++;
+	wait_on_page(page);
+	if (page->uptodate) {
+		free_page(address);
+		return 0;
 	}
-	memcpy_tofs(buf, data, hunk);
-	file->f_pos = pos + hunk;
-	nfs_refresh_inode(inode, &fattr);
-	cli();
-	if (cache[tail].in_use == 0) {
-		if (cache[tail].buf)
-			kfree_s(cache[tail].buf, cache[tail].buf_size);
-		cache[tail].buf = data;
-		cache[tail].buf_size = n;
-		cache[tail].inode_num = inode->i_ino;
-		cache[tail].file_pos = pos;
-		cache[tail].len = result;
-		cache[tail].time = jiffies;
-		if (++tail >= READ_CACHE_SIZE)
-			tail = 0;
-	} else
-		kfree_s(data, n);
-	sti();
-	return i + hunk;
+	page->locked = 1;
+	do_read_nfs(inode, (char *) address, page->offset);
+	page->locked = 0;
+	page->uptodate = 1;
+	wake_up(&page->wait);
+	free_page(address);
+	return 0;
 }
 
 static int nfs_file_write(struct inode *inode, struct file *file, const char *buf,
@@ -206,13 +173,6 @@
 	if (count <= 0)
 		return 0;
 
-	cli();
-	/* If hit, cache is dirty and must be expired. */
-	for (i = 0; i < READ_CACHE_SIZE; i++)
-		if(cache[i].inode_num == inode->i_ino)
-			cache[i].time -= EXPIRE_CACHE;
-        sti();
-
 	pos = file->f_pos;
 	if (file->f_flags & O_APPEND)
 		pos = inode->i_size;
@@ -221,7 +181,7 @@
 		hunk = count - i;
 		if (hunk >= n)
 			hunk = n;
-		result = nfs_proc_write(NFS_SERVER(inode), NFS_FH(inode), 
+		result = nfs_proc_write(inode,
 			pos, hunk, buf, &fattr);
 		if (result < 0)
 			return result;
diff -u --recursive --new-file v1.3.66/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v1.3.66/linux/fs/nfs/inode.c	Wed Feb  7 15:11:34 1996
+++ linux/fs/nfs/inode.c	Tue Feb 20 06:58:40 1996
@@ -32,10 +32,11 @@
 static int nfs_notify_change(struct inode *, struct iattr *);
 static void nfs_put_inode(struct inode *);
 static void nfs_put_super(struct super_block *);
+static void nfs_read_inode(struct inode *);
 static void nfs_statfs(struct super_block *, struct statfs *, int bufsiz);
 
 static struct super_operations nfs_sops = { 
-	NULL,			/* read inode */
+	nfs_read_inode,		/* read inode */
 	nfs_notify_change,	/* notify change */
 	NULL,			/* write inode */
 	nfs_put_inode,		/* put inode */
@@ -45,9 +46,22 @@
 	NULL
 };
 
+/*
+ * The "read_inode" function doesn't actually do anything:
+ * the real data is filled in later in nfs_fhget. Here we
+ * just mark the cache times invalid.
+ */
+static void nfs_read_inode(struct inode * inode)
+{
+	NFS_READTIME(inode) = jiffies - 1000000;
+	NFS_OLDMTIME(inode) = 0;
+}
+
 static void nfs_put_inode(struct inode * inode)
 {
+#if 0
 	clear_inode(inode);
+#endif
 }
 
 void nfs_put_super(struct super_block *sb)
diff -u --recursive --new-file v1.3.66/linux/fs/nfs/mmap.c linux/fs/nfs/mmap.c
--- v1.3.66/linux/fs/nfs/mmap.c	Mon Jan  8 14:10:28 1996
+++ linux/fs/nfs/mmap.c	Thu Jan  1 02:00:00 1970
@@ -1,115 +0,0 @@
-/*
- *	fs/nfs/mmap.c	by Jon Tombs 15 Aug 1993
- *
- * This code is from
- *	linux/mm/mmap.c which was written by obz, Linus and Eric
- * and
- *	linux/mm/memory.c  by Linus Torvalds and others
- *
- *	Copyright (C) 1993
- *
- */
-
-#include <linux/stat.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/shm.h>
-#include <linux/errno.h>
-#include <linux/mman.h>
-#include <linux/string.h>
-#include <linux/malloc.h>
-#include <linux/nfs_fs.h>
-
-#include <asm/segment.h>
-#include <asm/system.h>
-
-/*
- * Return a page for mmap. We need to start using the page cache,
- * because otherwise we can't share pages between processes..
- */
-static unsigned long nfs_file_mmap_nopage(struct vm_area_struct * area,
-	unsigned long address, int no_share)
-{
-	struct inode * inode = area->vm_inode;
-	unsigned long page;
-	unsigned int clear;
-	unsigned long tmp;
-	int n;
-	int i;
-	int pos;
-	struct nfs_fattr fattr;
-
-	page = __get_free_page(GFP_KERNEL);
-	if (!page)
-		return page;
-	address &= PAGE_MASK;
-	pos = address - area->vm_start + area->vm_offset;
-
-	clear = 0;
-	if (address + PAGE_SIZE > area->vm_end) {
-		clear = address + PAGE_SIZE - area->vm_end;
-	}
-
-	n = NFS_SERVER(inode)->rsize; /* what we can read in one go */
-
-	for (i = 0; i < (PAGE_SIZE - clear); i += n) {
-		int hunk, result;
-
-		hunk = PAGE_SIZE - i;
-		if (hunk > n)
-			hunk = n;
-		result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode),
-			pos, hunk, (char *) (page + i), &fattr, 0);
-		if (result < 0)
-			break;
-		pos += result;
-		if (result < n) {
-			i += result;
-			break;
-		}
-	}
-
-#ifdef doweneedthishere
-	nfs_refresh_inode(inode, &fattr);
-#endif
-
-	tmp = page + PAGE_SIZE;
-	if (clear > 0){
-		memset ((char*)(tmp-clear),0,clear);
-	}
-
-	return page;
-}
-
-struct vm_operations_struct nfs_file_mmap = {
-	NULL,			/* open */
-	NULL,			/* close */
-	NULL,			/* unmap */
-	NULL,			/* protect */
-	NULL,			/* sync */
-	NULL,			/* advise */
-	nfs_file_mmap_nopage,	/* nopage */
-	NULL,			/* wppage */
-	NULL,			/* swapout */
-	NULL,			/* swapin */
-};
-
-
-/* This is used for a general mmap of a nfs file */
-int nfs_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
-{
-	if (vma->vm_flags & VM_SHARED)	/* only PAGE_COW or read-only supported now */
-		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;
-	}
-
-	vma->vm_inode = inode;
-	inode->i_count++;
-	vma->vm_ops = &nfs_file_mmap;
-	return 0;
-}
diff -u --recursive --new-file v1.3.66/linux/fs/nfs/proc.c linux/fs/nfs/proc.c
--- v1.3.66/linux/fs/nfs/proc.c	Fri Nov 17 08:42:27 1995
+++ linux/fs/nfs/proc.c	Tue Feb 20 09:49:41 1996
@@ -42,6 +42,8 @@
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/in.h>
+#include <linux/pagemap.h>
+
 #include <asm/segment.h>
 
 #ifdef NFS_PROC_DEBUG
@@ -150,16 +152,12 @@
 	return p + quadlen;
 }
 
-static inline int *xdr_decode_data(int *p, char *data, int *lenp, int maxlen,
-			int fs)
+static inline int *xdr_decode_data(int *p, char *data, int *lenp, int maxlen)
 {
 	unsigned len = *lenp = ntohl(*p++);
 	if (len > maxlen)
 		return NULL;
-	if (fs)
-		memcpy_tofs(data, p, len);
-	else
-		memcpy(data, p, len);
+	memcpy(data, p, len);
 	return p + QUADLEN(len);
 }
 
@@ -373,7 +371,7 @@
 }
 
 int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle,
-	  int offset, int count, char *data, struct nfs_fattr *fattr, int fs)
+	  int offset, int count, char *data, struct nfs_fattr *fattr)
 {
 	int *p, *p0;
 	int status;
@@ -397,7 +395,7 @@
 		status = -errno_NFSERR_IO;
 	else if ((status = ntohl(*p++)) == NFS_OK) {
 		p = xdr_decode_fattr(p, fattr);
-		if (!(p = xdr_decode_data(p, data, &len, count, fs))) {
+		if (!(p = xdr_decode_data(p, data, &len, count))) {
 			printk("nfs_proc_read: giant data size\n"); 
 			status = -errno_NFSERR_IO;
 		}
@@ -418,12 +416,15 @@
 	return status;
 }
 
-int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle,
-		   int offset, int count, const char *data, struct nfs_fattr *fattr)
+int nfs_proc_write(struct inode * inode, int offset,
+		   int count, const char *data, struct nfs_fattr *fattr)
 {
 	int *p, *p0;
 	int status;
 	int ruid = 0;
+	void * kdata;	/* address of kernel copy */
+	struct nfs_server * server = NFS_SERVER(inode);
+	struct nfs_fh *fhandle = NFS_FH(inode);
 
 	PRINTK("NFS call  write %d @ %d\n", count, offset);
 	if (!(p0 = nfs_rpc_alloc(server->wsize)))
@@ -434,6 +435,7 @@
 	*p++ = htonl(offset); /* traditional, could be any value */
 	*p++ = htonl(offset);
 	*p++ = htonl(count); /* traditional, could be any value */
+	kdata = (void *) (p+1);	/* start of data in RPC buffer */
 	p = xdr_encode_data(p, data, count);
 	if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
 		nfs_rpc_free(p0);
@@ -442,6 +444,7 @@
 	if (!(p = nfs_rpc_verify(p0)))
 		status = -errno_NFSERR_IO;
 	else if ((status = ntohl(*p++)) == NFS_OK) {
+		update_vm_cache(inode, offset, kdata, count);
 		p = xdr_decode_fattr(p, fattr);
 		PRINTK("NFS reply write\n");
 		/* status = 0; */
diff -u --recursive --new-file v1.3.66/linux/fs/pipe.c linux/fs/pipe.c
--- v1.3.66/linux/fs/pipe.c	Tue Dec 26 04:45:38 1995
+++ linux/fs/pipe.c	Mon Feb 19 13:29:08 1996
@@ -254,8 +254,10 @@
 
 static void pipe_rdwr_release(struct inode * inode, struct file * filp)
 {
-	PIPE_READERS(*inode)--;
-	PIPE_WRITERS(*inode)--;
+	if (filp->f_mode & FMODE_READ)
+		PIPE_READERS(*inode)--;
+	if (filp->f_mode & FMODE_WRITE)
+		PIPE_WRITERS(*inode)--;
 	wake_up_interruptible(&PIPE_WAIT(*inode));
 }
 
@@ -273,8 +275,10 @@
 
 static int pipe_rdwr_open(struct inode * inode, struct file * filp)
 {
-	PIPE_READERS(*inode)++;
-	PIPE_WRITERS(*inode)++;
+	if (filp->f_mode & FMODE_READ)
+		PIPE_READERS(*inode)++;
+	if (filp->f_mode & FMODE_WRITE)
+		PIPE_WRITERS(*inode)++;
 	return 0;
 }
 
diff -u --recursive --new-file v1.3.66/linux/fs/sysv/file.c linux/fs/sysv/file.c
--- v1.3.66/linux/fs/sysv/file.c	Thu Jan  4 21:54:58 1996
+++ linux/fs/sysv/file.c	Tue Feb 20 10:28:13 1996
@@ -45,7 +45,7 @@
 	NULL,			/* readdir - bad */
 	NULL,			/* select - default */
 	NULL,			/* ioctl - default */
-	generic_mmap,		/* mmap */
+	generic_file_mmap,	/* mmap */
 	NULL,			/* no special open is needed */
 	NULL,			/* release */
 	sysv_sync_file		/* fsync */
diff -u --recursive --new-file v1.3.66/linux/fs/umsdos/file.c linux/fs/umsdos/file.c
--- v1.3.66/linux/fs/umsdos/file.c	Wed Feb  7 15:11:35 1996
+++ linux/fs/umsdos/file.c	Tue Feb 20 10:28:13 1996
@@ -68,7 +68,7 @@
 	NULL,				/* readdir - bad */
 	NULL,				/* select - default */
 	NULL,				/* ioctl - default */
-	generic_mmap,			/* mmap */
+	generic_file_mmap,		/* mmap */
 	NULL,				/* no special open is needed */
 	NULL,				/* release */
 	file_fsync			/* fsync */
diff -u --recursive --new-file v1.3.66/linux/fs/xiafs/file.c linux/fs/xiafs/file.c
--- v1.3.66/linux/fs/xiafs/file.c	Thu Jan  4 21:54:58 1996
+++ linux/fs/xiafs/file.c	Tue Feb 20 10:28:13 1996
@@ -42,7 +42,7 @@
     NULL,			/* readdir - bad */
     NULL,			/* select - default */
     NULL,			/* ioctl - default */
-    generic_mmap,      		/* mmap */
+    generic_file_mmap,		/* mmap */
     NULL,			/* no special open is needed */
     NULL,			/* release */
     xiafs_sync_file		/* fsync */
diff -u --recursive --new-file v1.3.66/linux/include/asm-alpha/io.h linux/include/asm-alpha/io.h
--- v1.3.66/linux/include/asm-alpha/io.h	Tue Dec 26 04:45:40 1995
+++ linux/include/asm-alpha/io.h	Mon Feb 19 11:05:51 1996
@@ -94,8 +94,10 @@
 extern void		_outl (unsigned int l,unsigned long port);
 extern unsigned long	_readb(unsigned long addr);
 extern unsigned long	_readw(unsigned long addr);
+extern unsigned long	_readl(unsigned long addr);
 extern void		_writeb(unsigned char b, unsigned long addr);
 extern void		_writew(unsigned short b, unsigned long addr);
+extern void		_writel(unsigned int b, unsigned long addr);
 
 /*
  * The platform header files may define some of these macros to use
diff -u --recursive --new-file v1.3.66/linux/include/asm-i386/termios.h linux/include/asm-i386/termios.h
--- v1.3.66/linux/include/asm-i386/termios.h	Sun Dec 17 11:43:22 1995
+++ linux/include/asm-i386/termios.h	Tue Feb 20 07:51:42 1996
@@ -268,6 +268,8 @@
 
 #ifdef __KERNEL__
 
+#include <linux/string.h>
+
 /*
  * Translate a "termio" structure into a "termios". Ugh.
  */
diff -u --recursive --new-file v1.3.66/linux/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h
--- v1.3.66/linux/include/asm-i386/unistd.h	Sun Jan 14 16:30:14 1996
+++ linux/include/asm-i386/unistd.h	Mon Feb 19 07:55:24 1996
@@ -155,7 +155,6 @@
 #define __NR_getsid		147
 #define __NR_fdatasync		148
 #define __NR__sysctl		149
-
 #define __NR_mlock		150
 #define __NR_munlock		151
 #define __NR_mlockall		152
@@ -168,6 +167,7 @@
 #define __NR_sched_get_priority_max	159
 #define __NR_sched_get_priority_min	160
 #define __NR_sched_rr_get_interval	161
+#define __NR_nanosleep		162
 
 /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
 #define _syscall0(type,name) \
diff -u --recursive --new-file v1.3.66/linux/include/linux/fs.h linux/include/linux/fs.h
--- v1.3.66/linux/include/linux/fs.h	Fri Feb  9 17:53:08 1996
+++ linux/include/linux/fs.h	Tue Feb 20 10:28:13 1996
@@ -597,7 +597,7 @@
 
 extern int generic_readpage(struct inode *, struct page *);
 extern int generic_file_read(struct inode *, struct file *, char *, int);
-extern int generic_mmap(struct inode *, struct file *, struct vm_area_struct *);
+extern int generic_file_mmap(struct inode *, struct file *, struct vm_area_struct *);
 extern int brw_page(int, unsigned long, kdev_t, int [], int, int);
 
 extern void put_super(kdev_t dev);
diff -u --recursive --new-file v1.3.66/linux/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h
--- v1.3.66/linux/include/linux/nfs_fs.h	Sat Feb 17 16:02:54 1996
+++ linux/include/linux/nfs_fs.h	Tue Feb 20 09:49:55 1996
@@ -43,6 +43,8 @@
 
 #define NFS_SERVER(inode)		(&(inode)->i_sb->u.nfs_sb.s_server)
 #define NFS_FH(inode)			(&(inode)->u.nfs_i.fhandle)
+#define NFS_READTIME(inode)		((inode)->u.nfs_i.read_cache_jiffies)
+#define NFS_OLDMTIME(inode)		((inode)->u.nfs_i.read_cache_mtime)
 
 #ifdef __KERNEL__
 
@@ -60,10 +62,9 @@
 			unsigned int maxlen);
 extern int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle,
 			 int offset, int count, char *data,
-			 struct nfs_fattr *fattr, int fs);
-extern int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle,
-			  int offset, int count, const char *data,
-			  struct nfs_fattr *fattr);
+			 struct nfs_fattr *fattr);
+extern int nfs_proc_write(struct inode * inode, int offset,
+			  int count, const char *data, struct nfs_fattr *fattr);
 extern int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
 			   const char *name, struct nfs_sattr *sattr,
 			   struct nfs_fh *fhandle, struct nfs_fattr *fattr);
diff -u --recursive --new-file v1.3.66/linux/include/linux/nfs_fs_i.h linux/include/linux/nfs_fs_i.h
--- v1.3.66/linux/include/linux/nfs_fs_i.h	Wed Dec  1 14:44:15 1993
+++ linux/include/linux/nfs_fs_i.h	Tue Feb 20 06:58:40 1996
@@ -8,6 +8,18 @@
  */
 struct nfs_inode_info {
 	struct nfs_fh fhandle;
+	/*
+	 * read_cache_jiffies is when we started read-caching this inode,
+	 * and read_cache_mtime is the mtime of the inode at that time.
+	 *
+	 * We need to invalidate the cache for this inode if
+	 *
+	 *	jiffies - read_cache_jiffies > 30*HZ
+	 * AND
+	 *	mtime != read_cache_mtime
+	 */
+	unsigned long read_cache_jiffies;
+	unsigned long read_cache_mtime;
 };
 
 #endif
diff -u --recursive --new-file v1.3.66/linux/include/net/sock.h linux/include/net/sock.h
--- v1.3.66/linux/include/net/sock.h	Sat Feb 17 16:02:56 1996
+++ linux/include/net/sock.h	Tue Feb 20 13:53:48 1996
@@ -277,7 +277,7 @@
  
 struct proto 
 {
-	void			(*close)(struct sock *sk, int timeout);
+	void			(*close)(struct sock *sk, unsigned long timeout);
 	int			(*build_header)(struct sk_buff *skb,
 					__u32 saddr,
 					__u32 daddr,
diff -u --recursive --new-file v1.3.66/linux/include/net/tcp.h linux/include/net/tcp.h
--- v1.3.66/linux/include/net/tcp.h	Sat Feb 17 18:14:28 1996
+++ linux/include/net/tcp.h	Tue Feb 20 13:54:02 1996
@@ -54,14 +54,14 @@
 				  * close the socket, about 60 seconds	*/
 #define TCP_FIN_TIMEOUT (3*60*HZ) /* BSD style FIN_WAIT2 deadlock breaker */				  
 #define TCP_ACK_TIME	(3*HZ)	/* time to delay before sending an ACK	*/
-#define TCP_DONE_TIME	250	/* maximum time to wait before actually
+#define TCP_DONE_TIME	(5*HZ/2)/* maximum time to wait before actually
 				 * destroying a socket			*/
-#define TCP_WRITE_TIME	3000	/* initial time to wait for an ACK,
+#define TCP_WRITE_TIME	(30*HZ)	/* initial time to wait for an ACK,
 			         * after last transmit			*/
 #define TCP_TIMEOUT_INIT (3*HZ)	/* RFC 1122 initial timeout value	*/
 #define TCP_SYN_RETRIES	 10	/* number of times to retry opening a
 				 * connection 	(TCP_RETR2-....)	*/
-#define TCP_PROBEWAIT_LEN 100	/* time to wait between probes when
+#define TCP_PROBEWAIT_LEN (1*HZ)/* time to wait between probes when
 				 * I've got something to write and
 				 * there is no window			*/
 
@@ -317,6 +317,8 @@
 
 	case TCP_CLOSE:
 		tcp_cache_zap();
+		/* Should be about 2 rtt's */
+   		reset_timer(sk, TIME_DONE, min(sk->rtt * 2, TCP_DONE_TIME));
 		/* fall through */
 	default:
 		if (oldstate==TCP_ESTABLISHED)
diff -u --recursive --new-file v1.3.66/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v1.3.66/linux/kernel/ksyms.c	Sat Feb 17 16:02:56 1996
+++ linux/kernel/ksyms.c	Tue Feb 20 10:28:13 1996
@@ -184,7 +184,6 @@
 	X(permission),
 	X(inode_setattr),
 	X(inode_change_ok),
-	X(generic_mmap),
 	X(set_blocksize),
 	X(getblk),
 	X(bread),
@@ -199,6 +198,7 @@
 	X(dcache_add),
 	X(add_blkdev_randomness),
 	X(generic_file_read),
+	X(generic_file_mmap),
 	X(generic_readpage),
 
 	/* device registration */
diff -u --recursive --new-file v1.3.66/linux/kernel/sched.c linux/kernel/sched.c
--- v1.3.66/linux/kernel/sched.c	Sat Feb 17 16:02:57 1996
+++ linux/kernel/sched.c	Mon Feb 19 14:12:12 1996
@@ -337,11 +337,11 @@
 	 
 #endif	 
 #ifdef __SMP_PROF__ 
-        /* mark processor running an idle thread */
-        if (0==next->pid)
-                set_bit(this_cpu,&smp_idle_map);
-        else
-                clear_bit(this_cpu,&smp_idle_map);
+	/* mark processor running an idle thread */
+	if (0==next->pid)
+		set_bit(this_cpu,&smp_idle_map);
+	else
+		clear_bit(this_cpu,&smp_idle_map);
 #endif
 	if (current != next) {
 		struct timer_list timer;
@@ -763,7 +763,7 @@
 	struct timer_struct *tp;
 	long ltemp, psecs;
 #ifdef  __SMP_PROF__
-        int cpu,i;
+	int cpu,i;
 #endif
 
 	/* Advance the phase, once it gets to one microsecond, then
@@ -814,10 +814,10 @@
 	jiffies++;
 	calc_load();
 #ifdef  __SMP_PROF__
-        smp_idle_count[NR_CPUS]++;    /* count timer ticks */
-        cpu = smp_processor_id();
-        for (i=0;i<(0==smp_num_cpus?1:smp_num_cpus);i++) 
-        	if (test_bit(i,&smp_idle_map)) smp_idle_count[i]++;
+	smp_idle_count[NR_CPUS]++;    /* count timer ticks */
+	cpu = smp_processor_id();
+	for (i=0;i<(0==smp_num_cpus?1:smp_num_cpus);i++) 
+		if (test_bit(i,&smp_idle_map)) smp_idle_count[i]++;
 #endif
 	if (user_mode(regs)) {
 		current->utime++;
@@ -859,7 +859,7 @@
 			send_sig(SIGXCPU, current, 1);
 		/* and every five seconds thereafter. */
 		else if ((psecs > current->rlim[RLIMIT_CPU].rlim_cur) &&
-		        ((psecs - current->rlim[RLIMIT_CPU].rlim_cur) % 5) == 0)
+			((psecs - current->rlim[RLIMIT_CPU].rlim_cur) % 5) == 0)
 			send_sig(SIGXCPU, current, 1);
 	}
 
@@ -1017,7 +1017,7 @@
 	error = verify_area(VERIFY_READ, param, sizeof(struct sched_param));
 	if (error)
 		return error;
-        memcpy_fromfs(&lp, param, sizeof(struct sched_param));
+	memcpy_fromfs(&lp, param, sizeof(struct sched_param));
 
 	p = find_process_by_pid(pid);
 	if (!p)
@@ -1031,7 +1031,7 @@
 	
 	/*
 	 * Valid priorities for SCHED_FIFO and SCHED_RR are 1..99, valid
-         * priority for SCHED_OTHER is 0.
+	 * priority for SCHED_OTHER is 0.
 	 */
 	if (lp.sched_priority < 0 || lp.sched_priority > 99)
 		return -EINVAL;
@@ -1046,6 +1046,8 @@
 
 	p->policy = policy;
 	p->rt_priority = lp.sched_priority;
+	if (p->next_run)
+		move_last_runqueue(p);
 	schedule();
 
 	return 0;
@@ -1101,8 +1103,9 @@
 
 asmlinkage int sys_sched_yield(void)
 {
-	/* ... not yet implemented ... */
-	return -ENOSYS;
+	move_last_runqueue(current);
+
+	return 0;
 }
 
 asmlinkage int sys_sched_get_priority_max(int policy)
@@ -1144,6 +1147,76 @@
 	t.tv_nsec = 0;   /* <-- Linus, please fill correct value in here */
 	return -ENOSYS;  /* and then delete this line. Thanks!           */
 	memcpy_tofs(interval, &t, sizeof(struct timespec));
+
+	return 0;
+}
+
+/*
+ * change timeval to jiffies, trying to avoid the 
+ * most obvious overflows..
+ */
+static unsigned long timespectojiffies(struct timespec *value)
+{
+	unsigned long sec = (unsigned) value->tv_sec;
+	long nsec = value->tv_nsec;
+
+	if (sec > (LONG_MAX / HZ))
+		return LONG_MAX;
+	nsec += 1000000000L / HZ - 1;
+	nsec /= 1000000000L / HZ;
+	return HZ * sec + nsec;
+}
+
+static void jiffiestotimespec(unsigned long jiffies, struct timespec *value)
+{
+	value->tv_nsec = (jiffies % HZ) * (1000000000L / HZ);
+	value->tv_sec = jiffies / HZ;
+	return;
+}
+
+asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp)
+{
+	int error;
+	struct timespec t;
+	unsigned long expire;
+
+	error = verify_area(VERIFY_READ, rqtp, sizeof(struct timespec));
+	if (error)
+		return error;
+	memcpy_fromfs(&t, rqtp, sizeof(struct timespec));
+	if (rmtp) {
+		error = verify_area(VERIFY_WRITE, rmtp,
+				    sizeof(struct timespec));
+		if (error)
+			return error;
+	}
+
+	if (t.tv_nsec >= 1000000000L || t.tv_nsec < 0 || t.tv_sec < 0)
+		return -EINVAL;
+
+	if (t.tv_sec == 0 && t.tv_nsec <= 2000000L &&
+	    current->policy != SCHED_OTHER) {
+		/*
+		 * Short delay requests up to 2 ms will be handled with
+		 * high precision by a busy wait for all real-time processes.
+		 */
+		udelay((t.tv_nsec + 999) / 1000);
+		return 0;
+	}
+
+	expire = timespectojiffies(&t) + (t.tv_sec || t.tv_nsec) + jiffies;
+	current->timeout = expire;
+	current->state = TASK_INTERRUPTIBLE;
+	schedule();
+
+	if (expire > jiffies) {
+		if (rmtp) {
+			jiffiestotimespec(expire - jiffies -
+					  (expire > jiffies + 1), &t);
+			memcpy_tofs(rmtp, &t, sizeof(struct timespec));
+		}
+		return -EINTR;
+	}
 
 	return 0;
 }
diff -u --recursive --new-file v1.3.66/linux/mm/filemap.c linux/mm/filemap.c
--- v1.3.66/linux/mm/filemap.c	Wed Feb  7 15:11:40 1996
+++ linux/mm/filemap.c	Tue Feb 20 10:28:13 1996
@@ -165,17 +165,31 @@
  */
 void update_vm_cache(struct inode * inode, unsigned long pos, const char * buf, int count)
 {
-	struct page * page;
+	unsigned long offset, len;
 
-	page = find_page(inode, pos & PAGE_MASK);
-	if (page) {
-		unsigned long addr;
+	offset = (pos & ~PAGE_MASK);
+	pos = pos & PAGE_MASK;
+	len = PAGE_SIZE - offset;
+	do {
+		struct page * page;
 
-		wait_on_page(page);
-		addr = page_address(page);
-		memcpy((void *) ((pos & ~PAGE_MASK) + addr), buf, count);
-		free_page(addr);
-	}
+		if (len > count)
+			len = count;
+		page = find_page(inode, pos);
+		if (page) {
+			unsigned long addr;
+
+			wait_on_page(page);
+			addr = page_address(page);
+			memcpy((void *) (offset + addr), buf, len);
+			free_page(addr);
+		}
+		count -= len;
+		buf += len;
+		len = PAGE_SIZE;
+		offset = 0;
+		pos += PAGE_SIZE;
+	} while (count);
 }
 
 /*
@@ -695,7 +709,7 @@
 };
 
 /* This is used for a general mmap of a disk file */
-int generic_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
+int generic_file_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
 {
 	struct vm_operations_struct * ops;
 
diff -u --recursive --new-file v1.3.66/linux/mm/mmap.c linux/mm/mmap.c
--- v1.3.66/linux/mm/mmap.c	Mon Dec 11 15:42:08 1995
+++ linux/mm/mmap.c	Mon Feb 19 16:36:43 1996
@@ -174,18 +174,21 @@
 		kfree(vma);
 		return error;
 	}
+	flags = vma->vm_flags;
 	insert_vm_struct(current, vma);
 	merge_segments(current, vma->vm_start, vma->vm_end);
+
+	/* merge_segments might have merged our vma, so we can't use it any more */
 	current->mm->total_vm += len >> PAGE_SHIFT;
-	if (vma->vm_flags & VM_LOCKED) {
-		unsigned long start = vma->vm_start;
-		unsigned long end = vma->vm_end;
+	if (flags & VM_LOCKED) {
+		unsigned long start = addr;
 		current->mm->locked_vm += len >> PAGE_SHIFT;
-		while (start < end) {
+		do {
 			char c = get_user((char *) start);
-			__asm__ __volatile__("": :"r" (c));
+			len -= PAGE_SIZE;
 			start += PAGE_SIZE;
-		}
+			__asm__ __volatile__("": :"r" (c));
+		} while (len > 0);
 	}
 	return addr;
 }
diff -u --recursive --new-file v1.3.66/linux/net/core/sock.c linux/net/core/sock.c
--- v1.3.66/linux/net/core/sock.c	Sat Feb 17 18:14:28 1996
+++ linux/net/core/sock.c	Mon Feb 19 08:46:46 1996
@@ -570,10 +570,5 @@
 		sk->users = 0;
 		barrier();
 	}
-
-	if (sk->dead && sk->state == TCP_CLOSE) {
-		/* Should be about 2 rtt's */
-   		reset_timer(sk, TIME_DONE, min(sk->rtt * 2, TCP_DONE_TIME));
-	}
 #endif  
 }
diff -u --recursive --new-file v1.3.66/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v1.3.66/linux/net/ipv4/af_inet.c	Sat Feb 17 16:02:58 1996
+++ linux/net/ipv4/af_inet.c	Tue Feb 20 14:01:03 1996
@@ -743,22 +743,6 @@
 }
 
 /*
- *	Return 1 if we still have things to send in our buffers.
- */
- 
-static inline int closing(struct sock * sk)
-{
-	switch (sk->state) {
-		case TCP_FIN_WAIT1:
-		case TCP_CLOSING:
-		case TCP_LAST_ACK:
-			return 1;
-	}
-	return 0;
-}
-
-
-/*
  *	The peer socket should always be NULL (or else). When we call this
  *	function we are destroying the object and from then on nobody
  *	should refer to it.
@@ -766,7 +750,9 @@
  
 static int inet_release(struct socket *sock, struct socket *peer)
 {
+	unsigned long timeout;
 	struct sock *sk = (struct sock *) sock->data;
+
 	if (sk == NULL) 
 		return(0);
 
@@ -786,48 +772,19 @@
 	 * If the close is due to the process exiting, we never
 	 * linger..
 	 */
-
-	if (sk->linger == 0 || (current->flags & PF_EXITING))
-	{
-		sk->prot->close(sk,0);
-		sk->dead = 1;
-	} 
-	else 
-	{
-		sk->prot->close(sk, 0);
-		cli();
-		if (sk->lingertime)
-			current->timeout = jiffies + HZ*sk->lingertime;
-		while(closing(sk) && current->timeout>0) 
-		{
-			interruptible_sleep_on(sk->sleep);
-			if (current->signal & ~current->blocked) 
-			{
-				break;
-#if 0
-				/* not working now - closes can't be restarted */
-				sti();
-				current->timeout=0;
-				return(-ERESTARTSYS);
-#endif
-			}
-		}
-		current->timeout=0;
-		sti();
-		sk->dead = 1;
+	timeout = 0;
+	if (sk->linger) {
+		timeout = ~0UL;
+		if (!sk->lingertime)
+			timeout = jiffies + HZ*sk->lingertime;
 	}
-	lock_sock(sk);
+	if (current->flags & PF_EXITING)
+		timeout = 0;
 
-	/* This will destroy it. */
 	sock->data = NULL;
-	/* 
-	 *	Nasty here. release_sock can cause more frames
-	 *	to be played through the socket. That can
-	 *	reinitialise the tcp cache after tcp_close();
-	 */
-	release_sock(sk);
-	tcp_cache_zap();	/* Kill the cache again. */
 	sk->socket = NULL;
+
+	sk->prot->close(sk, timeout);
 	return(0);
 }
 
diff -u --recursive --new-file v1.3.66/linux/net/ipv4/ip_fw.c linux/net/ipv4/ip_fw.c
--- v1.3.66/linux/net/ipv4/ip_fw.c	Sat Feb 17 18:14:29 1996
+++ linux/net/ipv4/ip_fw.c	Sun Feb 18 10:43:25 1996
@@ -905,7 +905,7 @@
  		}
  		else ms->timer.expires = jiffies+MASQUERADE_EXPIRE_TCP;
  
-		skb->csum = csum_partial(th + 1, size - sizeof(*th), 0);
+		skb->csum = csum_partial((void *)(th + 1), size - sizeof(*th), 0);
  		tcp_send_check(th,iph->saddr,iph->daddr,size,skb);
  	}
  	add_timer(&ms->timer);
@@ -1011,7 +1011,7 @@
 #endif
 					}
 				}
-				skb->csum = csum_partial(portptr + sizeof(struct tcphdr),
+				skb->csum = csum_partial((void *)(((struct tcphdr *)portptr) + 1),
 					size - sizeof(struct tcphdr), 0);
  				tcp_send_check((struct tcphdr *)portptr,iph->saddr,iph->daddr,size,skb);
  			}
diff -u --recursive --new-file v1.3.66/linux/net/ipv4/packet.c linux/net/ipv4/packet.c
--- v1.3.66/linux/net/ipv4/packet.c	Sat Feb 17 16:02:58 1996
+++ linux/net/ipv4/packet.c	Tue Feb 20 13:52:31 1996
@@ -204,7 +204,7 @@
  *	file side of the object.
  */
 
-static void packet_close(struct sock *sk, int timeout)
+static void packet_close(struct sock *sk, unsigned long timeout)
 {
 	/*
 	 *	Stop more data and kill the socket off.
@@ -236,6 +236,7 @@
 	}
 	
 	release_sock(sk);
+	destroy_sock(sk);
 }
 
 /*
diff -u --recursive --new-file v1.3.66/linux/net/ipv4/raw.c linux/net/ipv4/raw.c
--- v1.3.66/linux/net/ipv4/raw.c	Sat Feb 17 16:02:58 1996
+++ linux/net/ipv4/raw.c	Tue Feb 20 13:52:03 1996
@@ -285,7 +285,7 @@
 	}
 }
 
-static void raw_close(struct sock *sk, int timeout)
+static void raw_close(struct sock *sk, unsigned long timeout)
 {
 	sk->state = TCP_CLOSE;
 #ifdef CONFIG_IP_MROUTE	
@@ -295,6 +295,7 @@
 		mroute_socket=NULL;
 	}
 #endif	
+	destroy_sock(sk);
 }
 
 
diff -u --recursive --new-file v1.3.66/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v1.3.66/linux/net/ipv4/tcp.c	Sat Feb 17 16:02:58 1996
+++ linux/net/ipv4/tcp.c	Tue Feb 20 14:01:03 1996
@@ -422,7 +422,7 @@
 unsigned long seq_offset;
 struct tcp_mib	tcp_statistics;
 
-static void tcp_close(struct sock *sk, int timeout);
+static void tcp_close(struct sock *sk, unsigned long timeout);
 
 /*
  *	The less said about this the better, but it works and will do for 1.2  (and 1.4 ;))
@@ -1782,8 +1782,27 @@
 	release_sock(sk);
 }
 
-static void tcp_close(struct sock *sk, int timeout)
+
+/*
+ *	Return 1 if we still have things to send in our buffers.
+ */
+ 
+static inline int closing(struct sock * sk)
 {
+	switch (sk->state) {
+		case TCP_FIN_WAIT1:
+		case TCP_CLOSING:
+		case TCP_LAST_ACK:
+			return 1;
+	}
+	return 0;
+}
+
+
+static void tcp_close(struct sock *sk, unsigned long timeout)
+{
+	struct sk_buff *skb;
+
 	/*
 	 * We need to grab some memory, and put together a FIN,	
 	 * and then put it into the queue to be sent.
@@ -1807,43 +1826,55 @@
 	if (!sk->dead) 
 	  	sk->state_change(sk);
 
-	if (timeout == 0) 
-	{
-		struct sk_buff *skb;
-		
-		/*
-		 *  We need to flush the recv. buffs.  We do this only on the
-		 *  descriptor close, not protocol-sourced closes, because the
-		 *  reader process may not have drained the data yet!
-		 */
+	/*
+	 *  We need to flush the recv. buffs.  We do this only on the
+	 *  descriptor close, not protocol-sourced closes, because the
+	 *  reader process may not have drained the data yet!
+	 */
 		 
-		while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
-			kfree_skb(skb, FREE_READ);
-		/*
-		 *	Get rid off any half-completed packets. 
-		 */
+	while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
+		kfree_skb(skb, FREE_READ);
 
-		if (sk->partial) 
-			tcp_send_partial(sk);
-	}
+	/*
+	 *	Get rid off any half-completed packets. 
+	 */
 
+	if (sk->partial) 
+		tcp_send_partial(sk);
 		
 	/*
 	 *	Timeout is not the same thing - however the code likes
 	 *	to send both the same way (sigh).
 	 */
 	 
-	if(timeout)
+	if (tcp_close_state(sk,1)==1)
 	{
-		tcp_set_state(sk, TCP_CLOSE);	/* Dead */
+		tcp_send_fin(sk);
 	}
-	else
-	{
-		if(tcp_close_state(sk,1)==1)
+
+	if (timeout) {
+		cli();
+		release_sock(sk);
+		current->timeout = timeout;
+		while(closing(sk) && current->timeout)
 		{
-			tcp_send_fin(sk);
+			interruptible_sleep_on(sk->sleep);
+			if (current->signal & ~current->blocked) 
+			{
+				break;
+			}
 		}
+		current->timeout=0;
+		lock_sock(sk);
+		sti();
 	}
+
+	/*
+	 * This will destroy it. The timers will take care of actually
+	 * free'ing up the memory.
+	 */
+	sk->dead = 1;
+	tcp_cache_zap();	/* Kill the cache again. */
 	release_sock(sk);
 }
 
diff -u --recursive --new-file v1.3.66/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v1.3.66/linux/net/ipv4/tcp_input.c	Sat Feb 17 18:14:29 1996
+++ linux/net/ipv4/tcp_input.c	Mon Feb 19 08:43:14 1996
@@ -1930,15 +1930,6 @@
 		kfree_skb(skb, FREE_READ);
 
 	/*
-	 * Finally, if we've moved to TCP_CLOSE, check if we should
-	 * get rid of the socket
-	 */
-	if (sk->dead && sk->state == TCP_CLOSE) {
-		/* Should be about 2 rtt's */
-   		reset_timer(sk, TIME_DONE, min(sk->rtt * 2, TCP_DONE_TIME));
-	}
-
-	/*
 	 *	And done
 	 */	
 	
diff -u --recursive --new-file v1.3.66/linux/net/ipv4/timer.c linux/net/ipv4/timer.c
--- v1.3.66/linux/net/ipv4/timer.c	Sat Feb 17 16:02:58 1996
+++ linux/net/ipv4/timer.c	Mon Feb 19 08:46:46 1996
@@ -114,9 +114,15 @@
 	switch (why) 
 	{
 		case TIME_DONE:
-			if (! sk->dead || sk->state != TCP_CLOSE) 
+			/* If the socket hasn't been closed off, re-try a bit later */
+			if (!sk->dead) {
+				reset_timer(sk, TIME_DONE, TCP_DONE_TIME);
+				break;
+			}
+
+			if (sk->state != TCP_CLOSE) 
 			{
-				printk ("non dead socket in time_done\n");
+				printk ("non CLOSE socket in time_done\n");
 				break;
 			}
 			destroy_sock (sk);
@@ -127,6 +133,7 @@
 		 *	We've waited for a while for all the memory associated with
 		 *	the socket to be freed.
 		 */
+
 			if(sk->wmem_alloc!=0 || sk->rmem_alloc!=0)
 			{
 				sk->wmem_alloc++;	/* So it DOESN'T go away */
diff -u --recursive --new-file v1.3.66/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v1.3.66/linux/net/ipv4/udp.c	Sat Feb 17 16:02:59 1996
+++ linux/net/ipv4/udp.c	Tue Feb 20 13:51:44 1996
@@ -573,15 +573,14 @@
 }
 
 
-static void udp_close(struct sock *sk, int timeout)
+static void udp_close(struct sock *sk, unsigned long timeout)
 {
 	lock_sock(sk);
 	sk->state = TCP_CLOSE;
 	if(uh_cache_sk==sk)
 		udp_cache_zap();
 	release_sock(sk);
-	if (sk->dead) 
-		destroy_sock(sk);
+	destroy_sock(sk);
 }
 
 
diff -u --recursive --new-file v1.3.66/linux/scripts/ksymoops.cc linux/scripts/ksymoops.cc
--- v1.3.66/linux/scripts/ksymoops.cc	Wed Feb  7 15:11:45 1996
+++ linux/scripts/ksymoops.cc	Tue Feb 20 12:38:52 1996
@@ -305,7 +305,8 @@
 		cout << endl;
 	    }
 	    cout << endl;
-	} else if (strequ(buffer, "ode:") || strequ(buffer, "Code:")) {
+	}
+	if (strequ(buffer, "ode:") || strequ(buffer, "Code:")) {
 	    // The 'C' might have been consumed as a hex number
 	    unsigned char code[code_size];
 	    unsigned char* cp = code;
