diff -u --recursive --new-file v2.0.18/linux/CREDITS linux/CREDITS
--- v2.0.18/linux/CREDITS	Sun Sep  8 19:50:20 1996
+++ linux/CREDITS	Tue Sep 10 09:08:32 1996
@@ -388,10 +388,10 @@
 D: Debugging: SCSI code; Cyclades serial driver; APM driver
 D: Debugging: XFree86 Mach 32 server, accelerated server code
 
-N: Juergen Fischer
-E: fischer@server.et-inf.fho-emden.de
+N: Jürgen Fischer
+E: fischer@et-inf.fho-emden.de (=?iso-8859-1?q?J=FCrgen?= Fischer)
 D: Author of Adaptec AHA-152x scsi driver
-S: Schulstrasse 18
+S: Schulstraße 18
 S: 26506 Norden
 S: Germany
 
@@ -532,9 +532,7 @@
 
 N: Kai Harrekilde-Petersen
 E: khp@dolphinics.no
-W: http://www.dolphinics.no/~khp
-P: 1024/D2CDF895 F6 33 E0 4E 01 17 85 8C  4F 7F 1F F8 14 E7 86 1D
-D: ftape-HOWTO, i82078 fdc detection code, ftape maintainer.
+D: Original author of the ftape-HOWTO, i82078 fdc detection code.
 S: Peder Holters vei 13
 S: 1168 Oslo
 S: Norway
diff -u --recursive --new-file v2.0.18/linux/Documentation/Changes linux/Documentation/Changes
--- v2.0.18/linux/Documentation/Changes	Sun Sep  8 19:50:20 1996
+++ linux/Documentation/Changes	Wed Sep 11 11:45:10 1996
@@ -34,7 +34,7 @@
 bunshou no nihongo ban wa
 http://jf.gee.kyoto-u.ac.jp/JF/v2.0/Changes-2.0.html ni arimasu.
 
-Last updated: September 02, 1996.
+Last updated: September 10, 1996.
 Current Author: Chris Ricker (gt1355b@prism.gatech.edu).
 
 Current Releases
@@ -74,6 +74,14 @@
 /etc/sysconfig/network-scripts/ifup-lo, changing the line `route add
 -net $(IPADDR)' to `route add -net 127.0.0.0' and you should be fine.
 
+   People have also reported problems due to the naming of the dummy
+network interface driver.  If the dummy driver is compiled into the
+kernel, its name is "dummy."  If the dummy driver is compiled as a
+module, its name is "dummy0."  Furthermore, more than one dummy driver
+can be loaded if compiled as a module.  Each subsequent loading of the
+driver adds a new dummy interface whose name is incremented by one
+("dummy1," "dummy2," etc.).
+
 Booting Changes
 ===============
 
@@ -194,6 +202,15 @@
 device drivers compiled into the kernel, so don't get grandiose ideas
 about going completely modular and then forget to compile ext2fs
 support and ide/SCSI drive support into your kernel ;-).
+
+Kernel messages
+===============
+
+   Kernel messages without a specific log level use the kernel's
+default log level.  In 1.2 kernels, the default log level was 6
+(information), while in 2.0.x kernels it is 4 (warning).  Adjust your
+configuration of syslogd appropriately (or edit printk.c in the kernel
+source ;-).
 
 PPP driver
 ==========
diff -u --recursive --new-file v2.0.18/linux/Documentation/networking/arcnet.txt linux/Documentation/networking/arcnet.txt
--- v2.0.18/linux/Documentation/networking/arcnet.txt	Mon May 27 14:22:44 1996
+++ linux/Documentation/networking/arcnet.txt	Tue Sep 10 09:08:32 1996
@@ -117,12 +117,9 @@
 Loadable Module Support
 -----------------------
 
-Configure and rebuild Linux.  When asked, answer 'n' to "arcnet support" if
+Configure and rebuild Linux.  When asked, answer 'm' to "arcnet support" if
 you want to use the loadable module.
 
-Actually, with Linux 1.3.24 and higher, you should answer 'm' to build the
-module.
-
 	make config
 	make dep
 	make clean	
@@ -130,15 +127,16 @@
 	make modules
 	
 If you're using a loadable module, you need to use insmod to load it, and
-you need to specify various characteristics of your card on the command
-line.  For example:
+you can specify various characteristics of your card on the command
+line.  (In recent versions of the driver, autoprobing is much more reliable
+and works as a module, so most of this is now unnecessary.)
+
+For example:
 	cd /usr/src/linux/modules
-	insmod arcnet.o io=0x300 irqnum=2 shmem=0xd0000
-You can also add a num=1, num=2 etc for additional arcnet cards that will
-use arc1, arc2 etc for their device names (instead of the default, arc0).
+	insmod arcnet.o io=0x300 irq=2 shmem=0xd0000
 
-** NEWS FLASH!  Starting with 2.30 ALPHA, the ARCnet driver can autoprobe
-   even as a module.  So "insmod arcnet.o" by itself should work.
+You can name the device using something like "device=arc1" (for a second
+card) or "device=eth0" (for weird compatibility reasons) if you like.
 	
 
 Using the Driver
@@ -154,6 +152,19 @@
 By the way, be sure to change all references from "eth0" to "arc0" in the
 HOWTOs.  Remember that ARCnet isn't a "true" ethernet, and the device name
 is DIFFERENT.
+
+
+Multiple Cards in One Computer
+------------------------------
+
+Linux has pretty good support for this now, but since I've been busy, the
+ARCnet driver has somewhat suffered in this respect.  For now, the easiest
+way to use multiple ARCnet cards is to build it as a loadable module and
+then do something like this:
+	insmod -o arc0 arcnet
+	insmod -o arc1 arcnet device=arc1
+(Note that in the first line, the default is device=arc0, but it doesn't
+hurt if you want to add it for consistency.)
 
 
 How do I get it to work with...?
diff -u --recursive --new-file v2.0.18/linux/Documentation/oops-tracing.txt linux/Documentation/oops-tracing.txt
--- v2.0.18/linux/Documentation/oops-tracing.txt	Sun Sep  8 19:50:20 1996
+++ linux/Documentation/oops-tracing.txt	Fri Sep  6 19:19:04 1996
@@ -126,7 +126,7 @@
 processed by klogd:
 ---------------------------------------------------------------------------
 Aug 29 09:51:01 blizard kernel: Unable to handle kernel paging request at virtual address f15e97cc
-Aug 29 09:51:01 blizard kernel: current->tss.cr3 = 0062d000, ^Pr3 = 0062d000
+Aug 29 09:51:01 blizard kernel: current->tss.cr3 = 0062d000, %cr3 = 0062d000
 Aug 29 09:51:01 blizard kernel: *pde = 00000000
 Aug 29 09:51:01 blizard kernel: Oops: 0002
 Aug 29 09:51:01 blizard kernel: CPU:    0
diff -u --recursive --new-file v2.0.18/linux/MAINTAINERS linux/MAINTAINERS
--- v2.0.18/linux/MAINTAINERS	Sat Aug 17 21:19:25 1996
+++ linux/MAINTAINERS	Tue Sep 10 09:08:32 1996
@@ -178,9 +178,8 @@
 S:	Maintained
 
 FTAPE/QIC-117:
-P:	Kai Harrekilde-Petersen
-M:	khp@dolphinics.no
-W:	http://www.dolphinics.no/~khp/ftape.html
+P:	Claus-Justus Heine
+M:	claus@momo.math.rwth-aachen.de
 L:	linux-tape@vger.rutgers.edu
 S:	Maintained
 
diff -u --recursive --new-file v2.0.18/linux/Makefile linux/Makefile
--- v2.0.18/linux/Makefile	Sun Sep  8 19:50:20 1996
+++ linux/Makefile	Sun Sep  8 20:14:51 1996
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 0
-SUBLEVEL = 18
+SUBLEVEL = 19
 
 ARCH = i386
 
diff -u --recursive --new-file v2.0.18/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c
--- v2.0.18/linux/arch/alpha/kernel/ptrace.c	Fri May  3 15:55:57 1996
+++ linux/arch/alpha/kernel/ptrace.c	Mon Sep  9 21:04:56 1996
@@ -266,7 +266,7 @@
 	struct vm_area_struct * vma;
 
 	addr &= PAGE_MASK;
-	vma = find_vma(tsk,addr);
+	vma = find_vma(tsk->mm,addr);
 	if (!vma)
 		return NULL;
 	if (vma->vm_start <= addr)
diff -u --recursive --new-file v2.0.18/linux/arch/alpha/mm/fault.c linux/arch/alpha/mm/fault.c
--- v2.0.18/linux/arch/alpha/mm/fault.c	Thu Aug  1 15:53:34 1996
+++ linux/arch/alpha/mm/fault.c	Mon Sep  9 21:04:56 1996
@@ -58,8 +58,11 @@
 	struct pt_regs regs)
 {
 	struct vm_area_struct * vma;
+	struct task_struct *tsk = current;
+	struct mm_struct *mm = tsk->mm;
 
-	vma = find_vma(current, address);
+	down(&mm->mmap_sem);
+	vma = find_vma(mm, address);
 	if (!vma)
 		goto bad_area;
 	if (vma->vm_start <= address)
@@ -85,6 +88,7 @@
 			goto bad_area;
 	}
 	handle_mm_fault(vma, address, cause > 0);
+	up(&mm->mmap_sem);
 	return;
 
 /*
@@ -92,11 +96,12 @@
  * Fix it, but check if it's kernel or user first..
  */
 bad_area:
+	up(&mm->mmap_sem);
 	if (user_mode(&regs)) {
 		printk("%s: memory violation at pc=%08lx rp=%08lx (bad address = %08lx)\n",
-			current->comm, regs.pc, regs.r26, address);
+			tsk->comm, regs.pc, regs.r26, address);
 		die_if_kernel("oops", &regs, cause);
-		force_sig(SIGSEGV, current);
+		force_sig(SIGSEGV, tsk);
 		return;
 	}
 /*
diff -u --recursive --new-file v2.0.18/linux/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile
--- v2.0.18/linux/arch/i386/kernel/Makefile	Wed Feb  7 08:55:34 1996
+++ linux/arch/i386/kernel/Makefile	Mon Sep  9 13:55:58 1996
@@ -11,7 +11,6 @@
 #	$(CPP) -D__ASSEMBLY__ -traditional $< -o $*.s
 
 ifdef SMP
-
 .S.o:
 	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
 else
diff -u --recursive --new-file v2.0.18/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- v2.0.18/linux/arch/i386/kernel/irq.c	Thu Jun  6 13:44:42 1996
+++ linux/arch/i386/kernel/irq.c	Mon Sep  9 09:32:19 1996
@@ -232,7 +232,7 @@
 		action = irq_action[i];
 		if (!action) 
 			continue;
-		len += sprintf(buf+len, "%2d: %8d %c %s",
+		len += sprintf(buf+len, "%2d: %10u %c %s",
 			i, kstat.interrupts[i],
 			(action->flags & SA_INTERRUPT) ? '+' : ' ',
 			action->name);
diff -u --recursive --new-file v2.0.18/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.0.18/linux/arch/i386/kernel/process.c	Sat Aug 17 21:19:26 1996
+++ linux/arch/i386/kernel/process.c	Mon Sep  9 13:06:14 1996
@@ -33,7 +33,6 @@
 #include <asm/io.h>
 #include <linux/smp.h>
 
-
 asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call");
 
 #ifdef CONFIG_APM
diff -u --recursive --new-file v2.0.18/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c
--- v2.0.18/linux/arch/i386/kernel/ptrace.c	Thu May  2 16:11:56 1996
+++ linux/arch/i386/kernel/ptrace.c	Mon Sep  9 21:04:56 1996
@@ -187,7 +187,7 @@
 	struct vm_area_struct * vma;
 
 	addr &= PAGE_MASK;
-	vma = find_vma(tsk,addr);
+	vma = find_vma(tsk->mm,addr);
 	if (!vma)
 		return NULL;
 	if (vma->vm_start <= addr)
diff -u --recursive --new-file v2.0.18/linux/arch/i386/lib/Makefile linux/arch/i386/lib/Makefile
--- v2.0.18/linux/arch/i386/lib/Makefile	Tue Aug 15 15:07:02 1995
+++ linux/arch/i386/lib/Makefile	Mon Sep  9 16:09:16 1996
@@ -2,7 +2,15 @@
 # Makefile for i386-specific library files..
 #
 
+ifdef SMP
+.S.o:
+	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+else
+.S.o:
+	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
+endif
+
 L_TARGET = lib.a
-L_OBJS  = checksum.o
+L_OBJS  = checksum.o semaphore.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.0.18/linux/arch/i386/lib/semaphore.S linux/arch/i386/lib/semaphore.S
--- v2.0.18/linux/arch/i386/lib/semaphore.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/i386/lib/semaphore.S	Wed Sep 11 14:15:08 1996
@@ -0,0 +1,31 @@
+/*
+ *  linux/arch/i386/lib/semaphore.S
+ *
+ *  Copyright (C) 1996  Linus Torvalds
+ */
+
+#include <linux/linkage.h>
+
+/*
+ * "down_failed" is called with the eventual return address
+ * in %eax, and the address of the semaphore in %ecx. We need
+ * to increment the number of waiters on the semaphore,
+ * call "__down()", and then eventually return to try again.
+ */
+.globl down_failed
+ALIGN
+down_failed:
+	pushl %eax
+	pushl %ecx
+	call SYMBOL_NAME(__down)
+	popl %ecx
+	ret
+
+.globl up_wakeup
+ALIGN
+up_wakeup:
+	pushl %eax
+	pushl %ecx
+	call SYMBOL_NAME(__up)
+	popl %ecx
+	ret
diff -u --recursive --new-file v2.0.18/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- v2.0.18/linux/arch/i386/mm/fault.c	Sun Sep  8 19:50:20 1996
+++ linux/arch/i386/mm/fault.c	Mon Sep  9 21:04:56 1996
@@ -33,13 +33,21 @@
  */
 asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
 {
+	void (*handler)(struct task_struct *,
+			struct vm_area_struct *,
+			unsigned long,
+			int);
+	struct task_struct *tsk = current;
+	struct mm_struct *mm = tsk->mm;
 	struct vm_area_struct * vma;
 	unsigned long address;
 	unsigned long page;
+	int write;
 
 	/* get the address */
 	__asm__("movl %%cr2,%0":"=r" (address));
-	vma = find_vma(current, address);
+	down(&mm->mmap_sem);
+	vma = find_vma(mm, address);
 	if (!vma)
 		goto bad_area;
 	if (vma->vm_start <= address)
@@ -63,36 +71,37 @@
  * we can handle it..
  */
 good_area:
-	/*
-	 * was it a write?
-	 */
-	if (error_code & 2) {
-		if (!(vma->vm_flags & VM_WRITE))
-			goto bad_area;
-	} else {
-		/* read with protection fault? */
-		if (error_code & 1)
-			goto bad_area;
-		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+	write = 0;
+	handler = do_no_page;
+	switch (error_code & 3) {
+		default:	/* 3: write, present */
+			handler = do_wp_page;
+#ifdef TEST_VERIFY_AREA
+			if (regs->cs == KERNEL_CS)
+				printk("WP fault at %08lx\n", regs->eip);
+#endif
+			/* fall through */
+		case 2:		/* write, not present */
+			if (!(vma->vm_flags & VM_WRITE))
+				goto bad_area;
+			write++;
+			break;
+		case 1:		/* read, present */
 			goto bad_area;
+		case 0:		/* read, not present */
+			if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+				goto bad_area;
 	}
+	handler(tsk, vma, address, write);
+	up(&mm->mmap_sem);
 	/*
 	 * Did it hit the DOS screen memory VA from vm86 mode?
 	 */
 	if (regs->eflags & VM_MASK) {
 		unsigned long bit = (address - 0xA0000) >> PAGE_SHIFT;
 		if (bit < 32)
-			current->tss.screen_bitmap |= 1 << bit;
-	}
-	if (error_code & 1) {
-#ifdef TEST_VERIFY_AREA
-		if (regs->cs == KERNEL_CS)
-			printk("WP fault at %08lx\n", regs->eip);
-#endif
-		do_wp_page(current, vma, address, error_code & 2);
-		return;
+			tsk->tss.screen_bitmap |= 1 << bit;
 	}
-	do_no_page(current, vma, address, error_code & 2);
 	return;
 
 /*
@@ -100,11 +109,12 @@
  * Fix it, but check if it's kernel or user first..
  */
 bad_area:
+	up(&mm->mmap_sem);
 	if (error_code & 4) {
-		current->tss.cr2 = address;
-		current->tss.error_code = error_code;
-		current->tss.trap_no = 14;
-		force_sig(SIGSEGV, current);
+		tsk->tss.cr2 = address;
+		tsk->tss.error_code = error_code;
+		tsk->tss.trap_no = 14;
+		force_sig(SIGSEGV, tsk);
 		return;
 	}
 /*
@@ -128,7 +138,7 @@
 	printk(" at virtual address %08lx\n",address);
 	__asm__("movl %%cr3,%0" : "=r" (page));
 	printk(KERN_ALERT "current->tss.cr3 = %08lx, %%cr3 = %08lx\n",
-		current->tss.cr3, page);
+		tsk->tss.cr3, page);
 	page = ((unsigned long *) page)[address >> 22];
 	printk(KERN_ALERT "*pde = %08lx\n", page);
 	if (page & 1) {
diff -u --recursive --new-file v2.0.18/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c
--- v2.0.18/linux/drivers/block/ide-tape.c	Wed Aug 21 09:18:07 1996
+++ linux/drivers/block/ide-tape.c	Tue Sep 10 19:50:32 1996
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/block/ide-tape.c	Version 1.6 - ALPHA	Aug  16, 1996
+ * linux/drivers/block/ide-tape.c	Version 1.7 - ALPHA	Sep  10, 1996
  *
  * Copyright (C) 1995, 1996 Gadi Oxman <gadio@netvision.net.il>
  *
@@ -32,7 +32,7 @@
  * ht0		major=37,minor=0	first IDE tape, rewind on close.
  * nht0		major=37,minor=128	first IDE tape, no rewind on close.
  *
- * Run /usr/src/linux/drivers/block/MAKEDEV.ide to create the above entries.
+ * Run /usr/src/linux/scripts/MAKEDEV.ide to create the above entries.
  * We currently support only one ide tape drive.
  *
  * The general magnetic tape commands compatible interface, as defined by
@@ -186,6 +186,7 @@
  *                       Fixed nasty null dereferencing bug.
  * Ver 1.6   Aug 16 96   Fixed FPU usage in the driver.
  *                       Fixed end of media bug.
+ * Ver 1.7   Sep 10 96   Minor changes for the CONNER CTT8000-A model.
  *
  * We are currently in an *alpha* stage. The driver is not complete and not
  * much tested. I would strongly suggest to:
@@ -1079,6 +1080,7 @@
 	printk ("LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
 	printk ("IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
 	printk ("IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
+	printk ("ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
 	printk ("PIO Cycle Timing Category: %d\n",id->tPIO);
 	printk ("DMA Cycle Timing Category: %d\n",id->tDMA);
 	printk ("Single Word DMA supported modes: ");
@@ -1487,7 +1489,9 @@
 		if (!pc->abort) {
 			printk ("ide-tape: %s: I/O error, ",drive->name);
 			printk ("pc = %x, key = %x, asc = %x, ascq = %x\n",pc->c[0],tape->sense_key,tape->asc,tape->ascq);
+#if IDETAPE_DEBUG_LOG
 			printk ("ide-tape: Maximum retries reached - Giving up\n");
+#endif /* IDETAPE_DEBUG_LOG */
 			pc->error=1;					/* Giving up */
 		}
 		tape->failed_pc=NULL;
@@ -1678,15 +1682,15 @@
 	if (!pc->writing) {					/* Reading - Check that we have enough space */
 		temp=(unsigned long) pc->actually_transferred + bcount.all;
 		if ( temp > pc->request_transfer) {
-			printk ("ide-tape: The tape wants to send us more data than requested - ");
 			if (temp > pc->buffer_size) {
-				printk ("Discarding data\n");
+				printk ("ide-tape: The tape wants to send us more data than requested - discarding data\n");
 				idetape_discard_data (drive,bcount.all);
 				ide_set_handler (drive,&idetape_pc_intr,WAIT_CMD);
 				return;
 			}
-			else
-				printk ("Allowing transfer\n");
+#if IDETAPE_DEBUG_LOG
+			printk ("ide-tape: The tape wants to send us more data than requested - allowing transfer\n");
+#endif /* IDETAPE_DEBUG_LOG */
 		}
 	}
 #if IDETAPE_DEBUG_BUGS	
@@ -2925,7 +2929,7 @@
 		printk ("ide-tape: The block device interface should not be used for data transfers.\n");
 		printk ("ide-tape: Use the character device interfaces\n");
 		printk ("ide-tape: /dev/ht0 and /dev/nht0 instead.\n");
-		printk ("ide-tape: (Run linux/drivers/block/MAKEDEV.ide to create them)\n");
+		printk ("ide-tape: (Run linux/scripts/MAKEDEV.ide to create them)\n");
 		printk ("ide-tape: Aborting request.\n");
 
 		ide_end_request (0,HWGROUP (drive));			/* Let the common code handle it */
diff -u --recursive --new-file v2.0.18/linux/drivers/block/ide-tape.h linux/drivers/block/ide-tape.h
--- v2.0.18/linux/drivers/block/ide-tape.h	Wed Aug 21 09:18:07 1996
+++ linux/drivers/block/ide-tape.h	Tue Sep 10 19:50:32 1996
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/block/ide-tape.h	Version 1.5 - ALPHA	Apr  12, 1996
+ * linux/drivers/block/ide-tape.h	Version 1.7 - ALPHA	Sep  10, 1996
  *
  * Copyright (C) 1995, 1996 Gadi Oxman <gadio@netvision.net.il>
  */
@@ -238,7 +238,7 @@
  */
  
 #define	IDETAPE_DSC_READ_WRITE_FALLBACK_FREQUENCY   5*HZ/100	/* 50 msec */
-#define IDETAPE_DSC_READ_WRITE_LOWEST_FREQUENCY	30*HZ/100	/* 300 msec */
+#define IDETAPE_DSC_READ_WRITE_LOWEST_FREQUENCY	40*HZ/100	/* 400 msec */
 #define	IDETAPE_DSC_FAST_MEDIA_ACCESS_FREQUENCY	1*HZ		/* 1 second */
 #define	IDETAPE_FAST_SLOW_THRESHOLD		5*60*HZ		/* 5 minutes */
 #define IDETAPE_DSC_SLOW_MEDIA_ACCESS_FREQUENCY	60*HZ		/* 1 minute */
diff -u --recursive --new-file v2.0.18/linux/drivers/block/triton.c linux/drivers/block/triton.c
--- v2.0.18/linux/drivers/block/triton.c	Sat Aug 17 21:19:26 1996
+++ linux/drivers/block/triton.c	Tue Sep 10 19:50:32 1996
@@ -127,7 +127,8 @@
  * known to work fine with this interface under Linux.
  */
 const char *good_dma_drives[] = {"Micropolis 2112A",
-				 "CONNER CTMA 4000"};
+				 "CONNER CTMA 4000",
+				 "CONNER CTT8000-A"};
 
 /*
  * Our Physical Region Descriptor (PRD) table should be large enough
diff -u --recursive --new-file v2.0.18/linux/drivers/char/psaux.c linux/drivers/char/psaux.c
--- v2.0.18/linux/drivers/char/psaux.c	Thu Aug 29 19:15:14 1996
+++ linux/drivers/char/psaux.c	Mon Sep  9 15:14:53 1996
@@ -567,6 +567,7 @@
 void cleanup_module(void)
 {
 	misc_deregister(&psaux_mouse);
+	kfree(queue);
 }
 #endif
 
diff -u --recursive --new-file v2.0.18/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.0.18/linux/drivers/char/tty_io.c	Sun Sep  8 19:50:20 1996
+++ linux/drivers/char/tty_io.c	Sat Sep  7 18:09:14 1996
@@ -777,8 +777,9 @@
 		ret = write(tty, file, buf, size);
 		if (ret <= 0)
 			break;
-		count -= ret;
 		written += ret;
+		buf += ret;
+		count -= ret;
 		if (!count)
 			break;
 		ret = -ERESTARTSYS;
diff -u --recursive --new-file v2.0.18/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- v2.0.18/linux/drivers/net/de4x5.c	Wed Aug 21 09:18:08 1996
+++ linux/drivers/net/de4x5.c	Tue Sep 10 09:08:32 1996
@@ -210,11 +210,13 @@
       0.44   13-Aug-96    Fix RX overflow bug in 2114[023] chips.
                           Fix EISA probe bugs reported by <os2@kpi.kharkov.ua>
 			  and <michael@compurex.com>
+      0.441   9-Sep-96    Change dc21041_autoconf() to probe quiet BNC media
+                           with a loopback packet.
 
     =========================================================================
 */
 
-static const char *version = "de4x5.c:v0.44 96/8/13 davies@wanton.lkg.dec.com\n";
+static const char *version = "de4x5.c:v0.441 96/9/9 davies@wanton.lkg.dec.com\n";
 
 #include <linux/module.h>
 
@@ -2227,12 +2229,8 @@
 	    if (sts < 0) {
 		next_tick = sts & ~TIMER_CB;
 	    } else {
-		if (!(inl(DE4X5_SISR) & SISR_SRA) && (lp->autosense == AUTO)) {
-		    lp->media = NC;
-		} else {
-		    lp->local_state++;         /* Ensure media connected */
-		    next_tick = dc21041_autoconf(dev);
-		}
+		lp->local_state++;             /* Ensure media connected */
+		next_tick = dc21041_autoconf(dev);
 	    }
 	    break;
 	    
diff -u --recursive --new-file v2.0.18/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.0.18/linux/drivers/pci/pci.c	Wed Aug 21 09:18:08 1996
+++ linux/drivers/pci/pci.c	Wed Sep 11 11:45:10 1996
@@ -69,6 +69,7 @@
 	DEVICE( DEC,		DEC_TULIP_FAST,	"DC21140"),
 	DEVICE( DEC,		DEC_FDDI,	"DEFPA"),
 	DEVICE( DEC,		DEC_TULIP_PLUS,	"DC21041"),
+	DEVICE( DEC,		DEC_21052_AB,	"DC21052-AB"),
 	DEVICE( CIRRUS,		CIRRUS_5430,	"GD 5430"),
 	DEVICE( CIRRUS,		CIRRUS_5434_4,	"GD 5434"),
 	DEVICE( CIRRUS,		CIRRUS_5434_8,	"GD 5434"),
@@ -230,8 +231,10 @@
 	DEVICE( INTEL,		INTEL_82371_1,	"82371 Triton PIIX"),
 	DEVICE( INTEL,		INTEL_82441,	"82441FX Natoma"),
 	DEVICE( INTEL,		INTEL_82439,	"82439HX Triton II"),
-	DEVICE(	INTEL,		INTEL_82371SB_0,"82371SB Natoma/Triton II PIIX"),
-	DEVICE(	INTEL,		INTEL_82371SB_1,"82371SB Natoma/Triton II PIIX"),
+	DEVICE(	INTEL,		INTEL_82371SB_0,"82371SB Natoma/Triton II PIIX3"),
+	DEVICE(	INTEL,		INTEL_82371SB_1,"82371SB Natoma/Triton II PIIX3"),
+	DEVICE( INTEL,		INTEL_82371SB_2,"82371SB Natoma/Triton II PIIX3"),
+	DEVICE( INTEL,		INTEL_82437VX,	"82437VX Triton II"),
 	DEVICE( INTEL,		INTEL_P6,	"Orion P6"),
 	DEVICE( ADAPTEC,	ADAPTEC_7850,	"AIC-7850"),
 	DEVICE( ADAPTEC,	ADAPTEC_7855,	"AIC-7855"),
@@ -433,6 +436,7 @@
 	      case PCI_CLASS_SERIAL_FIREWIRE:		return "FireWire (IEEE 1394)";
 	      case PCI_CLASS_SERIAL_ACCESS:		return "ACCESS Bus";
 	      case PCI_CLASS_SERIAL_SSA:		return "SSA";
+	      case PCI_CLASS_SERIAL_USB:		return "USB Controller";
 	      case PCI_CLASS_SERIAL_FIBER:		return "Fiber Channel";
 
 	      default:					return "Unknown class";
diff -u --recursive --new-file v2.0.18/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c
--- v2.0.18/linux/drivers/scsi/aha152x.c	Wed Aug 21 09:18:08 1996
+++ linux/drivers/scsi/aha152x.c	Sun Sep  8 19:45:09 1996
@@ -1,6 +1,6 @@
 /* aha152x.c -- Adaptec AHA-152x driver
- * Author: Juergen E. Fischer, fischer@et-inf.fho-emden.de
- * Copyright 1993, 1994, 1995, 1996 Juergen E. Fischer
+ * Author: Jürgen E. Fischer, fischer@et-inf.fho-emden.de
+ * Copyright 1993, 1994, 1995, 1996 Jürgen E. Fischer
  *
  *
  * This driver is based on
@@ -20,9 +20,12 @@
  * General Public License for more details.
  *
  *
- * $Id: aha152x.c,v 1.17 1996/08/17 16:05:14 fischer Exp fischer $
+ * $Id: aha152x.c,v 1.18 1996/09/07 20:10:40 fischer Exp $
  *
  * $Log: aha152x.c,v $
+ * Revision 1.18  1996/09/07 20:10:40  fischer
+ * - fixed can_queue handling (multiple outstanding commands working again)
+ *
  * Revision 1.17  1996/08/17 16:05:14  fischer
  * - biosparam improved
  * - interrupt verification
@@ -975,7 +978,7 @@
     shpnt->this_id=setup[i].scsiid;
   
     if(setup[i].reconnect)
-      shpnt->hostt->can_queue=AHA152X_MAXQUEUE;
+      shpnt->can_queue=AHA152X_MAXQUEUE;
 
     /* RESET OUT */
     SETBITS(SCSISEQ, SCSIRSTO);
diff -u --recursive --new-file v2.0.18/linux/drivers/scsi/aha152x.h linux/drivers/scsi/aha152x.h
--- v2.0.18/linux/drivers/scsi/aha152x.h	Wed Aug 21 09:18:09 1996
+++ linux/drivers/scsi/aha152x.h	Sun Sep  8 19:45:51 1996
@@ -2,7 +2,7 @@
 #define _AHA152X_H
 
 /*
- * $Id: aha152x.h,v 1.17 1996/08/17 16:07:38 fischer Exp fischer $
+ * $Id: aha152x.h,v 1.18 1996/09/07 20:10:26 fischer Exp $
  */
 
 #if defined(__KERNEL__)
@@ -23,7 +23,7 @@
    (unless we support more than 1 cmd_per_lun this should do) */
 #define AHA152X_MAXQUEUE 7
 
-#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.17 $"
+#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.18 $"
 
 extern struct proc_dir_entry proc_scsi_aha152x;
 
diff -u --recursive --new-file v2.0.18/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v2.0.18/linux/drivers/scsi/sr.c	Sat Aug 17 21:19:28 1996
+++ linux/drivers/scsi/sr.c	Sat Sep  7 18:13:04 1996
@@ -167,7 +167,8 @@
 	if (driver_byte(result) != 0 &&		    /* An error occurred */
 	    SCpnt->sense_buffer[0] == 0xF0 &&	    /* Sense data is valid */
 	    (SCpnt->sense_buffer[2] == MEDIUM_ERROR ||
-	     SCpnt->sense_buffer[2] == VOLUME_OVERFLOW))
+	     SCpnt->sense_buffer[2] == VOLUME_OVERFLOW ||
+	     SCpnt->sense_buffer[2] == ILLEGAL_REQUEST))
 	  {
 	    long error_sector = (SCpnt->sense_buffer[3] << 24) |
 				(SCpnt->sense_buffer[4] << 16) |
diff -u --recursive --new-file v2.0.18/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c
--- v2.0.18/linux/drivers/sound/sb_common.c	Mon Aug  5 10:13:53 1996
+++ linux/drivers/sound/sb_common.c	Tue Sep 10 10:08:12 1996
@@ -674,9 +674,6 @@
   devc->dev = num_audiodevs;
   devc->caps = hw_config->driver_use_1;
 
-  irq2devc[hw_config->irq] = devc;
-  devc->irq_ok = 0;
-
   if (snd_set_irq_handler (hw_config->irq,
 			   sbintr, "sound blaster", devc->osp) < 0)
     {
@@ -685,6 +682,9 @@
       return;
     }
 
+  irq2devc[hw_config->irq] = devc;
+  devc->irq_ok = 0;
+
   if (devc->major == 4)
     if (!sb16_set_irq_hw (devc, devc->irq))	/* Unsupported IRQ */
       {
@@ -705,7 +705,9 @@
     }
 
 #ifndef NO_SB_IRQ_TEST
-  for (n = 0; n < 3 && devc->irq_ok == 0; n++)
+  if (devc->major != 4 || devc->minor > 11) /* Not Sb16 v4.5 or v4.11 */
+  {
+    for (n = 0; n < 3 && devc->irq_ok == 0; n++)
     if (sb_dsp_command (devc, 0xf2))	/* Cause interrupt immediately */
       {
 	int             i;
@@ -723,6 +725,7 @@
     {
       DDB (printk ("IRQ test OK (IRQ%d)\n", devc->irq));
     }
+  }
 #endif
 
   request_region (hw_config->io_base, 16, "sound blaster");
diff -u --recursive --new-file v2.0.18/linux/fs/exec.c linux/fs/exec.c
--- v2.0.18/linux/fs/exec.c	Fri Jul  5 15:06:38 1996
+++ linux/fs/exec.c	Mon Sep  9 21:04:57 1996
@@ -299,7 +299,7 @@
 		mpnt->vm_offset = 0;
 		mpnt->vm_inode = NULL;
 		mpnt->vm_pte = 0;
-		insert_vm_struct(current, mpnt);
+		insert_vm_struct(current->mm, mpnt);
 		current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
 	}
 
diff -u --recursive --new-file v2.0.18/linux/fs/namei.c linux/fs/namei.c
--- v2.0.18/linux/fs/namei.c	Sun Jul  7 20:27:04 1996
+++ linux/fs/namei.c	Mon Sep  9 21:04:57 1996
@@ -32,7 +32,7 @@
 
 	if (get_fs() == KERNEL_DS)
 		return 0;
-	vma = find_vma(current, address);
+	vma = find_vma(current->mm, address);
 	if (!vma || vma->vm_start > address || !(vma->vm_flags & VM_READ))
 		return -EFAULT;
 	address = vma->vm_end - address;
diff -u --recursive --new-file v2.0.18/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c
--- v2.0.18/linux/fs/ncpfs/dir.c	Thu Jul 18 15:52:00 1996
+++ linux/fs/ncpfs/dir.c	Sun Sep  8 17:58:06 1996
@@ -252,7 +252,7 @@
 	if (c_entry == NULL) 
 	{
 		i = sizeof (struct ncp_dirent) * NCP_READDIR_CACHE_SIZE;
-		c_entry = (struct ncp_dirent *) ncp_kmalloc(i, GFP_KERNEL);
+		c_entry = (struct ncp_dirent *) vmalloc(i);
 		if (c_entry == NULL)
 		{
 			printk("ncp_readdir: no MEMORY for cache\n");
@@ -560,9 +560,8 @@
                 return;
 	}
 
-        ncp_kfree_s(c_entry,
-                    sizeof(struct ncp_dirent) * NCP_READDIR_CACHE_SIZE);
-        c_entry = NULL;
+	vfree(c_entry);
+	c_entry = NULL;
 
         DPRINTK("ncp_free_dir_cache: exit\n");
 }
diff -u --recursive --new-file v2.0.18/linux/fs/proc/mem.c linux/fs/proc/mem.c
--- v2.0.18/linux/fs/proc/mem.c	Thu May  2 16:00:28 1996
+++ linux/fs/proc/mem.c	Mon Sep  9 21:04:57 1996
@@ -23,12 +23,12 @@
  */
 #define mem_write NULL
 
-static int check_range(struct task_struct * tsk, unsigned long addr, int count)
+static int check_range(struct mm_struct * mm, unsigned long addr, int count)
 {
 	struct vm_area_struct *vma;
 	int retval;
 
-	vma = find_vma(tsk, addr);
+	vma = find_vma(mm, addr);
 	if (!vma)
 		return -EACCES;
 	if (vma->vm_start > addr)
@@ -93,7 +93,7 @@
 	if (!tsk)
 		return -ESRCH;
 	addr = file->f_pos;
-	count = check_range(tsk, addr, count);
+	count = check_range(tsk->mm, addr, count);
 	if (count < 0)
 		return count;
 	tmp = buf;
diff -u --recursive --new-file v2.0.18/linux/fs/smbfs/Makefile linux/fs/smbfs/Makefile
--- v2.0.18/linux/fs/smbfs/Makefile	Tue Nov  7 19:54:28 1995
+++ linux/fs/smbfs/Makefile	Sun Sep  8 17:58:06 1996
@@ -11,4 +11,8 @@
 O_OBJS   := proc.o sock.o inode.o file.o dir.o ioctl.o mmap.o
 M_OBJS   := $(O_TARGET)
 
+# If you want debugging output, please uncomment the following line
+
+# EXTRA_CFLAGS += -DDEBUG_SMB=1 -DDEBUG_SMB_MALLOC=1
+
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.0.18/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c
--- v2.0.18/linux/fs/smbfs/dir.c	Wed Jul  3 12:09:32 1996
+++ linux/fs/smbfs/dir.c	Sun Sep  8 17:58:06 1996
@@ -33,9 +33,6 @@
 get_pname_static(struct inode *dir, const char *name, int len,
                  char *path, int *res_len);
 
-static struct inode *
-smb_iget(struct inode *dir, char *path, struct smb_dirent *finfo);
-
 static void 
 put_pname(char *path);
 
@@ -129,17 +126,6 @@
  *  smb_readdir provides a listing in the form of filling the dirent structure.
  *  Note that dirent resides in the user space. This is to support reading of a
  *  directory "stream". 
- * Arguments:
- *  inode   ---  Pointer to to the directory.
- *  filp    ---  The directory stream. (filp->f_pos indicates
- *               position in the stream.)
- *  dirent  ---  Will hold count directory entries. (Is in user space.)
- *  count   ---  Number of entries to be read. Should indicate the total 
- *               buffer space available for filling with dirents.
- * Return values:
- *     < 0     ---  An error occurred (linux/errno.h).
- *     = 0     ---
- *     > 0     ---  Success, amount of bytes written to dirent.
  * Notes:
  *     Since we want to reduce directory lookups we revert into a
  *     dircache. It is taken rather directly out of the nfs_readdir.
@@ -462,45 +448,21 @@
    assume that path is allocated for us. */
 
 static struct inode *
-smb_iget(struct inode *dir, char *path, struct smb_dirent *finfo)
+smb_iget(struct inode *dir, char *path, struct smb_dirent *finfo,
+	 struct smb_inode_info *new_inode_info)
 {
-	struct smb_dirent newent = { 0 };
 	struct inode *inode;
-	int error, len;
-        struct smb_inode_info *new_inode_info;
+	int len;
         struct smb_inode_info *root;
 
-	if (!dir) {
-		printk("smb_iget: dir is NULL\n");
+	if (   (dir == NULL) || (path == NULL) || (finfo == NULL)
+	    || (new_inode_info == NULL))
+	{
+		printk("smb_iget: parameter is NULL\n");
 		return NULL;
 	}
 
-        if (!path) {
-                printk("smb_iget: path is NULL\n");
-                return NULL;
-        }
-
         len = strlen(path);
-        
-	if (!finfo) {
-		error = smb_proc_getattr(&(SMB_SBP(dir->i_sb)->s_server),
-                                         path, len, &newent);
-		if (error) {
-			printk("smb_iget: getattr error = %d\n", -error);
-			return NULL;
-		}		
-		finfo = &newent;
-		DPRINTK("smb_iget: Read finfo:\n");
-		DPRINTK("smb_iget: finfo->attr = 0x%X\n", finfo->attr);
-	}
-
-        new_inode_info = smb_kmalloc(sizeof(struct smb_inode_info),
-                                     GFP_KERNEL);
-
-        if (new_inode_info == NULL) {
-                printk("smb_iget: could not alloc mem for %s\n", path);
-                return NULL;
-        }
 
         new_inode_info->state = SMB_INODE_LOOKED_UP;
         new_inode_info->nused = 0;
@@ -525,6 +487,10 @@
         root->next = new_inode_info;
         
 	if (!(inode = iget(dir->i_sb, (int)new_inode_info))) {
+		new_inode_info->next->prev = new_inode_info->prev;
+		new_inode_info->prev->next = new_inode_info->next;
+		SMB_INOP(dir)->nused -= 1;
+
 		printk("smb_iget: iget failed!");
 		return NULL;
 	}
@@ -665,6 +631,8 @@
 	int error;
         int found_in_cache;
 
+	struct smb_inode_info *new_inode_info = NULL;
+
 	*result = NULL;
 
 	if (!dir || !S_ISDIR(dir->i_mode)) {
@@ -689,24 +657,29 @@
 
         result_info = smb_find_inode(SMB_SERVER(dir), name);
 
-        if (result_info != 0) {
-
+in_tree:
+        if (result_info != NULL) {
                 if (result_info->state == SMB_INODE_CACHED)
                         result_info->state = SMB_INODE_LOOKED_UP;
 
-                put_pname(name);
-
                 /* Here we convert the inode_info address into an
                    inode number */
 
                 *result = iget(dir->i_sb, (int)result_info);
+
+		if (new_inode_info != NULL)
+		{
+			smb_kfree_s(new_inode_info,
+				    sizeof(struct smb_inode_info));
+		}
+			
+                put_pname(name);
                 iput(dir);
 
-                if (*result == NULL) {
-                        return -EACCES;
-                } else {
-                        return 0;
-                }
+		if (*result == NULL) {
+			return -EACCES;
+		}
+		return 0;
         }
 
 	/* Ok, now we have made our name. We have to build a new
@@ -748,7 +721,19 @@
                 }
         }
 
-	if (!(*result = smb_iget(dir, name, &finfo))) {
+	new_inode_info = smb_kmalloc(sizeof(struct smb_inode_info),
+				     GFP_KERNEL);
+
+	/* Here somebody else might have inserted the inode */
+	result_info = smb_find_inode(SMB_SERVER(dir), name);
+	if (result_info != NULL)
+	{
+		goto in_tree;
+	}
+
+	if ((*result = smb_iget(dir, name, &finfo, new_inode_info)) == NULL)
+	{
+		smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info));
 		put_pname(name);
 		iput(dir);
 		return -EACCES;
@@ -766,6 +751,7 @@
 	int error;
 	char *path = NULL;
 	struct smb_dirent entry;
+	struct smb_inode_info *new_inode_info;
 
 	*result = NULL;
 
@@ -781,6 +767,15 @@
 		return error;
 	}
 
+	new_inode_info = smb_kmalloc(sizeof(struct smb_inode_info),
+				     GFP_KERNEL);
+	if (new_inode_info == NULL)
+	{
+		put_pname(path);
+		iput(dir);
+		return -ENOMEM;
+	}
+
         entry.attr  = 0;
         entry.ctime = CURRENT_TIME;
         entry.atime = CURRENT_TIME;
@@ -789,6 +784,7 @@
 
         error = smb_proc_create(SMB_SERVER(dir), path, len, &entry);
 	if (error < 0) {
+		smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info));
 		put_pname(path);
 		iput(dir);
 		return error;
@@ -796,7 +792,9 @@
 
         smb_invalid_dir_cache(dir->i_ino);
 
-	if (!(*result = smb_iget(dir, path, &entry)) < 0) {
+	if ((*result = smb_iget(dir, path, &entry, new_inode_info)) == NULL)
+	{
+		smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info));
 		put_pname(path);
 		iput(dir);
 		return error;
diff -u --recursive --new-file v2.0.18/linux/fs/smbfs/file.c linux/fs/smbfs/file.c
--- v2.0.18/linux/fs/smbfs/file.c	Wed Jun  5 13:22:47 1996
+++ linux/fs/smbfs/file.c	Sun Sep  8 17:58:06 1996
@@ -32,7 +32,6 @@
 smb_make_open(struct inode *i, int right)
 {
         struct smb_dirent *dirent;
-        int open_result;
 
         if (i == NULL) {
                 printk("smb_make_open: got NULL inode\n");
@@ -45,13 +44,13 @@
 
         if ((dirent->opened) == 0) {
                 /* tries max. rights */
-                open_result = smb_proc_open(SMB_SERVER(i),
-                                            dirent->path, dirent->len,
-                                            dirent);
-                if (open_result) 
+		int open_result = smb_proc_open(SMB_SERVER(i),
+						dirent->path, dirent->len,
+						dirent);
+                if (open_result)
+		{
                         return open_result;
-
-                dirent->opened = 1;
+		}
         }
 
         if (   ((right == O_RDONLY) && (   (dirent->access == O_RDONLY)
@@ -142,7 +141,8 @@
 }
 
 static int 
-smb_file_write(struct inode *inode, struct file *file, const char *buf, int count)
+smb_file_write(struct inode *inode, struct file *file, const char *buf,
+	       int count)
 {
 	int result, bufsize, to_write, already_written;
         off_t pos;
diff -u --recursive --new-file v2.0.18/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- v2.0.18/linux/fs/smbfs/inode.c	Wed Jun  5 13:22:48 1996
+++ linux/fs/smbfs/inode.c	Sun Sep  8 17:58:06 1996
@@ -121,28 +121,37 @@
 static void
 smb_put_inode(struct inode *inode)
 {
-        struct smb_dirent *finfo = SMB_FINFO(inode);
+        struct smb_dirent *finfo  = SMB_FINFO(inode);
+	struct smb_server *server = SMB_SERVER(inode);
+	struct smb_inode_info *info = SMB_INOP(inode);
+
+	int opened        = finfo->opened;
+	int mtime         = finfo->mtime;
+	int file_id       = finfo->fileid;
+	int isdir         = S_ISDIR(inode->i_mode);
+	unsigned long ino = inode->i_ino;
 
-        if (finfo->opened != 0) {
+	/* Remove the inode before closing the file, because the close
+           will sleep. This hopefully removes a race condition. */
 
-                /* smb_proc_close wants mtime in finfo */
-                finfo->mtime = inode->i_mtime;
-                
-                if (smb_proc_close(SMB_SERVER(inode), finfo)) {
-                        /* We can't do anything but complain. */
-                        printk("smb_put_inode: could not close\n");
-                }
-        }
-        
-        smb_free_inode_info(SMB_INOP(inode));
+	clear_inode(inode);
+        smb_free_inode_info(info);
 
-        if (S_ISDIR(inode->i_mode)) {
+        if (isdir)
+	{
                 DDPRINTK("smb_put_inode: put directory %ld\n",
                          inode->i_ino);
-                smb_invalid_dir_cache(inode->i_ino);
+                smb_invalid_dir_cache(ino);
         }                
 
-	clear_inode(inode);
+        if (opened != 0)
+	{
+                if (smb_proc_close(server, file_id, mtime))
+		{
+                        /* We can't do anything but complain. */
+                        DPRINTK("smb_put_inode: could not close\n");
+                }
+        }
 }
 
 static void
@@ -151,6 +160,7 @@
         struct smb_server *server = &(SMB_SBP(sb)->s_server);
 
         smb_proc_disconnect(server);
+	smb_dont_catch_keepalive(server);
 	close_fp(server->sock_file);
 
 	lock_super(sb);
@@ -299,6 +309,7 @@
 
  fail:
 	filp->f_count -= 1; 
+	smb_dont_catch_keepalive(server);
         smb_kfree_s(SMB_SBP(sb), sizeof(struct smb_sb_info));
         return NULL;
 }
diff -u --recursive --new-file v2.0.18/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c
--- v2.0.18/linux/fs/smbfs/proc.c	Thu Jul 11 13:52:06 1996
+++ linux/fs/smbfs/proc.c	Sun Sep  8 17:58:06 1996
@@ -545,6 +545,13 @@
 
         smb_lock_server(server);
 
+	if (entry->opened != 0)
+	{
+		/* Somebody else opened the file while we slept */
+		smb_unlock_server(server);
+		return 0;
+	}
+
  retry:
         p = smb_setup_header(server, SMBopen, 2, 2 + len);
         WSET(buf, smb_vwv0, 0x42); /* read/write */
@@ -585,9 +592,11 @@
         entry->size   = DVAL(buf, smb_vwv4);
         entry->access = WVAL(buf, smb_vwv6);
 
+	entry->opened = 1;
+	entry->access &= 3;
+
         smb_unlock_server(server);
 
-	entry->access &= 3;
         DPRINTK("smb_proc_open: entry->access = %d\n", entry->access);
 	return 0;
 }
@@ -595,13 +604,14 @@
 /* smb_proc_close: in finfo->mtime we can send a modification time to
    the server */
 int
-smb_proc_close(struct smb_server *server, struct smb_dirent *finfo)
+smb_proc_close(struct smb_server *server,
+	       __u16 fileid, __u32 mtime)
 {
         char *buf = server->packet;
 
 	smb_setup_header_exclusive(server, SMBclose, 3, 0);
-        WSET(buf, smb_vwv0, finfo->fileid);
-        DSET(buf, smb_vwv1, utc2local(finfo->mtime));
+        WSET(buf, smb_vwv0, fileid);
+        DSET(buf, smb_vwv1, utc2local(mtime));
 
         return smb_request_ok_unlock(server, SMBclose, 0, 0);
 }
@@ -756,24 +766,25 @@
 }
 
 
-/* smb_proc_do_create: We expect entry->attry & entry->ctime to be set. */
+/* smb_proc_create: We expect entry->attr & entry->ctime to be set. */
 
-static int
-smb_proc_do_create(struct smb_server *server, const char *path, int len, 
-                   struct smb_dirent *entry, word command)
+int
+smb_proc_create(struct smb_server *server, const char *path, int len, 
+		struct smb_dirent *entry)
 {
 	int error;
 	char *p;
         char *buf = server->packet;
+	__u16 fileid;
 
 	smb_lock_server(server);
  retry:
-	p = smb_setup_header(server, command, 3, len + 2);
+	p = smb_setup_header(server, SMBcreate, 3, len + 2);
         WSET(buf, smb_vwv0, entry->attr);
         DSET(buf, smb_vwv1, utc2local(entry->ctime));
 	smb_encode_ascii(p, path, len);
 
-	if ((error = smb_request_ok(server, command, 1, 0)) < 0) {
+	if ((error = smb_request_ok(server, SMBcreate, 1, 0)) < 0) {
                 if (smb_retry(server)) {
                         goto retry;
                 }
@@ -781,28 +792,14 @@
 		return error;
         }
 
-        entry->opened = 1;
-        entry->fileid = WVAL(buf, smb_vwv0);
+        entry->opened = 0;
+        fileid = WVAL(buf, smb_vwv0);
         smb_unlock_server(server);
 
-        smb_proc_close(server, entry);
+        smb_proc_close(server, fileid, 0);
 
 	return 0;
 }
-	
-int
-smb_proc_create(struct smb_server *server, const char *path, int len,
-                struct smb_dirent *entry)
-{
-	return smb_proc_do_create(server, path, len, entry, SMBcreate);
-}
-
-int
-smb_proc_mknew(struct smb_server *server, const char *path, int len,
-               struct smb_dirent *entry)
-{
-	return smb_proc_do_create(server, path, len, entry, SMBmknew);
-}
 
 int
 smb_proc_mv(struct smb_server *server, 
@@ -1154,6 +1151,7 @@
 
 	char *p;
 	char *lastname;
+	int   lastname_len;
 	int i;
 	int first, total_count;
         struct smb_dirent *current_entry;
@@ -1286,16 +1284,16 @@
                 p = resp_param;
                 if (first != 0)
                 {
-                        ff_dir_handle = WVAL(p,0);
+                        ff_dir_handle  = WVAL(p,0);
                         ff_searchcount = WVAL(p,2);
-                        ff_eos = WVAL(p,4);
-                        ff_lastname = WVAL(p,8);
+                        ff_eos         = WVAL(p,4);
+                        ff_lastname    = WVAL(p,8);
                 }
                 else
                 {
                         ff_searchcount = WVAL(p,0);
-                        ff_eos = WVAL(p,2);
-                        ff_lastname = WVAL(p,6);
+                        ff_eos         = WVAL(p,2);
+                        ff_lastname    = WVAL(p,6);
                 }
 
                 if (ff_searchcount == 0) 
@@ -1306,16 +1304,19 @@
 
                 /* we might need the lastname for continuations */
 		lastname = "";
+		lastname_len = 0;
                 if (ff_lastname > 0)
                 {
                         switch(info_level)
                         {
                         case 260:
-				lastname = p + ff_lastname + 94;
+				lastname = p + ff_lastname;
+				lastname_len = resp_data_len - ff_lastname;
 				ff_resume_key = 0;
                                 break;
                         case 1:
 				lastname = p + ff_lastname + 1;
+				lastname_len = strlen(lastname);
                                 ff_resume_key = 0;
                                 break;
                         }
@@ -1330,12 +1331,14 @@
 			mask = smb_kmalloc(dirlen, GFP_KERNEL);
 			if (mask == NULL)
 			{
-				printk("smb_proc_readdir_long: Memory allocation failed\n");
+				printk("smb_proc_readdir_long: "
+				       "Memory allocation failed\n");
 				result = -ENOMEM;
 				break;
 			}
-			strcpy(mask, lastname);
 		}
+		strncpy(mask, lastname, lastname_len);
+		mask[lastname_len] = '\0';
   
 		/* Now we are ready to parse smb directory entries. */
 		
@@ -1475,6 +1478,8 @@
                 int result = 0;
                 struct smb_dirent temp_entry;
 
+		memset(&temp_entry, 0, sizeof(temp_entry));
+
                 if ((result=smb_proc_open(server,path,len,
                                           &temp_entry)) < 0) {
                         /* We cannot open directories, so we try to use the
@@ -1489,8 +1494,8 @@
                         entry->ctime = temp_entry.ctime;
                         entry->size  = temp_entry.size;
                 }
-                
-                smb_proc_close(server, &temp_entry);
+
+                smb_proc_close(server, temp_entry.fileid, temp_entry.mtime);
                 return result;
 
         } else {
@@ -1824,7 +1829,6 @@
                 smb_decode_word(server->packet+32, &(server->server_uid));
         }
         else
-
         {
                 server->maxxmt = 0;
                 server->maxmux = 0;
@@ -1838,6 +1842,7 @@
 	smb_setup_header(server, SMBtcon, 0,
                          6 + strlen(server->m.service) +
                          strlen(server->m.password) + strlen(dev));
+
 	p = SMB_BUF(server->packet);
 	p = smb_encode_ascii(p, server->m.service, strlen(server->m.service));
 	p = smb_encode_ascii(p,server->m.password, strlen(server->m.password));
@@ -1891,11 +1896,14 @@
 {
         int result;
         smb_lock_server(server);
+
         result = smb_proc_reconnect(server);
+
         if ((result < 0) && (server->packet != NULL)) {
                 smb_kfree_s(server->packet, server->max_xmit);
                 server->packet = NULL;
         }
+
         smb_unlock_server(server);
         return result;
 }
diff -u --recursive --new-file v2.0.18/linux/fs/smbfs/sock.c linux/fs/smbfs/sock.c
--- v2.0.18/linux/fs/smbfs/sock.c	Wed Jun  5 13:22:48 1996
+++ linux/fs/smbfs/sock.c	Sun Sep  8 17:58:06 1996
@@ -24,8 +24,9 @@
 
 #define _S(nr) (1<<((nr)-1))
 
-static int _recvfrom(struct socket *sock, unsigned char *ubuf, int size, int noblock, unsigned flags,
-                struct sockaddr_in *sa, int *addr_len)
+static int
+_recvfrom(struct socket *sock, unsigned char *ubuf, int size,
+	  int noblock, unsigned flags, struct sockaddr_in *sa, int *addr_len)
 {
         struct iovec iov;
         struct msghdr msg;
@@ -44,7 +45,10 @@
         return sock->ops->recvmsg(sock, &msg, size, noblock, flags, addr_len);
 }
 
-static int _send(struct socket *sock, const void *buff, int len, int nonblock, unsigned flags) {
+static int
+_send(struct socket *sock, const void *buff, int len,
+      int nonblock, unsigned flags)
+{
         struct iovec iov;
         struct msghdr msg;
 
diff -u --recursive --new-file v2.0.18/linux/fs/super.c linux/fs/super.c
--- v2.0.18/linux/fs/super.c	Sat Aug 10 10:03:15 1996
+++ linux/fs/super.c	Mon Sep  9 21:04:57 1996
@@ -794,7 +794,7 @@
 	if (!data)
 		return 0;
 
-	vma = find_vma(current, (unsigned long) data);
+	vma = find_vma(current->mm, (unsigned long) data);
 	if (!vma || (unsigned long) data < vma->vm_start)
 		return -EFAULT;
 	if (!(vma->vm_flags & VM_READ))
diff -u --recursive --new-file v2.0.18/linux/include/asm-alpha/semaphore.h linux/include/asm-alpha/semaphore.h
--- v2.0.18/linux/include/asm-alpha/semaphore.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-alpha/semaphore.h	Wed Sep 11 14:18:02 1996
@@ -0,0 +1,43 @@
+#ifndef _ALPHA_SEMAPHORE_H
+#define _ALPHA_SEMAPHORE_H
+
+/*
+ * SMP- and interrupt-safe semaphores..
+ *
+ * (C) Copyright 1996 Linus Torvalds
+ */
+
+struct semaphore {
+	int count;
+	int waiting;
+	struct wait_queue * wait;
+};
+
+#define MUTEX ((struct semaphore) { 1, 0, NULL })
+#define MUTEX_LOCKED ((struct semaphore) { 0, 0, NULL })
+
+extern void __down(struct semaphore * sem);
+extern void wake_up(struct wait_queue ** p);
+
+/*
+ * These are not yet interrupt-safe: should use ldl_l/stl_c here..
+ *
+ * See include/asm-i386/semaphore.h on how to do this correctly
+ * without any jumps or wakeups taken for the no-contention cases.
+ */
+extern inline void down(struct semaphore * sem)
+{
+	sem->count--;
+	/* "down_failed" */
+	if (sem->count < 0)
+		__down(sem);
+}
+
+extern inline void up(struct semaphore * sem)
+{
+	sem->count++;
+	/* "up_wakeup" */
+	__up(sem);
+}	
+
+#endif
diff -u --recursive --new-file v2.0.18/linux/include/asm-i386/irq.h linux/include/asm-i386/irq.h
--- v2.0.18/linux/include/asm-i386/irq.h	Sun Sep  8 19:50:21 1996
+++ linux/include/asm-i386/irq.h	Tue Sep 10 10:17:55 1996
@@ -90,7 +90,7 @@
 	"outb %al,$0x21\n\t" \
 	"jmp 1f\n" \
 	"1:\tjmp 1f\n" \
-	"1:\tmovb $0x60+"#nr",%al\n\t" \
+	"1:\tmovb $0x20,%al\n\t" \
 	"outb %al,$0x20\n\t"
 
 #define ACK_SECOND(mask,nr) \
@@ -102,12 +102,11 @@
 	"outb %al,$0xA1\n\t" \
 	"jmp 1f\n" \
 	"1:\tjmp 1f\n" \
-	"1:\tmovb $0x60+"#nr",%al\n\t" \
+	"1:\tmovb $0x20,%al\n\t" \
 	"outb %al,$0xA0\n\t" \
 	"jmp 1f\n" \
 	"1:\tjmp 1f\n" \
-	"1:\tmovb $0x62,%al\n\t" \
-	"outb %al,$0x20\n\t"
+	"1:\toutb %al,$0x20\n\t"
 
 #define UNBLK_FIRST(mask) \
 	"inb $0x21,%al\n\t" \
diff -u --recursive --new-file v2.0.18/linux/include/asm-i386/semaphore.h linux/include/asm-i386/semaphore.h
--- v2.0.18/linux/include/asm-i386/semaphore.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-i386/semaphore.h	Wed Sep 11 13:17:14 1996
@@ -0,0 +1,65 @@
+#ifndef _I386_SEMAPHORE_H
+#define _I386_SEMAPHORE_H
+
+/*
+ * SMP- and interrupt-safe semaphores..
+ *
+ * (C) Copyright 1996 Linus Torvalds
+ */
+
+struct semaphore {
+	int count;
+	int waiting;
+	struct wait_queue * wait;
+};
+
+#define MUTEX ((struct semaphore) { 1, 0, NULL })
+#define MUTEX_LOCKED ((struct semaphore) { 0, 0, NULL })
+
+extern void __down(struct semaphore * sem);
+extern void wake_up(struct wait_queue ** p);
+
+/*
+ * This is ugly, but we want the default case to fall through.
+ * "down_failed" is a special asm handler that calls the C
+ * routine that actually waits. See arch/i386/lib/semaphore.S
+ */
+extern inline void down(struct semaphore * sem)
+{
+	__asm__ __volatile__(
+		"# atomic down operation\n"
+		"1:\n\t"
+		"leal 1b,%%eax\n\t"
+#ifdef __SMP__
+		"lock ; "
+#endif
+		"decl %0\n\t"
+		"js down_failed"
+		:/* no outputs */
+		:"m" (sem->count), "c" (sem)
+		:"ax","dx","memory");
+}
+
+/*
+ * Note! This is subtle. We jump to wake people up only if
+ * the semaphore was negative (== somebody was waiting on it).
+ * The default case (no contention) will result in NO
+ * jumps for both down() and up().
+ */
+extern inline void up(struct semaphore * sem)
+{
+	__asm__ __volatile__(
+		"# atomic up operation\n\t"
+		"leal 1f,%%eax\n\t"
+#ifdef __SMP__
+		"lock ; "
+#endif
+		"incl %0\n\t"
+		"jle up_wakeup\n"
+		"1:"
+		:/* no outputs */
+		:"m" (sem->count), "c" (sem)
+		:"ax", "dx", "memory");
+}
+
+#endif
diff -u --recursive --new-file v2.0.18/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.0.18/linux/include/linux/fs.h	Sun Sep  8 19:50:21 1996
+++ linux/include/linux/fs.h	Wed Sep 11 14:36:23 1996
@@ -16,6 +16,8 @@
 #include <linux/kdev_t.h>
 #include <linux/ioctl.h>
 
+#include <asm/semaphore.h>
+
 /*
  * It's silly to have NR_OPEN bigger than NR_FILE, but I'll fix
  * that later. Anyway, now the file code is no longer dependent
diff -u --recursive --new-file v2.0.18/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.0.18/linux/include/linux/mm.h	Sat Aug 10 10:03:15 1996
+++ linux/include/linux/mm.h	Wed Sep 11 14:36:23 1996
@@ -285,8 +285,8 @@
 /* mmap.c */
 extern unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
 	unsigned long prot, unsigned long flags, unsigned long off);
-extern void merge_segments(struct task_struct *, unsigned long, unsigned long);
-extern void insert_vm_struct(struct task_struct *, struct vm_area_struct *);
+extern void merge_segments(struct mm_struct *, unsigned long, unsigned long);
+extern void insert_vm_struct(struct mm_struct *, struct vm_area_struct *);
 extern void remove_shared_vm_struct(struct vm_area_struct *);
 extern void build_mmap_avl(struct mm_struct *);
 extern void exit_mmap(struct mm_struct *);
@@ -334,12 +334,12 @@
 #define avl_empty	(struct vm_area_struct *) NULL
 
 /* Look up the first VMA which satisfies  addr < vm_end,  NULL if none. */
-static inline struct vm_area_struct * find_vma (struct task_struct * task, unsigned long addr)
+static inline struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr)
 {
 	struct vm_area_struct * result = NULL;
 
-	if (task->mm) {
-		struct vm_area_struct * tree = task->mm->mmap_avl;
+	if (mm) {
+		struct vm_area_struct * tree = mm->mmap_avl;
 		for (;;) {
 			if (tree == avl_empty)
 				break;
@@ -357,13 +357,13 @@
 
 /* Look up the first VMA which intersects the interval start_addr..end_addr-1,
    NULL if none.  Assume start_addr < end_addr. */
-static inline struct vm_area_struct * find_vma_intersection (struct task_struct * task, unsigned long start_addr, unsigned long end_addr)
+static inline struct vm_area_struct * find_vma_intersection(struct mm_struct * mm, unsigned long start_addr, unsigned long end_addr)
 {
 	struct vm_area_struct * vma;
 
-	vma = find_vma(task,start_addr);
-	if (!vma || end_addr <= vma->vm_start)
-		return NULL;
+	vma = find_vma(mm,start_addr);
+	if (vma && end_addr <= vma->vm_start)
+		vma = NULL;
 	return vma;
 }
 
diff -u --recursive --new-file v2.0.18/linux/include/linux/pagemap.h linux/include/linux/pagemap.h
--- v2.0.18/linux/include/linux/pagemap.h	Sun Sep  8 19:50:21 1996
+++ linux/include/linux/pagemap.h	Wed Sep 11 14:36:23 1996
@@ -71,16 +71,21 @@
 
 static inline void remove_page_from_hash_queue(struct page * page)
 {
-	struct page **p = page_hash(page->inode,page->offset);
+	struct page **p;
+	struct page *next_hash, *prev_hash;
 
-	page_cache_size--;
-	if (page->next_hash)
-		page->next_hash->prev_hash = page->prev_hash;
-	if (page->prev_hash)
-		page->prev_hash->next_hash = page->next_hash;
+	next_hash = page->next_hash;
+	prev_hash = page->prev_hash;
+	page->next_hash = NULL;
+	page->prev_hash = NULL;
+	if (next_hash)
+		next_hash->prev_hash = prev_hash;
+	if (prev_hash)
+		prev_hash->next_hash = next_hash;
+	p = page_hash(page->inode,page->offset);
 	if (*p == page)
-		*p = page->next_hash;
-	page->next_hash = page->prev_hash = NULL;
+		*p = next_hash;
+	page_cache_size--;
 }
 
 static inline void __add_page_to_hash_queue(struct page * page, struct page **p)
diff -u --recursive --new-file v2.0.18/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.0.18/linux/include/linux/pci.h	Wed Aug 21 09:18:10 1996
+++ linux/include/linux/pci.h	Wed Sep 11 11:45:10 1996
@@ -264,6 +264,7 @@
 #define PCI_DEVICE_ID_DEC_TULIP_FAST	0x0009
 #define PCI_DEVICE_ID_DEC_FDDI		0x000F
 #define PCI_DEVICE_ID_DEC_TULIP_PLUS	0x0014
+#define PCI_DEVICE_ID_DEC_21052_AB	0x0021
 
 #define PCI_VENDOR_ID_CIRRUS		0x1013
 #define PCI_DEVICE_ID_CIRRUS_5430	0x00a0
@@ -555,6 +556,8 @@
 #define PCI_DEVICE_ID_INTEL_82439	0x1250
 #define PCI_DEVICE_ID_INTEL_82371SB_0	0x7000
 #define PCI_DEVICE_ID_INTEL_82371SB_1	0x7010
+#define PCI_DEVICE_ID_INTEL_82371SB_2	0x7020
+#define PCI_DEVICE_ID_INTEL_82437VX	0x7030
 #define PCI_DEVICE_ID_INTEL_P6		0x84c4
 
 #define PCI_VENDOR_ID_ADAPTEC		0x9004
diff -u --recursive --new-file v2.0.18/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.0.18/linux/include/linux/sched.h	Mon Sep  2 15:18:26 1996
+++ linux/include/linux/sched.h	Wed Sep 11 14:36:23 1996
@@ -17,7 +17,9 @@
 #include <linux/personality.h>
 #include <linux/tasks.h>
 #include <linux/kernel.h>
+
 #include <asm/system.h>
+#include <asm/semaphore.h>
 #include <asm/page.h>
 
 #include <linux/smp.h>
@@ -146,6 +148,7 @@
 	unsigned long def_flags;
 	struct vm_area_struct * mmap;
 	struct vm_area_struct * mmap_avl;
+	struct semaphore mmap_sem;
 };
 
 #define INIT_MM { \
@@ -157,7 +160,7 @@
 		0, 0, 0, 0, \
 		0, 0, 0, \
 		0, \
-		&init_mmap, &init_mmap }
+		&init_mmap, &init_mmap, MUTEX }
 
 struct signal_struct {
 	int count;
@@ -458,24 +461,6 @@
 	add_wait_queue(wait_address,&entry->wait);
 	p->nr++;
 }
-
-extern void __down(struct semaphore * sem);
-
-/*
- * These are not yet interrupt-safe
- */
-extern inline void down(struct semaphore * sem)
-{
-	if (sem->count <= 0)
-		__down(sem);
-	sem->count--;
-}
-
-extern inline void up(struct semaphore * sem)
-{
-	sem->count++;
-	wake_up(&sem->wait);
-}	
 
 #define REMOVE_LINKS(p) do { unsigned long flags; \
 	save_flags(flags) ; cli(); \
diff -u --recursive --new-file v2.0.18/linux/include/linux/smb_fs.h linux/include/linux/smb_fs.h
--- v2.0.18/linux/include/linux/smb_fs.h	Thu Jul 25 20:31:45 1996
+++ linux/include/linux/smb_fs.h	Wed Sep 11 14:41:26 1996
@@ -124,7 +124,8 @@
 byte *smb_encode_smb_length(byte *p, dword len);
 int smb_proc_open(struct smb_server *server, const char *pathname,
                   int len, struct smb_dirent *entry);
-int smb_proc_close(struct smb_server *server, struct smb_dirent *finfo);
+int smb_proc_close(struct smb_server *server, 
+		   __u16 fileid, __u32 mtime);
 int smb_proc_read(struct smb_server *server, struct smb_dirent *finfo, 
 		  off_t offset, long count, char *data, int fs);
 int smb_proc_read_raw(struct smb_server *server, struct smb_dirent *finfo, 
@@ -135,8 +136,6 @@
                        off_t offset, long count, const char *data);
 int smb_proc_create(struct smb_server *server, const char *path,
                     int len, struct smb_dirent *entry);
-int smb_proc_mknew(struct smb_server *server, const char *path, int len,
-                   struct smb_dirent *entry);
 int smb_proc_mv(struct smb_server *server, const char *opath, const int olen, 
 		const char *npath, const int nlen);
 int smb_proc_mkdir(struct smb_server *server, const char *path, const int len);
diff -u --recursive --new-file v2.0.18/linux/include/linux/wait.h linux/include/linux/wait.h
--- v2.0.18/linux/include/linux/wait.h	Sun Sep  1 09:15:33 1996
+++ linux/include/linux/wait.h	Mon Sep  9 16:09:16 1996
@@ -26,14 +26,6 @@
 	return head && head != WAIT_QUEUE_HEAD(q);
 }
 
-struct semaphore {
-	int count;
-	struct wait_queue * wait;
-};
-
-#define MUTEX ((struct semaphore) { 1, NULL })
-#define MUTEX_LOCKED ((struct semaphore) { 0, NULL })
-
 struct select_table_entry {
 	struct wait_queue wait;
 	struct wait_queue ** wait_address;
diff -u --recursive --new-file v2.0.18/linux/init/main.c linux/init/main.c
--- v2.0.18/linux/init/main.c	Sun Sep  8 19:50:21 1996
+++ linux/init/main.c	Wed Sep 11 11:44:54 1996
@@ -799,6 +799,7 @@
 		prof_len = (unsigned long) &_etext - (unsigned long) &_stext;
 		prof_len >>= prof_shift;
 		memory_start += prof_len * sizeof(unsigned int);
+		memset(prof_buffer, 0, prof_len * sizeof(unsigned int));
 	}
 	memory_start = console_init(memory_start,memory_end);
 #ifdef CONFIG_PCI
@@ -968,7 +969,7 @@
 
 	if ((open("/dev/tty1",O_RDWR,0) < 0) &&
 	    (open("/dev/ttyS0",O_RDWR,0) < 0))
-		printk("Unable to open a initial console.\n");
+		printk("Unable to open an initial console.\n");
 			
 	(void) dup(0);
 	(void) dup(0);
diff -u --recursive --new-file v2.0.18/linux/ipc/shm.c linux/ipc/shm.c
--- v2.0.18/linux/ipc/shm.c	Sun Sep  1 09:15:34 1996
+++ linux/ipc/shm.c	Mon Sep  9 21:04:57 1996
@@ -425,8 +425,8 @@
 
 	/* add new mapping */
 	current->mm->total_vm += (shmd->vm_end - shmd->vm_start) >> PAGE_SHIFT;
-	insert_vm_struct(current, shmd);
-	merge_segments(current, shmd->vm_start, shmd->vm_end);
+	insert_vm_struct(current->mm, shmd);
+	merge_segments(current->mm, shmd->vm_start, shmd->vm_end);
 
 	/* map page range */
 	error = 0;
@@ -505,7 +505,7 @@
 		return -EINVAL;
 	}
 	if (!(shmflg & SHM_REMAP))
-		if ((shmd = find_vma_intersection(current, addr, addr + shp->shm_segsz))) {
+		if ((shmd = find_vma_intersection(current->mm, addr, addr + shp->shm_segsz))) {
 			/* printk("shmat() -> EINVAL because the interval [0x%lx,0x%lx) intersects an already mapped interval [0x%lx,0x%lx).\n",
 				addr, addr + shp->shm_segsz, shmd->vm_start, shmd->vm_end); */
 			return -EINVAL;
diff -u --recursive --new-file v2.0.18/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.0.18/linux/kernel/ksyms.c	Thu Jul 18 14:28:48 1996
+++ linux/kernel/ksyms.c	Mon Sep  9 21:04:57 1996
@@ -121,8 +121,6 @@
 	X(verify_area),
 	X(do_mmap),
 	X(do_munmap),
-	X(insert_vm_struct),
-	X(merge_segments),
 	X(exit_mm),
 
 	/* internal kernel memory management */
diff -u --recursive --new-file v2.0.18/linux/kernel/sched.c linux/kernel/sched.c
--- v2.0.18/linux/kernel/sched.c	Sun Sep  8 19:50:21 1996
+++ linux/kernel/sched.c	Wed Sep 11 15:15:44 1996
@@ -482,17 +482,88 @@
 	printk("       *q = %p\n",*q);
 }
 
+/*
+ * Semaphores are implemented using a two-way counter:
+ * The "count" variable is decremented for each process
+ * that tries to sleep, while the "waiting" variable is
+ * incremented _while_ the process is sleeping on that
+ * semaphore. 
+ *
+ * Notably, the inline "up()" and "down()" functions can
+ * efficiently test if they need to do any extra work (up
+ * needs to do something only if count was negative before
+ * the increment operation.
+ */
+static inline void normalize_semaphore(struct semaphore *sem)
+{
+	atomic_add(xchg(&sem->waiting,0), &sem->count);
+}
+
+/*
+ * When __up() is called, the count was negative before
+ * incrementing it, and we need to wake up somebody. In
+ * most cases "waiting" will be positive, and the normalization
+ * will allow things to continue. However, if somebody has
+ * /just/ done a down(), it may be that count was negative
+ * without waiting being positive (or in the generic case
+ * "count is more negative than waiting is positive"), and
+ * the waiter needs to check this itself (see __down).
+ *
+ * Note that these functions are only called when there is
+ * contention on the lock, and as such all this is the
+ * "non-critical" part of the whole semaphore business. The
+ * critical part is the inline stuff in <asm/semaphore.h>
+ * where we want to avoid any extra jumps and calls.
+ */
+inline void __up(struct semaphore *sem)
+{
+	normalize_semaphore(sem);
+	wake_up(&sem->wait);
+}
+
 void __down(struct semaphore * sem)
 {
-	struct wait_queue wait = { current, NULL };
+	struct task_struct *tsk = current;
+	struct wait_queue wait = { tsk, NULL };
+
+	/*
+	 * The order here is important. We add ourselves to the
+	 * wait queues and mark ourselves sleeping _first_. That
+	 * way, if a "up()" comes in here, we'll either get
+	 * woken up (up happens after the wait queues are set up)
+	 * OR we'll have "waiting > 0".
+	 */
+	tsk->state = TASK_UNINTERRUPTIBLE;
 	add_wait_queue(&sem->wait, &wait);
-	current->state = TASK_UNINTERRUPTIBLE;
-	while (sem->count <= 0) {
-		schedule();
-		current->state = TASK_UNINTERRUPTIBLE;
+	atomic_inc(&sem->waiting);
+
+	/*
+	 * Ok, we're set up. The only race here is really that
+	 * an "up()" might have incremented count before we got
+	 * here, so we check "count+waiting". If that is larger
+	 * than zero, we shouldn't sleep, but re-try the lock.
+	 */
+	if (sem->count+sem->waiting <= 0) {
+		/*
+		 * If "count+waiting" <= 0, we have to wait
+		 * for a up(), which will normalize the count.
+		 * Remember, at this point we have decremented
+		 * count, and incremented up, so if count is
+		 * zero or positive we need to return to re-try
+		 * the lock.  It _may_ be that both count and
+		 * waiting is zero and that it is still locked,
+		 * but we still want to re-try the lock in that
+		 * case to make count go negative again so that
+		 * the optimized "up()" wake_up sequence works.
+		 */
+		do {
+			schedule();
+			tsk->state = TASK_UNINTERRUPTIBLE;
+		} while (sem->count < 0);
 	}
-	current->state = TASK_RUNNING;
+	tsk->state = TASK_RUNNING;
 	remove_wait_queue(&sem->wait, &wait);
+	normalize_semaphore(sem);
 }
 
 static inline void __sleep_on(struct wait_queue **p, int state)
diff -u --recursive --new-file v2.0.18/linux/mm/filemap.c linux/mm/filemap.c
--- v2.0.18/linux/mm/filemap.c	Sun Sep  8 19:50:22 1996
+++ linux/mm/filemap.c	Mon Sep  9 21:04:57 1996
@@ -1230,7 +1230,7 @@
 	 * If the interval [start,end) covers some unmapped address ranges,
 	 * just ignore them, but return -EFAULT at the end.
 	 */
-	vma = find_vma(current, start);
+	vma = find_vma(current->mm, start);
 	unmapped_error = 0;
 	for (;;) {
 		/* Still start < end. */
diff -u --recursive --new-file v2.0.18/linux/mm/memory.c linux/mm/memory.c
--- v2.0.18/linux/mm/memory.c	Sat Aug 17 21:19:29 1996
+++ linux/mm/memory.c	Mon Sep  9 21:04:57 1996
@@ -686,7 +686,7 @@
 	if (!size || get_fs() == KERNEL_DS)
 		return 0;
 
-	vma = find_vma(current, start);
+	vma = find_vma(current->mm, start);
 	if (!vma)
 		goto bad_area;
 	if (vma->vm_start > start)
diff -u --recursive --new-file v2.0.18/linux/mm/mlock.c linux/mm/mlock.c
--- v2.0.18/linux/mm/mlock.c	Sun Feb 25 11:17:59 1996
+++ linux/mm/mlock.c	Mon Sep  9 21:04:57 1996
@@ -40,7 +40,7 @@
 		n->vm_inode->i_count++;
 	if (n->vm_ops && n->vm_ops->open)
 		n->vm_ops->open(n);
-	insert_vm_struct(current, n);
+	insert_vm_struct(current->mm, n);
 	return 0;
 }
 
@@ -61,7 +61,7 @@
 		n->vm_inode->i_count++;
 	if (n->vm_ops && n->vm_ops->open)
 		n->vm_ops->open(n);
-	insert_vm_struct(current, n);
+	insert_vm_struct(current->mm, n);
 	return 0;
 }
 
@@ -93,8 +93,8 @@
 		vma->vm_ops->open(left);
 		vma->vm_ops->open(right);
 	}
-	insert_vm_struct(current, left);
-	insert_vm_struct(current, right);
+	insert_vm_struct(current->mm, left);
+	insert_vm_struct(current->mm, right);
 	return 0;
 }
 
@@ -148,7 +148,7 @@
 		return -EINVAL;
 	if (end == start)
 		return 0;
-	vma = find_vma(current, start);
+	vma = find_vma(current->mm, start);
 	if (!vma || vma->vm_start > start)
 		return -ENOMEM;
 
@@ -178,7 +178,7 @@
 			break;
 		}
 	}
-	merge_segments(current, start, end);
+	merge_segments(current->mm, start, end);
 	return error;
 }
 
@@ -240,7 +240,7 @@
 		if (error)
 			break;
 	}
-	merge_segments(current, 0, TASK_SIZE);
+	merge_segments(current->mm, 0, TASK_SIZE);
 	return error;
 }
 
diff -u --recursive --new-file v2.0.18/linux/mm/mmap.c linux/mm/mmap.c
--- v2.0.18/linux/mm/mmap.c	Sun Sep  8 19:50:22 1996
+++ linux/mm/mmap.c	Mon Sep  9 21:04:57 1996
@@ -66,19 +66,20 @@
 {
 	unsigned long rlim;
 	unsigned long newbrk, oldbrk;
+	struct mm_struct *mm = current->mm;
 
-	if (brk < current->mm->end_code)
-		return current->mm->brk;
+	if (brk < mm->end_code)
+		return mm->brk;
 	newbrk = PAGE_ALIGN(brk);
-	oldbrk = PAGE_ALIGN(current->mm->brk);
+	oldbrk = PAGE_ALIGN(mm->brk);
 	if (oldbrk == newbrk)
-		return current->mm->brk = brk;
+		return mm->brk = brk;
 
 	/*
 	 * Always allow shrinking brk
 	 */
-	if (brk <= current->mm->brk) {
-		current->mm->brk = brk;
+	if (brk <= mm->brk) {
+		mm->brk = brk;
 		do_munmap(newbrk, oldbrk-newbrk);
 		return brk;
 	}
@@ -88,25 +89,25 @@
 	rlim = current->rlim[RLIMIT_DATA].rlim_cur;
 	if (rlim >= RLIM_INFINITY)
 		rlim = ~0;
-	if (brk - current->mm->end_code > rlim)
-		return current->mm->brk;
+	if (brk - mm->end_code > rlim)
+		return mm->brk;
 
 	/*
 	 * Check against existing mmap mappings.
 	 */
-	if (find_vma_intersection(current, oldbrk, newbrk+PAGE_SIZE))
-		return current->mm->brk;
+	if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE))
+		return mm->brk;
 
 	/*
 	 * Check if we have enough memory..
 	 */
 	if (!vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT))
-		return current->mm->brk;
+		return mm->brk;
 
 	/*
 	 * Ok, looks good - let it rip.
 	 */
-	current->mm->brk = brk;
+	mm->brk = brk;
 	do_mmap(NULL, oldbrk, newbrk-oldbrk,
 		PROT_READ|PROT_WRITE|PROT_EXEC,
 		MAP_FIXED|MAP_PRIVATE, 0);
@@ -139,6 +140,7 @@
 unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
 	unsigned long prot, unsigned long flags, unsigned long off)
 {
+	struct mm_struct * mm = current->mm;
 	struct vm_area_struct * vma;
 
 	if ((len = PAGE_ALIGN(len)) == 0)
@@ -152,8 +154,8 @@
 		return -EINVAL;
 
 	/* mlock MCL_FUTURE? */
-	if (current->mm->def_flags & VM_LOCKED) {
-		unsigned long locked = current->mm->locked_vm << PAGE_SHIFT;
+	if (mm->def_flags & VM_LOCKED) {
+		unsigned long locked = mm->locked_vm << PAGE_SHIFT;
 		locked += len;
 		if (locked > current->rlim[RLIMIT_MEMLOCK].rlim_cur)
 			return -EAGAIN;
@@ -218,10 +220,10 @@
 	if (!vma)
 		return -ENOMEM;
 
-	vma->vm_mm = current->mm;
+	vma->vm_mm = mm;
 	vma->vm_start = addr;
 	vma->vm_end = addr + len;
-	vma->vm_flags = vm_flags(prot,flags) | current->mm->def_flags;
+	vma->vm_flags = vm_flags(prot,flags) | mm->def_flags;
 
 	if (file) {
 		if (file->f_mode & 1)
@@ -269,14 +271,14 @@
 	}
 
 	flags = vma->vm_flags;
-	insert_vm_struct(current, vma);
-	merge_segments(current, vma->vm_start, vma->vm_end);
+	insert_vm_struct(mm, vma);
+	merge_segments(mm, 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;
+	mm->total_vm += len >> PAGE_SHIFT;
 	if (flags & VM_LOCKED) {
 		unsigned long start = addr;
-		current->mm->locked_vm += len >> PAGE_SHIFT;
+		mm->locked_vm += len >> PAGE_SHIFT;
 		do {
 			char c = get_user((char *) start);
 			len -= PAGE_SIZE;
@@ -302,7 +304,7 @@
 		addr = TASK_SIZE / 3;
 	addr = PAGE_ALIGN(addr);
 
-	for (vmm = find_vma(current, addr); ; vmm = vmm->vm_next) {
+	for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
 		/* At this point:  (!vmm || addr < vmm->vm_end). */
 		if (TASK_SIZE - len < addr)
 			return 0;
@@ -752,7 +754,7 @@
 		if (mpnt->vm_ops && mpnt->vm_ops->open)
 			mpnt->vm_ops->open(mpnt);
 		area->vm_end = addr;	/* Truncate area */
-		insert_vm_struct(current, mpnt);
+		insert_vm_struct(current->mm, mpnt);
 	}
 
 	/* construct whatever mapping is needed */
@@ -766,7 +768,7 @@
 		area->vm_end = area->vm_start;
 		area->vm_ops->close(area);
 	}
-	insert_vm_struct(current, mpnt);
+	insert_vm_struct(current->mm, mpnt);
 }
 
 asmlinkage int sys_munmap(unsigned long addr, size_t len)
@@ -796,7 +798,7 @@
 	 * every area affected in some way (by any overlap) is put
 	 * on the list.  If nothing is put on, nothing is affected.
 	 */
-	mpnt = find_vma(current, addr);
+	mpnt = find_vma(current->mm, addr);
 	if (!mpnt)
 		return 0;
 	avl_neighbours(mpnt, current->mm->mmap_avl, &prev, &next);
@@ -887,7 +889,7 @@
  * Insert vm structure into process list sorted by address
  * and into the inode's i_mmap ring.
  */
-void insert_vm_struct(struct task_struct *t, struct vm_area_struct *vmp)
+void insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vmp)
 {
 	struct vm_area_struct *share;
 	struct inode * inode;
@@ -895,7 +897,7 @@
 #if 0 /* equivalent, but slow */
 	struct vm_area_struct **p, *mpnt;
 
-	p = &t->mm->mmap;
+	p = &mm->mmap;
 	while ((mpnt = *p) != NULL) {
 		if (mpnt->vm_start > vmp->vm_start)
 			break;
@@ -908,13 +910,13 @@
 #else
 	struct vm_area_struct * prev, * next;
 
-	avl_insert_neighbours(vmp, &t->mm->mmap_avl, &prev, &next);
-	if ((prev ? prev->vm_next : t->mm->mmap) != next)
+	avl_insert_neighbours(vmp, &mm->mmap_avl, &prev, &next);
+	if ((prev ? prev->vm_next : mm->mmap) != next)
 		printk("insert_vm_struct: tree inconsistent with list\n");
 	if (prev)
 		prev->vm_next = vmp;
 	else
-		t->mm->mmap = vmp;
+		mm->mmap = vmp;
 	vmp->vm_next = next;
 #endif
 
@@ -963,14 +965,16 @@
  * We don't need to traverse the entire list, only those segments
  * which intersect or are adjacent to a given interval.
  */
-void merge_segments (struct task_struct * task, unsigned long start_addr, unsigned long end_addr)
+void merge_segments (struct mm_struct * mm, unsigned long start_addr, unsigned long end_addr)
 {
 	struct vm_area_struct *prev, *mpnt, *next;
 
-	mpnt = find_vma(task, start_addr);
+	down(&mm->mmap_sem);
+	mpnt = find_vma(mm, start_addr);
 	if (!mpnt)
-		return;
-	avl_neighbours(mpnt, task->mm->mmap_avl, &prev, &next);
+		goto no_vma;
+
+	avl_neighbours(mpnt, mm->mmap_avl, &prev, &next);
 	/* we have  prev->vm_next == mpnt && mpnt->vm_next = next */
 
 	if (!prev) {
@@ -1014,7 +1018,7 @@
 		 * big segment can possibly merge with the next one.
 		 * The old unused mpnt is freed.
 		 */
-		avl_remove(mpnt, &task->mm->mmap_avl);
+		avl_remove(mpnt, &mm->mmap_avl);
 		prev->vm_end = mpnt->vm_end;
 		prev->vm_next = mpnt->vm_next;
 		if (mpnt->vm_ops && mpnt->vm_ops->close) {
@@ -1028,4 +1032,6 @@
 		kfree_s(mpnt, sizeof(*mpnt));
 		mpnt = prev;
 	}
+no_vma:
+	up(&mm->mmap_sem);
 }
diff -u --recursive --new-file v2.0.18/linux/mm/mprotect.c linux/mm/mprotect.c
--- v2.0.18/linux/mm/mprotect.c	Wed Apr  3 10:59:33 1996
+++ linux/mm/mprotect.c	Mon Sep  9 21:04:57 1996
@@ -112,7 +112,7 @@
 		n->vm_inode->i_count++;
 	if (n->vm_ops && n->vm_ops->open)
 		n->vm_ops->open(n);
-	insert_vm_struct(current, n);
+	insert_vm_struct(current->mm, n);
 	return 0;
 }
 
@@ -135,7 +135,7 @@
 		n->vm_inode->i_count++;
 	if (n->vm_ops && n->vm_ops->open)
 		n->vm_ops->open(n);
-	insert_vm_struct(current, n);
+	insert_vm_struct(current->mm, n);
 	return 0;
 }
 
@@ -169,8 +169,8 @@
 		vma->vm_ops->open(left);
 		vma->vm_ops->open(right);
 	}
-	insert_vm_struct(current, left);
-	insert_vm_struct(current, right);
+	insert_vm_struct(current->mm, left);
+	insert_vm_struct(current->mm, right);
 	return 0;
 }
 
@@ -216,7 +216,7 @@
 		return -EINVAL;
 	if (end == start)
 		return 0;
-	vma = find_vma(current, start);
+	vma = find_vma(current->mm, start);
 	if (!vma || vma->vm_start > start)
 		return -EFAULT;
 
@@ -248,6 +248,6 @@
 			break;
 		}
 	}
-	merge_segments(current, start, end);
+	merge_segments(current->mm, start, end);
 	return error;
 }
diff -u --recursive --new-file v2.0.18/linux/mm/mremap.c linux/mm/mremap.c
--- v2.0.18/linux/mm/mremap.c	Wed Jun 26 09:44:52 1996
+++ linux/mm/mremap.c	Mon Sep  9 21:04:57 1996
@@ -143,8 +143,8 @@
 				new_vma->vm_inode->i_count++;
 			if (new_vma->vm_ops && new_vma->vm_ops->open)
 				new_vma->vm_ops->open(new_vma);
-			insert_vm_struct(current, new_vma);
-			merge_segments(current, new_vma->vm_start, new_vma->vm_end);
+			insert_vm_struct(current->mm, new_vma);
+			merge_segments(current->mm, new_vma->vm_start, new_vma->vm_end);
 			do_munmap(addr, old_len);
 			return new_addr;
 		}
@@ -180,7 +180,7 @@
 	/*
 	 * Ok, we need to grow..
 	 */
-	vma = find_vma(current, addr);
+	vma = find_vma(current->mm, addr);
 	if (!vma || vma->vm_start > addr)
 		return -EFAULT;
 	/* We can't remap across vm area boundaries */
diff -u --recursive --new-file v2.0.18/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.0.18/linux/mm/vmscan.c	Sat Aug 17 21:19:29 1996
+++ linux/mm/vmscan.c	Mon Sep  9 21:04:57 1996
@@ -109,7 +109,7 @@
 			if (page_map->count != 1)
 				return 0;
 			if (!(entry = get_swap_page()))
-				return -1;	/* Aieee!!! Out of swap space! */
+				return 0;	/* Aieee!!! Out of swap space! */
 			vma->vm_mm->rss--;
 			flush_cache_page(vma, address);
 			set_pte(page_table, __pte(entry));
@@ -253,7 +253,7 @@
 	/*
 	 * Find the proper vm-area
 	 */
-	vma = find_vma(p, address);
+	vma = find_vma(p->mm, address);
 	if (!vma)
 		return 0;
 	if (address < vma->vm_start)
@@ -312,8 +312,6 @@
 		if (!--p->swap_cnt)
 			swap_task++;
 		switch (swap_out_process(p, dma, wait)) {
-			case -1:
-				return 0;
 			case 0:
 				if (p->swap_cnt)
 					swap_task++;
