diff -u --recursive --new-file v2.1.51/linux/CREDITS linux/CREDITS
--- v2.1.51/linux/CREDITS	Mon Aug 18 18:19:41 1997
+++ linux/CREDITS	Tue Sep  2 15:18:10 1997
@@ -529,6 +529,7 @@
 
 N: Richard Günther
 E: richard.guenther@student.uni-tuebingen.de
+P: 2048/2E829319 2F 83 FC 93 E9 E4 19 E2  93 7A 32 42 45 37 23 57
 D: binfmt_misc
 S: Fichtenweg 3/511
 S: 72076 Tübingen
@@ -1467,10 +1468,12 @@
 S: 2615 Australia
 
 N: Winfried Trümper
-E: truemper@MI.Uni-Koeln.DE
-D: German HOWTO, Enhanced German HOWTO, Crash-Kurs Linux (German)
-D: 1- or 5-days tutorials on Linux twice a year (free of charge)
-D: Linux-Workshop Köln (aka LUUG cologne, germany)
+E: winni@xpilot.org
+W: http://www.shop.de/~winni/
+D: German HOWTO, Crash-Kurs Linux (German, 100 comprehensive pages)
+D: CD-Writing HOWTO, various mini-HOWTOs
+D: one-week tutorials on Linux twice a year (free of charge)
+D: Linux-Workshop Köln (aka LUG Cologne, Germany), Installfests
 S: Tacitusstr. 6
 S: D-50968 Köln
 
diff -u --recursive --new-file v2.1.51/linux/Documentation/Changes linux/Documentation/Changes
--- v2.1.51/linux/Documentation/Changes	Sun Jul 27 12:11:00 1997
+++ linux/Documentation/Changes	Fri Aug 22 10:04:33 1997
@@ -54,6 +54,7 @@
 - Autofs                 0.3.7                   ; automount --version
 - NFS                    0.4.21                  ; showmount --version
 - Bash                   1.14.7                  ; bash -version
+- Smbfs                  2.1.0
 
 Upgrade notes
 *************
@@ -159,6 +160,10 @@
 to a 2.6 release.  Also, amd is being phased out in favor of the much
 better autofs.  You'll also have to get the appropriate utils to use
 autofs as well as the new NFS utils.
+
+The smbfs code is also being revised. This results in an incompatible
+mount interface. See the README of smbfs-2.1.0 or later for a
+description of the new mount command.
 
 RPM
 ===
diff -u --recursive --new-file v2.1.51/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.51/linux/Documentation/Configure.help	Mon Aug 18 18:19:42 1997
+++ linux/Documentation/Configure.help	Mon Aug 25 13:01:58 1997
@@ -1982,12 +1982,10 @@
 CONFIG_SCSI_NCR53C8XX
   This is the BSD ncr driver adapted to linux for the NCR53C8XX family
   of PCI-SCSI controllers. This driver supports parity checking,
-  tagged command queuing, fast scsi II transfer up to 10 MB/s with
-  narrow scsi devices and 20 MB/s with wide scsi devices.
-  Support of Ultra SCSI data transfers with NCR53C860 and NCR53C875 
-  controllers has been recently added to the driver.
+  tagged command queuing, Fast-20 data transfer up to 20 MB/s with
+  narrow scsi devices and 40 MB/s with wide scsi devices.
   Please read drivers/scsi/README.ncr53c8xx for more information.
-  Linux/i386 and Linux/Alpha are supported by this driver.
+  Linux/i386, Linux/Alpha and Linux/PPC are supported by this driver.
 
 synchronous data transfers frequency
 CONFIG_SCSI_NCR53C8XX_SYNC
@@ -2015,10 +2013,11 @@
 CONFIG_SCSI_NCR53C8XX_IOMAPPED
   This option allows you to force the driver to use normal IO.
   Memory mapped IO has less latency than normal IO and works for most 
-  Intel-based hardware.
-  Under Linux/Alpha only normal IO is currently supported by the driver 
-  and so, this option has no effect.
-  The normal answer therefore is N. Try Y only if you have problems.
+  Intel-based hardware.  Under Linux/Alpha and Linux/PPC only normal 
+  IO is currently supported by the driver and so, this option has no
+  effect. On Linux/PPC MMIO and normal IO are done the same (all IO
+  is memory mapped) so you loose nothing by using normal IO. The normal
+  answer therefore is N. Try Y only if you have problems.
 
 not allow targets to disconnect
 CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
diff -u --recursive --new-file v2.1.51/linux/Documentation/binfmt_misc.txt linux/Documentation/binfmt_misc.txt
--- v2.1.51/linux/Documentation/binfmt_misc.txt	Sun Jul 27 12:11:00 1997
+++ linux/Documentation/binfmt_misc.txt	Sun Aug 31 09:40:01 1997
@@ -9,7 +9,7 @@
 with which binary. Binfmt_misc recognises the binary-type by matching some bytes
 at the beginning of the file with a magic byte sequence (masking out specified
 bits) you have supplied. Binfmt_misc can also recognise a filename extension
-(aka .com) and optionally strip it off.
+aka '.com' or '.exe'.
 
 To actually register a new binary type, you have to set up a string looking like
 :name:type:offset:magic:mask:interpreter: (where you can choose the ':' upon
@@ -18,44 +18,46 @@
  - 'name' is an identifier string. A new /proc file will be created with this
    name below /proc/sys/fs/binfmt_misc
  - 'type' is the type of recognition. Give 'M' for magic and 'E' for extension.
-   Give the corresponding lowercase letter to let binfmt_misc strip off the
-   filename extension.
  - 'offset' is the offset of the magic/mask in the file, counted in bytes. This
    defaults to 0 if you omit it (i.e. you write ':name:type::magic...')
  - 'magic' is the byte sequence binfmt_misc is matching for. The magic string
    may contain hex-encoded characters like \x0a or \xA4. In a shell environment
    you will have to write \\x0a to prevent the shell from eating your \.
    If you chose filename extension matching, this is the extension to be
-   recognised (the \x0a specials are not allowed). Extension matching is case
-   sensitive!
+   recognised (without the '.', the \x0a specials are not allowed). Extension
+   matching is case sensitive!
  - 'mask' is an (optional, defaults to all 0xff) mask. You can mask out some
    bits from matching by supplying a string like magic and as long as magic.
    The mask is anded with the byte sequence of the file.
  - 'interpreter' is the program that should be invoked with the binary as first
    argument (specify the full path)
+
 There are some restrictions:
  - the whole register string may not exceed 255 characters
  - the magic must resist in the first 128 bytes of the file, i.e.
    offset+size(magic) has to be less than 128
  - the interpreter string may not exceed 127 characters
+
 You may want to add the binary formats in one of your /etc/rc scripts during
 boot-up. Read the manual of your init program to figure out how to do this
 right.
 
+Think about the order of adding entries! Later added entries are matched first!
+
 
 A few examples (assumed you are in /proc/sys/fs/binfmt_misc):
 
 - enable support for em86 (like binfmt_em86, for Alpha AXP only):
-  echo ":i386:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:" > register
-  echo ":i486:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:" > register
+  echo ':i386:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:' > register
+  echo ':i486:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:' > register
 
 - enable support for packed DOS applications (pre-configured dosemu hdimages):
-  echo ":DEXE:M::\x0eDEX::/usr/bin/dosexec:" > register
+  echo ':DEXE:M::\x0eDEX::/usr/bin/dosexec:' > register
 
 - enable support for DOS/Windows executables (using mzloader and dosemu/wine):
-  echo ":DOSWin:M::MZ::/usr/sbin/mzloader:" > register
-  echo ":DOScom:E::com::/usr/sbin/mzloader:" > register
-  echo ":DOSexe:E::exe::/usr/sbin/mzloader:" > register
+  echo ':DOSWin:M::MZ::/usr/sbin/mzloader:' > register
+  echo ':DOScom:E::com::/usr/sbin/mzloader:' > register
+  echo ':DOSexe:E::exe::/usr/sbin/mzloader:' > register
 
 
 You can enable/disable binfmt_misc or one binary type by echoing 0 (to disable)
@@ -71,11 +73,11 @@
 
 To emulate binfmt_java the following register-strings could be used: 
 for compiled Java programs use
-  ":Java:M::\xca\xfe\xba\xbe::/usr/local/java/bin/javawrapper:"
+  ':Java:M::\xca\xfe\xba\xbe::/usr/local/java/bin/javawrapper:'
 for simple applet support use
-  ":Applet:E::html::/usr/local/java/bin/appletviewer:"
+  ':Applet:E::html::/usr/local/java/bin/appletviewer:'
 for more selective applet support (like binfmt_java) use
-  ":Applet:M::\<\!--applet::/usr/local/java/bin/appletviewer:"
+  ':Applet:M::<!--applet::/usr/local/java/bin/appletviewer:'
 
 Note, that for the more selective applet support you have to modify
 existing html-files to contain <!--applet--> in the first line to
@@ -94,7 +96,7 @@
 if [ -L "$1" ] ; then
 	CLASS=`ls --color=no -l $1 | tr -s '\t ' '  ' | cut -d ' ' -f 11` 
 fi
-CLASSN=`basename $CLASS | sed s/\.class$//`
+CLASSN=`basename $CLASS .class`
 CLASSP=`dirname $CLASS`
 
 FOO=$PATH
diff -u --recursive --new-file v2.1.51/linux/Documentation/filesystems/smbfs.txt linux/Documentation/filesystems/smbfs.txt
--- v2.1.51/linux/Documentation/filesystems/smbfs.txt	Sun Jul 27 12:11:00 1997
+++ linux/Documentation/filesystems/smbfs.txt	Fri Aug 22 10:04:33 1997
@@ -8,6 +8,6 @@
 netbios name or share.
 
 To use smbfs, you need a special mount program, which can be found in
-the ksmbfs package, found on
+the smbfs package, found on
 
-	sunsite.unc.edu:/pub/Linux/system/filesystems/smbfs
+	ftp://ftp.gwdg.de/pub/linux/misc/smbfs/
diff -u --recursive --new-file v2.1.51/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt
--- v2.1.51/linux/Documentation/ioctl-number.txt	Mon Aug 11 14:47:04 1997
+++ linux/Documentation/ioctl-number.txt	Mon Sep  1 11:22:52 1997
@@ -1,5 +1,5 @@
 Ioctl Numbers
-7 Aug 1997
+1 Sep 1997
 Michael Chastain
 <mec@shout.net>
 
@@ -106,6 +106,8 @@
 'u'	all	linux/smb_fs.h
 'v'	all	linux/ext2_fs.h
 'w'	all	CERN SCI driver		in development
+'z'	00-3F	CAN bus card		in development:
+					<mailto:hdstich@connectu.ulm.circular.de>
 0x89	00-0F	asm-i386/sockios.h
 0x89	10-DF	linux/sockios.h
 0x89	E0-EF	linux/sockios.h		SIOCPROTOPRIVATE range
diff -u --recursive --new-file v2.1.51/linux/MAINTAINERS linux/MAINTAINERS
--- v2.1.51/linux/MAINTAINERS	Mon Aug 18 18:19:42 1997
+++ linux/MAINTAINERS	Tue Aug 26 14:52:44 1997
@@ -449,7 +449,7 @@
 P:	Phil Blundell
 M:	Philip.Blundell@pobox.com
 P:	Tim Waugh
-M:	tmw20@cyberelk.demon.co.uk
+M:	tim@cyberelk.demon.co.uk
 P:	David Campbell
 M:	campbell@tirian.che.curtin.edu.au
 L:	linux-parport@torque.net
diff -u --recursive --new-file v2.1.51/linux/Makefile linux/Makefile
--- v2.1.51/linux/Makefile	Mon Aug 18 18:19:42 1997
+++ linux/Makefile	Tue Sep  2 12:12:56 1997
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 51
+SUBLEVEL = 52
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
 
diff -u --recursive --new-file v2.1.51/linux/arch/alpha/config.in linux/arch/alpha/config.in
--- v2.1.51/linux/arch/alpha/config.in	Sun Jul 27 12:11:00 1997
+++ linux/arch/alpha/config.in	Sun Aug 31 09:40:45 1997
@@ -94,9 +94,9 @@
 bool 'Sysctl support' CONFIG_SYSCTL
 tristate 'Kernel support for a.out (ECOFF) binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
-  tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
+  tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
 fi
 tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86
 tristate 'Parallel port support' CONFIG_PARPORT
diff -u --recursive --new-file v2.1.51/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- v2.1.51/linux/arch/alpha/defconfig	Thu Jul 17 10:06:03 1997
+++ linux/arch/alpha/defconfig	Sat Aug 23 23:45:10 1997
@@ -43,7 +43,7 @@
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_EM86=y
-# CONFIG_PNP_PARPORT is not set
+# CONFIG_PARPORT is not set
 
 #
 # Plug and Play support
@@ -67,7 +67,6 @@
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_MD is not set
 # CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_BLK_DEV_EZ is not set
 # CONFIG_BLK_DEV_HD is not set
@@ -142,6 +141,7 @@
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_NCR53C7xx is not set
 # CONFIG_SCSI_NCR53C8XX is not set
+# CONFIG_SCSI_PPA is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
 CONFIG_SCSI_QLOGIC_ISP=y
@@ -150,6 +150,8 @@
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
 # CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
 
 #
 # Network device support
@@ -174,6 +176,7 @@
 # CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
 # CONFIG_DLCI is not set
+# CONFIG_PLIP is not set
 # CONFIG_PPP is not set
 # CONFIG_NET_RADIO is not set
 # CONFIG_SLIP is not set
@@ -215,6 +218,7 @@
 # CONFIG_ROMFS_FS is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_MAC_PARTITION is not set
 
 #
 # Character devices
@@ -230,12 +234,15 @@
 # CONFIG_MS_BUSMOUSE is not set
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
 # CONFIG_UMISC is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_FTAPE is not set
 # CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
+# CONFIG_NVRAM is not set
+# CONFIG_JOYSTICK is not set
 
 #
 # Sound
diff -u --recursive --new-file v2.1.51/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
--- v2.1.51/linux/arch/alpha/kernel/entry.S	Thu May 29 21:53:04 1997
+++ linux/arch/alpha/kernel/entry.S	Sat Aug 30 11:37:17 1997
@@ -437,8 +437,8 @@
 	stq $13,32($30)
 	stq $14,40($30)
 	stq $15,48($30)
-	bis $31,$30,$19
 	lda $8,0x3fff
+	addq $30,56,$19
 	bic $30,$8,$8
 	jsr $26,do_entUnaUser
 	ldq $9,0($30)
diff -u --recursive --new-file v2.1.51/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c
--- v2.1.51/linux/arch/alpha/kernel/traps.c	Thu Jul 17 10:06:03 1997
+++ linux/arch/alpha/kernel/traps.c	Sat Aug 30 11:37:17 1997
@@ -491,8 +491,22 @@
 			| 1L << 0x2c | 1L << 0x2d   /* stl stq */	\
 			| 1L << 0xd )		    /* stw */
 
+#define R(x)	((size_t) &((struct pt_regs *)0)->x)
+
+static int unauser_reg_offsets[32] = {
+	R(r0), R(r1), R(r2), R(r3), R(r4), R(r5), R(r6), R(r7), R(r8),
+	/* r9 ... r15 are stored in front of regs.  */
+	-56, -48, -40, -32, -24, -16, -8,
+	R(r16), R(r17), R(r18),
+	R(r19), R(r20), R(r21), R(r22), R(r23), R(r24), R(r25), R(r26),
+	R(r27), R(r28), R(gp),
+	0, 0
+};
+
+#undef R
+
 asmlinkage void do_entUnaUser(void * va, unsigned long opcode,
-			      unsigned long reg, unsigned long * frame)
+			      unsigned long reg, struct pt_regs *regs)
 {
 	extern void alpha_write_fp_reg (unsigned long reg, unsigned long val);
 	extern unsigned long alpha_read_fp_reg (unsigned long reg);
@@ -501,12 +515,10 @@
 	static long last_time = 0;
 
 	unsigned long tmp1, tmp2, tmp3, tmp4;
-	unsigned long *reg_addr, *pc_addr, fake_reg;
+	unsigned long fake_reg, *reg_addr = &fake_reg;
 	unsigned long uac_bits;
 	long error;
 
-	pc_addr = frame + 7 + 20 + 1;			/* pc in PAL frame */
-
 	/* Check the UAC bits to decide what the user wants us to do
 	   with the unaliged access.  */
 
@@ -519,7 +531,7 @@
 			lock_kernel();
 			printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n",
 			       current->comm, current->pid,
-			       *pc_addr - 4, va, opcode, reg);
+			       regs->pc - 4, va, opcode, reg);
 			unlock_kernel();
 		}
 		last_time = jiffies;
@@ -540,51 +552,19 @@
 
 	++unaligned[1].count;
 	unaligned[1].va = (unsigned long)va;
-	unaligned[1].pc = *pc_addr - 4;
+	unaligned[1].pc = regs->pc - 4;
 
-	reg_addr = frame;
 	if ((1L << opcode) & OP_INT_MASK) {
 		/* it's an integer load/store */
-		switch (reg) {
-		      case 0: case 1: case 2: case 3: case 4:
-		      case 5: case 6: case 7: case 8:
-			/* v0-t7 in SAVE_ALL frame */
-			reg_addr += 7 + reg;
-			break;
-
-		      case 9: case 10: case 11: case 12:
-		      case 13: case 14: case 15:
-			/* s0-s6 in entUna frame */
-			reg_addr += (reg - 9);
-			break;
-
-		      case 16: case 17: case 18:
-			/* a0-a2 in PAL frame */
-			reg_addr += 7 + 20 + 3 + (reg - 16);
-			break;
-
-		      case 19: case 20: case 21: case 22: case 23:
-		      case 24: case 25: case 26: case 27: case 28:
-			/* a3-at in SAVE_ALL frame */
-			reg_addr += 7 + 9 + (reg - 19);
-			break;
-
-		      case 29:
-			/* gp in PAL frame */
-			reg_addr += 7 + 20 + 2;
-			break;
-
-		      case 30:
+		if (reg < 30) {
+			reg_addr = (unsigned long *)
+			  ((char *)regs + unauser_reg_offsets[reg]);
+		} else if (reg == 30) {
 			/* usp in PAL regs */
 			fake_reg = rdusp();
-			reg_addr = &fake_reg;
-			break;
-
-		      case 31:
+		} else {
 			/* zero "register" */
 			fake_reg = 0;
-			reg_addr = &fake_reg;
-			break;
 		}
 	}
 
@@ -728,7 +708,6 @@
 
 	case 0x26: /* sts */
 		fake_reg = s_reg_to_mem(alpha_read_fp_reg(reg));
-		reg_addr = &fake_reg;
 		/* FALLTHRU */
 
 	case 0x2c: /* stl */
@@ -763,7 +742,6 @@
 
 	case 0x27: /* stt */
 		fake_reg = alpha_read_fp_reg(reg);
-		reg_addr = &fake_reg;
 		/* FALLTHRU */
 
 	case 0x2d: /* stq */
@@ -807,14 +785,14 @@
 	return;
 
 give_sigsegv:
-	*pc_addr -= 4;  /* make pc point to faulting insn */
+	regs->pc -= 4;  /* make pc point to faulting insn */
 	lock_kernel();
 	force_sig(SIGSEGV, current);
 	unlock_kernel();
 	return;
 
 give_sigbus:
-	*pc_addr -= 4;
+	regs->pc -= 4;
 	lock_kernel();
 	force_sig(SIGBUS, current);
 	unlock_kernel();
diff -u --recursive --new-file v2.1.51/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.1.51/linux/arch/i386/config.in	Sun Jul 27 12:11:00 1997
+++ linux/arch/i386/config.in	Sun Aug 31 09:40:45 1997
@@ -36,7 +36,7 @@
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
+  tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
 fi
 
 choice 'Processor type' \
diff -u --recursive --new-file v2.1.51/linux/arch/m68k/config.in linux/arch/m68k/config.in
--- v2.1.51/linux/arch/m68k/config.in	Mon Aug  4 16:25:36 1997
+++ linux/arch/m68k/config.in	Sun Aug 31 09:40:45 1997
@@ -52,9 +52,7 @@
 bool 'Sysctl support' CONFIG_SYSCTL
 tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
-fi
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 
 if [ "$CONFIG_AMIGA" = "y" ]; then
   bool 'Amiga AutoConfig Identification' CONFIG_ZORRO
diff -u --recursive --new-file v2.1.51/linux/arch/mips/config.in linux/arch/mips/config.in
--- v2.1.51/linux/arch/mips/config.in	Mon Aug 18 18:19:42 1997
+++ linux/arch/mips/config.in	Sun Aug 31 09:40:45 1997
@@ -77,7 +77,8 @@
 define_bool CONFIG_BINFMT_ELF y
 define_bool CONFIG_BINFMT_AOUT n
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
+  tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+  tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
 fi
 bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
diff -u --recursive --new-file v2.1.51/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.1.51/linux/arch/ppc/config.in	Mon Aug 18 18:19:44 1997
+++ linux/arch/ppc/config.in	Sun Aug 31 09:40:46 1997
@@ -46,7 +46,7 @@
 define_bool CONFIG_BINFMT_ELF y
 define_bool CONFIG_KERNEL_ELF y
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
-tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
+tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
 
 if [ "$CONFIG_PMAC" = "y" ]; then
   define_bool CONFIG_PMAC_CONSOLE y
diff -u --recursive --new-file v2.1.51/linux/arch/sparc/config.in linux/arch/sparc/config.in
--- v2.1.51/linux/arch/sparc/config.in	Thu Jun 26 12:33:38 1997
+++ linux/arch/sparc/config.in	Sun Aug 31 09:40:46 1997
@@ -53,9 +53,9 @@
 bool 'Sysctl support' CONFIG_SYSCTL
 tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
-  tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
+  tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
 fi
 endmenu
 
diff -u --recursive --new-file v2.1.51/linux/arch/sparc64/config.in linux/arch/sparc64/config.in
--- v2.1.51/linux/arch/sparc64/config.in	Mon Aug 18 18:19:45 1997
+++ linux/arch/sparc64/config.in	Sun Aug 31 09:40:46 1997
@@ -58,10 +58,8 @@
   bool 'Kernel support for 32-bit (ie. SunOS) a.out binaries' CONFIG_BINFMT_AOUT32
 fi
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
-fi
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+  tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
 fi
 endmenu
 
diff -u --recursive --new-file v2.1.51/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v2.1.51/linux/drivers/char/lp.c	Mon Aug  4 16:25:37 1997
+++ linux/drivers/char/lp.c	Tue Aug 26 14:52:45 1997
@@ -36,11 +36,11 @@
 /* if you have more than 3 printers, remember to increase LP_NO */
 struct lp_struct lp_table[] =
 {
- {NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0,
+ {NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, 0,
   {0}},
- {NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0,
+ {NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, 0,
   {0}},
- {NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0,
+ {NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, 0,
   {0}}
 };
 #define LP_NO 3
@@ -60,6 +60,41 @@
 #undef LP_DEBUG
 #undef LP_READ_DEBUG
 
+static inline void lp_parport_release (int minor)
+{
+	parport_release (lp_table[minor].dev);
+	lp_table[minor].should_relinquish = 0;
+}
+
+static inline void lp_parport_claim (int minor)
+{
+	if (parport_claim (lp_table[minor].dev))
+		sleep_on (&lp_table[minor].lp_wait_q);
+}
+
+static inline void lp_schedule (int minor)
+{
+	if (lp_table[minor].should_relinquish) {
+		lp_parport_release (minor);
+		schedule ();
+		lp_parport_claim (minor);
+	}
+	else
+		schedule ();
+}
+
+
+static int lp_preempt (void *handle)
+{
+	struct lp_struct *lps = (struct lp_struct *)handle;
+
+	/* Just remember that someone wants the port */
+	lps->should_relinquish = 1;
+
+	/* Don't actually release the port now */
+	return 1;
+}
+
 static int lp_reset(int minor)
 {
 	w_ctr(minor, LP_PSELECP);
@@ -70,7 +105,8 @@
 
 static inline int lp_char_polled(char lpchar, int minor)
 {
-	int status, wait = 0;
+	int status;
+	unsigned int wait = 0;
 	unsigned long count = 0;
 	struct lp_stats *stats;
 
@@ -78,7 +114,7 @@
 		status = r_str(minor);
 		count++;
 		if (need_resched)
-			schedule();
+			lp_schedule (minor);
 	} while (!LP_READY(minor, status) && count < LP_CHAR(minor));
 
 	if (count == LP_CHAR(minor)) {
@@ -90,11 +126,11 @@
 	stats->chars++;
 	/* must wait before taking strobe high, and after taking strobe
 	   low, according spec.  Some printers need it, others don't. */
-	while (wait != LP_WAIT(minor))
+	while (wait != LP_WAIT(minor)) /* FIXME: should be a udelay() */
 		wait++;
 	/* control port takes strobe high */
 	w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE);
-	while (wait)
+	while (wait)			/* FIXME: should be a udelay() */
 		wait--;
 	/* take strobe low */
 	w_ctr(minor, LP_PSELECP | LP_PINITP);
@@ -116,14 +152,14 @@
 
 static inline int lp_char_interrupt(char lpchar, int minor)
 {
-	int wait;
+	unsigned int wait;
 	unsigned long count = 0;
 	unsigned char status;
 	struct lp_stats *stats;
 
 	do {
 		if(need_resched)
-			schedule();
+			lp_schedule (minor);
 		if ((status = r_str(minor)) & LP_PBUSY) {
 			if (!LP_CAREFUL_READY(minor, status))
 				return 0;
@@ -133,12 +169,12 @@
 			/* must wait before taking strobe high, and after taking strobe
 			   low, according spec.  Some printers need it, others don't. */
 			wait = 0;
-			while (wait != LP_WAIT(minor))
-				wait++;
+			while (wait != LP_WAIT(minor)) /* FIXME: should be */
+				wait++;		       /* a udelay ()      */
 			/* control port takes strobe high */
 			w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE);
 			while (wait)
-				wait--;
+				wait--;	/* FIXME: should be a udelay() */
 			/* take strobe low */
 			w_ctr(minor, LP_PSELECP | LP_PINITP);
 			/* update waittime statistics */
@@ -164,7 +200,7 @@
 	struct pardevice *pd = pb->cad;
 	struct lp_struct *lp_dev = (struct lp_struct *) pd->private;
 
-	if (lp_dev->lp_wait_q)
+	if (waitqueue_active (&lp_dev->lp_wait_q))
 		wake_up(&lp_dev->lp_wait_q);
 }
 
@@ -211,7 +247,8 @@
 				}
 				LP_STAT(minor).sleeps++;
 				cli();
-				w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN);
+				enable_irq(lp->dev->port->irq);
+				w_ctr(minor, LP_PSELECP|LP_PINITP|LP_PINTEN);
 				status = r_str(minor);
 				if ((!(status & LP_PACK) || (status & LP_PBUSY))
 				    && LP_CAREFUL_READY(minor, status)) {
@@ -222,6 +259,7 @@
 				lp_table[minor].runchars = 0;
 				current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
 				interruptible_sleep_on(&lp->lp_wait_q);
+
 				w_ctr(minor, LP_PSELECP | LP_PINITP);
 				sti();
 				if (current->signal & ~current->blocked) {
@@ -267,7 +305,7 @@
 					return temp-buf?temp-buf:-ENOSPC;
 				current->state = TASK_INTERRUPTIBLE;
 				current->timeout = jiffies + LP_TIMEOUT_POLLED;
-				schedule();
+				lp_schedule (minor);
 			} else
 			if (!(status & LP_PSELECD)) {
 				printk(KERN_INFO "lp%d off-line\n", minor);
@@ -275,7 +313,7 @@
 					return temp-buf?temp-buf:-EIO;
 				current->state = TASK_INTERRUPTIBLE;
 				current->timeout = jiffies + LP_TIMEOUT_POLLED;
-				schedule();
+				lp_schedule (minor);
 			} else
 			/* not offline or out of paper. on fire? */
 			if (!(status & LP_PERRORP)) {
@@ -284,7 +322,7 @@
 					return temp-buf?temp-buf:-EIO;
 				current->state = TASK_INTERRUPTIBLE;
 				current->timeout = jiffies + LP_TIMEOUT_POLLED;
-				schedule();
+				lp_schedule (minor);
 			}
 
 			/* check for signals before going to sleep */
@@ -302,7 +340,7 @@
 			lp_table[minor].runchars=0;
 			current->state = TASK_INTERRUPTIBLE;
 			current->timeout = jiffies + LP_TIME(minor);
-			schedule();
+			lp_schedule (minor);
 		}
 	}
 	return temp-buf;
@@ -322,16 +360,14 @@
  	/* Claim Parport or sleep until it becomes available
  	 * (see lp_wakeup() for details)
  	 */
- 	if (parport_claim(lp_table[minor].dev)) {
- 		sleep_on(&lp_table[minor].lp_wait_q);
- 		lp_table[minor].lp_wait_q = NULL;
- 	}
+ 	lp_parport_claim (minor);
+
  	if (LP_IRQ(minor) > 0)
  		retv = lp_write_interrupt(minor, buf, count);
   	else
  		retv = lp_write_polled(minor, buf, count);
  
- 	parport_release(lp_table[minor].dev);
+ 	lp_parport_release (minor);
  	return retv;
 }
 
@@ -370,10 +406,7 @@
  	/* Claim Parport or sleep until it becomes available
  	 * (see lp_wakeup() for details)
  	 */
- 	if (parport_claim(lp_table[minor].dev)) {
- 		sleep_on(&lp_table[minor].lp_wait_q);
- 		lp_table[minor].lp_wait_q = NULL;
- 	}
+ 	lp_parport_claim (minor);
 
 	temp=buf;	
 #ifdef LP_READ_DEBUG 
@@ -399,7 +432,7 @@
 			udelay(50);
 			counter++;
 			if (need_resched)
-				schedule();
+				lp_schedule (minor);
 		} while ( (status == 0x40) && (counter < 20) );
 		if ( counter == 20 ) { /* Timeout */
 #ifdef LP_READ_DEBUG
@@ -418,7 +451,7 @@
 			udelay(20);
 			counter++;
 			if (need_resched)
-				schedule();
+				lp_schedule (minor);
 		} while ( (status == 0) && (counter < 20) );
 		if (counter == 20) { /* Timeout */
 #ifdef LP_READ_DEBUG
@@ -434,7 +467,7 @@
 			}
 			current->state=TASK_INTERRUPTIBLE;
 			current->timeout=jiffies + LP_TIME(minor);
-			schedule();
+			lp_schedule (minor);
 		}
 		counter=0;
 		if (( i & 1) != 0) {
@@ -656,7 +689,7 @@
 {
 	struct lp_struct *lp_dev = (struct lp_struct *) ref;
 
-	if (!lp_dev->lp_wait_q)
+	if (!waitqueue_active (&lp_dev->lp_wait_q))
 		return;	/* Wake up whom? */
 
 	/* Claim the Parport */
@@ -691,8 +724,8 @@
 			    (parport[0] == -3 &&
 			     pb->probe_info.class == PARPORT_CLASS_PRINTER)) {
 				lp_table[count].dev =
-				  parport_register_device(pb, dev_name, NULL, 
-						lp_wakeup,
+				  parport_register_device(pb, dev_name, 
+						lp_preempt, lp_wakeup,
 						lp_interrupt, PARPORT_DEV_TRAN,
 						(void *) &lp_table[count]);
 				lp_table[count].flags |= LP_EXIST;
diff -u --recursive --new-file v2.1.51/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.1.51/linux/drivers/char/mem.c	Mon Aug  4 16:25:37 1997
+++ linux/drivers/char/mem.c	Tue Sep  2 10:57:37 1997
@@ -530,7 +530,8 @@
     defined (CONFIG_ATIXL_BUSMOUSE) || defined(CONFIG_SOFT_WATCHDOG) || \
     defined (CONFIG_AMIGAMOUSE) || defined (CONFIG_ATARIMOUSE) || \
     defined (CONFIG_PCWATCHDOG) || \
-    defined (CONFIG_APM) || defined (CONFIG_RTC) || defined (CONFIG_SUN_MOUSE)
+    defined (CONFIG_APM) || defined (CONFIG_RTC) || \
+    defined (CONFIG_SUN_MOUSE) || defined (CONFIG_NVRAM)
 	misc_init();
 #endif
 #ifdef CONFIG_SOUND
diff -u --recursive --new-file v2.1.51/linux/drivers/char/vt.c linux/drivers/char/vt.c
--- v2.1.51/linux/drivers/char/vt.c	Thu Aug 14 20:49:16 1997
+++ linux/drivers/char/vt.c	Wed Aug 20 14:03:40 1997
@@ -490,6 +490,8 @@
 	case KIOCSOUND:
 		if (!perm)
 			return -EPERM;
+		if (arg)
+			arg = 1193180 / arg;
 		kd_mksound(arg, 0);
 		return 0;
 
@@ -505,6 +507,8 @@
 		 */
 		ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
 		count = ticks ? (arg & 0xffff) : 0;
+		if (count)
+			count = 1193180 / count;
 		kd_mksound(count, ticks);
 		return 0;
 	}
diff -u --recursive --new-file v2.1.51/linux/drivers/misc/BUGS-parport linux/drivers/misc/BUGS-parport
--- v2.1.51/linux/drivers/misc/BUGS-parport	Sun Jul 27 12:11:00 1997
+++ linux/drivers/misc/BUGS-parport	Tue Aug 26 14:52:44 1997
@@ -1,12 +1,5 @@
 Currently known (or at least suspected) bugs in parport:
 
-o /proc/parport is untested under 2.0.XX
-
-o SCSI aborts for PPA under 2.0.29 [reported by jmr].  Under investigation.
-
-o make config (etc) allow you to select CONFIG_PNP_PARPORT=m, CONFIG_PPA=y -
-  the resulting kernel won't link.
-
 o IEEE1284 code does not do the terminating handshake after transfers, which
   seems to upset some devices.
 
diff -u --recursive --new-file v2.1.51/linux/drivers/misc/parport_arc.c linux/drivers/misc/parport_arc.c
--- v2.1.51/linux/drivers/misc/parport_arc.c	Mon Aug  4 16:25:37 1997
+++ linux/drivers/misc/parport_arc.c	Tue Aug 26 14:52:44 1997
@@ -1,7 +1,6 @@
-/* $Id$
- * Parallel-port routines for ARC onboard hardware.
+/* Parallel-port routines for ARC onboard hardware.
  *
- * Author: Phil Blundell <pjb27@cam.ac.uk>
+ * Author: Phil Blundell <Philip.Blundell@pobox.com>
  */
 
 #include <linux/tasks.h>
@@ -37,6 +36,20 @@
 	return data_copy;
 }
 
+static void arc_inc_use_count(void)
+{
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+}
+
+static void arc_dec_use_count(void)
+{
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+}
+
 static struct parport_operations arc_ops = 
 {
 	arc_write_data,
@@ -72,5 +85,8 @@
 
 	arc_enable_irq,
 	arc_disable_irq,
-	arc_examine_irq 
+	arc_examine_irq,
+
+	arc_inc_use_count,
+	arc_dec_use_count
 };
diff -u --recursive --new-file v2.1.51/linux/drivers/misc/parport_ieee1284.c linux/drivers/misc/parport_ieee1284.c
--- v2.1.51/linux/drivers/misc/parport_ieee1284.c	Sun Jul 27 12:11:00 1997
+++ linux/drivers/misc/parport_ieee1284.c	Tue Aug 26 14:52:44 1997
@@ -1,7 +1,6 @@
-/* $Id$ 
- * IEEE-1284 implementation for parport.
+/* IEEE-1284 implementation for parport.
  *
- * Authors: Philip Blundell <pjb27@cam.ac.uk>
+ * Authors: Phil Blundell <Philip.Blundell@pobox.com>
  *          Carsten Gross <carsten@sol.wohnheim.uni-ulm.de>
  *	    Jose Renau <renau@acm.org>
  */
diff -u --recursive --new-file v2.1.51/linux/drivers/misc/parport_init.c linux/drivers/misc/parport_init.c
--- v2.1.51/linux/drivers/misc/parport_init.c	Mon Aug  4 16:25:37 1997
+++ linux/drivers/misc/parport_init.c	Tue Aug 26 14:52:44 1997
@@ -1,8 +1,7 @@
-/* $Id: parport_init.c,v 1.1.2.2 1997/04/18 15:00:52 phil Exp $
- * Parallel-port initialisation code.
+/* Parallel-port initialisation code.
  * 
  * Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
- *          Tim Waugh <tmw20@cam.ac.uk>
+ *          Tim Waugh <tim@cyberelk.demon.co.uk>
  *	    Jose Renau <renau@acm.org>
  *
  * based on work by Grant Guenther <grant@torque.net>
@@ -62,17 +61,6 @@
 
 void cleanup_module(void)
 {
-	struct parport *port, *next;
-   
-	for (port = parport_enumerate(); port; port = next) {
-		next = port->next;
-		if (!(port->flags & PARPORT_FLAG_COMA))
-			parport_quiesce(port);
-		parport_proc_unregister(port);
-		kfree(port->name);
-		kfree(port);
-	}
-	
 	parport_proc_cleanup();
 }
 #else
diff -u --recursive --new-file v2.1.51/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c
--- v2.1.51/linux/drivers/misc/parport_pc.c	Mon Aug 11 14:47:04 1997
+++ linux/drivers/misc/parport_pc.c	Tue Aug 26 14:52:45 1997
@@ -1,13 +1,11 @@
-/* $Id: parport_pc.c,v 1.1.2.3 1997/04/18 15:00:52 phil Exp $ 
- * Parallel-port routines for PC architecture
+/* Parallel-port routines for PC architecture
  * 
- * Authors: Phil Blundell <pjb27@cam.ac.uk>
- *          Tim Waugh <tmw20@cam.ac.uk>
+ * Authors: Phil Blundell <Philip.Blundell@pobox.com>
+ *          Tim Waugh <tim@cyberelk.demon.co.uk>
  *	    Jose Renau <renau@acm.org>
  *          David Campbell <campbell@tirian.che.curtin.edu.au>
  *
- * based on work by Grant Guenther <grant@torque.net>
- *              and Philip Blundell <Philip.Blundell@pobox.com>
+ * based on work by Grant Guenther <grant@torque.net> and Phil Blundell.
  */
 
 #include <linux/stddef.h>
@@ -153,7 +151,7 @@
 {
 	/* FIXME check that resources are free */
 	if (p->irq != PARPORT_IRQ_NONE)
-		request_irq(p->irq, pc_null_intr_func, 0, p->name, NULL);
+		request_irq(p->irq, pc_null_intr_func, 0, p->name, p);
 	request_region(p->base, p->size, p->name);
 	if (p->modes & PARPORT_MODE_PCECR)
 		request_region(p->base+0x400, 3, p->name);
@@ -162,12 +160,14 @@
 
 static void pc_save_state(struct parport *p, struct parport_state *s)
 {
-	/* FIXME */
+	s->u.pc.ctr = pc_read_control(p);
+	s->u.pc.ecr = pc_read_econtrol(p);
 }
 
 static void pc_restore_state(struct parport *p, struct parport_state *s)
 {
-	/* FIXME */
+	pc_write_control(p, s->u.pc.ctr);
+	pc_write_econtrol(p, s->u.pc.ecr);
 }
 
 static unsigned int pc_epp_read_block(struct parport *p, void *buf, unsigned  int length)
@@ -195,6 +195,20 @@
 	return 0; /* FIXME */
 }
 
+static void pc_inc_use_count(void)
+{
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+}
+
+static void pc_dec_use_count(void)
+{
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+}
+
 static struct parport_operations pc_ops = 
 {
 	pc_write_data,
@@ -230,7 +244,10 @@
 
 	pc_enable_irq,
 	pc_disable_irq,
-	pc_examine_irq 
+	pc_examine_irq,
+
+	pc_inc_use_count,
+	pc_dec_use_count
 };
 
 /******************************************************
@@ -322,7 +339,6 @@
 		return dma;
 }
 
-#if 0
 /* Only called if port supports ECP mode.
  *
  * The only restriction on DMA channels is that it has to be
@@ -388,7 +404,6 @@
 	
 	return retv;
 }
-#endif
 
 /******************************************************
  *  MODE detection section:
@@ -449,18 +464,20 @@
 	  oecr = pc_read_econtrol(pb);
 
 	r = pc_read_control(pb);	
-	if ((pc_read_econtrol(pb) & 0x03) == (r & 0x03)) {
-		pc_write_control(pb, r ^ 0x03 ); /* Toggle bits 0-1 */
+	if ((pc_read_econtrol(pb) & 0x3) == (r & 0x3)) {
+		pc_write_control(pb, r ^ 0x2 ); /* Toggle bit 1 */
 
-		r= pc_read_control(pb);	
-		if ((pc_read_econtrol(pb) & 0x03) == (r & 0x03))
+		r = pc_read_control(pb);	
+		if ((pc_read_econtrol(pb) & 0x2) == (r & 0x2)) {
+			pc_write_control(pb, octr);
 			return 0; /* Sure that no ECR register exists */
+		}
 	}
 	
-	if ((pc_read_econtrol(pb) & 0x03 ) != 0x01)
+	if ((pc_read_econtrol(pb) & 0x3 ) != 0x1)
 		return 0;
 
-	pc_write_econtrol(pb,0x34);
+	pc_write_econtrol(pb, 0x34);
 	if (pc_read_econtrol(pb) != 0x35)
 		return 0;
 
@@ -846,6 +863,11 @@
 #undef printmode
 	printk("]\n");
 	parport_proc_register(p);
+	p->flags |= PARPORT_FLAG_COMA;
+
+	/* Done probing.  Now put the port into a sensible start-up state. */
+	pc_write_control(p, 0xc);
+	pc_write_data(p, 0);
 	return 1;
 }
 
@@ -860,11 +882,8 @@
 	} else {
 		/* Probe all the likely ports. */
 		count += probe_one_port(0x378, PARPORT_IRQ_AUTO, PARPORT_DMA_AUTO);
-		
-#if defined(__i386__)
 		count += probe_one_port(0x278, PARPORT_IRQ_AUTO, PARPORT_DMA_AUTO);
 		count += probe_one_port(0x3bc, PARPORT_IRQ_AUTO, PARPORT_DMA_AUTO);
-#endif
 	}
 	return count;
 }
@@ -877,22 +896,23 @@
 MODULE_PARM(irq, "1-" __MODULE_STRING(PC_MAX_PORTS) "i");
 MODULE_PARM(dma, "1-" __MODULE_STRING(PC_MAX_PORTS) "i");
 
-static int init_module(void)
+int init_module(void)
 {	
 	return (parport_pc_init(io, irq, dma)?0:1);
 }
 
-static void cleanup_module(void)
+void cleanup_module(void)
 {
-	struct parport *p = parport_enumerate();
+	struct parport *p = parport_enumerate(), *tmp;
 	while (p) {
+		tmp = p->next;
 		if (p->modes & PARPORT_MODE_PCSPP) { 
 			if (!(p->flags & PARPORT_FLAG_COMA)) 
 				parport_quiesce(p);
 			parport_proc_unregister(p);
 			parport_unregister_port(p);
 		}
-		p = p->next;
+		p = tmp;
 	}
 }
 #endif
diff -u --recursive --new-file v2.1.51/linux/drivers/misc/parport_procfs.c linux/drivers/misc/parport_procfs.c
--- v2.1.51/linux/drivers/misc/parport_procfs.c	Mon Aug  4 16:25:37 1997
+++ linux/drivers/misc/parport_procfs.c	Tue Aug 26 14:52:44 1997
@@ -1,5 +1,4 @@
-/* $Id: parport_procfs.c,v 1.1.2.2 1997/04/18 15:00:52 phil Exp $
- * Parallel port /proc interface code.
+/* Parallel port /proc interface code.
  * 
  * Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
  *          Tim Waugh <tmw20@cam.ac.uk>
diff -u --recursive --new-file v2.1.51/linux/drivers/misc/parport_share.c linux/drivers/misc/parport_share.c
--- v2.1.51/linux/drivers/misc/parport_share.c	Mon Aug  4 16:25:37 1997
+++ linux/drivers/misc/parport_share.c	Tue Aug 26 14:52:44 1997
@@ -1,8 +1,7 @@
-/* $Id: parport_share.c,v 1.1.2.2 1997/04/18 15:00:52 phil Exp $
- * Parallel-port resource manager code.
+/* Parallel-port resource manager code.
  * 
  * Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
- *          Tim Waugh <tmw20@cam.ac.uk>
+ *          Tim Waugh <tim@cyberelk.demon.co.uk>
  *	    Jose Renau <renau@acm.org>
  *
  * based on work by Grant Guenther <grant@torque.net>
@@ -19,6 +18,10 @@
 #include <linux/kernel.h>
 #include <linux/malloc.h>
 
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
+
 #undef PARPORT_PARANOID
 
 static struct parport *portlist = NULL, *portlist_tail = NULL;
@@ -27,6 +30,10 @@
 /* Return a list of all the ports we know about. */
 struct parport *parport_enumerate(void)
 {
+#ifdef CONFIG_KERNELD
+	if (portlist == NULL)
+		request_module("parport_lowlevel");
+#endif
 	return portlist;
 }
 
@@ -93,7 +100,8 @@
 	struct parport *p;
 	kfree(port->name);
 	if (portlist == port) {
-		portlist = port->next;
+		if ((portlist = port->next) == NULL)
+			portlist_tail = NULL;
 	} else {
 		for (p = portlist; (p != NULL) && (p->next != port); 
 		     p=p->next);
@@ -184,6 +192,7 @@
 		port->lurker = tmp;
 
 	inc_parport_count();
+	port->ops->inc_use_count();
 
 	return tmp;
 }
@@ -218,6 +227,7 @@
 	kfree(dev);
 
 	dec_parport_count();
+	port->ops->dec_use_count();
 
 	/* If there are no more devices, put the port to sleep. */
 	if (!port->devices)
diff -u --recursive --new-file v2.1.51/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.1.51/linux/drivers/net/Config.in	Mon Aug 11 14:47:04 1997
+++ linux/drivers/net/Config.in	Tue Aug 26 14:52:44 1997
@@ -123,8 +123,8 @@
   fi
 fi
 
-if [ ! "$CONFIG_PNP_PARPORT" = "n" ]; then
-  dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PNP_PARPORT
+if [ ! "$CONFIG_PARPORT" = "n" ]; then
+  dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT
 fi
 
 tristate 'PPP (point-to-point) support' CONFIG_PPP
diff -u --recursive --new-file v2.1.51/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c
--- v2.1.51/linux/drivers/net/eepro100.c	Tue May 13 22:41:09 1997
+++ linux/drivers/net/eepro100.c	Mon Sep  1 12:36:01 1997
@@ -1,7 +1,7 @@
 /* drivers/net/eepro100.c: An Intel i82557 ethernet driver for linux. */
 /*
    NOTICE: this version tested with kernels 1.3.72 and later only!
-	Written 1996 by Donald Becker.
+	Written 1996-1997 by Donald Becker.
 
 	This software may be used and distributed according to the terms
 	of the GNU Public License, incorporated herein by reference.
@@ -19,7 +19,7 @@
 */
 
 static const char *version =
-"eepro100.c:v0.31 3/29/97 Donald Becker linux-eepro100@cesdis.gsfc.nasa.gov\n";
+"eepro100.c:v0.34 8/30/97 Donald Becker linux-eepro100@cesdis.gsfc.nasa.gov\n";
 
 /* A few user-configurable values that apply to all boards.
    First set are undocumented and spelled per Intel recommendations. */
@@ -36,14 +36,17 @@
 #define SKBUFF_RX_COPYBREAK 256
 
 #include <linux/config.h>
-#include <linux/version.h>
 #ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
 #include <linux/module.h>
 #else
 #define MOD_INC_USE_COUNT
 #define MOD_DEC_USE_COUNT
 #endif
 
+#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -55,7 +58,6 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/bios32.h>
-#include <linux/init.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -113,6 +115,10 @@
 #define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
 #endif
 
+#if (LINUX_VERSION_CODE < 0x20123)
+#define test_and_set_bit(val, addr) set_bit(val, addr)
+#endif
+
 /* The total I/O port extent of the board.  Nominally 0x18, but rounded up
    for PCI allocation. */
 #define SPEEDO3_TOTAL_SIZE 0x20
@@ -143,7 +149,7 @@
 need to be set on the board.  The system BIOS should be set to assign the
 PCI INTA signal to an otherwise unused system IRQ line.  While it's
 possible to share PCI interrupt lines, it negatively impacts performance and
-only recent kernels support it. 
+only recent kernels support it.
 
 III. Driver operation
 
@@ -421,13 +427,17 @@
 	0x3f, 0x05, };
 
 /* PHY media interface chips. */
-static const char *phys[] = { "None", "i82553-A/B", "i82553-C", "i82503",
-								  "DP83840", "80c240", "80c24", "unknown" };
+static const char *phys[] = {
+	"None", "i82553-A/B", "i82553-C", "i82503",
+	"DP83840", "80c240", "80c24", "i82555",
+	"unknown-8", "unknown-9", "DP83840A", "unknown-11",
+	"unknown-12", "unknown-13", "unknown-14", "unknown-15", };
 enum phy_chips { NonSuchPhy=0, I82553AB, I82553C, I82503, DP83840, S80C240,
-					 S80C24, PhyUndefined, };
+					 S80C24, I82555, DP83840A=10, };
 static const char is_mii[] = { 0, 1, 1, 0, 1, 1, 0, 1 };
 
-static void speedo_found1(struct device *dev, int ioaddr, int irq, int options);
+static void speedo_found1(struct device *dev, int ioaddr, int irq,
+						  int options, int card_idx);
 
 static int read_eeprom(int ioaddr, int location);
 static int mdio_read(int ioaddr, int phy_id, int location);
@@ -448,18 +458,19 @@
 
 
 
-#ifdef MODULE
 /* The parameters that may be passed in... */
 /* 'options' is used to pass a transceiver override or full-duplex flag
    e.g. "options=16" for FD, "options=32" for 100mbps-only. */
+static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+#ifdef MODULE
 static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
 static int debug = -1;			/* The debug level */
+#endif
 
 /* A list of all installed Speedo devices, for removing the driver module. */
 static struct device *root_speedo_dev = NULL;
-#endif
 
-__initfunc(int eepro100_init(struct device *dev))
+int eepro100_init(struct device *dev)
 {
 	int cards_found = 0;
 
@@ -510,11 +521,13 @@
 				printk("  PCI latency timer (CFLT) is %#x.\n", pci_latency);
 
 #ifdef MODULE
-			speedo_found1(dev, pci_ioaddr, pci_irq_line, options[cards_found]);
+			speedo_found1(dev, pci_ioaddr, pci_irq_line, options[cards_found],
+						  cards_found);
 #else
 			speedo_found1(dev, pci_ioaddr, pci_irq_line,
-						  dev ? dev->mem_start : 0);
+						  dev ? dev->mem_start : 0, -1);
 #endif
+			dev = NULL;
 			cards_found++;
 		}
 	}
@@ -522,7 +535,8 @@
 	return cards_found;
 }
 
-__initfunc(static void speedo_found1(struct device *dev, int ioaddr, int irq, int options))
+static void speedo_found1(struct device *dev, int ioaddr, int irq, int options,
+						  int card_idx)
 {
 	static int did_version = 0;			/* Already printed version info. */
 	struct speedo_private *sp;
@@ -591,26 +605,27 @@
 			if (eeprom[5] & (1<<i))
 				printk(connectors[i]);
 		printk("\n"KERN_INFO"  Primary interface chip %s PHY #%d.\n",
-			   phys[(eeprom[6]>>8)&7], eeprom[6] & 0x1f);
+			   phys[(eeprom[6]>>8)&15], eeprom[6] & 0x1f);
 		if (eeprom[7] & 0x0700)
 			printk(KERN_INFO "    Secondary interface chip %s.\n",
 				   phys[(eeprom[7]>>8)&7]);
 #if defined(notdef)
 		/* ToDo: Read and set PHY registers through MDIO port. */
 		for (i = 0; i < 2; i++)
-			printk("  MDIO register %d is %4.4x.\n",
+			printk(KERN_INFO"  MDIO register %d is %4.4x.\n",
 				   i, mdio_read(ioaddr, eeprom[6] & 0x1f, i));
 		for (i = 5; i < 7; i++)
-			printk("  MDIO register %d is %4.4x.\n",
+			printk(KERN_INFO"  MDIO register %d is %4.4x.\n",
 				   i, mdio_read(ioaddr, eeprom[6] & 0x1f, i));
-		printk("  MDIO register %d is %4.4x.\n",
+		printk(KERN_INFO"  MDIO register %d is %4.4x.\n",
 			   25, mdio_read(ioaddr, eeprom[6] & 0x1f, 25));
 #endif
-		if (((eeprom[6]>>8) & 0x3f) == DP83840) {
+		if (((eeprom[6]>>8) & 0x3f) == DP83840
+			||  ((eeprom[6]>>8) & 0x3f) == DP83840A) {
 			int mdi_reg23 = mdio_read(ioaddr, eeprom[6] & 0x1f, 23) | 0x0422;
 			if (congenb)
 			  mdi_reg23 |= 0x0100;
-			printk("  DP83840 specific setup, setting register 23 to %4.4x.\n",
+			printk(KERN_INFO"  DP83840 specific setup, setting register 23 to %4.4x.\n",
 				   mdi_reg23);
 			mdio_write(ioaddr, eeprom[6] & 0x1f, 23, mdi_reg23);
 		}
@@ -642,7 +657,7 @@
 				   KERN_ERR " Verify that the card is a bus-master"
 				   " capable slot.\n",
 				   self_test_results[1]);
-		} else 
+		} else
 			printk(KERN_INFO "  General self-test: %s.\n"
 				   KERN_INFO "  Serial sub-system self-test: %s.\n"
 				   KERN_INFO "  Internal registers self-test: %s.\n"
@@ -670,7 +685,11 @@
 	root_speedo_dev = dev;
 #endif
 
-	sp->full_duplex = options >= 0 && (options & 0x10) ? 1 : 0;
+	if (card_idx >= 0) {
+		if (full_duplex[card_idx] >= 0)
+			sp->full_duplex = full_duplex[card_idx];
+	} else
+		sp->full_duplex = options >= 0 && (options & 0x10) ? 1 : 0;
 	sp->default_port = options >= 0 ? (options & 0x0f) : 0;
 
 	sp->phy[0] = eeprom[6];
@@ -715,16 +734,16 @@
 #define EE_READ_CMD		(6 << 6)
 #define EE_ERASE_CMD	(7 << 6)
 
-__initfunc(static int read_eeprom(int ioaddr, int location))
+static int read_eeprom(int ioaddr, int location)
 {
 	int i;
 	unsigned short retval = 0;
 	int ee_addr = ioaddr + SCBeeprom;
 	int read_cmd = location | EE_READ_CMD;
-	
+
 	outw(EE_ENB & ~EE_CS, ee_addr);
 	outw(EE_ENB, ee_addr);
-	
+
 	/* Shift the read command bits out. */
 	for (i = 10; i >= 0; i--) {
 		short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
@@ -736,7 +755,7 @@
 		eeprom_delay(250);
 	}
 	outw(EE_ENB, ee_addr);
-	
+
 	for (i = 15; i >= 0; i--) {
 		outw(EE_ENB | EE_SHIFT_CLK, ee_addr);
 		eeprom_delay(100);
@@ -830,22 +849,19 @@
 	/* Load the statistics block address. */
 	outl(virt_to_bus(&sp->lstats), ioaddr + SCBPointer);
 	outw(INT_MASK | CU_STATSADDR, ioaddr + SCBCmd);
-	synchronize_irq();
 	sp->lstats.done_marker = 0;
 
 	speedo_init_rx_ring(dev);
 	outl(0, ioaddr + SCBPointer);
 	outw(INT_MASK | RX_ADDR_LOAD, ioaddr + SCBCmd);
-	synchronize_irq();	
 
 	/* Todo: verify that we must wait for previous command completion. */
 	wait_for_cmd_done(ioaddr + SCBCmd);
 	outl(virt_to_bus(sp->rx_ringp[0]), ioaddr + SCBPointer);
 	outw(INT_MASK | RX_START, ioaddr + SCBCmd);
-	synchronize_irq();
 
 	/* Fill the first command with our physical address. */
-	{ 
+	{
 		unsigned short *eaddrs = (unsigned short *)dev->dev_addr;
 		unsigned short *setup_frm = (short *)&(sp->tx_ring[0].tx_desc_addr);
 
@@ -863,7 +879,6 @@
 
 	outl(0, ioaddr + SCBPointer);
 	outw(INT_MASK | CU_CMD_BASE, ioaddr + SCBCmd);
-	synchronize_irq();
 
 	dev->if_port = sp->default_port;
 
@@ -988,29 +1003,33 @@
 		   "command %4.4x.\n",
 		   dev->name, inw(ioaddr + SCBStatus), inw(ioaddr + SCBCmd));
 #ifndef final_version
-	printk("%s:  Tx timeout  fill index %d  scavenge index %d.\n",
+	printk(KERN_WARNING "%s:  Tx timeout  fill index %d  scavenge index %d.\n",
 		   dev->name, sp->cur_tx, sp->dirty_tx);
-	printk("    Tx queue ");
+	printk(KERN_WARNING "    Tx queue ");
 	for (i = 0; i < TX_RING_SIZE; i++)
 	  printk(" %8.8x", (int)sp->tx_ring[i].status);
-	printk(".\n    Rx ring ");
+	printk(".\n" KERN_WARNING "    Rx ring ");
 	for (i = 0; i < RX_RING_SIZE; i++)
 	  printk(" %8.8x", (int)sp->rx_ringp[i]->status);
 	printk(".\n");
-		
+
 #else
 	dev->if_port ^= 1;
-	printk("  (Media type switching not yet implemented.)\n");
+	printk(KERN_WARNING "  (Media type switching not yet implemented.)\n");
 	/* Do not do 'dev->tbusy = 0;' there -- it is incorrect. */
 #endif
 	if ((inw(ioaddr + SCBStatus) & 0x00C0) != 0x0080) {
-	  printk("%s: Trying to restart the transmitter...\n", dev->name);
+	  printk(KERN_WARNING "%s: Trying to restart the transmitter...\n",
+			 dev->name);
 	  outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]),
 		   ioaddr + SCBPointer);
 	  outw(CU_START, ioaddr + SCBCmd);
 	} else {
 	  outw(DRVR_INT, ioaddr + SCBCmd);
 	}
+	/* Reset the MII transceiver. */
+	if ((sp->phy[0] & 0x8000) == 0)
+		mdio_write(ioaddr, sp->phy[0] & 0x1f, 0, 0x8000);
 	sp->stats.tx_errors++;
 	dev->trans_start = jiffies;
 	return;
@@ -1151,7 +1170,7 @@
 		  printk(KERN_WARNING"%s: The EEPro100 receiver left the ready"
 				 " state -- %4.4x!  Index %d (%d).\n", dev->name, status,
 				 sp->cur_rx, sp->cur_rx % RX_RING_SIZE);
-		  printk("   Rx ring:\n ");
+		  printk(KERN_WARNING "   Rx ring:\n ");
 		  for (i = 0; i < RX_RING_SIZE; i++)
 			printk("   %d %8.8x %8.8x %8.8x %d %d.\n",
 				   i, sp->rx_ringp[i]->status, sp->rx_ringp[i]->link,
@@ -1194,7 +1213,8 @@
 
 #ifndef final_version
 			if (sp->cur_tx - dirty_tx > TX_RING_SIZE) {
-				printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+				printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d,"
+					   " full=%d.\n",
 					   dirty_tx, sp->cur_tx, sp->tx_full);
 				dirty_tx += TX_RING_SIZE;
 			}
@@ -1212,7 +1232,7 @@
 		}
 
 		if (--boguscnt < 0) {
-			printk("%s: Too much work at interrupt, status=0x%4.4x.\n",
+			printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n",
 				   dev->name, status);
 			/* Clear all interrupt sources. */
 			outl(0xfc00, ioaddr + SCBStatus);
@@ -1250,7 +1270,7 @@
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
 	int entry = sp->cur_rx % RX_RING_SIZE;
 	int status;
-		
+
 	if (speedo_debug > 4)
 		printk(KERN_DEBUG " In speedo_rx().\n");
 	/* If we own the next entry, it's a new packet. Send it up. */
@@ -1260,12 +1280,12 @@
 			printk(KERN_DEBUG "  speedo_rx() status %8.8x len %d.\n", status,
 				   sp->rx_ringp[entry]->count & 0x3fff);
 		if (status & 0x0200) {
-			printk("%s: Ethernet frame overran the Rx buffer, status %8.8x!\n",
-				   dev->name, status);
+			printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, "
+				   "status %8.8x!\n", dev->name, status);
 		} else if ( ! (status & 0x2000)) {
 			/* There was a fatal error.  This *should* be impossible. */
 			sp->stats.rx_errors++;
-			printk("%s: Anomalous event in speedo_rx(), status %8.8x.\n",
+			printk(KERN_ERR "%s: Anomalous event in speedo_rx(), status %8.8x.\n",
 				   dev->name, status);
 		} else {
 			/* Malloc up new buffer, compatible with net-2e. */
@@ -1284,7 +1304,7 @@
 #ifdef KERNEL_1_2
 				temp = skb->data;
 				if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp)
-					printk("%s: Warning -- the skbuff addresses do not match"
+					printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match"
 						   " in speedo_rx: %p vs. %p / %p.\n", dev->name,
 						   bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
 						   temp, skb->data);
@@ -1293,7 +1313,7 @@
 #else
 				temp = skb_put(skb, pkt_len);
 				if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp)
-					printk("%s: Warning -- the skbuff addresses do not match"
+					printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match"
 						   " in speedo_rx: %8.8x vs. %p / %p.\n", dev->name,
 						   sp->rx_ringp[entry]->rx_buf_addr, skb->head, temp);
 				/* Get a fresh skbuff to replace the filled one. */
@@ -1330,7 +1350,7 @@
 #endif
 			if (skb == NULL) {
 				int i;
-				printk("%s: Memory squeeze, deferring packet.\n", dev->name);
+				printk(KERN_ERR "%s: Memory squeeze, deferring packet.\n", dev->name);
 				/* Check that at least two ring entries are free.
 				   If not, free one and mark stats->rx_dropped++. */
 				/* ToDo: This is not correct!!!!  We should count the number
@@ -1377,7 +1397,7 @@
 		}
 
 		/*	ToDo: This is better than before, but should be checked. */
-		{ 
+		{
 			struct RxFD *rxf = sp->rx_ringp[entry];
 			rxf->status = 0xC0000003; 		/* '3' for verification only */
 			rxf->link = 0;			/* None yet. */
@@ -1414,7 +1434,6 @@
 	/* Disable interrupts, and stop the chip's Rx process. */
 	outw(INT_MASK, ioaddr + SCBCmd);
 	outw(INT_MASK | RX_ABORT, ioaddr + SCBCmd);
-	synchronize_irq();
 
 #ifdef SA_SHIRQ
 	free_irq(dev->irq, dev);
@@ -1446,19 +1465,20 @@
 
 	/* Print a few items for debugging. */
 	if (speedo_debug > 3) {
-		printk("%s:Printing Rx ring (next to receive into %d).\n",
+		int phy_num = sp->phy[0] & 0x1f;
+		printk(KERN_DEBUG "%s:Printing Rx ring (next to receive into %d).\n",
 			   dev->name, sp->cur_rx);
 
 		for (i = 0; i < RX_RING_SIZE; i++)
-			printk("  Rx ring entry %d  %8.8x.\n",
+			printk(KERN_DEBUG "  Rx ring entry %d  %8.8x.\n",
 				   i, (int)sp->rx_ringp[i]->status);
 
 		for (i = 0; i < 5; i++)
-			printk("  PHY index %d register %d is %4.4x.\n",
-				   1, i, mdio_read(ioaddr, 1, i));
+			printk(KERN_DEBUG "  PHY index %d register %d is %4.4x.\n",
+				   phy_num, i, mdio_read(ioaddr, phy_num, i));
 		for (i = 21; i < 26; i++)
-			printk("  PHY index %d register %d is %4.4x.\n",
-				   1, i, mdio_read(ioaddr, 1, i));
+			printk(KERN_DEBUG "  PHY index %d register %d is %4.4x.\n",
+				   phy_num, i, mdio_read(ioaddr, phy_num, i));
 	}
 	MOD_DEC_USE_COUNT;
 
@@ -1529,7 +1549,7 @@
 
 	if (sp->cur_tx - sp->dirty_tx >= TX_RING_SIZE - 1) {
 	  /* The Tx ring is full -- don't add anything!  Presumably the new mode
-	     is in config_cmd_data and will be added anyway. */
+		 is in config_cmd_data and will be added anyway. */
 		sp->rx_mode = -1;
 		return;
 	}
@@ -1565,7 +1585,7 @@
 		restore_flags(flags);
 		if (speedo_debug > 5) {
 			int i;
-			printk(" CmdConfig frame in entry %d.\n", entry);
+			printk(KERN_DEBUG " CmdConfig frame in entry %d.\n", entry);
 			for(i = 0; i < 32; i++)
 				printk(" %2.2x", ((unsigned char *)&sp->config_cmd)[i]);
 			printk(".\n");
@@ -1618,20 +1638,19 @@
 			if (sp->mc_setup_frm)
 				kfree(sp->mc_setup_frm);
 			sp->mc_setup_frm_len = 10 + dev->mc_count*6 + 24;
-			printk("%s: Allocating a setup frame of size %d.\n",
-				   dev->name, sp->mc_setup_frm_len);
-			sp->mc_setup_frm = kmalloc(sp->mc_setup_frm_len,
-									   in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+			sp->mc_setup_frm = kmalloc(sp->mc_setup_frm_len, GFP_ATOMIC);
 			if (sp->mc_setup_frm == NULL) {
-			  printk("%s: Failed to allocate a setup frame.\n", dev->name);
+			  printk(KERN_ERR "%s: Failed to allocate a setup frame.\n", dev->name);
 				sp->rx_mode = -1; /* We failed, try again. */
 				return;
 			}
 		}
 		mc_setup_frm = sp->mc_setup_frm;
 		/* Construct the new setup frame. */
-		printk("%s: Constructing a setup frame at %p, %d bytes.\n",
-			   dev->name, sp->mc_setup_frm, sp->mc_setup_frm_len);
+		if (speedo_debug > 1)
+			printk(KERN_DEBUG "%s: Constructing a setup frame at %p, "
+				   "%d bytes.\n",
+				   dev->name, sp->mc_setup_frm, sp->mc_setup_frm_len);
 		mc_setup_frm->status = 0;
 		mc_setup_frm->command = CmdSuspend | CmdIntr | CmdMulticastList;
 		/* Link set below. */
@@ -1645,7 +1664,7 @@
 			*setup_params++ = *eaddrs++;
 			*setup_params++ = *eaddrs++;
 		}
-		
+
 		/* Disable interrupts while playing with the Tx Cmd list. */
 		save_flags(flags);
 		cli();
@@ -1669,8 +1688,9 @@
 		outw(CU_RESUME, ioaddr + SCBCmd);
 		sp->last_cmd = mc_setup_frm;
 		restore_flags(flags);
-		printk("%s: Last command at %p is %4.4x.\n",
-			   dev->name, sp->last_cmd, sp->last_cmd->command);
+		if (speedo_debug > 1)
+			printk(KERN_DEBUG "%s: Last command at %p is %4.4x.\n",
+				   dev->name, sp->last_cmd, sp->last_cmd->command);
 	}
 
 	sp->rx_mode = new_rx_mode;
@@ -1693,7 +1713,7 @@
 
 	root_speedo_dev = NULL;
 	cards_found = eepro100_init(NULL);
-	return cards_found < 0 ? cards_found : 0;
+	return cards_found ? 0 : -ENODEV;
 }
 
 void
@@ -1711,7 +1731,7 @@
 	}
 }
 #else   /* not MODULE */
-__initfunc(int eepro100_probe(struct device *dev))
+int eepro100_probe(struct device *dev)
 {
 	int cards_found = 0;
 
@@ -1726,8 +1746,9 @@
 
 /*
  * Local variables:
- *  compile-command: "gcc -DCONFIG_MODVERSIONS -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c"
+ *  compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c"
  *  c-indent-level: 4
+ *  c-basic-offset: 4
  *  tab-width: 4
  * End:
  */
diff -u --recursive --new-file v2.1.51/linux/drivers/net/tlan.c linux/drivers/net/tlan.c
--- v2.1.51/linux/drivers/net/tlan.c	Thu Jul 17 10:06:05 1997
+++ linux/drivers/net/tlan.c	Thu Aug 28 19:39:13 1997
@@ -35,6 +35,7 @@
 #include <linux/ioport.h>
 #include <linux/pci.h>
 #include <linux/etherdevice.h>
+#include <linux/delay.h>
 
 
 
@@ -44,15 +45,21 @@
 	static	int				TLanDevicesInstalled = 0;
 #endif
 	static  int				debug = 0;
+	static	int				aui = 0;
 	static	u8				*TLanPadBuffer;
 	static	char			TLanSignature[] = "TLAN";
 	static	int				TLanVersionMajor = 0;
-	static	int				TLanVersionMinor = 27;
+	static	int				TLanVersionMinor = 32;
 
 	static	TLanPciId TLanDeviceList[] = {
 		{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10,  "Compaq Netelligent 10" },
 		{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100, "Compaq Netelligent 10/100" }, 
-		{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETFLEX_3_INTEGRATED, "Compaq Integrated NetFlex-3" }, 
+		{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETFLEX_3P_INTEGRATED, "Compaq Integrated NetFlex-3/P" }, 
+		{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETFLEX_3P, "Compaq NetFlex-3/P" },
+		{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETFLEX_3P_BNC, "Compaq NetFlex-3/P w/ BNC" },
+		{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100_PROLIANT, "Compaq ProLiant Netelligent 10/100" },
+		{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100_DUAL, "Compaq Dual Port Netelligent 10/100" },
+		{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_DESKPRO_4000_5233MMX, "Compaq Deskpro 4000 5233MMX" },
 		{ 0, 0, NULL } /* End of List */
 	};
 
@@ -100,6 +107,7 @@
 			u16 sio, tmp;
 			u32 i;
 			int	err;
+			int minten;
 
 			err = FALSE;
 			outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR);
@@ -108,8 +116,10 @@
 			cli();
 
 			TLan_MiiSync(base_port);
-
-			TLan_ClearBit(TLAN_NET_SIO_MINTEN, sio);		/* Disable PHY ints */
+			
+			minten = TLan_GetBit( TLAN_NET_SIO_MINTEN, sio );
+			if ( minten )
+				TLan_ClearBit(TLAN_NET_SIO_MINTEN, sio);
 
 			TLan_MiiSendData( base_port, 0x1, 2 );			/* Start ( 01b ) */
 			TLan_MiiSendData( base_port, 0x2, 2 );			/* Read  ( 10b ) */
@@ -145,7 +155,8 @@
 			TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);			/* Idle cycle */
 			TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
 
-			TLan_SetBit(TLAN_NET_SIO_MINTEN, sio);			/* Enable PHY ints */
+			if ( minten )
+				TLan_SetBit(TLAN_NET_SIO_MINTEN, sio);
 
 			*val = tmp;
 
@@ -250,6 +261,7 @@
 		void TLan_MiiWriteReg(u16 base_port, u16 dev, u16 reg, u16 val)
 		{
 			u16 sio;
+			int	minten;
 
 			outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR);
 			sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO;
@@ -258,7 +270,9 @@
 
 			TLan_MiiSync( base_port );
 
-			TLan_ClearBit( TLAN_NET_SIO_MINTEN, sio );
+			minten = TLan_GetBit( TLAN_NET_SIO_MINTEN, sio );
+			if ( minten )
+				TLan_ClearBit( TLAN_NET_SIO_MINTEN, sio );
 
 			TLan_MiiSendData( base_port, 0x1, 2 );			/* Start ( 01b ) */
 			TLan_MiiSendData( base_port, 0x1, 2 );			/* Write ( 01b ) */
@@ -271,7 +285,8 @@
 			TLan_ClearBit( TLAN_NET_SIO_MCLK, sio );		/* Idle cycle */
 			TLan_SetBit( TLAN_NET_SIO_MCLK, sio );
 
-			TLan_SetBit( TLAN_NET_SIO_MINTEN, sio );
+			if ( minten )
+				TLan_SetBit( TLAN_NET_SIO_MINTEN, sio );
 
 			sti();
 
@@ -447,11 +462,11 @@
 		int TLan_PhyInternalCheck( struct device *dev )
 		{
 			u16				gen_ctl;
-			int				i;
 			u32				io;
 			u16				phy;
 			TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
 			u16				value;
+			u8				sio;
 
 			io = dev->base_addr;
 			phy = priv->phyAddr;
@@ -461,8 +476,7 @@
 				TLan_MiiSync( io );
             	TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE );
             	TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK );
-				for ( i = 0; i < 500000; i++ )
-					SLOW_DOWN_IO;
+				udelay(50000);
             	TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_RESET | MII_GC_LOOPBK );
             	TLan_MiiSync( io );
 			}
@@ -475,14 +489,20 @@
             // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_DUPLEX );
             TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0 );
 
-				for ( i = 0; i < 500000; i++ )
-					SLOW_DOWN_IO;
+			udelay(500000);
+
+            TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value );
+			if ( aui ) 
+				value |= TLAN_TC_AUISEL;
+			else
+				value &= ~TLAN_TC_AUISEL;
+            TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value );
 
 			// Read Possible Latched Link Status
             TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); 
 			// Read Real Link Status
             TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); 
-			if ( value & MII_GS_LINK ) {
+			if ( ( value & MII_GS_LINK ) || aui ) {
 				priv->phyOnline = 1;
 				TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK );
 			} else {
@@ -494,6 +514,10 @@
             TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value );
             value |= TLAN_TC_INTEN;
             TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value );
+
+			sio = TLan_DioRead8( io, TLAN_NET_SIO );
+			sio |= TLAN_NET_SIO_MINTEN;
+			TLan_DioWrite8( io, TLAN_NET_SIO, sio );
 			
 			return 0;
 
@@ -530,7 +554,7 @@
 			TLan_MiiReadReg( io, phy, TLAN_TLPHY_STS, &tlphy_sts );
            	TLan_MiiReadReg( io, phy, MII_GEN_STS, &gen_sts ); 
            	TLan_MiiReadReg( io, phy, MII_AN_EXP, &an_exp ); 
-			if ( gen_sts & MII_GS_LINK ) {
+			if ( ( gen_sts & MII_GS_LINK ) || aui ) {
 				priv->phyOnline = 1;
 				TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK );
 			} else {
@@ -566,6 +590,7 @@
 			u16				phy;
 			TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
 			u16				value;
+			u8				sio;
 
 			io = dev->base_addr;
 			phy = priv->phyAddr;
@@ -612,6 +637,9 @@
             value |= TLAN_TC_INTEN;
             TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value );
 */
+			sio = TLan_DioRead8( dev->base_addr, TLAN_NET_SIO );
+			sio &= ~TLAN_NET_SIO_MINTEN;
+			TLan_DioWrite8( dev->base_addr, TLAN_NET_SIO, sio );
 			priv->phyOnline = 1;
 			
 			return 0;
@@ -741,7 +769,8 @@
 			printk( "TLAN:      Forward    = 0x%08x\n",  list->forward );
 			printk( "TLAN:      CSTAT      = 0x%04hx\n", list->cStat );
 			printk( "TLAN:      Frame Size = 0x%04hx\n", list->frameSize );
-			for ( i = 0; i < 10; i++ ) {
+			// for ( i = 0; i < 10; i++ ) {
+			for ( i = 0; i < 2; i++ ) {
 				printk( "TLAN:      Buffer[%d].count, addr = 0x%08x, 0x%08x\n", i, list->buffer[i].count, list->buffer[i].address );
 			}
 
@@ -874,14 +903,13 @@
 			TLan_SetBit( TLAN_NET_SIO_NMRST, dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO );
 		//	10a. Other.
 		//	12. Setup the NetMask register.
-		TLan_DioWrite8( dev->base_addr, TLAN_INT_DIS, TLAN_ID_TX_EOC | TLAN_ID_RX_EOC );
+		if ( priv->tlanRev >= 0x30 )
+			TLan_DioWrite8( dev->base_addr, TLAN_INT_DIS, TLAN_ID_TX_EOC | TLAN_ID_RX_EOC );
 		//TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, TLAN_NET_CMD_NRESET | TLAN_NET_CMD_NWRAP | TLAN_NET_CMD_DUPLEX | TLAN_NET_CMD_CAF );
 		TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, TLAN_NET_CMD_NRESET | TLAN_NET_CMD_NWRAP );
 		//	11. Initialize PHYs.
 		TLan_PhySelect( dev );
 		(*priv->phyCheck)( dev ); 
-		if ( debug >= 1 )
-			TLan_PhyPrint( dev );
 
 		//data8 = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5 | TLAN_NET_MASK_MASK6 | TLAN_NET_MASK_MASK7; 
 		data8 = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5 | TLAN_NET_MASK_MASK7; 
@@ -1226,7 +1254,7 @@
 			TLanList		*head_list;
 			u32				ack = 1;
 
-			// printk( "TLAN:  Handling Tx EOF\n" );
+			TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  Handling TX EOF (Head=%d Tail=%d)\n", priv->txHead, priv->txTail );
 			host_int = 0;
 			head_list = priv->txList + priv->txHead;
 			if ( head_list->cStat & TLAN_CSTAT_EOC )
@@ -1235,13 +1263,18 @@
 				printk( "TLAN:  Received interrupt for uncompleted TX frame.\n" );
 			}
 			// printk( "Ack %d CSTAT=%hx\n", priv->txHead, head_list->cStat );
+
+#if LINUX_KERNEL_VERSION > 0x20100
+			priv->stats->tx_bytes += head_list->frameSize;
+#endif
+
 			head_list->cStat = TLAN_CSTAT_UNUSED;
 			dev->tbusy = 0;
 			priv->txHead++;
 			if ( priv->txHead >= TLAN_NUM_TX_LISTS )
 				priv->txHead = 0;
 			if ( eoc ) {
-				// printk( "TLAN:  Handling Tx EOC\n" );
+				TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  Handling TX EOC (Head=%d Tail=%d)\n", priv->txHead, priv->txTail );
 				head_list = priv->txList + priv->txHead;
 				if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) {
 					outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM );
@@ -1326,7 +1359,7 @@
 			TLanList		*tail_list;
 			void			*t;
 
-			// printk( "TLAN:  Handling Rx EOF Head=%d Tail=%d\n", priv->rxHead, priv->rxTail );
+			TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE:  Handling RX EOF (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail );
 			host_int = 0;
 			head_list = priv->rxList + priv->rxHead;
 			tail_list = priv->rxList + priv->rxTail;
@@ -1344,6 +1377,11 @@
 					skb_reserve( skb, 2 );
 					t = (void *) skb_put( skb, head_list->frameSize );
 					// printk( " %hd %p %p\n", head_list->frameSize, skb->data, t );
+
+#if LINUX_KERNEL_VERSION > 0x20100
+					priv->stats->rx_bytes += head_list->frameSize;
+#endif
+
 					memcpy( t, head_buffer, head_list->frameSize );
 					skb->protocol = eth_type_trans( skb, dev );
 					netif_rx( skb );
@@ -1360,7 +1398,7 @@
 			if ( priv->rxTail >= TLAN_NUM_RX_LISTS )
 				priv->rxTail = 0;
 			if ( eoc ) { 
-				// printk( "TLAN:  Handling Rx EOC Head=%d Tail=%d\n", priv->rxHead, priv->rxTail );
+				TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE:  Handling RX EOC (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail );
 				head_list = priv->rxList + priv->rxHead;
 				outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM );
 				ack |= TLAN_HC_GO | TLAN_HC_RT;
@@ -1421,15 +1459,30 @@
 	 *
 	 *	This driver is structured to determine EOC occurances by reading the
 	 *	CSTAT member of the list structure.  Tx EOC interrupts are disabled
-	 *	via the DIO INTDIS register.
+	 *	via the DIO INTDIS register.  However, TLAN chips before revision 3.0
+	 *	didn't have this functionality, so process EOC events if this is the
+	 *	case.
 	 *
 	 ************************************************************************/
 
 		u32 TLan_HandleTxEOC( struct device *dev, u16 host_int )
 		{
+			TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+			TLanList		*head_list;
+			u32				ack = 1;
+
 			host_int = 0;
-			printk( "TLAN:  Tx EOC interrupt on %s.\n", dev->name );
-			return 1;
+			if ( priv->tlanRev < 0x30 ) {
+				TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  Handling TX EOC (Head=%d Tail=%d) -- IRQ\n", priv->txHead, priv->txTail );
+				head_list = priv->txList + priv->txHead;
+				if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) {
+					outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM );
+					ack |= TLAN_HC_GO;
+				} else {
+					priv->txInProgress = 0;
+				}
+			}
+			return ack;
 
 		} /* TLan_HandleTxEOC */
 
@@ -1485,10 +1538,13 @@
 				net_sts = TLan_DioRead8( dev->base_addr, TLAN_NET_STS );
 				if ( net_sts )
 					TLan_DioWrite8( dev->base_addr, TLAN_NET_STS, net_sts );
-				if ( net_sts & TLAN_NET_STS_MIRQ )
+				if ( net_sts & TLAN_NET_STS_MIRQ ) {
 					(*priv->phyService)( dev );
-					
-				TLAN_DBG( 1, "TLAN: Status Check! %s Net_Sts=%x\n", dev->name, (unsigned) net_sts );
+					if (debug) {
+						TLan_PhyPrint( dev );
+					}
+				}
+				TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  Status Check! %s Net_Sts=%x\n", dev->name, (unsigned) net_sts );
 			}
 
 			return ack;
@@ -1507,15 +1563,27 @@
 	 *
 	 *	This driver is structured to determine EOC occurances by reading the
 	 *	CSTAT member of the list structure.  Rx EOC interrupts are disabled
-	 *	via the DIO INTDIS register.
+	 *	via the DIO INTDIS register.  However, TLAN chips before revision 3.0
+	 *  didn't have this CSTAT member or a INTDIS register, so if this chip
+	 *	is pre-3.0, process EOC interrupts normally.
 	 *
 	 ************************************************************************/
 
 		u32 TLan_HandleRxEOC( struct device *dev, u16 host_int )
 		{
+			TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+			TLanList		*head_list;
+			u32				ack = 1;
+
 			host_int = 0;
-			printk( "TLAN:  Rx EOC interrupt on %s.\n", dev->name );
-			return 1;
+			if (  priv->tlanRev < 0x30 ) {
+				TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE:  Handling RX EOC (Head=%d Tail=%d) -- IRQ\n", priv->rxHead, priv->rxTail );
+				head_list = priv->rxList + priv->rxHead;
+				outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM );
+				ack |= TLAN_HC_GO | TLAN_HC_RT;
+				priv->rxEocCount++;
+			}
+			return ack;
 
 		} /* TLan_HandleRxEOC */
 
@@ -1629,7 +1697,7 @@
 	static	int		TLan_StartTx(struct sk_buff *, struct device *);
 	static	void	TLan_HandleInterrupt(int, void *, struct pt_regs *);
 	static	int		TLan_Close(struct device *);
-	static	struct enet_statistics *TLan_GetStats( struct device * );
+	static	struct net_device_stats *TLan_GetStats( struct device * );
 	static	void	TLan_SetMulticastList( struct device * );
 
 
@@ -1773,7 +1841,6 @@
 			u32				io_base, dl_ix;
 
 			found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &dl_ix );
-			TLAN_DBG( 1, "TLAN:  Probing...\n" );
 			if ( found ) {
 				dev->priv = kmalloc( sizeof(TLanPrivateInfo), GFP_KERNEL );
 				if ( dev->priv == NULL ) {
@@ -1865,7 +1932,7 @@
 												 pci_dfn
 											   );
 				if ( ! not_found ) {
-					TLAN_DBG( 1, "TLAN:   found: Vendor Id = 0x%hx, Device Id = 0x%hx\n",
+					TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  found: Vendor Id = 0x%hx, Device Id = 0x%hx\n",
 							TLanDeviceList[dl_index].vendorId,
 							TLanDeviceList[dl_index].deviceId
 						  );
@@ -1878,19 +1945,19 @@
 
 					if (pci_latency < 0x10) {
 						pcibios_write_config_byte( *pci_bus, *pci_dfn, PCI_LATENCY_TIMER, 0xff);
-						TLAN_DBG( 1, "TLAN:      Setting latency timer to max.\n");
+						TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:    Setting latency timer to max.\n");
 					}
 
 					if ((pci_command & PCI_COMMAND_IO) && (*pci_io_base & 0x3)) {
 						*pci_io_base &= PCI_BASE_ADDRESS_IO_MASK;
-						TLAN_DBG( 1, "TLAN:      IO mapping is available at %x.\n", *pci_io_base);
+						TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:    IO mapping is available at %x.\n", *pci_io_base);
 					} else {
 						*pci_io_base = 0;
-						printk("TLAN:      IO mapping not available, ignoring device.\n");
+						printk("TLAN:    IO mapping not available, ignoring device.\n");
 					}
 
 					if (pci_command & PCI_COMMAND_MASTER) {
-						TLAN_DBG( 1, "TLAN:      Bus mastering is active.\n");
+						TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:    Bus mastering is active.\n");
 					}
 
 					pci_index++;
@@ -1992,9 +2059,10 @@
 			int				err;
 			TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
 
+			priv->tlanRev = TLan_DioRead8( dev->base_addr, TLAN_DEF_REVISION );
 			err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ, TLanSignature, dev );
 			if ( err ) {
-				printk( "TLAN:  %s: IRQ %d already in use.\n", dev->name, dev->irq );
+				printk( "TLAN:  Cannot open %s because IRQ %d is already in use.\n", dev->name, dev->irq );
 				return -EAGAIN;
 			}
 
@@ -2010,6 +2078,7 @@
 			TLan_ResetLists( dev );
 			TLan_ReadAndClearStats( dev, TLAN_IGNORE );
 			TLan_Reset( dev );
+			TLan_Reset( dev );
 			TLan_SetMac( dev, 0, dev->dev_addr );
 			outb( ( TLAN_HC_INT_ON >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 );
 			if ( debug >= 1 )
@@ -2024,12 +2093,11 @@
 				priv->timerType = TLAN_TIMER_LINK;
 				add_timer( &priv->timer );
 			} else {
-				TLAN_DBG( 1, "TLAN:  RX GO\n" );
 				outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM );
 				outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD );
 			}
 
-			TLAN_DBG( 1, "TLAN:  Device %s opened.\n", dev->name );
+			TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  Device %s opened.  Revision = %x\n", dev->name, priv->tlanRev );
 
 			return 0;
 
@@ -2063,17 +2131,16 @@
 			u8				*tail_buffer;
 			int				pad;
 
-			// printk( "Entering StartTx\n" );
 			if ( ! priv->phyOnline ) {
+				TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  %s PHY is not ready\n", dev->name );
 				dev_kfree_skb( skb, FREE_WRITE );
 				return 0;
 			}
 
 			tail_list = priv->txList + priv->txTail;
 			if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) {
-				// printk( "TLAN:  %s TX is busy, Head=%d Tail=%d\n", dev->name, priv->txHead, priv->txTail );
+				TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  %s is busy (Head=%d Tail=%d)\n", dev->name, priv->txHead, priv->txTail );
 				dev->tbusy = 1;
-				// printk( "TLAN:   Tx is busy.\n");
 				priv->txBusyCount++;
 				return 1;
 			}
@@ -2098,14 +2165,11 @@
 			if ( ! priv->txInProgress ) {
 				priv->txInProgress = 1;
 				outw( 0x4, dev->base_addr + TLAN_HOST_INT );
-				// printk("TLAN: Sending GO for 0%d\n", priv->txTail );
+				TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  Starting TX on buffer %d\n", priv->txTail );
 				outl( virt_to_bus( tail_list ), dev->base_addr + TLAN_CH_PARM );
 				outl( TLAN_HC_GO | TLAN_HC_ACK, dev->base_addr + TLAN_HOST_CMD );
 			} else {
-				// printk("TLAN: Adding 0%d\n", priv->txTail );
-				// Assign previous list to point to this one.  If previous has
-				// already been read, the EOC check in the TX EOF interrupt handler
-				// will start another transfer.
+				TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  Adding buffer %d to TX channel\n", priv->txTail );
 				if ( priv->txTail == 0 )
 					( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward = virt_to_bus( tail_list );
 				else
@@ -2119,7 +2183,6 @@
 			dev_kfree_skb( skb, FREE_WRITE );
 				
 			dev->trans_start = jiffies;
-			// printk( "Leaving StartTx\n" );
 			return 0;
 
 		} /* TLan_StartTx */
@@ -2154,7 +2217,7 @@
 			dev = (struct device *) dev_id;
 
 			if ( dev->interrupt )
-				TLAN_DBG( 1, "TLAN:   Re-entering interrupt handler for %s: %d.\n" , dev->name, dev->interrupt );
+				printk( "TLAN:   Re-entering interrupt handler for %s: %d.\n" , dev->name, dev->interrupt );
 			dev->interrupt++;
 
 			cli();
@@ -2204,7 +2267,7 @@
 			if ( priv->timerSetAt != 0 )
 				del_timer( &priv->timer );
 			free_irq( dev->irq, dev );
-			TLAN_DBG( 1, "TLAN:   Device %s closed.\n", dev->name );
+			TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:   Device %s closed.\n", dev->name );
 
 			MOD_DEC_USE_COUNT;
 
@@ -2227,22 +2290,26 @@
 	 *
 	 ************************************************************************/
 
-		struct enet_statistics *TLan_GetStats( struct device *dev )
+		struct net_device_stats *TLan_GetStats( struct device *dev )
 		{
 			TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
 			int i;
 
 			/* Should only read stats if open ? */
 			TLan_ReadAndClearStats( dev, TLAN_RECORD );
-			printk( "TLAN:  %s Rx EOC Count: %d\n", dev->name, priv->rxEocCount );
-			printk( "TLAN:  %s Tx Busy Count: %d\n", dev->name, priv->txBusyCount );
-			// printk( "TLAN:   Got stats for %s.\n", dev->name );
-			TLan_PrintDio( dev->base_addr );
-			TLan_PhyPrint( dev );
-			for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ )
-				TLan_PrintList( priv->rxList + i, "RX", i );
-			for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ )
-				TLan_PrintList( priv->txList + i, "TX", i );
+
+			TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE:  %s EOC count = %d\n", dev->name, priv->rxEocCount );
+			TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  %s Busy count = %d\n", dev->name, priv->txBusyCount );
+			if ( debug & TLAN_DEBUG_GNRL ) {
+				TLan_PrintDio( dev->base_addr );
+				TLan_PhyPrint( dev );
+			}
+			if ( debug & TLAN_DEBUG_LIST ) {
+				for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ )
+					TLan_PrintList( priv->rxList + i, "RX", i );
+				for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ )
+					TLan_PrintList( priv->txList + i, "TX", i );
+			}
 			
 			return ( &( (TLanPrivateInfo *) dev->priv )->stats );
 
@@ -2307,3 +2374,6 @@
 			}
 
 		} /* TLan_SetRxMode */
+
+
+
diff -u --recursive --new-file v2.1.51/linux/drivers/net/tlan.h linux/drivers/net/tlan.h
--- v2.1.51/linux/drivers/net/tlan.h	Mon Aug 11 14:47:04 1997
+++ linux/drivers/net/tlan.h	Thu Aug 28 19:39:13 1997
@@ -1,3 +1,6 @@
+#ifndef TLAN_H
+#define TLAN_H
+
 /********************************************************************
  *
  *  Linux ThunderLAN Driver
@@ -18,6 +21,11 @@
 #include <asm/types.h>
 #include <linux/netdevice.h>
 
+#if LINUX_VERSION_CODE <= 0x20100
+#define net_device_stats	enet_statistics
+#endif
+
+
 
 
 	/*****************************************************************
@@ -37,7 +45,11 @@
 		#define TLAN_IGNORE	0
 		#define TLAN_RECORD	1
 
-		#define TLAN_DBG(lvl, format, args...)	if ( debug >= lvl ) printk( format, ##args );
+		#define TLAN_DBG(lvl, format, args...)	if ( debug & lvl ) printk( format, ##args );
+		#define TLAN_DEBUG_GNRL	0x0001
+		#define TLAN_DEBUG_TX	0x0002
+		#define TLAN_DEBUG_RX	0x0004 
+		#define TLAN_DEBUG_LIST	0x0008
 
 
 
@@ -50,7 +62,12 @@
 		/* NOTE: These should be moved to pci.h someday */
 		#define PCI_DEVICE_ID_NETELLIGENT_10 0xAE34
 		#define PCI_DEVICE_ID_NETELLIGENT_10_100 0xAE32
-		#define PCI_DEVICE_ID_NETFLEX_3_INTEGRATED 0xAE35
+		#define PCI_DEVICE_ID_NETFLEX_3P_INTEGRATED 0xAE35
+		#define PCI_DEVICE_ID_NETFLEX_3P 0xF130
+		#define PCI_DEVICE_ID_NETFLEX_3P_BNC 0xF150
+		#define PCI_DEVICE_ID_NETELLIGENT_10_100_PROLIANT 0xAE43
+		#define PCI_DEVICE_ID_NETELLIGENT_10_100_DUAL 0xAE40
+		#define PCI_DEVICE_ID_DESKPRO_4000_5233MMX 0xB011
 
 
 		typedef struct tlan_pci_id {
@@ -152,11 +169,12 @@
 			u32						timerSetAt;
 			u32						timerType;
 			struct timer_list		timer;
-			struct enet_statistics  stats;
+			struct net_device_stats	stats;
 			u32                     pciEntry;
 			u8                      pciRevision;
 			u8                      pciBus;
 			u8                      pciDeviceFn;
+			u8						tlanRev;
 			char                    devName[8];
 		} TLanPrivateInfo;
 
@@ -479,3 +497,7 @@
 
 } 
 
+
+
+
+#endif
diff -u --recursive --new-file v2.1.51/linux/drivers/pnp/parport_probe.c linux/drivers/pnp/parport_probe.c
--- v2.1.51/linux/drivers/pnp/parport_probe.c	Mon Aug  4 16:25:37 1997
+++ linux/drivers/pnp/parport_probe.c	Tue Aug 26 14:52:45 1997
@@ -52,7 +52,7 @@
 {
 	int i;
 	char *temp=buf;
-	int count = 0;
+	unsigned int count = 0;
 	unsigned char z=0;
 	unsigned char Byte=0;
 
diff -u --recursive --new-file v2.1.51/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx
--- v2.1.51/linux/drivers/scsi/ChangeLog.ncr53c8xx	Mon Aug 11 14:47:04 1997
+++ linux/drivers/scsi/ChangeLog.ncr53c8xx	Mon Aug 25 13:01:58 1997
@@ -1,3 +1,28 @@
+Thu Aug 23 23:43 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.5a
+	- Update Configure.help for inclusion in linux-2.1.51/2/3
+	- Use BASE_2 address from PCI config space instead of some 
+	  IO register for getting the on-board SRAM bus address.
+	- Remove error testing of pcibios_read/write functions.
+	  These functions are intended to be used for successfully 
+	  detected PCI devices. Expecting error condition from them 
+	  is nothing but paranoia.
+
+Thu Aug 21 23:00 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.5
+	- 53C860 chip support fix.
+	- Move the 'host_status' to the last DWORD of the CCB header.
+	  This header is copied back by the script processor. This 
+	  guarantees that the header is entirely copied back over 
+	  the PCI when the CPU completes a CCB.
+	- (re)read ISTAT prior to scanning CCBs for completion. This
+	  ensure that any posted buffer are flushed prior CCBs scan.
+	- Support for BIG ENDIAN cpu. Added by Cort <cort@cs.nmt.edu>.
+	  Initial patch did'nt support disconnections and tagged commands.
+	  I've completed the patch and it seems that all is ok now.
+	  Only some powerpc under 2.1.X is supported for the moment.
+	- Misc. trivial fixes and cleanups.
+
 Sat July 26 18:00 1997 Gerard Roudier (groudier@club-internet.fr)
 	* revision 2.4
 	Several clean-ups:
diff -u --recursive --new-file v2.1.51/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v2.1.51/linux/drivers/scsi/Config.in	Mon Aug 18 18:19:46 1997
+++ linux/drivers/scsi/Config.in	Tue Aug 26 14:52:45 1997
@@ -84,8 +84,8 @@
 if [ "$CONFIG_MCA" = "y" ]; then
   dep_tristate 'IBMMCA SCSI support' CONFIG_SCSI_IBMMCA $CONFIG_SCSI
 fi
-if [ "$CONFIG_PNP_PARPORT" != "n" ]; then
-  dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PNP_PARPORT
+if [ "$CONFIG_PARPORT" != "n" ]; then
+  dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PARPORT
   if [ "$CONFIG_SCSI_PPA" != "n" ]; then
     int  '  Pedantic EPP-checking'   CONFIG_SCSI_PPA_HAVE_PEDANTIC 2 0 3
     int  '  EPP timeout'             CONFIG_SCSI_PPA_EPP_TIME 128
diff -u --recursive --new-file v2.1.51/linux/drivers/scsi/README.ncr53c8xx linux/drivers/scsi/README.ncr53c8xx
--- v2.1.51/linux/drivers/scsi/README.ncr53c8xx	Mon Aug 11 14:47:05 1997
+++ linux/drivers/scsi/README.ncr53c8xx	Mon Aug 25 13:01:58 1997
@@ -4,7 +4,7 @@
 21 Rue Carnot
 95170 DEUIL LA BARRE - FRANCE
 
-19 June 1997
+23 August 1997
 ===============================================================================
 
 1.  Introduction
@@ -46,6 +46,9 @@
       17.1 Features
       17.2 Symbios NVRAM layout
       17.3 Tekram  NVRAM layout
+18. Support for Big Endian
+      18.1 Big Endian CPU
+      18.2 NCR chip in Big Endian mode of operations
 
 ===============================================================================
 
@@ -83,7 +86,7 @@
 driver, configuration parameters and control commands available
 through the proc SCSI file system read / write operations.
 
-This driver has been tested OK with linux/i386 and Linux/Alpha.
+This driver has been tested OK with linux/i386, Linux/Alpha and Linux/PPC.
 
 Latest driver version and patches are available at:
 
@@ -429,7 +432,10 @@
 
 CONFIG_SCSI_NCR53C8XX_IOMAPPED       (default answer: n)
     Answer "y" if you suspect your mother board to not allow memory mapped I/O.
-    May slow down performance a little.
+    May slow down performance a little.  This option is required by
+    Linux/PPC and is used no matter what you select here.  Linux/PPC
+    suffers no performance loss with this option since all IO is memory
+    mapped anyway.
 
 CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE    (default answer: n)
     Answer "y" if you are sure that all your SCSI devices that are able to 
@@ -1430,8 +1436,29 @@
 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0xfbbc
 
-===============================================================================
-End of NCR53C8XX driver README file
 
+18. Support for Big Endian
 
+The PCI local bus has been primarily designed for x86 architecture.
+As a consequence, PCI devices generally expect DWORDS using little endian 
+byte ordering.
+
+18.1 Big Endian CPU
+
+In order to support NCR chips on a Big Endian architecture the driver has to 
+perform byte reordering each time it is needed. This feature has been 
+added to the driver by Cort <cort@cs.nmt.edu> and is available in driver 
+version 2.5 and later ones. For the moment Big Endian support has only 
+been tested on Linux/PPC (PowerPC).
+
+18.2 NCR chip in Big Endian mode of operations
+
+It can be read in SYMBIOS documentation that some chips support a special 
+Big Endian mode, on paper: 53C815, 53C825A, 53C875, 53C875N, 53C895.
+This mode of operations is not software-selectable, but needs pin named 
+BigLit to be pulled-up. Using this mode, most of byte reorderings should 
+be avoided when the driver is running on a Big Endian CPU.
+Driver version 2.5 is also, in theory, ready for this feature.
 
+===============================================================================
+End of NCR53C8XX driver README file
diff -u --recursive --new-file v2.1.51/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
--- v2.1.51/linux/drivers/scsi/ncr53c8xx.c	Thu Aug 14 20:49:16 1997
+++ linux/drivers/scsi/ncr53c8xx.c	Mon Aug 25 13:01:58 1997
@@ -60,11 +60,14 @@
 **  May 19 1997 by Richard Waltham <dormouse@farsrobt.demon.co.uk>:
 **     Support for NvRAM detection and reading.
 **
+**  August 18 1997 by Cort <cort@cs.nmt.edu>:
+**     Support for Power/PC (Big Endian).
+**
 *******************************************************************************
 */
 
 /*
-**	26 July 1997, version 2.4
+**	23 August 1997, version 2.5a
 **
 **	Supported SCSI-II features:
 **	    Synchronous negotiation
@@ -306,6 +309,7 @@
 **	architecture.
 */
 
+#ifndef NCR_IOMAPPED
 __initfunc(
 static vm_offset_t remap_pci_mem(u_long base, u_long size)
 )
@@ -332,6 +336,7 @@
 		vfree((void *) (vaddr & PAGE_MASK));
 #endif
 }
+#endif	/* !NCR_IOMAPPED */
 
 #else /* linux-1.2.13 */
 
@@ -657,6 +662,7 @@
 	int	bus;
 	u_char	device_fn;
 	u_int	base;
+	u_int	base_2;
 	u_int	io_port;
 	int	irq;
 /* port and reg fields to use INB, OUTB macros */
@@ -743,79 +749,156 @@
 
 /*==========================================================
 **
-**	Access to the controller chip.
-**
-**	If NCR_IOMAPPED is defined, only IO are used by the driver.
+**	Big/Little endian support.
 **
 **==========================================================
 */
 
 /*
-**	IO mapped only input / ouput
+**	If the NCR uses big endian addressing mode over the 
+**	PCI, actual io register addresses for byte and word 
+**	accesses must be changed according to lane routing.
+**	Btw, ncr_offb() and ncr_offw() macros only apply to 
+**	constants and so donnot generate bloated code.
 */
 
-#define	IOM_INB(r)		inb (np->port + offsetof(struct ncr_reg, r))
-#define	IOM_INB_OFF(o)		inb (np->port + (o))
-#define	IOM_INW(r)		inw (np->port + offsetof(struct ncr_reg, r))
-#define	IOM_INL(r)		inl (np->port + offsetof(struct ncr_reg, r))
-#define	IOM_INL_OFF(o)		inl (np->port + (o))
-
-#define	IOM_OUTB(r, val)	outb ((val), np->port+offsetof(struct ncr_reg,r))
-#define	IOM_OUTW(r, val)	outw ((val), np->port+offsetof(struct ncr_reg,r))
-#define	IOM_OUTL(r, val)	outl ((val), np->port+offsetof(struct ncr_reg,r))
-#define	IOM_OUTL_OFF(o, val)	outl ((val), np->port + (o))
+#if	defined(SCSI_NCR_BIG_ENDIAN)
+
+#define ncr_offb(o)	(((o)&~3)+((~((o)&3))&3))
+#define ncr_offw(o)	(((o)&~3)+((~((o)&3))&2))
+
+#else
+
+#define ncr_offb(o)	(o)
+#define ncr_offw(o)	(o)
+
+#endif
 
 /*
-**	MEMORY mapped IO input / output
+**	If the CPU and the NCR use same endian-ness adressing,
+**	no byte reordering is needed for script patching.
+**	Macro cpu_to_scr() is to be used for script patching.
+**	Macro scr_to_cpu() is to be used for getting a DWORD 
+**	from the script.
 */
 
-#define MMIO_INB(r)		readb(&np->reg->r)
-#define MMIO_INB_OFF(o)		readb((char *)np->reg + (o))
-#define MMIO_INW(r)		readw(&np->reg->r)
-#define MMIO_INL(r)		readl(&np->reg->r)
-#define MMIO_INL_OFF(o)		readl((char *)np->reg + (o))
-
-#define MMIO_OUTB(r, val)	writeb((val), &np->reg->r)
-#define MMIO_OUTW(r, val)	writew((val), &np->reg->r)
-#define MMIO_OUTL(r, val)	writel((val), &np->reg->r)
-#define MMIO_OUTL_OFF(o, val)	writel((val), (char *)np->reg + (o))
+#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
+
+#define cpu_to_scr(dw)	cpu_to_le32(dw)
+#define scr_to_cpu(dw)	le32_to_cpu(dw)
+
+#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
+
+#define cpu_to_scr(dw)	cpu_to_be32(dw)
+#define scr_to_cpu(dw)	be32_to_cpu(dw)
+
+#else
+
+#define cpu_to_scr(dw)	(dw)
+#define scr_to_cpu(dw)	(dw)
+
+#endif
+
+/*==========================================================
+**
+**	Access to the controller chip.
+**
+**	If NCR_IOMAPPED is defined, only IO are used by the driver.
+**
+**==========================================================
+*/
 
 /*
-**	IO mapped input / output
+**	If the CPU and the NCR use same endian-ness adressing,
+**	no byte reordering is needed for accessing chip io 
+**	registers. Functions suffixed by '_raw' are assumed 
+**	to access the chip over the PCI without doing byte 
+**	reordering. Functions suffixed by '_l2b' are 
+**	assumed to perform little-endian to big-endian byte 
+**	reordering, those suffixed by '_b2l' blah, blah,
+**	blah, ...
 */
 
 #if defined(NCR_IOMAPPED)
 
-#define INB(r)             IOM_INB(r)
-#define INB_OFF(o)         IOM_INB_OFF(o)
-#define INW(r)             IOM_INW(r)
-#define INL(r)             IOM_INL(r)
-#define INL_OFF(o)         IOM_INL_OFF(o)
-
-#define OUTB(r, val)       IOM_OUTB(r, val)
-#define OUTW(r, val)       IOM_OUTW(r, val)
-#define OUTL(r, val)       IOM_OUTL(r, val)
-#define OUTL_OFF(o, val)   IOM_OUTL_OFF(o, val)
+/*
+**	IO mapped only input / ouput
+*/
+
+#define	INB_OFF(o)		inb (np->port + ncr_offb(o))
+#define	OUTB_OFF(o, val)	outb ((val), np->port + ncr_offb(o))
+
+#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
+
+#define	INW_OFF(o)		inw_l2b (np->port + ncr_offw(o))
+#define	INL_OFF(o)		inl_l2b (np->port + (o))
+
+#define	OUTW_OFF(o, val)	outw_b2l ((val), np->port + ncr_offw(o))
+#define	OUTL_OFF(o, val)	outl_b2l ((val), np->port + (o))
+
+#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
+
+#define	INW_OFF(o)		inw_b2l (np->port + ncr_offw(o))
+#define	INL_OFF(o)		inl_b2l (np->port + (o))
+
+#define	OUTW_OFF(o, val)	outw_l2b ((val), np->port + ncr_offw(o))
+#define	OUTL_OFF(o, val)	outl_l2b ((val), np->port + (o))
+
+#else
+
+#define	INW_OFF(o)		inw_raw (np->port + ncr_offw(o))
+#define	INL_OFF(o)		inl_raw (np->port + (o))
+
+#define	OUTW_OFF(o, val)	outw_raw ((val), np->port + ncr_offw(o))
+#define	OUTL_OFF(o, val)	outl_raw ((val), np->port + (o))
+
+#endif	/* ENDIANs */
+
+#else	/* defined NCR_IOMAPPED */
 
 /*
-**	MEMORY mapped only input / output
+**	MEMORY mapped IO input / output
 */
 
+#define INB_OFF(o)		readb((char *)np->reg + ncr_offb(o))
+#define OUTB_OFF(o, val)	writeb((val), (char *)np->reg + ncr_offb(o))
+
+#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
+
+#define INW_OFF(o)		readw_l2b((char *)np->reg + ncr_offw(o))
+#define INL_OFF(o)		readl_l2b((char *)np->reg + (o))
+
+#define OUTW_OFF(o, val)	writew_b2l((val), (char *)np->reg + ncr_offw(o))
+#define OUTL_OFF(o, val)	writel_b2l((val), (char *)np->reg + (o))
+
+#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
+
+#define INW_OFF(o)		readw_b2l((char *)np->reg + ncr_offw(o))
+#define INL_OFF(o)		readl_b2l((char *)np->reg + (o))
+
+#define OUTW_OFF(o, val)	writew_l2b((val), (char *)np->reg + ncr_offw(o))
+#define OUTL_OFF(o, val)	writel_l2b((val), (char *)np->reg + (o))
+
 #else
 
-#define INB(r)             MMIO_INB(r)
-#define INB_OFF(o)         MMIO_INB_OFF(o)
-#define INW(r)             MMIO_INW(r)
-#define INL(r)             MMIO_INL(r)
-#define INL_OFF(o)         MMIO_INL_OFF(o)
-
-#define OUTB(r, val)       MMIO_OUTB(r, val)
-#define OUTW(r, val)       MMIO_OUTW(r, val)
-#define OUTL(r, val)       MMIO_OUTL(r, val)
-#define OUTL_OFF(o, val)   MMIO_OUTL_OFF(o, val)
+#define INW_OFF(o)		readw_raw((char *)np->reg + ncr_offw(o))
+#define INL_OFF(o)		readl_raw((char *)np->reg + (o))
+
+#define OUTW_OFF(o, val)	writew_raw((val), (char *)np->reg + ncr_offw(o))
+#define OUTL_OFF(o, val)	writel_raw((val), (char *)np->reg + (o))
 
 #endif
 
+#endif	/* defined NCR_IOMAPPED */
+
+#define INB(r)		INB_OFF (offsetof(struct ncr_reg,r))
+#define INW(r)		INW_OFF (offsetof(struct ncr_reg,r))
+#define INL(r)		INL_OFF (offsetof(struct ncr_reg,r))
+
+#define OUTB(r, val)	OUTB_OFF (offsetof(struct ncr_reg,r), (val))
+#define OUTW(r, val)	OUTW_OFF (offsetof(struct ncr_reg,r), (val))
+#define OUTL(r, val)	OUTL_OFF (offsetof(struct ncr_reg,r), (val))
+
 /*
 **	Set bit field ON, OFF 
 */
@@ -827,6 +910,7 @@
 #define OUTONL(r, m)	OUTL(r, INL(r) | (m))
 #define OUTOFFL(r, m)	OUTL(r, INL(r) & ~(m))
 
+
 /*==========================================================
 **
 **	Command control block states.
@@ -1264,27 +1348,36 @@
 	**	status fields.
 	*/
 
-	u_char		status[8];
+	u_char		scr_st[4];	/* script status */
+	u_char		status[4];	/* host status. Must be the last */
+					/* DWORD of the CCB header */
 };
 
 /*
 **	The status bytes are used by the host and the script processor.
 **
-**	The first four byte are copied to the scratchb register
+**	The byte corresponding to the host_status must be stored in the 
+**	last DWORD of the CCB header since it is used for command 
+**	completion (ncr_wakeup()). Doing so, we are sure that the header 
+**	has been entirely copied back to the CCB when the host_status is 
+**	seen complete by the CPU.
+**
+**	The last four bytes (status[4]) are copied to the scratchb register
 **	(declared as scr0..scr3 in ncr_reg.h) just after the select/reselect,
 **	and copied back just after disconnecting.
 **	Inside the script the XX_REG are used.
 **
-**	The last four bytes are used inside the script by "COPY" commands.
+**	The first four bytes (scr_st[4]) are used inside the script by 
+**	"COPY" commands.
 **	Because source and destination must have the same alignment
-**	in a longword, the fields HAVE to be at the choosen offsets.
-**		xerr_st	(4)	0	(0x34)	scratcha
-**		sync_st	(5)	1	(0x05)	sxfer
-**		wide_st	(7)	3	(0x03)	scntl3
+**	in a DWORD, the fields HAVE to be at the choosen offsets.
+**		xerr_st		0	(0x34)	scratcha
+**		sync_st		1	(0x05)	sxfer
+**		wide_st		3	(0x03)	scntl3
 */
 
 /*
-**	First four bytes (script)
+**	Last four bytes (script)
 */
 #define  QU_REG	scr0
 #define  HS_REG	scr1
@@ -1293,7 +1386,7 @@
 #define  PS_REG	scr3
 
 /*
-**	First four bytes (host)
+**	Last four bytes (host)
 */
 #define  actualquirks  phys.header.status[0]
 #define  host_status   phys.header.status[1]
@@ -1301,15 +1394,15 @@
 #define  parity_status phys.header.status[3]
 
 /*
-**	Last four bytes (script)
+**	First four bytes (script)
 */
-#define  xerr_st       header.status[4]	/* MUST be ==0 mod 4 */
-#define  sync_st       header.status[5]	/* MUST be ==1 mod 4 */
-#define  nego_st       header.status[6]
-#define  wide_st       header.status[7]	/* MUST be ==3 mod 4 */
+#define  xerr_st       header.scr_st[0]
+#define  sync_st       header.scr_st[1]
+#define  nego_st       header.scr_st[2]
+#define  wide_st       header.scr_st[3]
 
 /*
-**	Last four bytes (host)
+**	First four bytes (host)
 */
 #define  xerr_status   phys.xerr_st
 #define  sync_status   phys.sync_st
@@ -1677,9 +1770,11 @@
 	/*
 	**	Timeout handler
 	*/
+#if 0
 	u_long		heartbeat;
 	u_short		ticks;
 	u_short		latetime;
+#endif
 	u_long		lasttime;
 
 	/*-----------------------------------------------
@@ -1771,7 +1866,7 @@
 **	of 825A, 875 and 895 chips.
 */
 struct script {
-	ncrcmd	start		[  7];
+	ncrcmd	start		[  4];
 	ncrcmd	start0		[  2];
 	ncrcmd	start1		[  3];
 	ncrcmd  startpos	[  1];
@@ -1974,13 +2069,14 @@
 
 static	struct script script0 __initdata = {
 /*--------------------------< START >-----------------------*/ {
+#if 0
 	/*
 	**	Claim to be still alive ...
 	*/
 	SCR_COPY (sizeof (((struct ncb *)0)->heartbeat)),
 		KVAR(SCRIPT_KVAR_JIFFIES),
 		NADDR (heartbeat),
-
+#endif
 	/*
 	**      Make data structure address invalid.
 	**      clear SIGP.
@@ -3593,7 +3689,8 @@
 
 	while (src < end) {
 
-		*dst++ = opcode = *src++;
+		opcode = *src++;
+		*dst++ = cpu_to_scr(opcode);
 
 		/*
 		**	If we forget to change the length
@@ -3638,7 +3735,7 @@
 			**	the NO FLUSH bit if present.
 			*/
 			if ((opcode & SCR_NO_FLUSH) && !(np->features & FE_PFEN)) {
-				dst[-1] = (opcode & ~SCR_NO_FLUSH);
+				dst[-1] = cpu_to_scr(opcode & ~SCR_NO_FLUSH);
 				++opchanged;
 			}
 			break;
@@ -3711,10 +3808,10 @@
 					break;
 				}
 
-				*dst++ = new;
+				*dst++ = cpu_to_scr(new);
 			}
 		} else
-			*dst++ = *src++;
+			*dst++ = cpu_to_scr(*src++);
 
 	};
 	if (bootverbose > 1 && opchanged)
@@ -3974,15 +4071,6 @@
 	np->maxsync = period > 2540 ? 254 : period / 10;
 
 	/*
-	**	Get on-board RAM bus address when supported
-	*/
-	if (np->features & FE_RAM) {
-		OUTONB(nc_ctest2, 0x8);
-		np->paddr2 = INL(nc_scr0);
-		OUTOFFB(nc_ctest2, 0x8);
-	}
-
-	/*
 	**	Prepare initial value of other IO registers
 	*/
 #if defined SCSI_NCR_TRUST_BIOS_SETTING
@@ -4338,7 +4426,8 @@
 	**	virtual and physical memory.
 	*/
 
-	np->paddr = device->slot.base;
+	np->paddr	= device->slot.base;
+	np->paddr2	= (np->features & FE_RAM)? device->slot.base_2 : 0;
 
 #ifndef NCR_IOMAPPED
 	np->vaddr = remap_pci_mem((u_long) np->paddr, (u_long) 128);
@@ -4446,17 +4535,20 @@
 	*/
 
 	if (np->features & FE_LED0) {
-		np->script0->reselect[0]  = SCR_REG_REG(gpreg, SCR_OR,  0x01);
-		np->script0->reselect1[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe);
-		np->script0->reselect2[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe);
+		np->script0->reselect[0]  =
+				cpu_to_scr(SCR_REG_REG(gpreg, SCR_OR,  0x01));
+		np->script0->reselect1[0] =
+				cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe));
+		np->script0->reselect2[0] =
+				cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe));
 	}
 
 	/*
 	**	init data structure
 	*/
 
-	np->jump_tcb.l_cmd	= SCR_JUMP;
-	np->jump_tcb.l_paddr	= NCB_SCRIPTH_PHYS (np, abort);
+	np->jump_tcb.l_cmd	= cpu_to_scr(SCR_JUMP);
+	np->jump_tcb.l_paddr	= cpu_to_scr(NCB_SCRIPTH_PHYS (np, abort));
 
 	/*
 	**	Reset chip.
@@ -4923,21 +5015,23 @@
 		u_long endp;
 	default:
 	case XferBoth:
-		cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_io);
+		cp->phys.header.savep =
+			cpu_to_scr(NCB_SCRIPT_PHYS (np, data_io));
 		cp->phys.header.goalp = cp->phys.header.savep;
 		break;
 	case XferIn:
 		endp = NCB_SCRIPT_PHYS (np, data_in) + MAX_SCATTER*16;
-		cp->phys.header.goalp = endp + 8;
-		cp->phys.header.savep = endp - segments*16;
+		cp->phys.header.goalp = cpu_to_scr(endp + 8);
+		cp->phys.header.savep = cpu_to_scr(endp - segments*16);
 		break;
 	case XferOut:
 		endp = NCB_SCRIPTH_PHYS (np, data_out) + MAX_SCATTER*16;
-		cp->phys.header.goalp = endp + 8;
-		cp->phys.header.savep = endp - segments*16;
+		cp->phys.header.goalp = cpu_to_scr(endp + 8);
+		cp->phys.header.savep = cpu_to_scr(endp - segments*16);
 		break;
 	case XferNone:
-		cp->phys.header.savep = NCB_SCRIPT_PHYS (np, no_data);
+		cp->phys.header.savep =
+			cpu_to_scr(NCB_SCRIPT_PHYS (np, no_data));
 		cp->phys.header.goalp = cp->phys.header.savep;
 		break;
 	}
@@ -4958,8 +5052,9 @@
 	/*
 	**	Startqueue
 	*/
-	cp->phys.header.launch.l_paddr	= NCB_SCRIPT_PHYS (np, select);
-	cp->phys.header.launch.l_cmd	= SCR_JUMP;
+	cp->phys.header.launch.l_paddr	=
+			cpu_to_scr(NCB_SCRIPT_PHYS (np, select));
+	cp->phys.header.launch.l_cmd	= cpu_to_scr(SCR_JUMP);
 	/*
 	**	select
 	*/
@@ -4969,21 +5064,21 @@
 	/*
 	**	message
 	*/
-	cp->phys.smsg.addr		= CCB_PHYS (cp, scsi_smsg);
-	cp->phys.smsg.size		= msglen;
+	cp->phys.smsg.addr		= cpu_to_scr(CCB_PHYS (cp, scsi_smsg));
+	cp->phys.smsg.size		= cpu_to_scr(msglen);
 
-	cp->phys.smsg2.addr		= CCB_PHYS (cp, scsi_smsg2);
-	cp->phys.smsg2.size		= msglen2;
+	cp->phys.smsg2.addr		= cpu_to_scr(CCB_PHYS (cp, scsi_smsg2));
+	cp->phys.smsg2.size		= cpu_to_scr(msglen2);
 	/*
 	**	command
 	*/
-	cp->phys.cmd.addr		= vtophys (&cmd->cmnd[0]);
-	cp->phys.cmd.size		= cmd->cmd_len;
+	cp->phys.cmd.addr		= cpu_to_scr(vtophys (&cmd->cmnd[0]));
+	cp->phys.cmd.size		= cpu_to_scr(cmd->cmd_len);
 	/*
 	**	sense command
 	*/
-	cp->phys.scmd.addr		= CCB_PHYS (cp, sensecmd);
-	cp->phys.scmd.size		= 6;
+	cp->phys.scmd.addr		= cpu_to_scr(CCB_PHYS (cp, sensecmd));
+	cp->phys.scmd.size		= cpu_to_scr(6);
 	/*
 	**	patch requested size into sense command
 	*/
@@ -4993,8 +5088,9 @@
 	/*
 	**	sense data
 	*/
-	cp->phys.sense.addr		= vtophys (&cmd->sense_buffer[0]);
-	cp->phys.sense.size		= sizeof(cmd->sense_buffer);
+	cp->phys.sense.addr		=
+			cpu_to_scr(vtophys (&cmd->sense_buffer[0]));
+	cp->phys.sense.size		= cpu_to_scr(sizeof(cmd->sense_buffer));
 	/*
 	**	status
 	*/
@@ -5019,8 +5115,10 @@
 	**	reselect pattern and activate this job.
 	*/
 
-	cp->jump_ccb.l_cmd	= (SCR_JUMP ^ IFFALSE (DATA (cp->tag)));
-	/* Compute a time limit bigger than the middle-level driver one */
+	cp->jump_ccb.l_cmd	=
+		cpu_to_scr((SCR_JUMP ^ IFFALSE (DATA (cp->tag))));
+
+	/* Compute a time limit greater than the middle-level driver one */
 	if (cmd->timeout_per_command > 0)
 		cp->tlimit	= jiffies + cmd->timeout_per_command + NCR_TIMEOUT_INCREASE;
 	else
@@ -5033,14 +5131,14 @@
 
 	qidx = np->squeueput + 1;
 	if (qidx >= MAX_START) qidx=0;
-	np->squeue [qidx	 ] = NCB_SCRIPT_PHYS (np, idle);
-	np->squeue [np->squeueput] = CCB_PHYS (cp, phys);
+	np->squeue [qidx	 ] = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
+	np->squeue [np->squeueput] = cpu_to_scr(CCB_PHYS (cp, phys));
 	np->squeueput = qidx;
 
 	if(DEBUG_FLAGS & DEBUG_QUEUE)
 		printf ("%s: queuepos=%d tryoffset=%d.\n", ncr_name (np),
 		np->squeueput,
-		(unsigned)(np->script->startpos[0]- 
+		(unsigned)(scr_to_cpu(np->script->startpos[0]) - 
 			   (NCB_SCRIPTH_PHYS (np, tryloop))));
 
 	/*
@@ -5246,10 +5344,12 @@
 	**	this condition in order to complete the canceled command 
 	**	after the script skipped the ccb, if necessary.
 	*/
-	cp->jump_ccb.l_cmd = (SCR_JUMP);
-	if (cp->phys.header.launch.l_paddr == NCB_SCRIPT_PHYS (np, select)) {
+	cp->jump_ccb.l_cmd = cpu_to_scr(SCR_JUMP);
+	if (cp->phys.header.launch.l_paddr ==
+		cpu_to_scr(NCB_SCRIPT_PHYS (np, select))) {
 		printf ("%s: abort ccb=%p (skip)\n", ncr_name (np), cp);
-		cp->phys.header.launch.l_paddr = NCB_SCRIPT_PHYS (np, skip);
+		cp->phys.header.launch.l_paddr =
+			cpu_to_scr(NCB_SCRIPT_PHYS (np, skip));
 	}
 
 	cp->tlimit = 0;
@@ -5440,12 +5540,12 @@
 	/*
 	**	No Reselect anymore.
 	*/
-	cp->jump_ccb.l_cmd = (SCR_JUMP);
+	cp->jump_ccb.l_cmd = cpu_to_scr(SCR_JUMP);
 
 	/*
 	**	No starting.
 	*/
-	cp->phys.header.launch.l_paddr= NCB_SCRIPT_PHYS (np, idle);
+	cp->phys.header.launch.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
 
 	/*
 	**	timestamp
@@ -5797,14 +5897,14 @@
 	**	Clear Start Queue
 	*/
 	for (i=0;i<MAX_START;i++)
-		np -> squeue [i] = NCB_SCRIPT_PHYS (np, idle);
+		np -> squeue [i] = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
 
 	/*
 	**	Start at first entry.
 	*/
 	np->squeueput = 0;
-	np->script0->startpos[0] = NCB_SCRIPTH_PHYS (np, tryloop);
-	np->script0->start0  [0] = SCR_INT ^ IFFALSE (0);
+	np->script0->startpos[0] = cpu_to_scr(NCB_SCRIPTH_PHYS (np, tryloop));
+	np->script0->start0  [0] = cpu_to_scr(SCR_INT ^ IFFALSE (0));
 
 	/*
 	**	Wakeup all pending jobs.
@@ -5856,7 +5956,11 @@
 	if (np->vaddr2) {
 		if (bootverbose)
 			printf ("%s: copying script fragments into the on-board RAM ...\n", ncr_name(np));
-		bcopy(np->script0, np->script, sizeof(struct script));
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,0,0)
+		memcpy_toio(np->script, np->script0, sizeof(struct script));
+#else
+		memcpy(np->script, np->script0, sizeof(struct script));
+#endif
 	}
 
 	/*
@@ -6477,7 +6581,6 @@
 {
 	u_long	thistime = jiffies;
 	u_long	count = 0;
-	long signed   t;
 	ccb_p cp;
 	u_long flags;
 
@@ -6551,10 +6654,12 @@
 		**
 		**----------------------------------------------------
 		*/
-
-		t = (thistime - np->heartbeat) / HZ;
-
-		if (t<2) np->latetime=0; else np->latetime++;
+#if 0
+		if (thistime < np->heartbeat + HZ + HZ)
+			np->latetime = 0;
+		else
+			np->latetime++;
+#endif
 
 		/*----------------------------------------------------
 		**
@@ -6597,7 +6702,7 @@
 				** still in start queue ?
 				*/
 				if (cp->phys.header.launch.l_paddr ==
-					NCB_SCRIPT_PHYS (np, skip))
+					cpu_to_scr(NCB_SCRIPT_PHYS (np, skip)))
 					continue;
 
 				/* fall through */
@@ -6746,15 +6851,18 @@
 
 	/*
 	**	interrupt on the fly ?
-	*/
-	while ((istat = INB (nc_istat)) & INTF) {
+	**	Since the global header may be copied back to a CCB 
+	**	using a posted PCI memory write, the last operation on 
+	**	the istat register is a READ in order to flush posted 
+	**	PCI commands (Btw, the 'do' loop is probably useless).
+	*/
+	istat = INB (nc_istat);
+	if (istat & INTF) {
+		do {
+			OUTB (nc_istat, (istat & SIGP) | INTF);
+			istat = INB (nc_istat);
+		} while (istat & INTF);
 		if (DEBUG_FLAGS & DEBUG_TINY) printf ("F ");
-#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
-	if (np->stalling)
-		OUTB (nc_istat, INTF);
-	else
-#endif
-		OUTB (nc_istat, (istat & SIGP) | INTF);
 		np->profile.num_fly++;
 		ncr_wakeup (np, 0);
 	};
@@ -6944,7 +7052,7 @@
 /*	assert ((diff <= MAX_START * 20) && !(diff % 20));*/
 
 	if ((diff <= MAX_START * 20) && !(diff % 20)) {
-		np->script->startpos[0] = scratcha;
+		np->script->startpos[0] = cpu_to_scr(scratcha);
 		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start));
 		return;
 	};
@@ -7136,20 +7244,20 @@
 	**	get old startaddress and old length.
 	*/
 
-	oadr = vdsp[1];
+	oadr = scr_to_cpu(vdsp[1]);
 
 	if (cmd & 0x10) {	/* Table indirect */
 		tblp = (u_int32 *) ((char*) &cp->phys + oadr);
-		olen = tblp[0];
-		oadr = tblp[1];
+		olen = scr_to_cpu(tblp[0]);
+		oadr = scr_to_cpu(tblp[1]);
 	} else {
 		tblp = (u_int32 *) 0;
-		olen = vdsp[0] & 0xffffff;
+		olen = scr_to_cpu(vdsp[0]) & 0xffffff;
 	};
 
 	if (DEBUG_FLAGS & DEBUG_PHASE) {
 		printf ("OCMD=%x\nTBLP=%p OLEN=%x OADR=%x\n",
-			(unsigned) (vdsp[0] >> 24),
+			(unsigned) (scr_to_cpu(vdsp[0]) >> 24),
 			tblp,
 			(unsigned) olen,
 			(unsigned) oadr);
@@ -7159,10 +7267,10 @@
 	**	check cmd against assumed interrupted script command.
 	*/
 
-	if (cmd != (vdsp[0] >> 24)) {
+	if (cmd != (scr_to_cpu(vdsp[0]) >> 24)) {
 		PRINT_ADDR(cp->cmd);
 		printf ("internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n",
-			(unsigned)cmd, (unsigned)vdsp[0] >> 24);
+			(unsigned)cmd, (unsigned)scr_to_cpu(vdsp[0]) >> 24);
 		
 		return;
 	}
@@ -7194,25 +7302,25 @@
 	*/
 
 	newcmd = cp->patch;
-	if (cp->phys.header.savep == vtophys (newcmd)) newcmd+=4;
+	if (cp->phys.header.savep == cpu_to_scr(vtophys (newcmd))) newcmd+=4;
 
 	/*
 	**	fillin the commands
 	*/
 
-	newcmd[0] = ((cmd & 0x0f) << 24) | rest;
-	newcmd[1] = oadr + olen - rest;
-	newcmd[2] = SCR_JUMP;
-	newcmd[3] = nxtdsp;
+	newcmd[0] = cpu_to_scr(((cmd & 0x0f) << 24) | rest);
+	newcmd[1] = cpu_to_scr(oadr + olen - rest);
+	newcmd[2] = cpu_to_scr(SCR_JUMP);
+	newcmd[3] = cpu_to_scr(nxtdsp);
 
 	if (DEBUG_FLAGS & DEBUG_PHASE) {
 		PRINT_ADDR(cp->cmd);
 		printf ("newcmd[%d] %x %x %x %x.\n",
 			(int) (newcmd - cp->patch),
-			(unsigned)newcmd[0],
-			(unsigned)newcmd[1],
-			(unsigned)newcmd[2],
-			(unsigned)newcmd[3]);
+			(unsigned)scr_to_cpu(newcmd[0]),
+			(unsigned)scr_to_cpu(newcmd[1]),
+			(unsigned)scr_to_cpu(newcmd[2]),
+			(unsigned)scr_to_cpu(newcmd[3]));
 	}
 	/*
 	**	fake the return address (to the patch).
@@ -7299,20 +7407,23 @@
 */
 		if (num == SIR_DATA_IO_IS_OUT) {
 			endp = NCB_SCRIPTH_PHYS (np, data_out) + MAX_SCATTER*16;
-			cp->phys.header.goalp = endp + 8;
-			cp->phys.header.savep = endp - cp->segments*16;
+			cp->phys.header.goalp = cpu_to_scr(endp + 8);
+			cp->phys.header.savep =
+				cpu_to_scr(endp - cp->segments*16);
 		} else {
 			endp = NCB_SCRIPT_PHYS (np, data_in)  + MAX_SCATTER*16;
-			cp->phys.header.goalp = endp + 8;
-			cp->phys.header.savep = endp - cp->segments*16;
+			cp->phys.header.goalp = cpu_to_scr(endp + 8);
+			cp->phys.header.savep =
+				cpu_to_scr(endp - cp->segments*16);
 		}
 
 		cp->phys.header.lastp	= cp->phys.header.savep;
 		np->header.savep	= cp->phys.header.savep;
 		np->header.goalp	= cp->phys.header.goalp;
 		np->header.lastp	= cp->phys.header.lastp;
-		OUTL (nc_temp,	np->header.savep);
-		OUTL (nc_dsp,	np->header.savep);
+
+		OUTL (nc_temp,	scr_to_cpu(np->header.savep));
+		OUTL (nc_dsp,	scr_to_cpu(np->header.savep));
 		return;
 		/* break; */
 
@@ -7359,7 +7470,7 @@
 		**	no job, resume normal processing
 		*/
 		if (DEBUG_FLAGS & DEBUG_RESTART) printf (" -- remove trap\n");
-		np->script->start0[0] =  SCR_INT ^ IFFALSE (0);
+		np->script->start0[0] =  cpu_to_scr(SCR_INT ^ IFFALSE (0));
 		break;
 
 	case SIR_SENSE_FAILED:
@@ -7385,7 +7496,7 @@
 		/*
 		**	And patch code to restart it.
 		*/
-		np->script->start0[0] =  SCR_INT;
+		np->script->start0[0] =  cpu_to_scr(SCR_INT);
 		break;
 
 /*-----------------------------------------------------------------------------
@@ -7742,7 +7853,7 @@
 
 		PRINT_ADDR(cp->cmd);
 		printf ("M_REJECT received (%x:%x).\n",
-			(unsigned)np->lastmsg, np->msgout[0]);
+			(unsigned)scr_to_cpu(np->lastmsg), np->msgout[0]);
 		break;
 
 	case SIR_REJECT_SENT:
@@ -7792,8 +7903,8 @@
 		printf ("M_DISCONNECT received, but datapointer not saved: "
 			"data=%x save=%x goal=%x.\n",
 			(unsigned) INL (nc_temp),
-			(unsigned) np->header.savep,
-			(unsigned) np->header.goalp);
+			(unsigned) scr_to_cpu(np->header.savep),
+			(unsigned) scr_to_cpu(np->header.goalp));
 		break;
 
 #if 0   /* This stuff does not work */
@@ -7824,7 +7935,7 @@
 		PRINT_ADDR(cp->cmd);
 		printf ("queue full.\n");
 
-		np->script->start1[0] =  SCR_INT;
+		np->script->start1[0] =  cpu_to_scr(SCR_INT);
 
 		/*
 		**	Try to disable tagged transfers.
@@ -7872,7 +7983,7 @@
 		*/
 
 		printf ("%s: queue empty.\n", ncr_name (np));
-		np->script->start1[0] =  SCR_INT ^ IFFALSE (0);
+		np->script->start1[0] =  cpu_to_scr(SCR_INT ^ IFFALSE (0));
 		break;
 #endif   /* This stuff does not work */
 	};
@@ -8011,33 +8122,37 @@
 	tp=&np->target[target];
 
 	if (!tp->jump_tcb.l_cmd) {
-
 		/*
 		**	initialize it.
 		*/
-		tp->jump_tcb.l_cmd   = (SCR_JUMP^IFFALSE (DATA (0x80 + target)));
+		tp->jump_tcb.l_cmd   =
+			cpu_to_scr((SCR_JUMP^IFFALSE (DATA (0x80 + target))));
 		tp->jump_tcb.l_paddr = np->jump_tcb.l_paddr;
 
-		tp->getscr[0] =
-			(np->features & FE_PFEN)? SCR_COPY(1) : SCR_COPY_F(1);
-		tp->getscr[1] = vtophys (&tp->sval);
-		tp->getscr[2] = np->paddr + offsetof (struct ncr_reg, nc_sxfer);
-		tp->getscr[3] =
-			(np->features & FE_PFEN)? SCR_COPY(1) : SCR_COPY_F(1);
-		tp->getscr[4] = vtophys (&tp->wval);
-		tp->getscr[5] = np->paddr + offsetof (struct ncr_reg, nc_scntl3);
+		tp->getscr[0] =	(np->features & FE_PFEN) ?
+			cpu_to_scr(SCR_COPY(1)):cpu_to_scr(SCR_COPY_F(1));
+		tp->getscr[1] = cpu_to_scr(vtophys (&tp->sval));
+		tp->getscr[2] =
+		cpu_to_scr(np->paddr + offsetof (struct ncr_reg, nc_sxfer));
+
+		tp->getscr[3] =	(np->features & FE_PFEN) ?
+			cpu_to_scr(SCR_COPY(1)):cpu_to_scr(SCR_COPY_F(1));
+		tp->getscr[4] = cpu_to_scr(vtophys (&tp->wval));
+		tp->getscr[5] =
+		cpu_to_scr(np->paddr + offsetof (struct ncr_reg, nc_scntl3));
 
 		assert (( (offsetof(struct ncr_reg, nc_sxfer) ^
 			offsetof(struct tcb    , sval    )) &3) == 0);
 		assert (( (offsetof(struct ncr_reg, nc_scntl3) ^
 			offsetof(struct tcb    , wval    )) &3) == 0);
 
-		tp->call_lun.l_cmd   = (SCR_CALL);
-		tp->call_lun.l_paddr = NCB_SCRIPT_PHYS (np, resel_lun);
-
-		tp->jump_lcb.l_cmd   = (SCR_JUMP);
-		tp->jump_lcb.l_paddr = NCB_SCRIPTH_PHYS (np, abort);
-		np->jump_tcb.l_paddr = vtophys (&tp->jump_tcb);
+		tp->call_lun.l_cmd   = cpu_to_scr(SCR_CALL);
+		tp->call_lun.l_paddr =
+			cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_lun));
+
+		tp->jump_lcb.l_cmd   = cpu_to_scr(SCR_JUMP);
+		tp->jump_lcb.l_paddr = cpu_to_scr(NCB_SCRIPTH_PHYS (np, abort));
+		np->jump_tcb.l_paddr = cpu_to_scr(vtophys (&tp->jump_tcb));
 	}
 
 	/*
@@ -8060,14 +8175,17 @@
 		**	Initialize it
 		*/
 		bzero (lp, sizeof (*lp));
-		lp->jump_lcb.l_cmd   = (SCR_JUMP ^ IFFALSE (DATA (lun)));
+		lp->jump_lcb.l_cmd   =
+			cpu_to_scr(SCR_JUMP ^ IFFALSE (DATA (lun)));
 		lp->jump_lcb.l_paddr = tp->jump_lcb.l_paddr;
 
-		lp->call_tag.l_cmd   = (SCR_CALL);
-		lp->call_tag.l_paddr = NCB_SCRIPT_PHYS (np, resel_tag);
-
-		lp->jump_ccb.l_cmd   = (SCR_JUMP);
-		lp->jump_ccb.l_paddr = NCB_SCRIPTH_PHYS (np, aborttag);
+		lp->call_tag.l_cmd   = cpu_to_scr(SCR_CALL);
+		lp->call_tag.l_paddr =
+			cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_tag));
+
+		lp->jump_ccb.l_cmd   = cpu_to_scr(SCR_JUMP);
+		lp->jump_ccb.l_paddr =
+			cpu_to_scr(NCB_SCRIPTH_PHYS (np, aborttag));
 
 		lp->actlink = 1;
 
@@ -8076,7 +8194,7 @@
 		/*
 		**   Chain into LUN list
 		*/
-		tp->jump_lcb.l_paddr = vtophys (&lp->jump_lcb);
+		tp->jump_lcb.l_paddr = cpu_to_scr(vtophys (&lp->jump_lcb));
 		tp->lp[lun] = lp;
 
 		ncr_setmaxtags (np, tp, driver_setup.default_tags);
@@ -8128,11 +8246,11 @@
 	/*
 	**	Chain into reselect list
 	*/
-	cp->jump_ccb.l_cmd   = SCR_JUMP;
+	cp->jump_ccb.l_cmd   = cpu_to_scr(SCR_JUMP);
 	cp->jump_ccb.l_paddr = lp->jump_ccb.l_paddr;
-	lp->jump_ccb.l_paddr = CCB_PHYS (cp, jump_ccb);
-	cp->call_tmp.l_cmd   = SCR_CALL;
-	cp->call_tmp.l_paddr = NCB_SCRIPT_PHYS (np, resel_tmp);
+	lp->jump_ccb.l_paddr = cpu_to_scr(CCB_PHYS (cp, jump_ccb));
+	cp->call_tmp.l_cmd   = cpu_to_scr(SCR_CALL);
+	cp->call_tmp.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_tmp));
 
 	/*
 	**	Chain into wakeup list
@@ -8245,9 +8363,9 @@
 	if (!use_sg) {
 		if (cmd->request_bufflen) {
 			data = &data[MAX_SCATTER - 1];
-			data[0].addr	= vtophys(cmd->request_buffer);
-			data[0].size	= cmd->request_bufflen;
-			cp->data_len	= data[0].size;
+			data[0].addr = cpu_to_scr(vtophys(cmd->request_buffer));
+			data[0].size = cpu_to_scr(cmd->request_bufflen);
+			cp->data_len = cmd->request_bufflen;
 			segment = 1;
 		}
 	}
@@ -8256,9 +8374,11 @@
 
 		data = &data[MAX_SCATTER - use_sg];
 		while (segment < use_sg) {
-			data[segment].addr = vtophys(scatter[segment].address);
-			data[segment].size = scatter[segment].length;
-			cp->data_len	   += data[segment].size;
+			data[segment].addr =
+				cpu_to_scr(vtophys(scatter[segment].address));
+			data[segment].size =
+				cpu_to_scr(scatter[segment].length);
+			cp->data_len	   += scatter[segment].length;
 			++segment;
 		}
 	}
@@ -8328,7 +8448,7 @@
 	/*
 	**	Set memory and register.
 	*/
-	np->ncr_cache = host_wr;
+	np->ncr_cache = cpu_to_scr(host_wr);
 	OUTL (nc_temp, ncr_wr);
 	/*
 	**	Start script (exchange values)
@@ -8347,7 +8467,7 @@
 	/*
 	**	Read memory and register.
 	*/
-	host_rd = np->ncr_cache;
+	host_rd = scr_to_cpu(np->ncr_cache);
 	ncr_rd  = INL (nc_scratcha);
 	ncr_bk  = INL (nc_temp);
 	/*
@@ -8791,7 +8911,7 @@
 		else if	(!strncmp(cur, "safe:", 5) && val)
 			memcpy(&driver_setup, &driver_safe_setup, sizeof(driver_setup));
 		else
-			printf("ncr53c8xx_setup: unexpected boot option '%.*s' ignored\n", pc-cur+1, cur);
+			printf("ncr53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
 
 		if ((cur = strchr(cur, ',')) != NULL)
 			++cur;
@@ -9068,11 +9188,11 @@
 	uchar cache_line_size, latency_timer;
 	uchar irq, revision;
 #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
-	uint base, io_port; 
+	uint base, base_2, io_port; 
 #else
-	ulong base, io_port; 
+	ulong base, base_2; 
 #endif
-	int i, error;
+	int i;
 
 #ifdef SCSI_NCR_NVRAM_SUPPORT
 	ncr_nvram *nvram = device->nvram;
@@ -9082,20 +9202,32 @@
 	printk(KERN_INFO "ncr53c8xx: at PCI bus %d, device %d, function %d\n",
 		bus, (int) (device_fn & 0xf8) >> 3, (int) device_fn & 7);
 	/*
-	 * Read info from the PCI config space
+	 * Read info from the PCI config space.
+	 * pcibios_read_config_xxx() functions are assumed to be used for 
+	 * successfully detected PCI devices.
+	 * Expecting error conditions from them is just paranoia,
+	 * thus void cast.
 	 */
-	if (
-		(error=pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID, &vendor_id))	||
-		(error=pcibios_read_config_word(bus, device_fn, PCI_DEVICE_ID, &device_id))	||
-		(error=pcibios_read_config_word( bus, device_fn, PCI_COMMAND, &command))	||
-		(error=pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0,&io_port))	|| 
-		(error=pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_1, &base))	||
-		(error=pcibios_read_config_byte(bus, device_fn, PCI_CLASS_REVISION,&revision))	||
-		(error=pcibios_read_config_byte(bus, device_fn, PCI_INTERRUPT_LINE, &irq))	||
-		(error=pcibios_read_config_byte(bus, device_fn, PCI_CACHE_LINE_SIZE, &cache_line_size)) ||
-		(error=pcibios_read_config_byte(bus, device_fn, PCI_LATENCY_TIMER, &latency_timer))
-	)
-		goto err_pcibios;
+	(void) pcibios_read_config_word(bus, device_fn,
+					PCI_VENDOR_ID, &vendor_id);
+	(void) pcibios_read_config_word(bus, device_fn,
+					PCI_DEVICE_ID, &device_id);
+	(void) pcibios_read_config_word(bus, device_fn,
+					PCI_COMMAND, &command);
+	(void) pcibios_read_config_dword(bus, device_fn,
+					PCI_BASE_ADDRESS_0, &io_port);	
+	(void) pcibios_read_config_dword(bus, device_fn,
+					PCI_BASE_ADDRESS_1, &base);
+	(void) pcibios_read_config_dword(bus, device_fn,
+					PCI_BASE_ADDRESS_2, &base_2);
+	(void) pcibios_read_config_byte(bus, device_fn,
+					PCI_CLASS_REVISION,&revision);	
+	(void) pcibios_read_config_byte(bus, device_fn,
+					PCI_INTERRUPT_LINE, &irq);
+	(void) pcibios_read_config_byte(bus, device_fn,
+					PCI_CACHE_LINE_SIZE, &cache_line_size);
+	(void) pcibios_read_config_byte(bus, device_fn,
+					PCI_LATENCY_TIMER, &latency_timer);
 
 	/*
 	 *	Check if the chip is supported
@@ -9148,6 +9280,8 @@
 		return -1;
 	}
 
+	base_2 &= PCI_BASE_ADDRESS_MEM_MASK;
+
 	if (io_port && check_region (io_port, 128)) {
 		printk("ncr53c8xx: IO region 0x%x to 0x%x is in use\n",
 			(int) io_port, (int) (io_port + 127));
@@ -9188,9 +9322,8 @@
 		case 5:	cache_line_size = 8; break;
 		}
 		if (cache_line_size)
-			error = pcibios_write_config_byte(bus, device_fn, PCI_CACHE_LINE_SIZE, cache_line_size);
-		if (error)
-			goto err_pcibios;
+			(void) pcibios_write_config_byte(bus, device_fn,
+					PCI_CACHE_LINE_SIZE, cache_line_size);
 		if (initverbose)
 			printk("ncr53c8xx: setting PCI_CACHE_LINE_SIZE to %d (fix-up).\n", cache_line_size);
 	}
@@ -9198,9 +9331,8 @@
 	if ((driver_setup.pci_fix_up & 2) && cache_line_size &&
 	    (chip->features & FE_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) {
 		command |= PCI_COMMAND_INVALIDATE;
-		error=pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
-		if (error)
-			goto err_pcibios;
+		(void) pcibios_write_config_word(bus, device_fn,
+						PCI_COMMAND, command);
 		if (initverbose)
 			printk("ncr53c8xx: setting PCI_COMMAND_INVALIDATE bit (fix-up).\n");
 	}
@@ -9242,10 +9374,8 @@
 			latency_timer = lt;
 			if (initverbose)
 				printk("ncr53c8xx: setting PCI_LATENCY_TIMER to %d bus clocks (fix-up).\n", latency_timer);
-			error = pcibios_write_config_byte(bus, device_fn,
+			 (void) pcibios_write_config_byte(bus, device_fn,
 					PCI_LATENCY_TIMER, latency_timer);
-			if (error)
-				goto err_pcibios;
 		}
 	}
 
@@ -9271,6 +9401,7 @@
 	device->slot.bus	= bus;
 	device->slot.device_fn	= device_fn;
 	device->slot.base	= base;
+	device->slot.base_2	= base_2;
 	device->slot.io_port	= io_port;
 	device->slot.irq	= irq;
 	device->attached	= 0;
@@ -9321,11 +9452,6 @@
 
 #endif	/* SCSI_NCR_NVRAM_SUPPORT */
 	return 0;     
-
-err_pcibios:
-	printk("ncr53c8xx: error %s reading configuration space\n",
-		pcibios_strerror(error));
-	return -1;
 }
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,0,0)
diff -u --recursive --new-file v2.1.51/linux/drivers/scsi/ncr53c8xx.h linux/drivers/scsi/ncr53c8xx.h
--- v2.1.51/linux/drivers/scsi/ncr53c8xx.h	Mon Aug 11 14:47:05 1997
+++ linux/drivers/scsi/ncr53c8xx.h	Mon Sep  1 12:43:52 1997
@@ -45,7 +45,7 @@
 /*
 **	Name and revision of the driver
 */
-#define SCSI_NCR_DRIVER_NAME		"ncr53c8xx - revision 2.4"
+#define SCSI_NCR_DRIVER_NAME		"ncr53c8xx - revision 2.5a"
 
 /*
 **	Check supported Linux versions
@@ -155,9 +155,11 @@
 #endif
 
 /*
- * Use normal IO if configured. Forced for alpha.
+ * Use normal IO if configured. Forced for alpha and ppc.
  */
-#if defined(CONFIG_SCSI_NCR53C8XX_IOMAPPED) || defined(__alpha__)
+#if defined(CONFIG_SCSI_NCR53C8XX_IOMAPPED)
+#define	SCSI_NCR_IOMAPPED
+#elif defined(__alpha__) || defined(__powerpc__)
 #define	SCSI_NCR_IOMAPPED
 #endif
 
@@ -316,6 +318,45 @@
 #ifndef HOSTS_C
 
 /*
+**	IO functions definition for big/little endian support.
+**	For now, the NCR is only supported in little endian addressing mode, 
+**	and big endian byte ordering is only supported for the PPC.
+**	MMIO is not used on PPC.
+*/
+
+#ifdef	__BIG_ENDIAN
+
+#if	LINUX_VERSION_CODE < LinuxVersionCode(2,1,0)
+#error	"BIG ENDIAN byte ordering needs kernel version >= 2.1.0"
+#endif
+
+#ifdef	__powerpc__
+#define	inw_l2b		inw
+#define	inl_l2b		inl
+#define	outw_b2l	outw
+#define	outl_b2l	outl
+#else
+#error	"Support for BIG ENDIAN is only available for the PowerPC"
+#endif
+
+#else	/* Assumed x86 or alpha */
+
+#define	inw_raw		inw
+#define	inl_raw		inl
+#define	outw_raw	outw
+#define	outl_raw	outl
+#define	readw_raw	readw
+#define	readl_raw	readl
+#define	writew_raw	writew
+#define	writel_raw	writel
+
+#endif
+
+#ifdef	SCSI_NCR_BIG_ENDIAN
+#error	"The NCR in BIG ENDIAN adressing mode is not (yet) supported"
+#endif
+
+/*
 **	NCR53C8XX Device Ids
 */
 
@@ -416,7 +457,7 @@
  FE_WIDE|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}		\
  ,									\
  {PCI_DEVICE_ID_NCR_53C860, 0xff, "860",  4,  8, 5,			\
- FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE_SET|FE_BOF|FE_LDSTR|FE_PFEN|FE_RAM}	\
+ FE_ULTRA|FE_CLK80|FE_CACHE_SET|FE_BOF|FE_LDSTR|FE_PFEN}		\
  ,									\
  {PCI_DEVICE_ID_NCR_53C875, 0x01, "875",  7, 16, 5,			\
  FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
diff -u --recursive --new-file v2.1.51/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c
--- v2.1.51/linux/drivers/scsi/scsi_ioctl.c	Tue Mar  4 10:25:24 1997
+++ linux/drivers/scsi/scsi_ioctl.c	Mon Aug 25 12:52:54 1997
@@ -9,6 +9,7 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
+#include <asm/page.h>
 
 #include <linux/errno.h>
 #include <linux/kernel.h>
@@ -23,7 +24,7 @@
 
 #define MAX_RETRIES 5   
 #define MAX_TIMEOUT (9 * HZ)
-#define MAX_BUF 4096
+#define MAX_BUF PAGE_SIZE
 
 #define max(a,b) (((a) > (b)) ? (a) : (b))
 
@@ -73,12 +74,9 @@
  * 
  * *(char *) ((int *) arg)[2] the actual command byte.   
  * 
- * Note that no more than MAX_BUF data bytes will be transfered.  Since
- * SCSI block device size is 512 bytes, I figured 1K was good.
- * but (WDE) changed it to 8192 to handle large bad track buffers.
- * ERY: I changed this to a dynamic allocation using scsi_malloc - we were
- * getting a kernel stack overflow which was crashing the system when we
- * were using 8192 bytes.
+ * Note that if more than MAX_BUF bytes are requested to be transfered,
+ * the ioctl will fail with error EINVAL.  MAX_BUF can be increased in
+ * the future by increasing the size that scsi_malloc will accept.
  * 
  * This size *does not* include the initial lengths that were passed.
  * 
@@ -201,8 +199,8 @@
      * If the user needs to transfer more data than this, they
      * should use scsi_generics instead.
      */
-    if( inlen > MAX_BUF ) inlen = MAX_BUF;
-    if( outlen > MAX_BUF ) outlen = MAX_BUF;
+    if( inlen > MAX_BUF ) return -EINVAL;
+    if( outlen > MAX_BUF ) return -EINVAL;
 
     cmd_in = sic->data;
     get_user(opcode, cmd_in); 
diff -u --recursive --new-file v2.1.51/linux/fs/attr.c linux/fs/attr.c
--- v2.1.51/linux/fs/attr.c	Thu Jul 17 10:06:06 1997
+++ linux/fs/attr.c	Fri Aug 22 21:18:39 1997
@@ -17,83 +17,87 @@
 /* POSIX UID/GID verification for setting inode attributes. */
 int inode_change_ok(struct inode *inode, struct iattr *attr)
 {
+	int retval = -EPERM;
+	unsigned int ia_valid = attr->ia_valid;
+
 	/* If force is set do it anyway. */
-	if (attr->ia_valid & ATTR_FORCE)
-		return 0;
+	if (ia_valid & ATTR_FORCE)
+		goto fine;
 
 	/* Make sure a caller can chown. */
-	if ((attr->ia_valid & ATTR_UID) &&
+	if ((ia_valid & ATTR_UID) &&
 	    (current->fsuid != inode->i_uid ||
 	     attr->ia_uid != inode->i_uid) && !fsuser())
-		return -EPERM;
+		goto error;
 
 	/* Make sure caller can chgrp. */
-	if ((attr->ia_valid & ATTR_GID) &&
+	if ((ia_valid & ATTR_GID) &&
 	    (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid) &&
 	    !fsuser())
-		return -EPERM;
+		goto error;
 
 	/* Make sure a caller can chmod. */
-	if (attr->ia_valid & ATTR_MODE) {
+	if (ia_valid & ATTR_MODE) {
 		if ((current->fsuid != inode->i_uid) && !fsuser())
-			return -EPERM;
+			goto error;
 		/* Also check the setgid bit! */
-		if (!fsuser() && !in_group_p((attr->ia_valid & ATTR_GID) ? attr->ia_gid :
+		if (!fsuser() && !in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
 					     inode->i_gid))
 			attr->ia_mode &= ~S_ISGID;
 	}
 
 	/* Check for setting the inode time. */
-	if ((attr->ia_valid & ATTR_ATIME_SET) &&
-	    ((current->fsuid != inode->i_uid) && !fsuser()))
-		return -EPERM;
-	if ((attr->ia_valid & ATTR_MTIME_SET) &&
-	    ((current->fsuid != inode->i_uid) && !fsuser()))
-		return -EPERM;
-	return 0;
+	if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) {
+		if (current->fsuid != inode->i_uid && !fsuser())
+			goto error;
+	}
+fine:
+	retval = 0;
+error:
+	return retval;
 }
 
 void inode_setattr(struct inode * inode, struct iattr * attr)
 {
-	if(attr->ia_valid &
-	   (ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_MTIME|ATTR_CTIME|ATTR_MODE)) {
-		if (attr->ia_valid & ATTR_UID)
-			inode->i_uid = attr->ia_uid;
-		if (attr->ia_valid & ATTR_GID)
-			inode->i_gid = attr->ia_gid;
-		if (attr->ia_valid & ATTR_SIZE)
-			inode->i_size = attr->ia_size;
-		if (attr->ia_valid & ATTR_ATIME)
-			inode->i_atime = attr->ia_atime;
-		if (attr->ia_valid & ATTR_MTIME)
-			inode->i_mtime = attr->ia_mtime;
-		if (attr->ia_valid & ATTR_CTIME)
-			inode->i_ctime = attr->ia_ctime;
-		if (attr->ia_valid & ATTR_MODE) {
-			inode->i_mode = attr->ia_mode;
-			if (!fsuser() && !in_group_p(inode->i_gid))
-				inode->i_mode &= ~S_ISGID;
-		}
-		mark_inode_dirty(inode);
+	unsigned int ia_valid = attr->ia_valid;
+
+	if (ia_valid & ATTR_UID)
+		inode->i_uid = attr->ia_uid;
+	if (ia_valid & ATTR_GID)
+		inode->i_gid = attr->ia_gid;
+	if (ia_valid & ATTR_SIZE)
+		inode->i_size = attr->ia_size;
+	if (ia_valid & ATTR_ATIME)
+		inode->i_atime = attr->ia_atime;
+	if (ia_valid & ATTR_MTIME)
+		inode->i_mtime = attr->ia_mtime;
+	if (ia_valid & ATTR_CTIME)
+		inode->i_ctime = attr->ia_ctime;
+	if (ia_valid & ATTR_MODE) {
+		inode->i_mode = attr->ia_mode;
+		if (!fsuser() && !in_group_p(inode->i_gid))
+			inode->i_mode &= ~S_ISGID;
 	}
+	mark_inode_dirty(inode);
 }
 
 int notify_change(struct inode * inode, struct iattr * attr)
 {
 	int error;
 	time_t now = CURRENT_TIME;
+	unsigned int ia_valid = attr->ia_valid;
 
 	attr->ia_ctime = now;
-	if ((attr->ia_valid & (ATTR_ATIME | ATTR_ATIME_SET)) == ATTR_ATIME)
+	if (!(ia_valid & ATTR_ATIME_SET))
 		attr->ia_atime = now;
-	if ((attr->ia_valid & (ATTR_MTIME | ATTR_MTIME_SET)) == ATTR_MTIME)
+	if (!(ia_valid & ATTR_MTIME_SET))
 		attr->ia_mtime = now;
-	attr->ia_valid &= ~(ATTR_CTIME);
+
 	if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->notify_change) 
 		return inode->i_sb->s_op->notify_change(inode, attr);
+
 	error = inode_change_ok(inode, attr);
-	if(!error)
+	if (!error)
 		inode_setattr(inode, attr);
 	return error;
 }
-
diff -u --recursive --new-file v2.1.51/linux/fs/binfmt_misc.c linux/fs/binfmt_misc.c
--- v2.1.51/linux/fs/binfmt_misc.c	Mon Aug  4 16:25:38 1997
+++ linux/fs/binfmt_misc.c	Sun Aug 31 09:40:01 1997
@@ -12,6 +12,7 @@
  *  1997-05-19 cleanup
  *  1997-06-26 hpa: pass the real filename rather than argv[0]
  *  1997-06-30 minor cleanup
+ *  1997-08-09 removed extension stripping, locking cleanup
  */
 
 #include <linux/module.h>
@@ -31,10 +32,6 @@
 
 #define VERBOSE_STATUS /* undef this to save 400 bytes kernel memory */
 
-#ifndef MIN
-#define MIN(x,y) (((x)<(y))?(x):(y))
-#endif
-
 struct binfmt_entry {
 	struct binfmt_entry *next;
 	int id;
@@ -50,7 +47,6 @@
 
 #define ENTRY_ENABLED 1		/* the old binfmt_entry.enabled */
 #define	ENTRY_MAGIC 8		/* not filename detection */
-#define ENTRY_STRIP_EXT 32	/* strip off last filename extension */
 
 static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs);
 static void entry_proc_cleanup(struct binfmt_entry *e);
@@ -70,7 +66,9 @@
 static int free_id = 1;
 static int enabled = 1;
 
+#ifdef __SMP__
 static rwlock_t entries_lock = RW_LOCK_UNLOCKED;
+#endif
 
 
 /*
@@ -84,12 +82,14 @@
 	ep = &entries;
 	while (*ep && ((*ep)->id != id))
 		ep = &((*ep)->next);
-	if ((e = *ep)) {
+	if ((e = *ep))
 		*ep = e->next;
+	write_unlock(&entries_lock);
+
+	if (e) {
 		entry_proc_cleanup(e);
 		kfree(e);
 	}
-	write_unlock(&entries_lock);
 }
 
 /*
@@ -97,29 +97,45 @@
  */
 static void clear_entries(void)
 {
-	struct binfmt_entry *e;
+	struct binfmt_entry *e, *n;
 
 	write_lock(&entries_lock);
-	while ((e = entries)) {
-		entries = entries->next;
+	n = entries;
+	entries = NULL;
+	write_unlock(&entries_lock);
+
+	while ((e = n)) {
+		n = e->next;
 		entry_proc_cleanup(e);
 		kfree(e);
 	}
-	write_unlock(&entries_lock);
 }
 
 /*
- * Find entry through id - caller has to do locking
+ * Find entry through id and lock it
  */
 static struct binfmt_entry *get_entry(int id)
 {
-	struct binfmt_entry *e = entries;
+	struct binfmt_entry *e;
 
+	read_lock(&entries_lock);
+	e = entries;
 	while (e && (e->id != id))
 		e = e->next;
+	if (!e)
+		read_unlock(&entries_lock);
 	return e;
 }
 
+/*
+ * unlock entry
+ */
+static inline void put_entry(struct binfmt_entry *e)
+{
+	if (e)
+		read_unlock(&entries_lock);
+}
+
 
 /* 
  * Check if we support the binfmt
@@ -128,10 +144,11 @@
  */
 static struct binfmt_entry *check_file(struct linux_binprm *bprm)
 {
-	struct binfmt_entry *e = entries;
+	struct binfmt_entry *e;
 	char *p = strrchr(bprm->filename, '.');
 	int j;
 
+	e = entries;
 	while (e) {
 		if (e->flags & ENTRY_ENABLED) {
 			if (!(e->flags & ENTRY_MAGIC)) {
@@ -160,7 +177,7 @@
 	struct binfmt_entry *fmt;
 	struct dentry * dentry;
 	char iname[128];
-	char *iname_addr = iname, *p;
+	char *iname_addr = iname;
 	int retval, fmt_flags = 0;
 
 	MOD_INC_USE_COUNT;
@@ -186,9 +203,6 @@
 	bprm->dentry = NULL;
 
 	/* Build args for interpreter */
-	if ((fmt_flags & ENTRY_STRIP_EXT) &&
-	    (p = strrchr(bprm->filename, '.')))
-		*p = '\0';
 	remove_arg_zero(bprm);
 	bprm->p = copy_strings(1, &bprm->filename, bprm->page, bprm->p, 2);
 	bprm->argc++;
@@ -288,13 +302,12 @@
 
 	e->proc_name = copyarg(&dp, &sp, &cnt, del, 0, &err);
 
-	/* we can use bit 3 and 5 of type for ext/magic and ext-strip
-	   flag due to the nice encoding of E, M, e and m */
-	if ((*sp & 0x92) || (sp[1] != del))
+	/* we can use bit 3 of type for ext/magic
+	   flag due to the nice encoding of E and M */
+	if ((*sp & ~('E' | 'M')) || (sp[1] != del))
 		err = -EINVAL;
 	else
-		e->flags = (*sp++ & (ENTRY_MAGIC | ENTRY_STRIP_EXT))
-			    | ENTRY_ENABLED;
+		e->flags = (*sp++ & (ENTRY_MAGIC | ENTRY_ENABLED));
 	cnt -= 2; sp++;
 
 	e->offset = 0;
@@ -342,17 +355,17 @@
 {
 	struct binfmt_entry *e;
 	char *dp;
-	int elen, i;
+	int elen, i, err;
 
 	MOD_INC_USE_COUNT;
 #ifndef VERBOSE_STATUS
 	if (data) {
-		read_lock(&entries_lock);
-		if (!(e = get_entry((int) data)))
-			i = 0;
-		else
-			i = e->flags & ENTRY_ENABLED;
-		read_unlock(&entries_lock);
+		if (!(e = get_entry((int) data))) {
+			err = -ENOENT;
+			goto _err;
+		}
+		i = e->flags & ENTRY_ENABLED;
+		put_entry(e);
 	} else {
 		i = enabled;
 	} 
@@ -361,10 +374,9 @@
 	if (!data)
 		sprintf(page, "%s\n", (enabled ? "enabled" : "disabled"));
 	else {
-		read_lock(&entries_lock);
 		if (!(e = get_entry((int) data))) {
-			*page = '\0';
-			goto _out;
+			err = -ENOENT;
+			goto _err;
 		}
 		sprintf(page, "%s\ninterpreter %s\n",
 		        (e->flags & ENTRY_ENABLED ? "enabled" : "disabled"),
@@ -391,10 +403,7 @@
 			*dp++ = '\n';
 			*dp = '\0';
 		}
-		if (e->flags & ENTRY_STRIP_EXT)
-			sprintf(dp, "extension stripped\n");
-_out:
-		read_unlock(&entries_lock);
+		put_entry(e);
 	}
 #endif
 
@@ -403,9 +412,11 @@
 		elen = 0;
 	*eof = (elen <= count) ? 1 : 0;
 	*start = page + off;
+	err = elen;
 
+_err:
 	MOD_DEC_USE_COUNT;
-	return elen;
+	return err;
 }
 
 /*
@@ -419,18 +430,18 @@
 	int res = count;
 
 	MOD_INC_USE_COUNT;
-	if (((buffer[0] == '1') || (buffer[0] == '0')) &&
-	    ((count == 1) || ((count == 2) && (buffer[1] == '\n')))) {
+	if (buffer[count-1] == '\n')
+		count--;
+	if ((count == 1) && !(buffer[0] & ~('0' | '1'))) {
 		if (data) {
-			read_lock(&entries_lock);
 			if ((e = get_entry((int) data)))
-				e->flags = (e->flags & -2) | (int) (buffer[0] - '0');
-			read_unlock(&entries_lock);
+				e->flags = (e->flags & ~ENTRY_ENABLED)
+					    | (int)(buffer[0] - '0');
+			put_entry(e);
 		} else {
 			enabled = buffer[0] - '0';
 		}
-	} else if ((buffer[0] == '-') && (buffer[1] == '1') &&
-	       ((count == 2) || ((count == 3) && (buffer[2] == '\n')))) {
+	} else if ((count == 2) && (buffer[0] == '-') && (buffer[1] == '1')) {
 		if (data)
 			clear_entry((int) data);
 		else
diff -u --recursive --new-file v2.1.51/linux/fs/buffer.c linux/fs/buffer.c
--- v2.1.51/linux/fs/buffer.c	Thu Aug 14 20:49:17 1997
+++ linux/fs/buffer.c	Mon Sep  1 11:24:35 1997
@@ -823,12 +823,8 @@
 struct buffer_head * getblk(kdev_t dev, int block, int size)
 {
 	struct buffer_head * bh;
-	int isize = BUFSIZE_INDEX(size);
+	int isize;
 
-	/* If there are too many dirty buffers, we wake up the update process
-	 * now so as to ensure that there are still clean buffers available
-	 * for user processes to use (and dirty).
-	 */
 repeat:
 	bh = get_hash_table(dev, block, size);
 	if (bh) {
@@ -841,17 +837,15 @@
 		return bh;
 	}
 
-	while(!free_list[isize])
-		refill_freelist(size);
-	
-	if (find_buffer(dev,block,size))
-		 goto repeat;
-
+	isize = BUFSIZE_INDEX(size);
+get_free:
 	bh = free_list[isize];
+	if (!bh)
+		goto refill;
 	remove_from_free_list(bh);
 
 	/* OK, FINALLY we know that this buffer is the only one of its kind,
-	 * and that it's unused (b_count=0), unlocked (buffer_locked=0), and clean.
+	 * and that it's unused (b_count=0), unlocked, and clean.
 	 */
 	bh->b_count=1;
 	bh->b_list	= BUF_CLEAN;
@@ -862,6 +856,16 @@
 	bh->b_blocknr=block;
 	insert_into_queues(bh);
 	return bh;
+
+	/*
+	 * If we block while refilling the free list, somebody may
+	 * create the buffer first ... search the hashes again.
+	 */
+refill:
+	refill_freelist(size);
+	if (!find_buffer(dev,block,size))
+		goto get_free;
+	goto repeat;
 }
 
 void set_writetime(struct buffer_head * buf, int flag)
diff -u --recursive --new-file v2.1.51/linux/fs/dcache.c linux/fs/dcache.c
--- v2.1.51/linux/fs/dcache.c	Mon Aug 18 18:19:46 1997
+++ linux/fs/dcache.c	Wed Sep  3 11:43:09 1997
@@ -19,6 +19,9 @@
 #include <linux/malloc.h>
 #include <linux/init.h>
 
+/* For managing the dcache */
+extern int nr_free_pages, free_pages_low;
+
 /*
  * This is the single most critical data structure when it comes
  * to the dcache: the hashtable for lookups. Somebody should try
@@ -72,13 +75,13 @@
 		dentry->d_count = count;
 		if (!count) {
 			list_del(&dentry->d_lru);
+			if (dentry->d_op && dentry->d_op->d_delete)
+				dentry->d_op->d_delete(dentry);
 			if (list_empty(&dentry->d_hash)) {
 				struct inode *inode = dentry->d_inode;
 				struct dentry * parent;
-				if (inode) {
-					list_del(&dentry->d_alias);
+				if (inode)
 					iput(inode);
-				}
 				parent = dentry->d_parent;
 				d_free(dentry);
 				if (dentry == parent)
@@ -134,7 +137,6 @@
 			if (dentry->d_inode) {
 				struct inode * inode = dentry->d_inode;
 
-				list_del(&dentry->d_alias);
 				dentry->d_inode = NULL;
 				iput(inode);
 			}
@@ -152,6 +154,13 @@
 	char * str;
 	struct dentry *dentry;
 
+	/*
+	 * Check whether to shrink the dcache ... this greatly reduces
+	 * the likelyhood that kmalloc() will need additional memory.
+	 */
+	if (nr_free_pages < free_pages_low)
+		shrink_dcache();
+
 	dentry = kmalloc(sizeof(struct dentry), GFP_KERNEL);
 	if (!dentry)
 		return NULL;
@@ -172,7 +181,6 @@
 	dentry->d_mounts = dentry;
 	dentry->d_covers = dentry;
 	INIT_LIST_HEAD(&dentry->d_hash);
-	INIT_LIST_HEAD(&dentry->d_alias);
 	INIT_LIST_HEAD(&dentry->d_lru);
 
 	dentry->d_name.name = str;
@@ -194,9 +202,6 @@
  */
 void d_instantiate(struct dentry *entry, struct inode * inode)
 {
-	if (inode)
-		list_add(&entry->d_alias, &inode->i_dentry);
-
 	entry->d_inode = inode;
 }
 
@@ -312,10 +317,10 @@
 	 */
 	if (dentry->d_count == 1) {
 		struct inode * inode = dentry->d_inode;
-
-		dentry->d_inode = NULL;
-		list_del(&dentry->d_alias);
-		iput(inode);
+		if (inode) {
+			dentry->d_inode = NULL;
+			iput(inode);
+		}
 		return;
 	}
 
diff -u --recursive --new-file v2.1.51/linux/fs/exec.c linux/fs/exec.c
--- v2.1.51/linux/fs/exec.c	Mon Aug 18 18:19:46 1997
+++ linux/fs/exec.c	Mon Sep  1 12:11:16 1997
@@ -134,21 +134,23 @@
 }
 #endif	/* CONFIG_MODULES */
 
+/* N.B. Error returns must be < 0 */
 int open_dentry(struct dentry * dentry, int mode)
 {
 	int fd;
 	struct inode * inode = dentry->d_inode;
+	struct file * f;
+	int error;
 
+	error = -EINVAL;
 	if (!inode->i_op || !inode->i_op->default_file_ops)
-		return -EINVAL;
+		goto out;
 	fd = get_unused_fd();
 	if (fd >= 0) {
-		struct file * f = get_empty_filp();
-
-		if (!f) {
-			put_unused_fd(fd);
-			return -ENFILE;
-		}
+		error = -ENFILE;
+		f = get_empty_filp();
+		if (!f)
+			goto out_fd;
 		f->f_flags = mode;
 		f->f_mode = (mode+1) & O_ACCMODE;
 		f->f_dentry = dentry;
@@ -156,17 +158,23 @@
 		f->f_reada = 0;
 		f->f_op = inode->i_op->default_file_ops;
 		if (f->f_op->open) {
-			int error = f->f_op->open(inode,f);
-			if (error) {
-				put_filp(f);
-				put_unused_fd(fd);
-				return error;
-			}
+			error = f->f_op->open(inode,f);
+			if (error)
+				goto out_filp;
 		}
 		current->files->fd[fd] = f;
 		dget(dentry);
 	}
 	return fd;
+
+out_filp:
+	if (error > 0)
+		error = -EIO;
+	put_filp(f);
+out_fd:
+	put_unused_fd(fd);
+out:
+	return error;
 }
 
 /*
@@ -379,37 +387,53 @@
 	return result;
 }
 
-static void exec_mmap(void)
+static int exec_mmap(void)
 {
+	struct mm_struct * mm, * old_mm;
+	int retval;
+
+	if (current->mm->count == 1) {
+		flush_cache_mm(current->mm);
+		exit_mmap(current->mm);
+		clear_page_tables(current);
+		flush_tlb_mm(current->mm);
+		return 0;
+	}
+
 	/*
 	 * The clear_page_tables done later on exec does the right thing
 	 * to the page directory when shared, except for graceful abort
 	 * (the oom is wrong there, too, IMHO)
 	 */
-	if (current->mm->count > 1) {
-		struct mm_struct *mm = kmem_cache_alloc(mm_cachep, SLAB_KERNEL);
-		if (!mm) {
-			/* this is wrong, I think. */
-			oom(current);
-			return;
-		}
-		*mm = *current->mm;
-		init_new_context(mm);
-		mm->def_flags = 0;	/* should future lockings be kept? */
-		mm->cpu_vm_mask = (1UL << smp_processor_id());
-		mm->count = 1;
-		mm->mmap = mm->mmap_cache = NULL;
-		mm->total_vm = 0;
-		mm->rss = 0;
-		current->mm->count--;
-		current->mm = mm;
-		new_page_tables(current);
-		return;
-	}
-	flush_cache_mm(current->mm);
-	exit_mmap(current->mm);
-	clear_page_tables(current);
-	flush_tlb_mm(current->mm);
+	retval = -ENOMEM;
+	mm = mm_alloc();
+	if (!mm)
+		goto fail_nomem;
+	mm->cpu_vm_mask = (1UL << smp_processor_id());
+	mm->total_vm = 0;
+	mm->rss = 0;
+	old_mm = current->mm;
+	current->mm = mm;
+	retval = new_page_tables(current);
+	if (retval)
+		goto fail_restore;
+	mmput(old_mm);
+	return 0;
+
+	/*
+	 * Failure ... restore the prior mm_struct.
+	 */
+fail_restore:
+	current->mm = old_mm;
+	mmput(mm);
+
+	/*
+	 * N.B. binfmt_xxx needs to handle the error instead of oom()
+	 */
+fail_nomem:
+	/* this is wrong, I think. */
+	oom(current);
+	return retval;
 }
 
 /*
@@ -454,9 +478,16 @@
 
 void flush_old_exec(struct linux_binprm * bprm)
 {
-	int i;
-	int ch;
 	char * name;
+	int i, ch, retval;
+
+	/* 
+	 * Release all of the old mmap stuff ... do this first
+	 * so we can bail out on failure.
+	 */
+	retval = exec_mmap();
+	if (retval)
+		goto out;
 
 	if (current->euid == current->uid && current->egid == current->gid)
 		current->dumpable = 1;
@@ -470,9 +501,6 @@
 	}
 	current->comm[i] = '\0';
 
-	/* Release all of the old mmap stuff. */
-	exec_mmap();
-
 	flush_thread();
 
 	if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || 
@@ -481,6 +509,8 @@
 
 	flush_old_signals(current->sig);
 	flush_old_files(current->files);
+out:
+	return; /* retval; FIXME. */
 }
 
 /* 
diff -u --recursive --new-file v2.1.51/linux/fs/file_table.c linux/fs/file_table.c
--- v2.1.51/linux/fs/file_table.c	Sun Jul 20 20:41:58 1997
+++ linux/fs/file_table.c	Mon Sep  1 12:11:58 1997
@@ -43,26 +43,6 @@
 	file->f_pprev = &inuse_filps;
 }
 
-/* Get more free filp's. */
-static int grow_files(void)
-{
-	int i = 16;
-
-	while(i--) {
-		struct file * file = kmem_cache_alloc(filp_cache, SLAB_KERNEL);
-		if(!file) {
-			if(i == 15)
-				return 0;
-			goto got_some;
-		}
-
-		insert_file_free(file);
-		nr_files++;
-	}
-got_some:
-	return 1;
-}
-
 void file_table_init(void)
 {
 	filp_cache = kmem_cache_create("filp", sizeof(struct file),
@@ -78,28 +58,36 @@
  */
 struct file * get_empty_filp(void)
 {
+	static int old_max = 0;
 	struct file * f;
 
-again:
-	if((f = free_filps) != NULL) {
-		remove_filp(f);
-		memset(f, 0, sizeof(*f));
-		f->f_count = 1;
-		f->f_version = ++event;
-		put_inuse(f);
-	} else {
-		int max = max_files;
-
-		/* Reserve a few files for the super-user.. */
-		if (current->euid)
-			max -= 10;
-
-		if (nr_files < max && grow_files())
-			goto again;
+	f = free_filps;
+	if (!f) 
+		goto get_more;
+	remove_filp(f);
+got_one:
+	memset(f, 0, sizeof(*f));
+	f->f_count = 1;
+	f->f_version = ++event;
+	put_inuse(f);
+	return f;
 
+get_more:
+	/* Reserve a few files for the super-user.. */
+	if (nr_files < (current->euid ? max_files - 10 : max_files)) {
+		f = kmem_cache_alloc(filp_cache, SLAB_KERNEL);
+		if (f) {
+			nr_files++;
+			goto got_one;
+		}
 		/* Big problems... */
+		printk("VFS: filp allocation failed\n");
+
+	} else if (max_files > old_max) {
+		printk("VFS: file-max limit %d reached\n", max_files);
+		old_max = max_files;
 	}
-	return f;
+	return NULL;
 }
 
 /*
diff -u --recursive --new-file v2.1.51/linux/fs/inode.c linux/fs/inode.c
--- v2.1.51/linux/fs/inode.c	Thu Aug 14 20:49:17 1997
+++ linux/fs/inode.c	Tue Aug 19 10:53:21 1997
@@ -109,7 +109,6 @@
 {
 	memset(inode, 0, sizeof(*inode));
 	init_waitqueue(&inode->i_wait);
-	INIT_LIST_HEAD(&inode->i_dentry);
 	INIT_LIST_HEAD(&inode->i_hash);
 	sema_init(&inode->i_sem, 1);
 }
diff -u --recursive --new-file v2.1.51/linux/fs/msdos/namei.c linux/fs/msdos/namei.c
--- v2.1.51/linux/fs/msdos/namei.c	Thu Aug 14 20:49:17 1997
+++ linux/fs/msdos/namei.c	Wed Aug 20 15:46:44 1997
@@ -232,8 +232,11 @@
 
 	sb->s_op = &msdos_sops;
 	res =  fat_read_super(sb, data, silent);
-	if (res == NULL)
+	if (res == NULL) {
+		sb->s_dev = 0;
 		MOD_DEC_USE_COUNT;
+		return NULL;
+	}
 	sb->s_root->d_op = &msdos_dentry_operations;
 	return res;
 }
diff -u --recursive --new-file v2.1.51/linux/fs/namei.c linux/fs/namei.c
--- v2.1.51/linux/fs/namei.c	Mon Aug 18 18:19:46 1997
+++ linux/fs/namei.c	Mon Sep  1 13:04:13 1997
@@ -460,16 +460,42 @@
 	return dentry;
 }
 
-static inline struct inode *get_parent(struct dentry *dentry)
+static inline struct dentry *get_parent(struct dentry *dentry)
 {
-	return dentry->d_parent->d_inode;
+	return dget(dentry->d_parent);
 }
 
-static inline struct inode *lock_parent(struct dentry *dentry)
+static inline void unlock_dir(struct dentry *dir)
 {
-	struct inode *dir = dentry->d_parent->d_inode;
+	up(&dir->d_inode->i_sem);
+	dput(dir);
+}
 
-	down(&dir->i_sem);
+/*
+ * Locking the parent is needed to:
+ *  - serialize directory operations
+ *  - make sure the parent doesn't change from
+ *    under us in the middle of an operation.
+ *
+ * NOTE! Right now we'd rather use a "struct inode"
+ * for this, but as I expect things to move toward
+ * using dentries instead for most things it is
+ * probably better to start with the conceptually
+ * better interface of relying on a path of dentries.
+ */
+static inline struct dentry *lock_parent(struct dentry *dentry)
+{
+	struct dentry *dir = dget(dentry->d_parent);
+
+	down(&dir->d_inode->i_sem);
+
+	/* Un-hashed or moved?  Punt if so.. */
+	if (dir != dentry->d_parent || list_empty(&dentry->d_hash)) {
+		if (dir != dentry) {
+			unlock_dir(dir);
+			dir = ERR_PTR(-ENOENT);
+		}
+	}
 	return dir;
 }
 
@@ -501,9 +527,12 @@
 
 	acc_mode = ACC_MODE(flag);
 	if (flag & O_CREAT) {
-		struct inode *dir;
+		struct dentry *dir;
 
 		dir = lock_parent(dentry);
+		error = PTR_ERR(dir);
+		if (IS_ERR(dir))
+			goto exit;
 		/*
 		 * The existence test must be done _after_ getting the directory
 		 * semaphore - the dentry might otherwise change.
@@ -512,19 +541,19 @@
 			error = 0;
 			if (flag & O_EXCL)
 				error = -EEXIST;
-		} else if (IS_RDONLY(dir))
+		} else if (IS_RDONLY(dir->d_inode))
 			error = -EROFS;
-		else if (!dir->i_op || !dir->i_op->create)
+		else if (!dir->d_inode->i_op || !dir->d_inode->i_op->create)
 			error = -EACCES;
-		else if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) == 0) {
-			if (dir->i_sb && dir->i_sb->dq_op)
-				dir->i_sb->dq_op->initialize(dir, -1);
-			error = dir->i_op->create(dir, dentry, mode);
+		else if ((error = permission(dir->d_inode,MAY_WRITE | MAY_EXEC)) == 0) {
+			if (dir->d_inode->i_sb && dir->d_inode->i_sb->dq_op)
+				dir->d_inode->i_sb->dq_op->initialize(dir->d_inode, -1);
+			error = dir->d_inode->i_op->create(dir->d_inode, dentry, mode);
 			/* Don't check for write permission, don't truncate */
 			acc_mode = 0;
 			flag &= ~O_TRUNC;
 		}
-		up(&dir->i_sem);
+		unlock_dir(dir);
 		if (error)
 			goto exit;
 	}
@@ -600,7 +629,7 @@
 struct dentry * do_mknod(const char * filename, int mode, dev_t dev)
 {
 	int error;
-	struct inode *dir;
+	struct dentry *dir;
 	struct dentry *dentry, *retval;
 
 	mode &= ~current->fs->umask;
@@ -609,33 +638,37 @@
 		return dentry;
 
 	dir = lock_parent(dentry);
+	retval = dir;
+	if (IS_ERR(dir))
+		goto exit;
 
 	retval = ERR_PTR(-EEXIST);
 	if (dentry->d_inode)
 		goto exit_lock;
 
 	retval = ERR_PTR(-EROFS);
-	if (IS_RDONLY(dir))
+	if (IS_RDONLY(dir->d_inode))
 		goto exit_lock;
 
-	error = permission(dir,MAY_WRITE | MAY_EXEC);
+	error = permission(dir->d_inode,MAY_WRITE | MAY_EXEC);
 	retval = ERR_PTR(error);
 	if (error)
 		goto exit_lock;
 
 	retval = ERR_PTR(-EPERM);
-	if (!dir->i_op || !dir->i_op->mknod)
+	if (!dir->d_inode->i_op || !dir->d_inode->i_op->mknod)
 		goto exit_lock;
 
-	if (dir->i_sb && dir->i_sb->dq_op)
-		dir->i_sb->dq_op->initialize(dir, -1);
-	error = dir->i_op->mknod(dir, dentry, mode, dev);
+	if (dir->d_inode->i_sb && dir->d_inode->i_sb->dq_op)
+		dir->d_inode->i_sb->dq_op->initialize(dir->d_inode, -1);
+	error = dir->d_inode->i_op->mknod(dir->d_inode, dentry, mode, dev);
 	retval = ERR_PTR(error);
 	if (!error)
 		retval = dget(dentry);
 
 exit_lock:
-	up(&dir->i_sem);
+	unlock_dir(dir);
+exit:
 	dput(dentry);
 	return retval;
 }
@@ -682,7 +715,7 @@
 static inline int do_mkdir(const char * pathname, int mode)
 {
 	int error;
-	struct inode *dir;
+	struct dentry *dir;
 	struct dentry *dentry;
 
 	dentry = lookup_dentry(pathname, NULL, 1);
@@ -692,29 +725,33 @@
 
 	dir = lock_parent(dentry);
 
+	error = PTR_ERR(dir);
+	if (IS_ERR(dir))
+		goto exit;
+
 	error = -EEXIST;
 	if (dentry->d_inode)
 		goto exit_lock;
 
 	error = -EROFS;
-	if (IS_RDONLY(dir))
+	if (IS_RDONLY(dir->d_inode))
 		goto exit_lock;
 
-	error = permission(dir,MAY_WRITE | MAY_EXEC);
+	error = permission(dir->d_inode,MAY_WRITE | MAY_EXEC);
 	if (error)
 		goto exit_lock;
 
 	error = -EPERM;
-	if (!dir->i_op || !dir->i_op->mkdir)
+	if (!dir->d_inode->i_op || !dir->d_inode->i_op->mkdir)
 		goto exit_lock;
 
-	if (dir->i_sb && dir->i_sb->dq_op)
-		dir->i_sb->dq_op->initialize(dir, -1);
+	if (dir->d_inode->i_sb && dir->d_inode->i_sb->dq_op)
+		dir->d_inode->i_sb->dq_op->initialize(dir->d_inode, -1);
 	mode &= 0777 & ~current->fs->umask;
-	error = dir->i_op->mkdir(dir, dentry, mode);
+	error = dir->d_inode->i_op->mkdir(dir->d_inode, dentry, mode);
 
 exit_lock:
-	up(&dir->i_sem);
+	unlock_dir(dir);
 	dput(dentry);
 exit:
 	return error;
@@ -739,7 +776,7 @@
 static inline int do_rmdir(const char * name)
 {
 	int error;
-	struct inode *dir;
+	struct dentry *dir;
 	struct dentry *dentry;
 
 	dentry = lookup_dentry(name, NULL, 0);
@@ -748,15 +785,20 @@
 		goto exit;
 
 	dir = lock_parent(dentry);
+
+	error = PTR_ERR(dir);
+	if (IS_ERR(dir))
+		goto exit;
+
 	error = -ENOENT;
 	if (!dentry->d_inode)
 		goto exit_lock;
 
 	error = -EROFS;
-	if (IS_RDONLY(dir))
+	if (IS_RDONLY(dir->d_inode))
 		goto exit_lock;
 
-	error = permission(dir,MAY_WRITE | MAY_EXEC);
+	error = permission(dir->d_inode,MAY_WRITE | MAY_EXEC);
 	if (error)
 		goto exit_lock;
 
@@ -764,25 +806,25 @@
 	 * A subdirectory cannot be removed from an append-only directory.
 	 */
 	error = -EPERM;
-	if (IS_APPEND(dir))
+	if (IS_APPEND(dir->d_inode))
 		goto exit_lock;
 
 	/* Disallow removals of mountpoints. */
 	error = -EBUSY;
-	if (dentry->d_covers != dentry)
+	if (dentry == dir)
 		goto exit_lock;
 
 	error = -EPERM;
-	if (!dir->i_op || !dir->i_op->rmdir)
+	if (!dir->d_inode->i_op || !dir->d_inode->i_op->rmdir)
 		goto exit_lock;
 
-	if (dir->i_sb && dir->i_sb->dq_op)
-		dir->i_sb->dq_op->initialize(dir, -1);
+	if (dir->d_inode->i_sb && dir->d_inode->i_sb->dq_op)
+		dir->d_inode->i_sb->dq_op->initialize(dir->d_inode, -1);
 
-	error = dir->i_op->rmdir(dir, dentry);
+	error = dir->d_inode->i_op->rmdir(dir->d_inode, dentry);
 
 exit_lock:
-        up(&dir->i_sem);
+        unlock_dir(dir);
 	dput(dentry);
 exit:
 	return error;
@@ -807,7 +849,7 @@
 static inline int do_unlink(const char * name)
 {
 	int error;
-	struct inode *dir;
+	struct dentry *dir;
 	struct dentry *dentry;
 
 	dentry = lookup_dentry(name, NULL, 0);
@@ -817,15 +859,24 @@
 
 	dir = lock_parent(dentry);
 
+	error = PTR_ERR(dir);
+	if (IS_ERR(dir))
+		goto exit;
+
 	error = -ENOENT;
 	if (!dentry->d_inode)
 		goto exit_lock;
 
+	/* Mount point? */
+	error = -EBUSY;
+	if (dentry == dir)
+		goto exit_lock;
+
 	error = -EROFS;
-	if (IS_RDONLY(dir))
+	if (IS_RDONLY(dir->d_inode))
 		goto exit_lock;
 
-	error = permission(dir,MAY_WRITE | MAY_EXEC);
+	error = permission(dir->d_inode,MAY_WRITE | MAY_EXEC);
 	if (error)
 		goto exit_lock;
 
@@ -833,20 +884,20 @@
 	 * A file cannot be removed from an append-only directory.
 	 */
 	error = -EPERM;
-	if (IS_APPEND(dir))
+	if (IS_APPEND(dir->d_inode))
 		goto exit_lock;
 
 	error = -EPERM;
-	if (!dir->i_op || !dir->i_op->unlink)
+	if (!dir->d_inode->i_op || !dir->d_inode->i_op->unlink)
 		goto exit_lock;
 
-	if (dir->i_sb && dir->i_sb->dq_op)
-		dir->i_sb->dq_op->initialize(dir, -1);
+	if (dir->d_inode->i_sb && dir->d_inode->i_sb->dq_op)
+		dir->d_inode->i_sb->dq_op->initialize(dir->d_inode, -1);
 
-	error = dir->i_op->unlink(dir, dentry);
+	error = dir->d_inode->i_op->unlink(dir->d_inode, dentry);
 
 exit_lock:
-        up(&dir->i_sem);
+        unlock_dir(dir);
 	dput(dentry);
 exit:
 	return error;
@@ -871,7 +922,7 @@
 static inline int do_symlink(const char * oldname, const char * newname)
 {
 	int error;
-	struct inode *dir;
+	struct dentry *dir;
 	struct dentry *dentry;
 
 	dentry = lookup_dentry(newname, NULL, 0);
@@ -882,28 +933,32 @@
 
 	dir = lock_parent(dentry);
 
+	error = PTR_ERR(dir);
+	if (IS_ERR(dir))
+		goto exit;
+
 	error = -EEXIST;
 	if (dentry->d_inode)
 		goto exit_lock;
 
 	error = -EROFS;
-	if (IS_RDONLY(dir))
+	if (IS_RDONLY(dir->d_inode))
 		goto exit_lock;
 
-	error = permission(dir,MAY_WRITE | MAY_EXEC);
+	error = permission(dir->d_inode,MAY_WRITE | MAY_EXEC);
 	if (error)
 		goto exit_lock;
 
 	error = -EPERM;
-	if (!dir->i_op || !dir->i_op->symlink)
+	if (!dir->d_inode->i_op || !dir->d_inode->i_op->symlink)
 		goto exit_lock;
 
-	if (dir->i_sb && dir->i_sb->dq_op)
-		dir->i_sb->dq_op->initialize(dir, -1);
-	error = dir->i_op->symlink(dir, dentry, oldname);
+	if (dir->d_inode->i_sb && dir->d_inode->i_sb->dq_op)
+		dir->d_inode->i_sb->dq_op->initialize(dir->d_inode, -1);
+	error = dir->d_inode->i_op->symlink(dir->d_inode, dentry, oldname);
 
 exit_lock:
-	up(&dir->i_sem);
+	unlock_dir(dir);
 	dput(dentry);
 exit:
 	return error;
@@ -933,8 +988,8 @@
 
 static inline int do_link(const char * oldname, const char * newname)
 {
-	struct dentry *old_dentry, *new_dentry;
-	struct inode *dir, *inode;
+	struct dentry *old_dentry, *new_dentry, *dir;
+	struct inode *inode;
 	int error;
 
 	old_dentry = lookup_dentry(oldname, NULL, 1);
@@ -949,6 +1004,10 @@
 
 	dir = lock_parent(new_dentry);
 
+	error = PTR_ERR(dir);
+	if (IS_ERR(dir))
+		goto exit;
+
 	error = -ENOENT;
 	inode = old_dentry->d_inode;
 	if (!inode)
@@ -959,14 +1018,14 @@
 		goto exit_lock;
 
 	error = -EROFS;
-	if (IS_RDONLY(dir))
+	if (IS_RDONLY(dir->d_inode))
 		goto exit_lock;
 
 	error = -EXDEV;
-	if (dir->i_dev != inode->i_dev)
+	if (dir->d_inode->i_dev != inode->i_dev)
 		goto exit_lock;
 
-	error = permission(dir, MAY_WRITE | MAY_EXEC);
+	error = permission(dir->d_inode, MAY_WRITE | MAY_EXEC);
 	if (error)
 		goto exit_lock;
 
@@ -978,15 +1037,15 @@
 		goto exit_lock;
 
 	error = -EPERM;
-	if (!dir->i_op || !dir->i_op->link)
+	if (!dir->d_inode->i_op || !dir->d_inode->i_op->link)
 		goto exit_lock;
 
-	if (dir->i_sb && dir->i_sb->dq_op)
-		dir->i_sb->dq_op->initialize(dir, -1);
-	error = dir->i_op->link(inode, dir, new_dentry);
+	if (dir->d_inode->i_sb && dir->d_inode->i_sb->dq_op)
+		dir->d_inode->i_sb->dq_op->initialize(dir->d_inode, -1);
+	error = dir->d_inode->i_op->link(inode, dir->d_inode, new_dentry);
 
 exit_lock:
-	up(&dir->i_sem);
+	unlock_dir(dir);
 	dput(new_dentry);
 exit_old:
 	dput(old_dentry);
@@ -1020,30 +1079,37 @@
  * Whee.. Deadlock country. Happily there is only one VFS
  * operation that does this..
  */
-static inline void double_down(struct semaphore *s1, struct semaphore *s2)
+static inline void double_lock(struct dentry *d1, struct dentry *d2)
 {
-	if ((unsigned long) s1 < (unsigned long) s2) {
-		down(s1);
-		down(s2);
-	} else if (s1 == s2) {
-		down(s1);
-	} else {
-		down(s2);
+	struct semaphore *s1 = &d1->d_inode->i_sem;
+	struct semaphore *s2 = &d2->d_inode->i_sem;
+
+	if (s1 != s2) {
+		if ((unsigned long) s1 < (unsigned long) s2) {
+			struct semaphore *tmp = s2;
+			s2 = s1; s1 = tmp;
+		}
 		down(s1);
 	}
+	down(s2);
 }
 
-static inline void double_up(struct semaphore *s1, struct semaphore *s2)
+static inline void double_unlock(struct dentry *d1, struct dentry *d2)
 {
+	struct semaphore *s1 = &d1->d_inode->i_sem;
+	struct semaphore *s2 = &d2->d_inode->i_sem;
+
 	up(s1);
 	if (s1 != s2)
 		up(s2);
+	dput(d1);
+	dput(d2);
 }
 
 static inline int do_rename(const char * oldname, const char * newname)
 {
 	int error;
-	struct inode * old_dir, * new_dir;
+	struct dentry * old_dir, * new_dir;
 	struct dentry * old_dentry, *new_dentry;
 
 	old_dentry = lookup_dentry(oldname, NULL, 0);
@@ -1061,52 +1127,49 @@
 	new_dir = get_parent(new_dentry);
 	old_dir = get_parent(old_dentry);
 
-	double_down(&new_dir->i_sem, &old_dir->i_sem);
+	double_lock(new_dir, old_dir);
 
 	error = -ENOENT;
 	if (!old_dentry->d_inode)
 		goto exit_lock;
 
-	error = permission(old_dir,MAY_WRITE | MAY_EXEC);
+	error = permission(old_dir->d_inode,MAY_WRITE | MAY_EXEC);
 	if (error)
 		goto exit_lock;
-	error = permission(new_dir,MAY_WRITE | MAY_EXEC);
+	error = permission(new_dir->d_inode,MAY_WRITE | MAY_EXEC);
 	if (error)
 		goto exit_lock;
 
-	/*
-	 * Disallow moves of mountpoints.  There is no technical 
-	 * reason for this, but user level stuff gets too confused.
-	 */
+	/* Disallow moves of mountpoints. */
 	error = -EBUSY;
-	if (old_dentry->d_covers != old_dentry)
+	if (old_dir == old_dentry || new_dir == new_dentry)
 		goto exit_lock;
 
 	error = -EXDEV;
-	if (new_dir->i_dev != old_dir->i_dev)
+	if (new_dir->d_inode->i_dev != old_dir->d_inode->i_dev)
 		goto exit_lock;
 
 	error = -EROFS;
-	if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir))
+	if (IS_RDONLY(new_dir->d_inode) || IS_RDONLY(old_dir->d_inode))
 		goto exit_lock;
 
 	/*
 	 * A file cannot be removed from an append-only directory.
 	 */
 	error = -EPERM;
-	if (IS_APPEND(old_dir))
+	if (IS_APPEND(old_dir->d_inode))
 		goto exit_lock;
 
 	error = -EPERM;
-	if (!old_dir->i_op || !old_dir->i_op->rename)
+	if (!old_dir->d_inode->i_op || !old_dir->d_inode->i_op->rename)
 		goto exit_lock;
 
-	if (new_dir->i_sb && new_dir->i_sb->dq_op)
-		new_dir->i_sb->dq_op->initialize(new_dir, -1);
-	error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
+	if (new_dir->d_inode->i_sb && new_dir->d_inode->i_sb->dq_op)
+		new_dir->d_inode->i_sb->dq_op->initialize(new_dir->d_inode, -1);
+	error = old_dir->d_inode->i_op->rename(old_dir->d_inode, old_dentry, new_dir->d_inode, new_dentry);
 
 exit_lock:
-	double_up(&new_dir->i_sem, &old_dir->i_sem);
+	double_unlock(new_dir, old_dir);
 	dput(new_dentry);
 exit_old:
 	dput(old_dentry);
diff -u --recursive --new-file v2.1.51/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.1.51/linux/fs/nfs/dir.c	Mon Aug 18 18:19:46 1997
+++ linux/fs/nfs/dir.c	Sun Aug 24 11:10:29 1997
@@ -7,6 +7,13 @@
  *
  * 10 Apr 1996	Added silly rename for unlink	--okir
  * 28 Sep 1996	Improved directory cache --okir
+ * 23 Aug 1997  Claus Heine claus@momo.math.rwth-aachen.de 
+ *              Re-implemented silly rename for unlink, newly implemented
+ *              silly rename for nfs_rename() following the suggestions
+ *              of Olaf Kirch (okir) found in this file.
+ *              Following Linus comments on my original hack, this version
+ *              depends only on the dcache stuff and doesn't touch the inode
+ *              layer (iput() and friends).
  */
 
 #include <linux/sched.h>
@@ -349,10 +356,13 @@
 	return time < max;
 }
 
+static void nfs_silly_delete(struct dentry *);
+
 static struct dentry_operations nfs_dentry_operations = {
 	nfs_lookup_revalidate,
 	0,			/* d_hash */
 	0,			/* d_compare */
+	nfs_silly_delete,
 };
 
 static int nfs_lookup(struct inode *dir, struct dentry * dentry)
@@ -378,7 +388,6 @@
 
 	inode = NULL;
 	if (!error) {
-		error = -ENOENT;
 		inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
 		if (!inode)
 			return -EACCES;
@@ -530,9 +539,150 @@
 	return 0;
 }
 
-/*
- * We should do silly-rename here, but I'm too lazy to fix
- * up the directory entry implications of it..
+
+/*  Note: we copy the code from lookup_dentry() here, only: we have to
+ *  omit the directory lock. We are already the owner of the lock when
+ *  we reach here. And "down(&dir->i_sem)" would make us sleep forever
+ *  ('cause WE have the lock)
+ * 
+ *  VERY IMPORTANT: calculate the hash for this dentry!!!!!!!!
+ *  Otherwise the cached lookup DEFINITELY WILL fail. And a new dentry
+ *  is created. Without the DCACHE_NFSFS_RENAMED flag. And with d_count
+ *  == 1. And trouble.
+ *
+ *  Concerning my choice of the temp name: it is just nice to have
+ *  i_ino part of the temp name, as this offers another check whether
+ *  somebody attempts to remove the "silly renamed" dentry
+ *  itself. Which is something that I consider evil. Your opinion may
+ *  vary.
+ *  BUT:
+ *  Now that I compute the hash value right, it should be possible to simply
+ *  check for the DCACHE_NFSFS_RENAMED flag in dentry->d_flag instead of
+ *  doing the string compare.
+ *  WHICH MEANS:
+ *  This offers the opportunity to shorten the temp name. Currently, I use
+ *  the hex representation of i_ino + the hex value of jiffies. This
+ *  sums up to as much as 36 characters for a 64 bit machine, and needs
+ *  20 chars on a 32 bit machine. Have a look at jiffiesize etc.
+ *  QUINTESSENCE
+ *  The use of i_ino is simply cosmetic. All we need is a unique temp
+ *  file name for the .nfs files. The hex representation of "jiffies"
+ *  seemed to be adequate. And as we retry in case such a file already
+ *  exists we are guaranteed to succed (after some jiffies have passed
+ *  by :)
+ */
+
+static
+struct dentry *nfs_silly_lookup(struct dentry *parent, char *silly, int slen)
+{
+	struct qstr    sqstr;
+	struct dentry *sdentry;
+	int i, error;
+
+	sqstr.name = silly;
+	sqstr.len  = slen;
+	sqstr.hash = init_name_hash();
+	for (i= 0; i < slen; i++)
+		sqstr.hash = partial_name_hash(silly[i], sqstr.hash);
+	sqstr.hash = end_name_hash(sqstr.hash);
+	sdentry = d_lookup(parent, &sqstr);
+	if (!sdentry) {
+		sdentry = d_alloc(parent, &sqstr);
+		if (sdentry == NULL)
+			return ERR_PTR(-ENOMEM);
+		error = nfs_lookup(parent->d_inode, sdentry);
+		if (error) {
+			dput(sdentry);
+			return ERR_PTR(error);
+		}
+	}
+	return sdentry;
+}
+
+static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
+{
+	static unsigned int sillycounter = 0;
+	const int      i_inosize  = sizeof(dir->i_ino)*2;
+	const int      countersize = sizeof(sillycounter)*2;
+	const int      slen       = strlen(".nfs") + i_inosize + countersize;
+	char           silly[slen+1];
+	int            error;
+	struct dentry *sdentry;
+
+	if (dentry->d_count == 1) {
+		return -EIO;  /* No need to silly rename. */
+	}
+
+	if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
+		return -EBUSY; /* don't allow to unlink silly inode -- nope,
+				* think a bit: silly DENTRY, NOT inode --
+				* itself
+				*/
+	}
+
+	sprintf(silly, ".nfs%*.*lx",
+		i_inosize, i_inosize, dentry->d_inode->i_ino);
+
+	sdentry = NULL;
+	do {
+		char *suffix = silly + slen - countersize;
+
+		dput(sdentry);
+		sillycounter++;
+		sprintf(suffix, "%*.*x", countersize, countersize, sillycounter);
+
+		dfprintk(VFS, "trying to rename %s to %s\n",
+			 dentry->d_name.name, silly);
+		
+		sdentry = nfs_silly_lookup(dentry->d_parent, silly, slen);
+		if (IS_ERR(sdentry)) {
+			return -EIO; /* FIXME ? */
+		}		
+	} while(sdentry->d_inode != NULL); /* need negative lookup */
+
+	error = nfs_proc_rename(NFS_SERVER(dir),
+				NFS_FH(dir), dentry->d_name.name,
+				NFS_FH(dir), silly);
+	if (error) {
+		dput(sdentry);
+		return error;
+	}
+	nfs_invalidate_dircache(dir);
+	d_move(dentry, sdentry);
+	dput(sdentry);
+	dentry->d_flags |= DCACHE_NFSFS_RENAMED;
+
+	return 0; /* don't unlink */
+}
+
+static void nfs_silly_delete(struct dentry *dentry)
+{
+	if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
+		struct inode *dir = dentry->d_parent->d_inode;
+		int error;
+		
+		dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
+
+		/* Unhash it first */
+		d_drop(dentry);
+		dfprintk(VFS, "trying to unlink %s\n", dentry->d_name.name);
+		error = nfs_proc_remove(NFS_SERVER(dir),
+					NFS_FH(dir), dentry->d_name.name);
+		if (error < 0)
+			printk("NFS " __FUNCTION__ " failed (err = %d)\n",
+			       -error);
+		dentry->d_inode->i_nlink --;
+		nfs_invalidate_dircache(dir);
+	}
+}
+
+/*  We do silly rename. In case sillyrename() returns -EBUSY, the inode
+ *  belongs to an active ".nfs..." file and we return -EBUSY.
+ *
+ *  If sillyrename() returns 0, we do nothing, otherwise we unlink.
+ * 
+ *  inode->i_nlink is updated here rather than waiting for the next
+ *  nfs_refresh_inode() for cosmetic reasons only.
  */
 static int nfs_unlink(struct inode *dir, struct dentry *dentry)
 {
@@ -549,12 +699,21 @@
 	if (dentry->d_name.len > NFS_MAXNAMLEN)
 		return -ENAMETOOLONG;
 
-	error = nfs_proc_remove(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name);
-	if (error)
-		return error;
+	error = nfs_sillyrename(dir, dentry);
+
+	if (error == -EBUSY) {
+		return -EBUSY;
+	} else if (error < 0) {
+		error = nfs_proc_remove(NFS_SERVER(dir),
+					NFS_FH(dir), dentry->d_name.name);
+		if (error < 0)
+			return error;
+		
+		dentry->d_inode->i_nlink --;
+		nfs_invalidate_dircache(dir);
+		d_delete(dentry);
+	}
 
-	nfs_invalidate_dircache(dir);
-	d_delete(dentry);
 	return 0;
 }
 
@@ -588,7 +747,7 @@
 		return error;
 
 	nfs_invalidate_dircache(dir);
-	/*  this looks _funny_ doesn't it? But: nfs_proc_symlynk()
+	/*  this looks _funny_ doesn't it? But: nfs_proc_symlink()
 	 *  only fills in sattr, not fattr. Thus nfs_fhget() cannot be
 	 *  called, it would be pointless, without a valid fattr
 	 *  argument. Other possibility: call nfs_proc_lookup()
@@ -623,7 +782,8 @@
 		return error;
 
 	nfs_invalidate_dircache(dir);
-	inode->i_count++;
+	inode->i_count ++;
+	inode->i_nlink ++; /* no need to wait for nfs_refresh_inode() */
 	d_instantiate(dentry, inode);
 	return 0;
 }
@@ -634,8 +794,17 @@
  * different file handle for the same inode after a rename (e.g. when
  * moving to a different directory). A fail-safe method to do so would
  * be to look up old_dir/old_name, create a link to new_dir/new_name and
- * rename the old file using the silly_rename stuff. This way, the original
+ * rename the old file using the sillyrename stuff. This way, the original
  * file in old_dir will go away when the last process iput()s the inode.
+ *
+ * FIXED.
+ * 
+ * It actually works quite well. One needs to have the possibility for
+ * at least one ".nfs..." file in each directory the file ever gets
+ * moved or linked to which happens automagically with the new
+ * implementation that only depends on the dcache stuff instead of
+ * using the inode layer
+ *
  */
 static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 		      struct inode *new_dir, struct dentry *new_dentry)
@@ -659,10 +828,22 @@
 	if (old_dentry->d_name.len > NFS_MAXNAMLEN || new_dentry->d_name.len > NFS_MAXNAMLEN)
 		return -ENAMETOOLONG;
 
-	error = nfs_proc_rename(NFS_SERVER(old_dir),
-		NFS_FH(old_dir), old_dentry->d_name.name,
-		NFS_FH(new_dir), new_dentry->d_name.name);
+	if (new_dir != old_dir) {
+		error = nfs_sillyrename(old_dir, old_dentry);
 
+		if (error == -EBUSY) {
+			return -EBUSY;
+		} else if (error == 0) { /* did silly rename stuff */
+			error = nfs_link(old_dentry->d_inode,
+					 new_dir, new_dentry);
+			
+			return error;
+		}
+		/* no need for silly rename, proceed as usual */
+	}
+	error = nfs_proc_rename(NFS_SERVER(old_dir),
+				NFS_FH(old_dir), old_dentry->d_name.name,
+				NFS_FH(new_dir), new_dentry->d_name.name);
 	if (error)
 		return error;
 
@@ -737,3 +918,10 @@
 	} else
 		inode->i_op = NULL;
 }
+
+/*
+ * Local variables:
+ *  version-control: t
+ *  kept-new-versions: 5
+ * End:
+ */
diff -u --recursive --new-file v2.1.51/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v2.1.51/linux/fs/nfs/inode.c	Thu Jul 17 10:06:07 1997
+++ linux/fs/nfs/inode.c	Sat Aug 23 16:47:12 1997
@@ -77,10 +77,6 @@
 	dprintk("NFS: put_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
 }
 
-/*
- * This should do any silly-rename cleanups once we
- * get silly-renaming working again..
- */
 static void
 nfs_delete_inode(struct inode * inode)
 {
@@ -454,6 +450,8 @@
 init_nfs_fs(void)
 {
 #ifdef CONFIG_PROC_FS
+	rpc_register_sysctl();
+	rpc_proc_init();
 	rpc_proc_register(&nfs_rpcstat);
 #endif
         return register_filesystem(&nfs_fs_type);
diff -u --recursive --new-file v2.1.51/linux/fs/nfsd/nfs3proc.c linux/fs/nfsd/nfs3proc.c
--- v2.1.51/linux/fs/nfsd/nfs3proc.c	Sun Jul 27 12:11:01 1997
+++ linux/fs/nfsd/nfs3proc.c	Mon Sep  1 12:26:04 1997
@@ -46,6 +46,7 @@
 
 /*
  * Get a file's attributes
+ * N.B. After this call resp->fh needs an fh_put
  */
 static int
 nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle  *argp,
@@ -64,6 +65,7 @@
 
 /*
  * Set a file's attributes
+ * N.B. After this call resp->fh needs an fh_put
  */
 static int
 nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp,
@@ -82,6 +84,7 @@
 
 /*
  * Look up a path name component
+ * N.B. After this call _both_ resp->dirfh and resp->fh need an fh_put
  */
 static int
 nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
@@ -134,11 +137,13 @@
 	/* Read the symlink. */
 	resp->len = NFS3_MAXPATHLEN;
 	nfserr = nfsd_readlink(rqstp, &argp->fh, (char *) path, &resp->len);
+	fh_put(&argp->fh);
 	RETURN(nfserr);
 }
 
 /*
  * Read a portion of a file.
+ * N.B. After this call resp->fh needs an fh_put
  */
 static int
 nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
@@ -180,6 +185,7 @@
 
 /*
  * Write data to a file
+ * N.B. After this call resp->fh needs an fh_put
  */
 static int
 nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
@@ -207,6 +213,7 @@
  * With NFSv3, CREATE processing is a lot easier than with NFSv2.
  * At least in theory; we'll see how it fares in practice when the
  * first reports about SunOS compatibility problems start to pour in...
+ * N.B. After this call _both_ resp->dirfh and resp->fh need an fh_put
  */
 static int
 nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
@@ -246,6 +253,7 @@
 	RETURN(nfserr);
 }
 
+/* N.B. Is nfsd3_attrstat * correct for resp?? table says "void" */
 static int
 nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
 					  struct nfsd3_attrstat  *resp)
@@ -257,11 +265,16 @@
 				SVCFH_INO(&argp->fh),
 				argp->name);
 
+	/* Is this correct?? */
 	fh_copy(&resp->fh, &argp->fh);
 
 	/* Unlink. -S_IFDIR means file must not be a directory */
-	nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR,
-					argp->name, argp->len);
+	nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len);
+	/* 
+	 * N.B. Should be an fh_put here ... nfsd3_proc_rmdir has one,
+	 * or else as an xdr release function
+	 */
+	fh_put(&resp->fh);
 	RETURN(nfserr);
 }
 
@@ -336,6 +349,7 @@
 
 /*
  * Make directory. This operation is not idempotent.
+ * N.B. After this call resp->fh needs an fh_put
  */
 static int
 nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
@@ -449,13 +463,13 @@
   PROC(getattr,	 fhandle,	attrstat,	fhandle, RC_NOCACHE),
   PROC(setattr,  sattrargs,	attrstat,	fhandle, RC_REPLBUFF),
   PROC(none,	 void,		void,		void,	 RC_NOCACHE),
-  PROC(lookup,	 diropargs,	diropres,	fhandle, RC_NOCACHE),
+  PROC(lookup,	 diropargs,	diropres,	fhandle2,RC_NOCACHE),
   PROC(readlink, fhandle,	readlinkres,	void,	 RC_NOCACHE),
   PROC(read,	 readargs,	readres,	fhandle, RC_NOCACHE),
   PROC(none,	 void,		void,		void,	 RC_NOCACHE),
   PROC(write,	 writeargs,	attrstat,	fhandle, RC_REPLBUFF),
-  PROC(create,	 createargs,	diropres,	fhandle, RC_REPLBUFF),
-  PROC(remove,	 diropargs,	void,		void,	 RC_REPLSTAT),
+  PROC(create,	 createargs,	diropres,	fhandle2,RC_REPLBUFF),
+  PROC(remove,	 diropargs,	void,/* ??*/	void,	 RC_REPLSTAT),
   PROC(rename,	 renameargs,	void,		void,	 RC_REPLSTAT),
   PROC(link,	 linkargs,	void,		void,	 RC_REPLSTAT),
   PROC(symlink,	 symlinkargs,	void,		void,	 RC_REPLSTAT),
diff -u --recursive --new-file v2.1.51/linux/fs/nfsd/nfsproc.c linux/fs/nfsd/nfsproc.c
--- v2.1.51/linux/fs/nfsd/nfsproc.c	Sun Jul 27 12:11:01 1997
+++ linux/fs/nfsd/nfsproc.c	Mon Sep  1 12:26:04 1997
@@ -50,6 +50,7 @@
 
 /*
  * Get a file's attributes
+ * N.B. After this call resp->fh needs an fh_put
  */
 static int
 nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle  *argp,
@@ -63,6 +64,7 @@
 
 /*
  * Set a file's attributes
+ * N.B. After this call resp->fh needs an fh_put
  */
 static int
 nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp,
@@ -76,6 +78,7 @@
 
 /*
  * Look up a path name component
+ * N.B. After this call resp->fh needs an fh_put
  */
 static int
 nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
@@ -119,6 +122,7 @@
 
 /*
  * Read a portion of a file.
+ * N.B. After this call resp->fh needs an fh_put
  */
 static int
 nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp,
@@ -156,6 +160,7 @@
 
 /*
  * Write data to a file
+ * N.B. After this call resp->fh needs an fh_put
  */
 static int
 nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp,
@@ -181,6 +186,7 @@
  * and the actual create() call, but one could even consider this a
  * feature because this only happens if someone else creates the file
  * at the same time.
+ * N.B. After this call _both_ argp->fh and resp->fh need an fh_put
  */
 static int
 nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
@@ -188,7 +194,7 @@
 {
 	struct inode	*dirp, *inode = NULL;
 	struct iattr	*attr;
-	svc_fh		*dirfhp, *newfhp = NULL;
+	svc_fh		*dirfhp, *newfhp;
 	int		nfserr, type, mode;
 	int		rdonly = 0, exists;
 	dev_t		rdev = NODEV;
@@ -202,7 +208,7 @@
 	/* Get the directory inode */
 	nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, MAY_EXEC);
 	if (nfserr)
-		RETURN(nfserr);
+		goto done; /* must fh_put dirfhp even on error */
 	dirp = dirfhp->fh_handle.fh_dentry->d_inode;
 
 	/* Check for MAY_WRITE separately. */
@@ -211,10 +217,8 @@
 				 MAY_WRITE);
 	if (nfserr == nfserr_rofs) {
 		rdonly = 1;	/* Non-fatal error for echo > /dev/null */
-	} else if (nfserr) {
-		fh_put(dirfhp);
-		RETURN(nfserr);
-	}
+	} else if (nfserr)
+		goto done;
 
 	/* First, check if the file already exists.  */
 	exists = !nfsd_lookup(rqstp, dirfhp, argp->name, argp->len, newfhp);
@@ -378,6 +382,7 @@
 
 /*
  * Make directory. This operation is not idempotent.
+ * N.B. After this call resp->fh needs an fh_put
  */
 static int
 nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
@@ -389,6 +394,7 @@
 		SVCFH_DENTRY(&argp->fh),
 		argp->name);
 
+	/* N.B. what about the dentry count?? */
 	resp->fh.fh_dverified = 0; /* paranoia */
 	nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
 				    &argp->attrs, S_IFDIR, 0, &resp->fh);
diff -u --recursive --new-file v2.1.51/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- v2.1.51/linux/fs/nfsd/vfs.c	Sun Jul 27 12:11:01 1997
+++ linux/fs/nfsd/vfs.c	Mon Sep  1 12:26:04 1997
@@ -44,7 +44,7 @@
 
 /* Hack until we have a macro check for mandatory locks. */
 #ifndef IS_ISMNDLK
-#define IS_ISMNDLK(i)	(((i)->i_mode & (S_ISGID|S_ISVTX)) == S_ISGID)
+#define IS_ISMNDLK(i)	(((i)->i_mode & (S_ISGID|S_IXGRP)) == S_ISGID)
 #endif
 
 /* Check for dir entries '.' and '..' */
@@ -95,6 +95,7 @@
 
 /*
  * Look up one component of a pathname.
+ * N.B. After this call _both_ fhp and resfh need an fh_put
  */
 int
 nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
@@ -139,6 +140,7 @@
 
 /*
  * Set various file attributes.
+ * N.B. After this call fhp needs an fh_put
  */
 int
 nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap)
@@ -216,6 +218,7 @@
 /*
  * Open an existing file or directory.
  * The wflag argument indicates write access.
+ * N.B. After this call fhp needs an fh_put
  */
 int
 nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
@@ -328,6 +331,7 @@
 /*
  * Read data from a file. count must contain the requested read count
  * on entry. On return, *count contains the number of bytes actually read.
+ * N.B. After this call fhp needs an fh_put
  */
 int
 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, char *buf,
@@ -387,6 +391,7 @@
 /*
  * Write data to a file.
  * The stable flag requests synchronous writes.
+ * N.B. After this call fhp needs an fh_put
  */
 int
 nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
@@ -490,6 +495,7 @@
 /*
  * Create a file (regular, directory, device, fifo).
  * UNIX sockets not yet implemented.
+ * N.B. Every call to nfsd_create needs an fh_put for _both_ fhp and resfhp
  */
 int
 nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
@@ -578,6 +584,7 @@
  * field and call notify_change.
  *
  * XXX Nobody calls this thing? -DaveM
+ * N.B. After this call fhp needs an fh_put
  */
 int
 nfsd_truncate(struct svc_rqst *rqstp, struct svc_fh *fhp, unsigned long size)
@@ -615,6 +622,7 @@
 /*
  * Read a symlink. On entry, *lenp must contain the maximum path length that
  * fits into the buffer. On return, it contains the true length.
+ * N.B. After this call fhp needs an fh_put
  */
 int
 nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
@@ -647,6 +655,7 @@
 
 /*
  * Create a symlink and look up its inode
+ * N.B. After this call _both_ fhp and resfhp need an fh_put
  */
 int
 nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
@@ -697,6 +706,7 @@
 
 /*
  * Create a hardlink
+ * N.B. After this call _both_ ffhp and tfhp need an fh_put
  */
 int
 nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
@@ -753,6 +763,7 @@
 }
 
 /* More "hidden treasure" from the generic VFS. -DaveM */
+/* N.B. VFS double_down was modified to fix a bug ... should use VFS one */
 static inline void nfsd_double_down(struct semaphore *s1, struct semaphore *s2)
 {
 	if((unsigned long) s1 < (unsigned long) s2) {
@@ -769,6 +780,7 @@
 
 /*
  * Rename a file
+ * N.B. After this call _both_ ffhp and tfhp need an fh_put
  */
 int
 nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
@@ -829,6 +841,7 @@
 
 /*
  * Unlink a file or directory
+ * N.B. After this call fhp needs an fh_put
  */
 int
 nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
@@ -951,6 +964,7 @@
 
 /*
  * Get file system stats
+ * N.B. After this call fhp needs an fh_put
  */
 int
 nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct statfs *stat)
diff -u --recursive --new-file v2.1.51/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.1.51/linux/fs/proc/array.c	Mon Aug  4 16:25:39 1997
+++ linux/fs/proc/array.c	Wed Aug 20 13:59:36 1997
@@ -295,14 +295,20 @@
 static int get_meminfo(char * buffer)
 {
 	struct sysinfo i;
+	int len;
 
 	si_meminfo(&i);
 	si_swapinfo(&i);
-
+	len = sprintf(buffer, "        total:    used:    free:  shared: buffers:  cached:\n"
+		"Mem:  %8lu %8lu %8lu %8lu %8lu %8lu\n"
+		"Swap: %8lu %8lu %8lu\n",
+		i.totalram, i.totalram-i.freeram, i.freeram, i.sharedram, i.bufferram, page_cache_size*PAGE_SIZE,
+		i.totalswap, i.totalswap-i.freeswap, i.freeswap);
 	/*
-	 * Tagged format, for easy grepping and expansion.
+	 * Tagged format, for easy grepping and expansion. The above will go away
+	 * eventually, once the tools have been updated.
 	 */
-	return sprintf(buffer,
+	return len + sprintf(buffer+len,
 		"MemTotal:  %8lu kB\n"
 		"MemFree:   %8lu kB\n"
 		"MemShared: %8lu kB\n"
diff -u --recursive --new-file v2.1.51/linux/fs/proc/openpromfs.c linux/fs/proc/openpromfs.c
--- v2.1.51/linux/fs/proc/openpromfs.c	Mon Aug 18 18:19:46 1997
+++ linux/fs/proc/openpromfs.c	Mon Aug 18 20:17:14 1997
@@ -840,26 +840,19 @@
 	
 	if (!dir)
 		return -ENOENT;
-	if (dentry->d_name.len > 256) {
-		iput (dir);
+	if (dentry->d_name.len > 256)
 		return -EINVAL;
-	}
-	if (aliases_nodes == ALIASES_NNODES) {
-		iput (dir);
+	if (aliases_nodes == ALIASES_NNODES)
 		return -EIO;
-	}
 	p = kmalloc (dentry->d_name.len + 1, GFP_KERNEL);
-	if (!p) {
-		iput (dir);
+	if (!p)
 		return -ENOMEM;
-	}
 	strncpy (p, dentry->d_name.name, dentry->d_name.len);
 	p [dentry->d_name.len] = 0;
 	alias_names [aliases_nodes++] = p;
 	inode = proc_get_inode (dir->i_sb,
 				NODEP2INO(NODE(dir->i_ino).first_prop)
 				+ aliases_nodes, 0);
-	iput (dir);
 	if (!inode)
 		return -EINVAL;
 	inode->i_mode = S_IFREG | S_IRUGO | S_IWUSR;
diff -u --recursive --new-file v2.1.51/linux/fs/romfs/inode.c linux/fs/romfs/inode.c
--- v2.1.51/linux/fs/romfs/inode.c	Mon Aug  4 16:25:39 1997
+++ linux/fs/romfs/inode.c	Tue Aug 19 10:57:45 1997
@@ -455,15 +455,6 @@
 	int len, cnt;
 	struct dentry *dentry;
 
-	/* Note: 2.1.46+ calls this for our strange directories...
-	 * What I do is not really right, but I like it better for now,
-	 * than a separate i_op table.  Anyway, our directories won't
-	 * have multiple "real" links to them, so it maybe loses nothing.  */
-	if (!S_ISLNK(inode->i_mode)) {
-		dentry = dget(i_dentry(inode));
-		goto outnobuf;
-	}
-
 	len = inode->i_size;
 
 	dentry = ERR_PTR(-EAGAIN);			/* correct? */
@@ -548,7 +539,7 @@
  * will protect from type mismatch.
  */
 
-static struct inode_operations romfs_dirlink_inode_operations = {
+static struct inode_operations romfs_dir_inode_operations = {
 	&romfs_dir_operations,
 	NULL,			/* create */
 	romfs_lookup,		/* lookup */
@@ -559,6 +550,27 @@
 	NULL,			/* rmdir */
 	NULL,			/* mknod */
 	NULL,			/* rename */
+	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	NULL,			/* readpage */
+	NULL,			/* writepage */
+	NULL,			/* bmap */
+	NULL,			/* truncate */
+	NULL,			/* permission */
+	NULL,			/* smap */
+};
+
+static struct inode_operations romfs_link_inode_operations = {
+	NULL,			/* no file operations on symlinks */
+	NULL,			/* create */
+	NULL,			/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
 	romfs_readlink,		/* readlink */
 	romfs_follow_link,	/* follow_link */
 	NULL,			/* readpage */
@@ -578,9 +590,9 @@
 static struct inode_operations *romfs_inoops[] =
 {
 	NULL,				/* hardlink, handled elsewhere */
-	&romfs_dirlink_inode_operations,
+	&romfs_dir_inode_operations,
 	&romfs_file_inode_operations,
-	&romfs_dirlink_inode_operations,
+	&romfs_link_inode_operations,
 	&blkdev_inode_operations,	/* standard handlers */
 	&chrdev_inode_operations,
 	NULL,				/* socket */
diff -u --recursive --new-file v2.1.51/linux/fs/select.c linux/fs/select.c
--- v2.1.51/linux/fs/select.c	Mon Jun 16 16:35:59 1997
+++ linux/fs/select.c	Fri Aug 22 19:56:43 1997
@@ -423,7 +423,7 @@
 	wait_table.nr = 0;
 	wait_table.entry = entry;
 
-	fdcount = do_poll(nfds, fds, &wait_table);
+	fdcount = do_poll(nfds, fds, timeout ? &wait_table : NULL);
 	current->timeout = 0;
 
 	free_wait(&wait_table);
diff -u --recursive --new-file v2.1.51/linux/fs/smbfs/Makefile linux/fs/smbfs/Makefile
--- v2.1.51/linux/fs/smbfs/Makefile	Sun Dec  1 08:22:08 1996
+++ linux/fs/smbfs/Makefile	Fri Aug 22 10:04:33 1997
@@ -8,11 +8,11 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 O_TARGET := smbfs.o
-O_OBJS   := proc.o sock.o inode.o file.o dir.o ioctl.o mmap.o
+O_OBJS   := proc.o dir.o sock.o inode.o file.o ioctl.o 
 M_OBJS   := $(O_TARGET)
 
 # If you want debugging output, please uncomment the following line
 
-# EXTRA_CFLAGS += -DDEBUG_SMB=1 -DDEBUG_SMB_MALLOC=1
+# EXTRA_CFLAGS += -DDEBUG -DDEBUG_SMB_MALLOC=1
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.51/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c
--- v2.1.51/linux/fs/smbfs/dir.c	Mon Jun 16 16:35:59 1997
+++ linux/fs/smbfs/dir.c	Fri Aug 22 10:13:04 1997
@@ -2,6 +2,7 @@
  *  dir.c
  *
  *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1997 by Volker Lendecke
  *
  */
 
@@ -19,35 +20,19 @@
 #include <asm/semaphore.h>
 
 static long
- smb_dir_read(struct inode *inode, struct file *filp, char *buf, unsigned long count);
+smb_dir_read(struct inode *inode, struct file *filp,
+	     char *buf, unsigned long count);
 
 static int
- smb_readdir(struct inode *inode, struct file *filp,
-	     void *dirent, filldir_t filldir);
+smb_readdir(struct inode *inode, struct file *filp,
+	    void *dirent, filldir_t filldir);
 
-static struct smb_inode_info *
- smb_find_dir_inode(struct inode *parent, const char *name, int len);
-
-static int
- smb_lookup(struct inode *dir, const char *__name,
-	    int len, struct inode **result);
-
-static int
- smb_create(struct inode *dir, const char *name, int len, int mode,
-	    struct inode **result);
-
-static int
- smb_mkdir(struct inode *dir, const char *name, int len, int mode);
-
-static int
- smb_rmdir(struct inode *dir, const char *name, int len);
-
-static int
- smb_unlink(struct inode *dir, const char *name, int len);
-
-static int
- smb_rename(struct inode *old_dir, const char *old_name, int old_len,
-	    struct inode *new_dir, const char *new_name, int new_len);
+static int smb_lookup(struct inode *, struct dentry *);
+static int smb_create(struct inode *, struct dentry *, int);
+static int smb_mkdir(struct inode *, struct dentry *, int);
+static int smb_rmdir(struct inode *, struct dentry *);
+static int smb_unlink(struct inode *, struct dentry *);
+static int smb_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
 
 static struct file_operations smb_dir_operations =
 {
@@ -56,7 +41,7 @@
 	NULL,			/* write - bad */
 	smb_readdir,		/* readdir */
 	NULL,			/* poll - default */
-	smb_ioctl,		/* ioctl - default */
+	smb_ioctl,		/* ioctl */
 	NULL,			/* mmap */
 	NULL,			/* no special open code */
 	NULL,			/* no special release code */
@@ -76,6 +61,7 @@
 	NULL,			/* mknod */
 	smb_rename,		/* rename */
 	NULL,			/* readlink */
+	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -84,100 +70,13 @@
 	NULL			/* smap */
 };
 
-static int
-strncasecmp(const char *s1, const char *s2, int len)
-{
-	int result = 0;
-
-	for (; len > 0; len -= 1)
-	{
-		char c1, c2;
-
-		c1 = (*s1 >= 'a' && *s1 <= 'z') ? *s1 - ('a' - 'A') : *s1;
-		c2 = (*s2 >= 'a' && *s2 <= 'z') ? *s2 - ('a' - 'A') : *s2;
-		s1 += 1;
-		s2 += 1;
-
-		if ((result = c1 - c2) != 0 || c1 == 0)
-		{
-			return result;
-		}
-	}
-	return result;
-}
-
-static int
-compare_filename(const struct smb_server *server,
-		 const char *s1, int len, struct smb_dirent *entry)
-{
-	if (len != entry->len)
-	{
-		return 1;
-	}
-	if (server->case_handling == CASE_DEFAULT)
-	{
-		return strncasecmp(s1, entry->name, len);
-	}
-	return strncmp(s1, entry->name, len);
-}
-
-struct smb_inode_info *
-smb_find_inode(struct smb_server *server, ino_t ino)
-{
-	struct smb_inode_info *root = &(server->root);
-	struct smb_inode_info *this = root;
-
-	do
-	{
-		if (ino == smb_info_ino(this))
-		{
-			return this;
-		}
-		this = this->next;
-	}
-	while (this != root);
-
-	return NULL;
-}
-
-static ino_t
-smb_fresh_inodes(struct smb_server *server, int no)
-{
-	static ino_t seed = 1;
-	struct smb_inode_info *root = &(server->root);
-	struct smb_inode_info *this;
-
-      retry:
-	if (seed + no <= no)
-	{
-		/* avoid inode number of 0 at wrap-around */
-		seed += no;
-	}
-	this = root;
-	do
-	{
-		/* We assume that ino_t is unsigned! */
-		if (this->finfo.f_ino - seed < no)
-		{
-			seed += no;
-			goto retry;
-		}
-		this = this->next;
-	}
-	while (this != root);
-
-	seed += no;
-
-	return seed - no;
-}
-
 static long
-smb_dir_read(struct inode *inode, struct file *filp, char *buf, unsigned long count)
+smb_dir_read(struct inode *inode, struct file *filp, char *buf,
+	     unsigned long count)
 {
 	return -EISDIR;
 }
 
-
 static unsigned long c_ino = 0;
 static kdev_t c_dev;
 static int c_size;
@@ -206,8 +105,7 @@
 }
 
 static int
-smb_refill_dir_cache(struct smb_server *server, struct inode *dir,
-		     unsigned long f_pos)
+smb_refill_dir_cache(struct inode *dir, unsigned long f_pos)
 {
 	int result;
 	static struct semaphore sem = MUTEX;
@@ -217,7 +115,7 @@
 	do
 	{
 		down(&sem);
-		result = smb_proc_readdir(server, dir, f_pos,
+		result = smb_proc_readdir(dir, f_pos,
 					  SMB_READDIR_CACHE_SIZE, c_entry);
 
 		if (result <= 0)
@@ -232,15 +130,12 @@
 		c_size = result;
 		c_last_returned_index = 0;
 
-		ino = smb_fresh_inodes(server, c_size);
+		ino = smb_invent_inos(c_size);
+
 		for (i = 0; i < c_size; i++)
-		{
-			c_entry[i].f_ino = ino;
-			ino += 1;
-		}
+			c_entry[i].attr.f_ino = ino++;
 
 		up(&sem);
-
 	}
 	while ((c_dev != dir->i_dev) || (c_ino != dir->i_ino));
 
@@ -253,15 +148,13 @@
 {
 	int result, i = 0;
 	struct smb_dirent *entry = NULL;
-	struct smb_server *server = SMB_SERVER(dir);
 
-	DPRINTK("smb_readdir: filp->f_pos = %d\n", (int) filp->f_pos);
-	DDPRINTK("smb_readdir: dir->i_ino = %ld, c_ino = %ld\n",
+	pr_debug("smb_readdir: filp->f_pos = %d\n", (int) filp->f_pos);
+	pr_debug("smb_readdir: dir->i_ino = %ld, c_ino = %ld\n",
 		 dir->i_ino, c_ino);
 
 	if ((dir == NULL) || !S_ISDIR(dir->i_mode))
 	{
-		printk("smb_readdir: dir is NULL or not a directory\n");
 		return -EBADF;
 	}
 	if (c_entry == NULL)
@@ -270,7 +163,6 @@
 		c_entry = (struct smb_dirent *) smb_vmalloc(i);
 		if (c_entry == NULL)
 		{
-			printk("smb_readdir: no MEMORY for cache\n");
 			return -ENOMEM;
 		}
 	}
@@ -280,20 +172,17 @@
 		c_dev = 0;
 		c_seen_eof = 0;
 
-		if (filldir(dirent, ".", 1, filp->f_pos,
-			    smb_info_ino(SMB_INOP(dir))) < 0)
-		{
+		if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino) < 0)
 			return 0;
-		}
+
 		filp->f_pos += 1;
 	}
 	if (filp->f_pos == 1)
 	{
 		if (filldir(dirent, "..", 2, filp->f_pos,
-			    smb_info_ino(SMB_INOP(dir)->dir)) < 0)
-		{
+			    filp->f_dentry->d_parent->d_inode->i_ino) < 0)
 			return 0;
-		}
+
 		filp->f_pos += 1;
 	}
 	entry = smb_search_in_cache(dir, filp->f_pos);
@@ -305,7 +194,7 @@
 			/* End of directory */
 			return 0;
 		}
-		result = smb_refill_dir_cache(server, dir, filp->f_pos);
+		result = smb_refill_dir_cache(dir, filp->f_pos);
 		if (result <= 0)
 		{
 			return result;
@@ -314,35 +203,18 @@
 	}
 	while (entry < &(c_entry[c_size]))
 	{
-		/* We found it.  For getwd(), we have to return the
-		   correct inode in d_ino if the inode is currently in
-		   use. Otherwise the inode number does not
-		   matter. (You can argue a lot about this..) */
-
-		struct smb_inode_info *ino_info
-		= smb_find_dir_inode(dir, entry->name, entry->len);
+		ino_t ino = entry->attr.f_ino;
 
-		ino_t ino = entry->f_ino;
-
-		if (ino_info != NULL)
-		{
-			ino = smb_info_ino(ino_info);
-		}
-		DDPRINTK("smb_readdir: entry->name = %s\n", entry->name);
-		DDPRINTK("smb_readdir: entry->f_pos = %ld\n", entry->f_pos);
+		pr_debug("smb_readdir: entry->name = %s\n", entry->name);
 
 		if (filldir(dirent, entry->name, strlen(entry->name),
 			    entry->f_pos, ino) < 0)
-		{
 			break;
-		}
+
 		if ((dir->i_dev != c_dev) || (dir->i_ino != c_ino)
 		    || (entry->f_pos != filp->f_pos))
-		{
-			/* Someone has destroyed the cache while we slept
-			   in filldir */
 			break;
-		}
+
 		filp->f_pos += 1;
 		entry += 1;
 	}
@@ -360,7 +232,7 @@
 void
 smb_invalid_dir_cache(unsigned long ino)
 {
-	/* TODO: check for dev as well */
+	/* FIXME: check for dev as well */
 	if (ino == c_ino)
 	{
 		c_ino = 0;
@@ -378,466 +250,198 @@
 	c_entry = NULL;
 }
 
-/* Insert a NEW smb_inode_info into the inode tree of our filesystem,
-   under dir. The caller must assure that it's not already there. We
-   assume that path is allocated for us. */
-
-static struct inode *
-smb_iget(struct inode *dir, struct smb_inode_info *new_inode_info)
+static int
+smb_lookup(struct inode *dir, struct dentry *d_entry)
 {
+	struct smb_fattr finfo;
 	struct inode *inode;
-	struct smb_inode_info *root;
-
-	if ((dir == NULL) || (new_inode_info == NULL))
-	{
-		printk("smb_iget: parameter is NULL\n");
-		return NULL;
-	}
-	new_inode_info->state = SMB_INODE_LOOKED_UP;
-	new_inode_info->nused = 0;
-	new_inode_info->dir = SMB_INOP(dir);
-
-	SMB_INOP(dir)->nused += 1;
-
-	/* We have to link the new inode_info into the doubly linked
-	   list of inode_infos to make a complete linear search
-	   possible. */
-
-	root = &(SMB_SERVER(dir)->root);
-
-	new_inode_info->prev = root;
-	new_inode_info->next = root->next;
-	root->next->prev = new_inode_info;
-	root->next = new_inode_info;
-
-	if (!(inode = iget(dir->i_sb, smb_info_ino(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;
-	}
-	return inode;
-}
+	int len = d_entry->d_name.len;
+	int error;
 
-void
-smb_free_inode_info(struct smb_inode_info *i)
-{
-	if (i == NULL)
-	{
-		printk("smb_free_inode: i == NULL\n");
-		return;
+	if (!dir || !S_ISDIR(dir->i_mode)) {
+		printk("smb_lookup: inode is NULL or not a directory\n");
+		return -ENOENT;
 	}
-	i->state = SMB_INODE_CACHED;
-	while ((i->nused == 0) && (i->state == SMB_INODE_CACHED))
-	{
-		struct smb_inode_info *dir = i->dir;
-
-		i->next->prev = i->prev;
-		i->prev->next = i->next;
 
-		smb_kfree_s(i, sizeof(struct smb_inode_info));
+	if (len > SMB_MAXNAMELEN)
+		return -ENAMETOOLONG;
 
-		if (dir == NULL)
-		{
-			return;
-		}
-		dir->nused -= 1;
-		i = dir;
-	}
-}
-
-void
-smb_init_root(struct smb_server *server)
-{
-	struct smb_inode_info *root = &(server->root);
+	error = smb_proc_getattr(dir, &(d_entry->d_name), &finfo);
 
-	root->state = SMB_INODE_LOOKED_UP;
-	root->nused = 1;
-	root->dir = NULL;
-	root->next = root->prev = root;
+	inode = NULL;
+	if (!error) {
+		error = -ENOENT;
+		finfo.f_ino = smb_invent_inos(1);
+		inode = smb_iget(dir->i_sb, &finfo);
+		if (!inode)
+			return -EACCES;
+	} else if (error != -ENOENT)
+		return error;
 
-	return;
+	d_add(d_entry, inode);
+	return 0;
 }
 
-void
-smb_free_all_inodes(struct smb_server *server)
+static int smb_create(struct inode *dir, struct dentry *dentry, int mode)
 {
-	/* Here nothing should be to do. I do not know whether it's
-	   better to leave some memory allocated or be stuck in an
-	   endless loop */
-#if 1
-	struct smb_inode_info *root = &(server->root);
+	struct smb_fattr fattr;
+	struct inode *inode;
+	int error;
 
-	if (root->next != root)
-	{
-		printk("smb_free_all_inodes: INODES LEFT!!!\n");
-	}
-	while (root->next != root)
+	if (!dir || !S_ISDIR(dir->i_mode))
 	{
-		printk("smb_free_all_inodes: freeing inode\n");
-		smb_free_inode_info(root->next);
-		/* In case we have an endless loop.. */
-		schedule();
+		printk("smb_create: inode is NULL or not a directory\n");
+		return -ENOENT;
 	}
-#endif
 
-	return;
-}
+	if (dentry->d_name.len > SMB_MAXNAMELEN)
+		return -ENAMETOOLONG;
 
-/* This has to be called when a connection has gone down, so that all
-   file-handles we got from the server are invalid */
-void
-smb_invalidate_all_inodes(struct smb_server *server)
-{
-	struct smb_inode_info *ino = &(server->root);
+	error = smb_proc_create(dir, &(dentry->d_name), 0, CURRENT_TIME);
+	if (error < 0)
+		return error;
 
-	do
-	{
-		ino->finfo.opened = 0;
-		ino = ino->next;
-	}
-	while (ino != &(server->root));
+	smb_invalid_dir_cache(dir->i_ino);
 
-	return;
-}
+	/* FIXME: In the CIFS create call we get the file in open
+         * state. Currently we close it directly again, although this
+	 * is not necessary anymore. */
 
-/* We will search the inode that belongs to this name, currently by a
-   complete linear search through the inodes belonging to this
-   filesystem. This has to be fixed. */
-static struct smb_inode_info *
-smb_find_dir_inode(struct inode *parent, const char *name, int len)
-{
-	struct smb_server *server = SMB_SERVER(parent);
-	struct smb_inode_info *dir = SMB_INOP(parent);
-	struct smb_inode_info *result = &(server->root);
+	error = smb_proc_getattr(dir, &(dentry->d_name), &fattr);
+	if (error < 0)
+		return error;
 
-	if (name == NULL)
-	{
-		return NULL;
-	}
-	if ((len == 1) && (name[0] == '.'))
-	{
-		return dir;
-	}
-	if ((len == 2) && (name[0] == '.') && (name[1] == '.'))
-	{
-		return dir->dir;
-	}
-	do
-	{
-		if (result->dir == dir)
-		{
-			if (compare_filename(server, name, len,
-					     &(result->finfo)) == 0)
-			{
-				return result;
-			}
-		}
-		result = result->next;
-	}
-	while (result != &(server->root));
+	fattr.f_ino = smb_invent_inos(1);
 
-	return NULL;
+	inode = smb_iget(dir->i_sb, &fattr);
+	if (!inode)
+		return -EACCES;
+
+	d_instantiate(dentry, inode);
+	return 0;
 }
 
 static int
-smb_lookup(struct inode *dir, const char *name, int len,
-	   struct inode **result)
+smb_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
-	struct smb_dirent finfo;
-	struct smb_inode_info *result_info;
+	struct smb_fattr fattr;
+	struct inode *inode;
 	int error;
-	int found_in_cache;
-
-	struct smb_inode_info *new_inode_info = NULL;
-
-	*result = NULL;
 
 	if (!dir || !S_ISDIR(dir->i_mode))
 	{
-		printk("smb_lookup: inode is NULL or not a directory.\n");
-		iput(dir);
+		printk("smb_mkdir: inode is NULL or not a directory\n");
 		return -ENOENT;
 	}
-	DDPRINTK("smb_lookup: %s\n", name);
-
-	/* Fast cheat for . */
-	if (len == 0 || (len == 1 && name[0] == '.'))
-	{
-		*result = dir;
-		return 0;
-	}
-	/* ..and for .. */
-	if (len == 2 && name[0] == '.' && name[1] == '.')
-	{
-		struct smb_inode_info *parent = SMB_INOP(dir)->dir;
-
-		if (parent->state == SMB_INODE_CACHED)
-		{
-			parent->state = SMB_INODE_LOOKED_UP;
-		}
-		*result = iget(dir->i_sb, smb_info_ino(parent));
-		iput(dir);
-		if (*result == 0)
-		{
-			return -EACCES;
-		}
-		return 0;
-	}
-	result_info = smb_find_dir_inode(dir, name, len);
-
-      in_tree:
-	if (result_info != NULL)
-	{
-		if (result_info->state == SMB_INODE_CACHED)
-		{
-			result_info->state = SMB_INODE_LOOKED_UP;
-		}
-		*result = iget(dir->i_sb, smb_info_ino(result_info));
-		iput(dir);
-
-		if (new_inode_info != NULL)
-		{
-			smb_kfree_s(new_inode_info,
-				    sizeof(struct smb_inode_info));
-		}
-		if (*result == NULL)
-		{
-			return -EACCES;
-		}
-		return 0;
-	}
-	/* If the file is in the dir cache, we do not have to ask the
-	   server. */
-	found_in_cache = 0;
 
-	if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino) && (c_size != 0))
-	{
-		int first = c_last_returned_index;
-		int i;
+	if (dentry->d_name.len > SMB_MAXNAMELEN)
+		return -ENAMETOOLONG;
 
-		i = first;
-		do
-		{
-			if (compare_filename(SMB_SERVER(dir), name, len,
-					     &(c_entry[i])) == 0)
-			{
-				finfo = c_entry[i];
-				found_in_cache = 1;
-				break;
-			}
-			i = (i + 1) % c_size;
-		}
-		while (i != first);
-	}
-	if (found_in_cache == 0)
-	{
-		DPRINTK("smb_lookup: not found in cache: %s\n", name);
-		if (len > SMB_MAXNAMELEN)
-		{
-			iput(dir);
-			return -ENAMETOOLONG;
-		}
-		error = smb_proc_getattr(dir, name, len, &finfo);
-		if (error < 0)
-		{
-			iput(dir);
-			return error;
-		}
-		finfo.f_ino = smb_fresh_inodes(SMB_SERVER(dir), 1);
-	}
-	new_inode_info = smb_kmalloc(sizeof(struct smb_inode_info),
-				     GFP_KERNEL);
+	error = smb_proc_mkdir(dir, &(dentry->d_name));
+	if (error)
+		return error;
 
-	/* Here somebody else might have inserted the inode */
+	smb_invalid_dir_cache(dir->i_ino);
 
-	result_info = smb_find_dir_inode(dir, name, len);
-	if (result_info != NULL)
-	{
-		goto in_tree;
-	}
-	new_inode_info->finfo = finfo;
+	error = smb_proc_getattr(dir, &(dentry->d_name), &fattr);
+	if (error < 0)
+		return error;
 
-	DPRINTK("attr: %x\n", finfo.attr);
+	fattr.f_ino = smb_invent_inos(1);
 
-	if ((*result = smb_iget(dir, new_inode_info)) == NULL)
-	{
-		smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info));
-		iput(dir);
+	inode = smb_iget(dir->i_sb, &fattr);
+	if (!inode)
 		return -EACCES;
-	}
-	DDPRINTK("smb_lookup: %s => %lu\n", name, (unsigned long) result_info);
-	iput(dir);
+
+	d_instantiate(dentry, inode);
 	return 0;
 }
 
 static int
-smb_create(struct inode *dir, const char *name, int len, int mode,
-	   struct inode **result)
+smb_rmdir(struct inode *dir, struct dentry *dentry)
 {
 	int error;
-	struct smb_dirent entry;
-	struct smb_inode_info *new_inode_info;
-
-	*result = NULL;
 
 	if (!dir || !S_ISDIR(dir->i_mode))
 	{
-		printk("smb_create: inode is NULL or not a directory\n");
-		iput(dir);
+		printk("smb_rmdir: inode is NULL or not a directory\n");
 		return -ENOENT;
 	}
-	new_inode_info = smb_kmalloc(sizeof(struct smb_inode_info),
-				     GFP_KERNEL);
-	if (new_inode_info == NULL)
-	{
-		iput(dir);
-		return -ENOMEM;
-	}
-	error = smb_proc_create(dir, name, len, 0, CURRENT_TIME);
-	if (error < 0)
-	{
-		smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info));
-		iput(dir);
-		return error;
-	}
-	smb_invalid_dir_cache(dir->i_ino);
-
-	if ((error = smb_proc_getattr(dir, name, len, &entry)) < 0)
-	{
-		smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info));
-		iput(dir);
-		return error;
-	}
-	entry.f_ino = smb_fresh_inodes(SMB_SERVER(dir), 1);
 
-	new_inode_info->finfo = entry;
+	if (dentry->d_name.len > NFS_MAXNAMLEN)
+		return -ENAMETOOLONG;
 
-	if ((*result = smb_iget(dir, new_inode_info)) == NULL)
-	{
-		smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info));
-		iput(dir);
+	error = smb_proc_rmdir(dir, &(dentry->d_name));
+	if (error)
 		return error;
-	}
-	iput(dir);
+
+	d_delete(dentry);
 	return 0;
 }
 
 static int
-smb_mkdir(struct inode *dir, const char *name, int len, int mode)
+smb_unlink(struct inode *dir, struct dentry *dentry)
 {
 	int error;
 
 	if (!dir || !S_ISDIR(dir->i_mode))
 	{
-		iput(dir);
-		return -EINVAL;
-	}
-	if ((error = smb_proc_mkdir(dir, name, len)) == 0)
-	{
-		smb_invalid_dir_cache(dir->i_ino);
+		printk("smb_unlink: inode is NULL or not a directory\n");
+		return -ENOENT;
 	}
-	iput(dir);
-	return error;
-}
 
-static int
-smb_rmdir(struct inode *dir, const char *name, int len)
-{
-	int error;
+	if (dentry->d_name.len > SMB_MAXNAMELEN)
+		return -ENAMETOOLONG;
 
-	if (!dir || !S_ISDIR(dir->i_mode))
-	{
-		printk("smb_rmdir: inode is NULL or not a directory\n");
-		iput(dir);
-		return -ENOENT;
-	}
-	if (smb_find_dir_inode(dir, name, len) != NULL)
-	{
-		error = -EBUSY;
-	} else
-	{
-		if ((error = smb_proc_rmdir(dir, name, len)) == 0)
-		{
-			smb_invalid_dir_cache(dir->i_ino);
-		}
-	}
-	iput(dir);
-	return error;
-}
+	error = smb_proc_unlink(dir, &(dentry->d_name));
+	if (error)
+		return error;
 
-static int
-smb_unlink(struct inode *dir, const char *name, int len)
-{
-	int error;
+	smb_invalid_dir_cache(dir->i_ino);
 
-	if (!dir || !S_ISDIR(dir->i_mode))
-	{
-		printk("smb_unlink: inode is NULL or not a directory\n");
-		iput(dir);
-		return -ENOENT;
-	}
-	if (smb_find_dir_inode(dir, name, len) != NULL)
-	{
-		error = -EBUSY;
-	} else
-	{
-		if ((error = smb_proc_unlink(dir, name, len)) == 0)
-		{
-			smb_invalid_dir_cache(dir->i_ino);
-		}
-	}
-	iput(dir);
-	return error;
+	d_delete(dentry);
+	return 0;
 }
 
-static int
-smb_rename(struct inode *old_dir, const char *old_name, int old_len,
-	   struct inode *new_dir, const char *new_name, int new_len)
+static int smb_rename(struct inode *old_dir, struct dentry *old_dentry,
+		      struct inode *new_dir, struct dentry *new_dentry)
 {
-	int res;
+	int error;
 
 	if (!old_dir || !S_ISDIR(old_dir->i_mode))
 	{
 		printk("smb_rename: old inode is NULL or not a directory\n");
-		res = -ENOENT;
-		goto finished;
+		return -ENOENT;
 	}
+
 	if (!new_dir || !S_ISDIR(new_dir->i_mode))
 	{
 		printk("smb_rename: new inode is NULL or not a directory\n");
-		res = -ENOENT;
-		goto finished;
-	}
-	if ((smb_find_dir_inode(old_dir, old_name, old_len) != NULL)
-	    || (smb_find_dir_inode(new_dir, new_name, new_len) != NULL))
-	{
-		res = -EBUSY;
-		goto finished;
+		return -ENOENT;
 	}
-	res = smb_proc_mv(old_dir, old_name, old_len,
-			  new_dir, new_name, new_len);
 
-	if (res == -EEXIST)
-	{
-		int res1 = smb_proc_unlink(old_dir, new_name, new_len);
+	if (old_dentry->d_name.len > SMB_MAXNAMELEN ||
+	    new_dentry->d_name.len > SMB_MAXNAMELEN)
+		return -ENAMETOOLONG;
+
+	error = smb_proc_mv(old_dir, &(old_dentry->d_name),
+			    new_dir, &(new_dentry->d_name));
+
+	if (error == -EEXIST)
+	{
+		error = smb_proc_unlink(old_dir, &(new_dentry->d_name));
+					
+		if (error)
+			return error;
 
-		if (res1 == 0)
-		{
-			res = smb_proc_mv(old_dir, old_name, old_len,
-					  new_dir, new_name, new_len);
-		}
-	}
-	if (res == 0)
-	{
-		smb_invalid_dir_cache(old_dir->i_ino);
-		smb_invalid_dir_cache(new_dir->i_ino);
+		error = smb_proc_mv(old_dir, &(old_dentry->d_name),
+				    new_dir, &(new_dentry->d_name));
 	}
-      finished:
-	iput(old_dir);
-	iput(new_dir);
-	return res;
+
+	if (error)
+		return error;
+
+	smb_invalid_dir_cache(old_dir->i_ino);
+	smb_invalid_dir_cache(new_dir->i_ino);
+	return 0;
 }
diff -u --recursive --new-file v2.1.51/linux/fs/smbfs/file.c linux/fs/smbfs/file.c
--- v2.1.51/linux/fs/smbfs/file.c	Mon Aug 18 18:19:46 1997
+++ linux/fs/smbfs/file.c	Fri Aug 22 10:04:33 1997
@@ -1,7 +1,8 @@
 /*
  *  file.c
  *
- *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1995, 1996, 1997 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1997 by Volker Lendecke
  *
  */
 
@@ -13,6 +14,7 @@
 #include <linux/mm.h>
 #include <linux/smb_fs.h>
 #include <linux/malloc.h>
+#include <linux/pagemap.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -29,184 +31,204 @@
 	return 0;
 }
 
-int
-smb_make_open(struct inode *i, int right)
+/*
+ * Read a page synchronously.
+ */
+static int
+smb_readpage_sync(struct inode *inode, struct page *page)
 {
-	struct smb_dirent *dirent;
+	unsigned long offset = page->offset;
+	char *buffer = (char *) page_address(page);
+	int rsize = SMB_SERVER(inode)->opt.max_xmit - (SMB_HEADER_LEN+15);
+	int result, refresh = 0;
+	int count = PAGE_SIZE;
+
+	pr_debug("SMB: smb_readpage_sync(%p)\n", page);
+	clear_bit(PG_error, &page->flags);
+
+	result = smb_open(inode, O_RDONLY);
+	if (result < 0)
+		goto io_error;
+
+	do {
+		if (count < rsize)
+			rsize = count;
 
-	if (i == NULL)
-	{
-		printk("smb_make_open: got NULL inode\n");
-		return -EINVAL;
-	}
-	dirent = &(SMB_INOP(i)->finfo);
-
-	DDPRINTK("smb_make_open: dirent->opened = %d\n", dirent->opened);
+		result = smb_proc_read(inode, offset, rsize, buffer);
+		if (result < 0)
+			goto io_error;
 
-	if ((dirent->opened) == 0)
-	{
-		/* tries max. rights */
-		int open_result = smb_proc_open(SMB_SERVER(i),
-						SMB_INOP(i)->dir,
-						dirent->name, dirent->len,
-						dirent);
-		if (open_result)
-		{
-			return open_result;
-		}
-	}
-	if (((right == O_RDONLY) && ((dirent->access == O_RDONLY)
-				     || (dirent->access == O_RDWR)))
-	    || ((right == O_WRONLY) && ((dirent->access == O_WRONLY)
-					|| (dirent->access == O_RDWR)))
-	    || ((right == O_RDWR) && (dirent->access == O_RDWR)))
-		return 0;
+		refresh = 1;
+		count -= result;
+		offset += result;
+		buffer += result;
+		if (result < rsize)
+			break;
+	} while (count);
 
-	return -EACCES;
+	memset(buffer, 0, count);
+	set_bit(PG_uptodate, &page->flags);
+	result = 0;
+
+io_error:
+	if (refresh)
+		smb_refresh_inode(inode);
+	clear_bit(PG_locked, &page->flags);
+	wake_up(&page->wait);
+	return result;
 }
 
-static long
-smb_file_read(struct inode *inode, struct file *file, char *buf, unsigned long count)
+int
+smb_readpage(struct inode *inode, struct page *page)
 {
-	int result, bufsize, to_read, already_read;
-	off_t pos;
-	int errno;
-
-	DPRINTK("smb_file_read: enter %s\n", SMB_FINFO(inode)->name);
-
-	if (!inode)
-	{
-		DPRINTK("smb_file_read: inode = NULL\n");
-		return -EINVAL;
-	}
-	if (!S_ISREG(inode->i_mode))
-	{
-		DPRINTK("smb_file_read: read from non-file, mode %07o\n",
-			inode->i_mode);
-		return -EINVAL;
-	}
-	if ((errno = smb_make_open(inode, O_RDONLY)) != 0)
-		return errno;
+	unsigned long	address;
+	int		error = -1;
 
-	pos = file->f_pos;
+	pr_debug("SMB: smb_readpage %08lx\n", page_address(page));
+	set_bit(PG_locked, &page->flags);
+	address = page_address(page);
+	atomic_inc(&page->count);
+	error = smb_readpage_sync(inode, page);
+	free_page(address);
+	return error;
+}
 
-	if (pos + count > inode->i_size)
-	{
-		count = inode->i_size - pos;
-	}
-	if (count <= 0)
-	{
-		return 0;
-	}
-	bufsize = SMB_SERVER(inode)->max_xmit - SMB_HEADER_LEN - 5 * 2 - 5;
+/*
+ * Write a page synchronously.
+ * Offset is the data offset within the page.
+ */
+static int
+smb_writepage_sync(struct inode *inode, struct page *page,
+		   unsigned long offset, unsigned int count)
+{
+	int wsize = SMB_SERVER(inode)->opt.max_xmit - (SMB_HEADER_LEN+15);
+	int result, refresh = 0, written = 0;
+	u8 *buffer;
+
+	pr_debug("SMB:      smb_writepage_sync(%x/%ld %d@%ld)\n",
+		 inode->i_dev, inode->i_ino,
+		 count, page->offset + offset);
+
+	buffer = (u8 *) page_address(page) + offset;
+	offset += page->offset;
+
+	do {
+		if (count < wsize)
+			wsize = count;
+
+		result = smb_proc_write(inode, offset, wsize, buffer);
+
+		if (result < 0) {
+			/* Must mark the page invalid after I/O error */
+			clear_bit(PG_uptodate, &page->flags);
+			goto io_error;
+		}
+		refresh = 1;
+		buffer += wsize;
+		offset += wsize;
+		written += wsize;
+		count -= wsize;
+	} while (count);
+
+io_error:
+	if (refresh)
+		smb_refresh_inode(inode);
 
-	already_read = 0;
+	clear_bit(PG_locked, &page->flags);
+	return written ? written : result;
+}
 
-	/* First read in as much as possible for each bufsize. */
-	while (already_read < count)
-	{
-		to_read = min(bufsize, count - already_read);
-		result = smb_proc_read(SMB_SERVER(inode), SMB_FINFO(inode),
-				       pos, to_read, buf, 1);
-		if (result < 0)
-		{
-			return result;
-		}
-		pos += result;
-		buf += result;
-		already_read += result;
+/*
+ * Write a page to the server. This will be used for NFS swapping only
+ * (for now), and we currently do this synchronously only.
+ */
+static int
+smb_writepage(struct inode *inode, struct page *page)
+{
+	return smb_writepage_sync(inode, page, 0, PAGE_SIZE);
+}
 
-		if (result < to_read)
-		{
-			break;
-		}
-	}
+static int
+smb_updatepage(struct inode *inode, struct page *page, const char *buffer,
+	       unsigned long offset, unsigned int count, int sync)
+{
+	u8		*page_addr;
 
-	file->f_pos = pos;
+	pr_debug("SMB:      smb_updatepage(%x/%ld %d@%ld, sync=%d)\n",
+		 inode->i_dev, inode->i_ino,
+		 count, page->offset+offset, sync);
 
-	if (!IS_RDONLY(inode))
-		inode->i_atime = CURRENT_TIME;
-	mark_inode_dirty(inode);
-	
-	DPRINTK("smb_file_read: exit %s\n", SMB_FINFO(inode)->name);
+	page_addr = (u8 *) page_address(page);
 
-	return already_read;
+	copy_from_user(page_addr + offset, buffer, count);
+	return smb_writepage_sync(inode, page, offset, count);
 }
 
 static long
-smb_file_write(struct inode *inode, struct file *file, const char *buf,
-	       unsigned long count)
+smb_file_read(struct inode * inode, struct file * file,
+	      char * buf, unsigned long count)
 {
-	int result, bufsize, to_write, already_written;
-	off_t pos;
-	int errno;
-
-	if (!inode)
-	{
-		DPRINTK("smb_file_write: inode = NULL\n");
-		return -EINVAL;
-	}
-	if (!S_ISREG(inode->i_mode))
-	{
-		DPRINTK("smb_file_write: write to non-file, mode %07o\n",
-			inode->i_mode);
-		return -EINVAL;
-	}
-	DPRINTK("smb_file_write: enter %s\n", SMB_FINFO(inode)->name);
+	int	status;
 
-	if (count <= 0)
-	{
-		return 0;
-	}
-	if ((errno = smb_make_open(inode, O_RDWR)) != 0)
-	{
-		return errno;
-	}
-	pos = file->f_pos;
+	pr_debug("SMB: read(%x/%ld (%d), %lu@%lu)\n",
+		 inode->i_dev, inode->i_ino, inode->i_count,
+		 count, (unsigned long) file->f_pos);
+
+	status = smb_revalidate_inode(inode);
+	if (status < 0)
+		return status;
 
-	if (file->f_flags & O_APPEND)
-		pos = inode->i_size;
+	return generic_file_read(inode, file, buf, count);
+}
 
-	bufsize = SMB_SERVER(inode)->max_xmit - SMB_HEADER_LEN - 5 * 2 - 5;
+static int
+smb_file_mmap(struct inode * inode, struct file * file,
+				struct vm_area_struct * vma)
+{
+	int	status;
 
-	already_written = 0;
+	status = smb_revalidate_inode(inode);
+	if (status < 0)
+		return status;
 
-	DPRINTK("smb_write_file: blkmode = %d, blkmode & 2 = %d\n",
-		SMB_SERVER(inode)->blkmode,
-		SMB_SERVER(inode)->blkmode & 2);
+	return generic_file_mmap(inode, file, vma);
+}
 
-	while (already_written < count)
-	{
-		to_write = min(bufsize, count - already_written);
-		result = smb_proc_write(SMB_SERVER(inode), SMB_FINFO(inode),
-					pos, to_write, buf);
+/* 
+ * Write to a file (through the page cache).
+ */
+static long
+smb_file_write(struct inode *inode, struct file *file,
+	       const char *buf, unsigned long count)
+{
+	int	result;
 
-		if (result < 0)
-		{
-			return result;
-		}
-		pos += result;
-		buf += result;
-		already_written += result;
+	pr_debug("SMB: write(%x/%ld (%d), %lu@%lu)\n",
+		 inode->i_dev, inode->i_ino, inode->i_count,
+		 count, (unsigned long) file->f_pos);
 
-		if (result < to_write)
-		{
-			break;
-		}
+	if (!inode) {
+		printk("smb_file_write: inode = NULL\n");
+		return -EINVAL;
 	}
 
-	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	mark_inode_dirty(inode);
-	
-	file->f_pos = pos;
-
-	if (pos > inode->i_size)
-	{
-		inode->i_size = pos;
+	result = smb_revalidate_inode(inode);
+	if (result < 0)
+		return result;
+
+	result = smb_open(inode, O_WRONLY);
+	if (result < 0)
+		return result;
+
+	if (!S_ISREG(inode->i_mode)) {
+		printk("smb_file_write: write to non-file, mode %07o\n",
+			inode->i_mode);
+		return -EINVAL;
 	}
-	DPRINTK("smb_file_write: exit %s\n", SMB_FINFO(inode)->name);
+	if (count <= 0)
+		return 0;
 
-	return already_written;
+	return generic_file_write(inode, file, buf, count);
 }
 
 static struct file_operations smb_file_operations =
@@ -217,7 +239,7 @@
 	NULL,			/* readdir - bad */
 	NULL,			/* poll - default */
 	smb_ioctl,		/* ioctl */
-	smb_mmap,		/* mmap */
+	smb_file_mmap,		/* mmap */
 	NULL,			/* open */
 	NULL,			/* release */
 	smb_fsync,		/* fsync */
@@ -236,8 +258,13 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* readpage */
-	NULL,			/* writepage */
+	NULL,			/* follow_link */
+	smb_readpage,		/* readpage */
+	smb_writepage,		/* writepage */
 	NULL,			/* bmap */
-	NULL			/* truncate */
+	NULL,			/* truncate */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	smb_updatepage,		/* updatepage */
+	smb_revalidate_inode,	/* revalidate */
 };
diff -u --recursive --new-file v2.1.51/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- v2.1.51/linux/fs/smbfs/inode.c	Mon Aug 18 18:19:46 1997
+++ linux/fs/smbfs/inode.c	Fri Aug 22 10:04:33 1997
@@ -2,6 +2,7 @@
  *  inode.c
  *
  *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1997 by Volker Lendecke
  *
  */
 
@@ -28,329 +29,237 @@
 extern int close_fp(struct file *filp);
 
 static void smb_put_inode(struct inode *);
+static void smb_delete_inode(struct inode *);
 static void smb_read_inode(struct inode *);
 static void smb_put_super(struct super_block *);
-static void smb_statfs(struct super_block *, struct statfs *, int bufsiz);
+static int smb_statfs(struct super_block *, struct statfs *, int);
 
 static struct super_operations smb_sops =
 {
 	smb_read_inode,		/* read inode */
-	smb_notify_change,	/* notify change */
 	NULL,			/* write inode */
 	smb_put_inode,		/* put inode */
+	smb_delete_inode,	/* delete inode */
+	smb_notify_change,	/* notify change */
 	smb_put_super,		/* put superblock */
 	NULL,			/* write superblock */
 	smb_statfs,		/* stat filesystem */
-	NULL
+	NULL			/* remount filesystem */
 };
 
-/* smb_read_inode: Called from iget, it only traverses the allocated
-   smb_inode_info's and initializes the inode from the data found
-   there.  It does not allocate or deallocate anything. */
+/* FIXME: Look at all inodes whether so that we do not get duplicate
+ * inode numbers. */
+
+unsigned long
+smb_invent_inos(unsigned long n)
+{
+	static unsigned long ino = 1;
+
+	if (ino + 2*n < ino)
+	{
+		/* wrap around */
+		ino += n;
+	}
+	ino += n;
+	return ino;
+}
+
+static struct smb_fattr *read_fattr;
+static struct semaphore read_semaphore = MUTEX;
+
+struct inode *
+smb_iget(struct super_block *sb, struct smb_fattr *fattr)
+{
+	struct inode *result;
+
+	pr_debug("smb_iget: %p\n", fattr);
+
+	down(&read_semaphore);
+	read_fattr = fattr;
+	result = iget(sb, fattr->f_ino);
+	up(&read_semaphore);
+	return result;
+}
 
 static void
 smb_read_inode(struct inode *inode)
 {
-	/* Our task should be extremely simple here. We only have to
-	   look up the information somebody else (smb_iget) put into
-	   the inode tree. */
-	struct smb_server *server = SMB_SERVER(inode);
-	struct smb_inode_info *inode_info
-	= smb_find_inode(server, inode->i_ino);
+	pr_debug("smb_iget: %p\n", read_fattr);
 
-	if (inode_info == NULL)
+	if ((atomic_read(&read_semaphore.count) == 1) ||
+	    (inode->i_ino != read_fattr->f_ino))
 	{
-		/* Ok, now we're in trouble. The inode info is not
-		   there. What should we do now??? */
-		printk("smb_read_inode: inode info not found\n");
+		printk("smb_read_inode called from invalid point\n");
 		return;
 	}
-	inode_info->state = SMB_INODE_VALID;
+	inode->i_mode = read_fattr->f_mode;
+	inode->i_nlink = read_fattr->f_nlink;
+	inode->i_uid = read_fattr->f_uid;
+	inode->i_gid = read_fattr->f_gid;
+	inode->i_rdev = read_fattr->f_rdev;
+	inode->i_size = read_fattr->f_size;
+	inode->i_mtime = read_fattr->f_mtime;
+	inode->i_ctime = read_fattr->f_ctime;
+	inode->i_atime = read_fattr->f_atime;
+	inode->i_blksize = read_fattr->f_blksize;
+	inode->i_blocks = read_fattr->f_blocks;
 
-	SMB_INOP(inode) = inode_info;
-	inode->i_mode = inode_info->finfo.f_mode;
-	inode->i_nlink = inode_info->finfo.f_nlink;
-	inode->i_uid = inode_info->finfo.f_uid;
-	inode->i_gid = inode_info->finfo.f_gid;
-	inode->i_rdev = inode_info->finfo.f_rdev;
-	inode->i_size = inode_info->finfo.f_size;
-	inode->i_mtime = inode_info->finfo.f_mtime;
-	inode->i_ctime = inode_info->finfo.f_ctime;
-	inode->i_atime = inode_info->finfo.f_atime;
-	inode->i_blksize = inode_info->finfo.f_blksize;
-	inode->i_blocks = inode_info->finfo.f_blocks;
+	memset(&(inode->u.smbfs_i), 0, sizeof(inode->u.smbfs_i));
 
 	if (S_ISREG(inode->i_mode))
-	{
 		inode->i_op = &smb_file_inode_operations;
-	} else if (S_ISDIR(inode->i_mode))
-	{
+	else if (S_ISDIR(inode->i_mode))
 		inode->i_op = &smb_dir_inode_operations;
-	} else
-	{
+	else
 		inode->i_op = NULL;
-	}
+}
+
+void
+smb_invalidate_inodes(struct smb_sb_info *server)
+{
+	printk("smb_invalidate_inodes\n");
+}
+
+int
+smb_revalidate_inode(struct inode *i)
+{
+	pr_debug("smb_revalidate_inode\n");
+	return 0;
+}
+
+int
+smb_refresh_inode(struct inode *i)
+{
+	pr_debug("smb_refresh_inode\n");
+	return 0;
 }
 
 static void
-smb_put_inode(struct inode *inode)
+smb_put_inode(struct inode *ino)
 {
-	struct smb_dirent *finfo = SMB_FINFO(inode);
-	struct smb_server *server = SMB_SERVER(inode);
-	struct smb_inode_info *info = SMB_INOP(inode);
+	pr_debug("smb_put_inode: count = %d\n", ino->i_count);
 
-	if (S_ISDIR(inode->i_mode))
-	{
-		smb_invalid_dir_cache(inode->i_ino);
-	}
-	if (finfo->opened != 0)
-	{
-		if (smb_proc_close(server, finfo->fileid, inode->i_mtime))
-		{
-			/* We can't do anything but complain. */
-			DPRINTK("smb_put_inode: could not close\n");
-		}
-	}
-	smb_free_inode_info(info);
-	clear_inode(inode);
+	if (smb_close(ino))
+		printk("smbfs: could not close inode\n");
 }
 
 static void
-smb_put_super(struct super_block *sb)
+smb_delete_inode(struct inode *i)
 {
-	struct smb_server *server = &(SMB_SBP(sb)->s_server);
+	pr_debug("smb_delete_inode\n");
+}
 
-	smb_proc_disconnect(server);
-	smb_dont_catch_keepalive(server);
-	close_fp(server->sock_file);
+static void
+smb_put_super(struct super_block *sb)
+{
+	struct smb_sb_info *server = &(sb->u.smbfs_sb);
 
 	lock_super(sb);
 
-	smb_free_all_inodes(server);
+	if (server->sock_file) {
+		smb_proc_disconnect(server);
+		smb_dont_catch_keepalive(server);
+		close_fp(server->sock_file);
+	}
 
-	smb_vfree(server->packet);
-	server->packet = NULL;
+	if (server->conn_pid)
+	       kill_proc(server->conn_pid, SIGTERM, 0);
 
+	if (server->packet)
+		smb_vfree(server->packet);
 	sb->s_dev = 0;
-	smb_kfree_s(SMB_SBP(sb), sizeof(struct smb_sb_info));
 
 	unlock_super(sb);
 
 	MOD_DEC_USE_COUNT;
 }
 
-struct smb_mount_data_v4
-{
-	int version;
-	unsigned int fd;
-	uid_t mounted_uid;
-	struct sockaddr_in addr;
-
-	char server_name[17];
-	char client_name[17];
-	char service[64];
-	char root_path[64];
-
-	char username[64];
-	char password[64];
-
-	unsigned short max_xmit;
-
-	uid_t uid;
-	gid_t gid;
-	mode_t file_mode;
-	mode_t dir_mode;
-};
-
-static int
-smb_get_mount_data(struct smb_mount_data *target, void *source)
-{
-	struct smb_mount_data_v4 *v4 = (struct smb_mount_data_v4 *) source;
-	struct smb_mount_data *cur = (struct smb_mount_data *) source;
-
-	if (source == NULL)
-	{
-		return 1;
-	}
-	if (cur->version == SMB_MOUNT_VERSION)
-	{
-		memcpy(target, cur, sizeof(struct smb_mount_data));
-		return 0;
-	}
-	if (v4->version == 4)
-	{
-		target->version = 5;
-		target->fd = v4->fd;
-		target->mounted_uid = v4->mounted_uid;
-		target->addr = v4->addr;
-
-		memcpy(target->server_name, v4->server_name, 17);
-		memcpy(target->client_name, v4->client_name, 17);
-		memcpy(target->service, v4->service, 64);
-		memcpy(target->root_path, v4->root_path, 64);
-		memcpy(target->username, v4->username, 64);
-		memcpy(target->password, v4->password, 64);
-
-		target->max_xmit = v4->max_xmit;
-		target->uid = v4->uid;
-		target->gid = v4->gid;
-		target->file_mode = v4->file_mode;
-		target->dir_mode = v4->dir_mode;
-
-		memset(target->domain, 0, 64);
-		strcpy(target->domain, "?");
-		return 0;
-	}
-	return 1;
-}
-
 struct super_block *
 smb_read_super(struct super_block *sb, void *raw_data, int silent)
 {
-	struct smb_mount_data data;
-	struct smb_server *server;
-	struct smb_sb_info *smb_sb;
-	unsigned int fd;
-	struct file *filp;
+	struct smb_mount_data *data = (struct smb_mount_data *)raw_data;
+	struct smb_fattr root;
 	kdev_t dev = sb->s_dev;
-	int error;
+	unsigned char *packet;
 
-	if (smb_get_mount_data(&data, raw_data) != 0)
-	{
-		printk("smb_read_super: wrong data argument\n");
-		sb->s_dev = 0;
-		return NULL;
-	}
-	fd = data.fd;
-	if (fd >= NR_OPEN || !(filp = current->files->fd[fd]))
-	{
-		printk("smb_read_super: invalid file descriptor\n");
+	MOD_INC_USE_COUNT;
+
+	if (!data) {
+		printk("smb_read_super: missing data argument\n");
 		sb->s_dev = 0;
+		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
-	if (!S_ISSOCK(filp->f_dentry->d_inode->i_mode))
+		
+	if (data->version != SMB_MOUNT_VERSION)
 	{
-		printk("smb_read_super: not a socket!\n");
+		printk(KERN_ERR "smb_read_super: wrong data argument."
+		       " Recompile smbmount.\n");
 		sb->s_dev = 0;
+		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
-	/* We must malloc our own super-block info */
-	smb_sb = (struct smb_sb_info *) smb_kmalloc(sizeof(struct smb_sb_info),
-						    GFP_KERNEL);
 
-	if (smb_sb == NULL)
+	packet = smb_vmalloc(SMB_INITIAL_PACKET_SIZE);	
+	if (!packet)
 	{
-		printk("smb_read_super: could not alloc smb_sb_info\n");
-		return NULL;
-	}
-	filp->f_count++;
+		pr_debug("smb_read_super: could not alloc packet\n");
+		sb->s_dev = 0;
+		MOD_DEC_USE_COUNT;
+  		return NULL;
+  	}
 
 	lock_super(sb);
 
-	SMB_SBP(sb) = smb_sb;
-
 	sb->s_blocksize = 1024;	/* Eh...  Is this correct? */
 	sb->s_blocksize_bits = 10;
 	sb->s_magic = SMB_SUPER_MAGIC;
 	sb->s_dev = dev;
 	sb->s_op = &smb_sops;
 
-	server = &(SMB_SBP(sb)->s_server);
-	server->sock_file = filp;
-	server->lock = 0;
-	server->wait = NULL;
-	server->packet = NULL;
-	server->max_xmit = data.max_xmit;
-	if (server->max_xmit <= 0)
-	{
-		server->max_xmit = SMB_DEF_MAX_XMIT;
-	}
-	server->tid = 0;
-	server->pid = current->pid;
-	server->mid = current->pid + 20;
-
-	server->m = data;
-	server->m.file_mode = (server->m.file_mode &
-			       (S_IRWXU | S_IRWXG | S_IRWXO)) | S_IFREG;
-	server->m.dir_mode = (server->m.dir_mode &
-			      (S_IRWXU | S_IRWXG | S_IRWXO)) | S_IFDIR;
-
-	smb_init_root(server);
+	sb->u.smbfs_sb.sock_file = NULL;
+	sb->u.smbfs_sb.sem = MUTEX;
+	sb->u.smbfs_sb.conn_pid = 0;
+	sb->u.smbfs_sb.packet = packet;
+	sb->u.smbfs_sb.packet_size = SMB_INITIAL_PACKET_SIZE;
+	sb->u.smbfs_sb.generation = 1;
+
+	sb->u.smbfs_sb.m = *data;
+	sb->u.smbfs_sb.m.file_mode = (sb->u.smbfs_sb.m.file_mode &
+				      (S_IRWXU | S_IRWXG | S_IRWXO)) | S_IFREG;
+	sb->u.smbfs_sb.m.dir_mode = (sb->u.smbfs_sb.m.dir_mode &
+				     (S_IRWXU | S_IRWXG | S_IRWXO)) | S_IFDIR;
 
-	error = smb_proc_connect(server);
+	smb_init_root_dirent(&(sb->u.smbfs_sb), &root);
 
 	unlock_super(sb);
 
-	if (error < 0)
-	{
-		sb->s_dev = 0;
-		DPRINTK("smb_read_super: Failed connection, bailing out "
-			"(error = %d).\n", -error);
-		goto fail;
-	}
-	if (server->protocol >= PROTOCOL_LANMAN2)
-	{
-		server->case_handling = CASE_DEFAULT;
-	} else
-	{
-		server->case_handling = CASE_LOWER;
-	}
-
-	if ((error = smb_proc_dskattr(sb, &(SMB_SBP(sb)->s_attr))) < 0)
+	sb->s_root = d_alloc_root(smb_iget(sb, &root), NULL);
+	if (!sb->s_root)
 	{
 		sb->s_dev = 0;
-		printk("smb_read_super: could not get super block "
-		       "attributes\n");
-		goto fail;
-	}
-	smb_init_root_dirent(server, &(server->root.finfo));
-
-	if (!(sb->s_root = d_alloc_root(iget(sb, 
-	                                smb_info_ino(&(server->root))),NULL)))
-	{
-		sb->s_dev = 0;
-		printk("smb_read_super: get root inode failed\n");
-		goto fail;
+		printk(KERN_ERR "smb_read_super: get root inode failed\n");
+		smb_vfree(sb->u.smbfs_sb.packet);
+		MOD_DEC_USE_COUNT;
+		return NULL;
 	}
-	MOD_INC_USE_COUNT;
 	return sb;
-
-      fail:
-	if (server->packet != NULL)
-	{
-		smb_vfree(server->packet);
-		server->packet = NULL;
-	}
-	put_filp(filp);
-	smb_dont_catch_keepalive(server);
-	smb_kfree_s(SMB_SBP(sb), sizeof(struct smb_sb_info));
-	return NULL;
 }
 
-static void
+static int
 smb_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
 {
-	int error;
-	struct smb_dskattr attr;
-	struct statfs tmp;
+	struct statfs attr;
 
-	error = smb_proc_dskattr(sb, &attr);
+	memset(&attr, 0, sizeof(attr));
 
-	if (error)
-	{
-		printk("smb_statfs: dskattr error = %d\n", -error);
-		attr.total = attr.allocblocks = attr.blocksize =
-		    attr.free = 0;
-	}
-	tmp.f_type = SMB_SUPER_MAGIC;
-	tmp.f_bsize = attr.blocksize * attr.allocblocks;
-	tmp.f_blocks = attr.total;
-	tmp.f_bfree = attr.free;
-	tmp.f_bavail = attr.free;
-	tmp.f_files = -1;
-	tmp.f_ffree = -1;
-	tmp.f_namelen = SMB_MAXPATHLEN;
-	copy_to_user(buf, &tmp, bufsiz);
+	smb_proc_dskattr(sb, &attr);
+
+	attr.f_type = SMB_SUPER_MAGIC;
+	attr.f_files = -1;
+	attr.f_ffree = -1;
+	attr.f_namelen = SMB_MAXPATHLEN;
+	return copy_to_user(buf, &attr, bufsiz) ? -EFAULT : 0;
 }
 
 int
@@ -375,50 +284,48 @@
 
 	if ((attr->ia_valid & ATTR_SIZE) != 0)
 	{
-
-		if ((error = smb_make_open(inode, O_WRONLY)) < 0)
+		if ((error = smb_open(inode, O_WRONLY)) < 0)
 			goto fail;
 
 		if ((error = smb_proc_trunc(SMB_SERVER(inode),
-					    SMB_FINFO(inode)->fileid,
+					    inode->u.smbfs_i.fileid,
 					    attr->ia_size)) < 0)
 			goto fail;
-
 	}
 	if ((attr->ia_valid & (ATTR_CTIME | ATTR_MTIME | ATTR_ATIME)) != 0)
 	{
 
-		struct smb_dirent finfo;
+		struct smb_fattr fattr;
 
-		finfo.attr = 0;
-		finfo.f_size = inode->i_size;
-		finfo.f_blksize = inode->i_blksize;
+		fattr.attr = 0;
+		fattr.f_size = inode->i_size;
+		fattr.f_blksize = inode->i_blksize;
 
 		if ((attr->ia_valid & ATTR_CTIME) != 0)
-			finfo.f_ctime = attr->ia_ctime;
+			fattr.f_ctime = attr->ia_ctime;
 		else
-			finfo.f_ctime = inode->i_ctime;
+			fattr.f_ctime = inode->i_ctime;
 
 		if ((attr->ia_valid & ATTR_MTIME) != 0)
-			finfo.f_mtime = attr->ia_mtime;
+			fattr.f_mtime = attr->ia_mtime;
 		else
-			finfo.f_mtime = inode->i_mtime;
+			fattr.f_mtime = inode->i_mtime;
 
 		if ((attr->ia_valid & ATTR_ATIME) != 0)
-			finfo.f_atime = attr->ia_atime;
+			fattr.f_atime = attr->ia_atime;
 		else
-			finfo.f_atime = inode->i_atime;
+			fattr.f_atime = inode->i_atime;
 
 		if ((error = smb_proc_setattr(SMB_SERVER(inode),
-					      inode, &finfo)) >= 0)
+					      inode, &fattr)) >= 0)
 		{
-			inode->i_ctime = finfo.f_ctime;
-			inode->i_mtime = finfo.f_mtime;
-			inode->i_atime = finfo.f_atime;
+			inode->i_ctime = fattr.f_ctime;
+			inode->i_mtime = fattr.f_mtime;
+			inode->i_atime = fattr.f_atime;
 		}
 	}
       fail:
-	smb_invalid_dir_cache(smb_info_ino(SMB_INOP(inode)->dir));
+/*	smb_invalid_dir_cache(smb_info_ino(SMB_INOP(inode)->dir));*/
 
 	return error;
 }
@@ -448,7 +355,7 @@
 int
 init_module(void)
 {
-	DPRINTK("smbfs: init_module called\n");
+	pr_debug("smbfs: init_module called\n");
 
 #ifdef DEBUG_SMB_MALLOC
 	smb_malloced = 0;
@@ -457,6 +364,7 @@
 #endif
 
 	smb_init_dir_cache();
+	read_semaphore = MUTEX;
 
 	return init_smb_fs();
 }
@@ -464,13 +372,13 @@
 void
 cleanup_module(void)
 {
-	DPRINTK("smbfs: cleanup_module called\n");
+	pr_debug("smbfs: cleanup_module called\n");
 	smb_free_dir_cache();
 	unregister_filesystem(&smb_fs_type);
 #ifdef DEBUG_SMB_MALLOC
-	printk("smb_malloced: %d\n", smb_malloced);
-	printk("smb_current_kmalloced: %d\n", smb_current_kmalloced);
-	printk("smb_current_vmalloced: %d\n", smb_current_vmalloced);
+	printk(KERN_DEBUG "smb_malloced: %d\n", smb_malloced);
+	printk(KERN_DEBUG "smb_current_kmalloced: %d\n",smb_current_kmalloced);
+	printk(KERN_DEBUG "smb_current_vmalloced: %d\n",smb_current_vmalloced);
 #endif
 }
 
diff -u --recursive --new-file v2.1.51/linux/fs/smbfs/ioctl.c linux/fs/smbfs/ioctl.c
--- v2.1.51/linux/fs/smbfs/ioctl.c	Sun Dec  1 09:02:04 1996
+++ linux/fs/smbfs/ioctl.c	Fri Aug 22 10:04:33 1997
@@ -2,6 +2,7 @@
  *  ioctl.c
  *
  *  Copyright (C) 1995, 1996 by Volker Lendecke
+ *  Copyright (C) 1997 by Volker Lendecke
  *
  */
 
@@ -21,8 +22,29 @@
 	switch (cmd)
 	{
 	case SMB_IOC_GETMOUNTUID:
-		return put_user(SMB_SERVER(inode)->m.mounted_uid, (uid_t *) arg);
+		return put_user(SMB_SERVER(inode)->m.mounted_uid,
+				(uid_t *) arg);
 
+	case SMB_IOC_NEWCONN:
+	{
+		struct smb_conn_opt opt;
+		int result;
+
+		if (arg == 0)
+		{
+			/* The process offers a new connection upon SIGUSR1 */
+			return smb_offerconn(SMB_SERVER(inode));
+		}
+
+		if ((result = verify_area(VERIFY_READ, (uid_t *) arg,
+					  sizeof(opt))) != 0)
+		{
+			return result;
+		}
+		copy_from_user(&opt, (void *)arg, sizeof(opt));
+
+		return smb_newconn(SMB_SERVER(inode), &opt);
+	}
 	default:
 		return -EINVAL;
 	}
diff -u --recursive --new-file v2.1.51/linux/fs/smbfs/mmap.c linux/fs/smbfs/mmap.c
--- v2.1.51/linux/fs/smbfs/mmap.c	Mon Aug 18 18:19:46 1997
+++ linux/fs/smbfs/mmap.c	Wed Dec 31 16:00:00 1969
@@ -1,126 +0,0 @@
-/*
- *  mmap.c
- *
- *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
- *
- */
-
-#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/smb_fs.h>
-#include <linux/fcntl.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-/*
- * Fill in the supplied page for mmap
- */
-static unsigned long
-smb_file_mmap_nopage(struct vm_area_struct *area,
-		     unsigned long address, int no_share)
-{
-	struct inode *inode = area->vm_dentry->d_inode;
-	unsigned long page;
-	unsigned int clear;
-	unsigned long tmp;
-	int n;
-	int i;
-	int pos;
-
-	page = __get_free_page(GFP_KERNEL);
-	if (!page)
-		return 0;
-	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;
-	}
-	/* what we can read in one go */
-	n = SMB_SERVER(inode)->max_xmit - SMB_HEADER_LEN - 5 * 2 - 3 - 10;
-
-	if (smb_make_open(inode, O_RDONLY) < 0)
-	{
-		clear = PAGE_SIZE;
-	} else
-	{
-
-		for (i = 0; i < (PAGE_SIZE - clear); i += n)
-		{
-			int hunk, result;
-
-			hunk = PAGE_SIZE - i;
-			if (hunk > n)
-				hunk = n;
-
-			DDPRINTK("smb_file_mmap_nopage: reading\n");
-			DDPRINTK("smb_file_mmap_nopage: pos = %d\n", pos);
-			result = smb_proc_read(SMB_SERVER(inode),
-					       SMB_FINFO(inode), pos, hunk,
-					       (char *) (page + i), 0);
-			DDPRINTK("smb_file_mmap_nopage: result= %d\n", result);
-			if (result < 0)
-				break;
-			pos += result;
-			if (result < n)
-			{
-				i += result;
-				break;
-			}
-		}
-	}
-
-	tmp = page + PAGE_SIZE;
-	while (clear--)
-	{
-		*(char *) --tmp = 0;
-	}
-	return page;
-}
-
-struct vm_operations_struct smb_file_mmap =
-{
-	NULL,			/* open */
-	NULL,			/* close */
-	NULL,			/* unmap */
-	NULL,			/* protect */
-	NULL,			/* sync */
-	NULL,			/* advise */
-	smb_file_mmap_nopage,	/* nopage */
-	NULL,			/* wppage */
-	NULL,			/* swapout */
-	NULL,			/* swapin */
-};
-
-
-/* This is used for a general mmap of a smb file */
-int
-smb_mmap(struct inode *inode, struct file *file, struct vm_area_struct *vma)
-{
-	DPRINTK("smb_mmap: called\n");
-
-	/* only PAGE_COW or read-only supported now */
-	if (vma->vm_flags & VM_SHARED)
-		return -EINVAL;
-	if (!inode->i_sb || !S_ISREG(inode->i_mode))
-		return -EACCES;
-	if (!IS_RDONLY(inode))
-	{
-		inode->i_atime = CURRENT_TIME;
-		mark_inode_dirty(inode);
-	}
-
-	vma->vm_dentry = dget(file->f_dentry);
-	vma->vm_ops = &smb_file_mmap;
-	return 0;
-}
diff -u --recursive --new-file v2.1.51/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c
--- v2.1.51/linux/fs/smbfs/proc.c	Mon Dec 30 01:54:12 1996
+++ linux/fs/smbfs/proc.c	Fri Aug 22 10:04:33 1997
@@ -2,6 +2,7 @@
  *  proc.c
  *
  *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1997 by Volker Lendecke
  *
  *  28/06/96 - Fixed long file name support (smb_proc_readdir_long) by Yuri Per
  */
@@ -20,15 +21,15 @@
 #include <asm/string.h>
 
 #define SMB_VWV(packet)  ((packet) + SMB_HEADER_LEN)
-#define SMB_CMD(packet)  (BVAL(packet,8))
-#define SMB_WCT(packet)  (BVAL(packet, SMB_HEADER_LEN - 1))
+#define SMB_CMD(packet)  (*(packet+8))
+#define SMB_WCT(packet)  (*(packet+SMB_HEADER_LEN - 1))
 #define SMB_BCC(packet)  smb_bcc(packet)
 #define SMB_BUF(packet)  ((packet) + SMB_HEADER_LEN + SMB_WCT(packet) * 2 + 2)
 
 #define SMB_DIRINFO_SIZE 43
 #define SMB_STATUS_SIZE  21
 
-static int smb_request_ok(struct smb_server *s, int command, int wct, int bcc);
+static int smb_request_ok(struct smb_sb_info *s, int command, int wct, int bcc);
 
 static inline int
 min(int a, int b)
@@ -64,132 +65,57 @@
 /*                                                                           */
 /*****************************************************************************/
 
-static inline byte *
-smb_decode_word(byte * p, word * data)
-{
-	*data = WVAL(p, 0);
-	return p + 2;
-}
-
-byte *
-smb_encode_smb_length(byte * p, dword len)
+__u8 *
+smb_encode_smb_length(__u8 * p, __u32 len)
 {
-	BSET(p, 0, 0);
-	BSET(p, 1, 0);
-	BSET(p, 2, (len & 0xFF00) >> 8);
-	BSET(p, 3, (len & 0xFF));
+	*p = 0;
+	*(p+1) = 0;
+	*(p+2) = (len & 0xFF00) >> 8;
+	*(p+3) = (len & 0xFF);
 	if (len > 0xFFFF)
 	{
-		BSET(p, 1, 1);
+		*(p+1) = 1;
 	}
 	return p + 4;
 }
 
-static byte *
-smb_encode_ascii(byte * p, const byte * name, int len)
+static int smb_d_path(struct dentry * entry, char * buf)
 {
-	*p++ = 4;
-	strcpy(p, name);
-	return p + len + 1;
-}
-
-static byte *
-smb_encode_this_name(byte * p, const char *name, const int len)
-{
-	*p++ = '\\';
-	strncpy(p, name, len);
-	return p + len;
-}
+	if (IS_ROOT(entry)) {
+		*buf = '\\';
+		return 1;
+	} else {
+		int len = smb_d_path(entry->d_parent, buf);
 
-/* I put smb_encode_parents into a separate function so that the
-   recursion only takes 16 bytes on the stack per path component on a
-   386. */
-
-static byte *
-smb_encode_parents(byte * p, struct smb_inode_info *ino)
-{
-	byte *q;
-
-	if (ino->dir == NULL)
-	{
-		return p;
-	}
-	q = smb_encode_parents(p, ino->dir);
-	if (q - p + 1 + ino->finfo.len > SMB_MAXPATHLEN)
-	{
-		return p;
+		buf += len;
+		if (len > 1) {
+			*buf++ = '\\';
+			len++;
+		}
+		memcpy(buf, entry->d_name.name, entry->d_name.len);
+		return len + entry->d_name.len;
 	}
-	return smb_encode_this_name(q, ino->finfo.name, ino->finfo.len);
 }
 
-static byte *
-smb_encode_path(struct smb_server *server,
-		byte * p, struct smb_inode_info *dir,
-		const char *name, const int len)
+static char *smb_encode_path(struct smb_sb_info *server, char *buf,
+			     struct inode *dir, struct qstr *name)
 {
-	byte *start = p;
-	if (dir != NULL)
-	{
-		p = smb_encode_parents(p, dir);
-	}
-	p = smb_encode_this_name(p, name, len);
-	*p++ = 0;
-	if (server->protocol <= PROTOCOL_COREPLUS)
-	{
-		str_upper(start);
-	}
-	return p;
-}
+	char *start = buf;
 
-static byte *
-smb_decode_data(byte * p, byte * data, word * data_len, int fs)
-{
-	word len;
+	if (dir != NULL)
+		buf += smb_d_path(i_dentry(dir), buf);
 
-	if (!(*p == 1 || *p == 5))
-	{
-		printk("smb_decode_data: Warning! Data block not starting "
-		       "with 1 or 5\n");
+	if (name != NULL) {
+		*buf++ = '\\';
+		memcpy(buf, name->name, name->len);
+		buf += name->len;
+		*buf++ = 0;
 	}
-	len = WVAL(p, 1);
-	p += 3;
-
-	if (fs)
-		copy_to_user(data, p, len);
-	else
-		memcpy(data, p, len);
-
-	*data_len = len;
-
-	return p + len;
-}
-
-static byte *
-smb_name_mangle(byte * p, const byte * name)
-{
-	int len, pad = 0;
-
-	len = strlen(name);
-
-	if (len < 16)
-		pad = 16 - len;
 
-	*p++ = 2 * (len + pad);
-
-	while (*name)
-	{
-		*p++ = (*name >> 4) + 'A';
-		*p++ = (*name & 0x0F) + 'A';
-		name++;
-	}
-	while (pad--)
-	{
-		*p++ = 'C';
-		*p++ = 'A';
-	}
-	*p++ = '\0';
+	if (server->opt.protocol <= SMB_PROTOCOL_COREPLUS)
+		str_upper(start);
 
-	return p;
+	return buf;
 }
 
 /* The following are taken directly from msdos-fs */
@@ -235,7 +161,7 @@
 /* Convert linear UNIX date to a MS-DOS time/date pair. */
 
 static void
-date_unix2dos(int unix_date, byte * date, byte * time)
+date_unix2dos(int unix_date, __u8 * date, __u8 * time)
 {
 	int day, year, nl_day, month;
 
@@ -271,16 +197,16 @@
 /*                                                                           */
 /*****************************************************************************/
 
-dword
-smb_len(byte * p)
+__u32
+smb_len(__u8 * p)
 {
-	return ((BVAL(p, 1) & 0x1) << 16L) | (BVAL(p, 2) << 8L) | (BVAL(p, 3));
+	return ((*(p+1) & 0x1) << 16L) | (*(p+2) << 8L) | *(p+3);
 }
 
-static word
-smb_bcc(byte * packet)
+static __u16
+smb_bcc(__u8 * packet)
 {
-	int pos = SMB_HEADER_LEN + SMB_WCT(packet) * sizeof(word);
+	int pos = SMB_HEADER_LEN + SMB_WCT(packet) * sizeof(__u16);
 	return WVAL(packet, pos);
 }
 
@@ -288,10 +214,8 @@
    requirements of a smb packet */
 
 static int
-smb_valid_packet(byte * packet)
+smb_valid_packet(__u8 * packet)
 {
-	DDPRINTK("len: %d, wct: %d, bcc: %d\n",
-		 smb_len(packet), SMB_WCT(packet), SMB_BCC(packet));
 	return (packet[4] == 0xff
 		&& packet[5] == 'S'
 		&& packet[6] == 'M'
@@ -304,7 +228,7 @@
    got enough data. If bcc == -1, we don't care. */
 
 static int
-smb_verify(byte * packet, int command, int wct, int bcc)
+smb_verify(__u8 * packet, int command, int wct, int bcc)
 {
 	return (SMB_CMD(packet) == command &&
 		SMB_WCT(packet) >= wct &&
@@ -404,23 +328,16 @@
 	return 0;
 }
 
-static void
-smb_lock_server(struct smb_server *server)
+static inline void
+smb_lock_server(struct smb_sb_info *server)
 {
-	while (server->lock)
-		sleep_on(&server->wait);
-	server->lock = 1;
+	down(&(server->sem));
 }
 
-static void
-smb_unlock_server(struct smb_server *server)
+static inline void
+smb_unlock_server(struct smb_sb_info *server)
 {
-	if (server->lock != 1)
-	{
-		printk("smb_unlock_server: was not locked!\n");
-	}
-	server->lock = 0;
-	wake_up(&server->wait);
+	up(&(server->sem));
 }
 
 /* smb_request_ok: We expect the server to be locked. Then we do the
@@ -429,7 +346,7 @@
    the answer is <=0, the returned number is a valid unix errno. */
 
 static int
-smb_request_ok(struct smb_server *s, int command, int wct, int bcc)
+smb_request_ok(struct smb_sb_info *s, int command, int wct, int bcc)
 {
 	int result = 0;
 	s->rcls = 0;
@@ -437,18 +354,18 @@
 
 	if (smb_request(s) < 0)
 	{
-		DPRINTK("smb_request failed\n");
+		pr_debug("smb_request failed\n");
 		result = -EIO;
 	} else if (smb_valid_packet(s->packet) != 0)
 	{
-		DPRINTK("not a valid packet!\n");
+		pr_debug("not a valid packet!\n");
 		result = -EIO;
 	} else if (s->rcls != 0)
 	{
 		result = -smb_errno(s->rcls, s->err);
 	} else if (smb_verify(s->packet, command, wct, bcc) != 0)
 	{
-		DPRINTK("smb_verify failed\n");
+		pr_debug("smb_verify failed\n");
 		result = -EIO;
 	}
 	return result;
@@ -461,69 +378,111 @@
    of any use. */
 
 static int
-smb_retry(struct smb_server *server)
+smb_retry(struct smb_sb_info *server)
 {
 	if (server->state != CONN_INVALID)
 	{
 		return 0;
 	}
-	if (smb_release(server) < 0)
+	if (server->sock_file != NULL)
 	{
-		DPRINTK("smb_retry: smb_release failed\n");
-		server->state = CONN_RETRIED;
-		return 0;
+		close_fp(server->sock_file);
+		server->sock_file = NULL;
 	}
-	if (smb_proc_reconnect(server) < 0)
+
+	if (server->conn_pid == 0)
 	{
-		DPRINTK("smb_proc_reconnect failed\n");
 		server->state = CONN_RETRIED;
 		return 0;
 	}
-	server->state = CONN_VALID;
-	return 1;
+
+	kill_proc(server->conn_pid, SIGUSR1, 0);
+	server->conn_pid = 0;
+
+	smb_lock_server(server);
+
+	if (server->sock_file != NULL)
+	{
+		server->state = CONN_VALID;
+		return 1;
+	}
+	return 0;
 }
 
-static int
-smb_request_ok_unlock(struct smb_server *s, int command, int wct, int bcc)
+int
+smb_offerconn(struct smb_sb_info *server)
 {
-	int result = smb_request_ok(s, command, wct, bcc);
+	if (!suser() && (current->uid != server->m.mounted_uid))
+	{
+		return -EACCES;
+	}
+	server->conn_pid = current->pid;
+	return 0;
+}
 
-	smb_unlock_server(s);
+int
+smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt)
+{
+	struct file *filp;
 
-	return result;
+	if (opt->fd >= NR_OPEN || !(filp = current->files->fd[opt->fd]))
+	{
+		return -EBADF;
+	}
+	if (!S_ISSOCK(filp->f_dentry->d_inode->i_mode))
+	{
+		return -EBADF;
+	}
+	if (!suser() && (current->uid != server->m.mounted_uid))
+	{
+		return -EACCES;
+	}
+	if (server->sock_file != NULL)
+	{
+		close_fp(server->sock_file);
+		server->sock_file = NULL;
+	}
+	filp->f_count += 1;
+	server->sock_file = filp;
+	smb_catch_keepalive(server);
+	server->opt = *opt;
+	pr_debug("smb_newconn: protocol = %d\n", server->opt.protocol);
+	server->conn_pid = 0;
+	server->generation += 1;
+	smb_unlock_server(server);
+	return 0;
 }
 
 /* smb_setup_header: We completely set up the packet. You only have to
    insert the command-specific fields */
 
 __u8 *
-smb_setup_header(struct smb_server * server, byte command, word wct, word bcc)
+smb_setup_header(struct smb_sb_info * server, __u8 command, __u16 wct, __u16 bcc)
 {
-	dword xmit_len = SMB_HEADER_LEN + wct * sizeof(word) + bcc + 2;
-	byte *p = server->packet;
-	byte *buf = server->packet;
+	__u32 xmit_len = SMB_HEADER_LEN + wct * sizeof(__u16) + bcc + 2;
+	__u8 *p = server->packet;
+	__u8 *buf = server->packet;
 
 	p = smb_encode_smb_length(p, xmit_len - 4);
 
-	BSET(p, 0, 0xff);
-	BSET(p, 1, 'S');
-	BSET(p, 2, 'M');
-	BSET(p, 3, 'B');
-	BSET(p, 4, command);
+	*p++ = 0xff;
+	*p++ = 'S';
+	*p++ = 'M';
+	*p++ = 'B';
+	*p++ = command;
 
-	p += 5;
 	memset(p, '\0', 19);
 	p += 19;
 	p += 8;
 
-	WSET(buf, smb_tid, server->tid);
-	WSET(buf, smb_pid, server->pid);
-	WSET(buf, smb_uid, server->server_uid);
-	WSET(buf, smb_mid, server->mid);
+	WSET(buf, smb_tid, server->opt.tid);
+	WSET(buf, smb_pid, 1);
+	WSET(buf, smb_uid, server->opt.server_uid);
+	WSET(buf, smb_mid, 1);
 
-	if (server->protocol > PROTOCOL_CORE)
+	if (server->opt.protocol > SMB_PROTOCOL_CORE)
 	{
-		BSET(buf, smb_flg, 0x8);
+		*(buf+smb_flg) = 0x8;
 		WSET(buf, smb_flg2, 0x3);
 	}
 	*p++ = wct;		/* wct */
@@ -532,20 +491,8 @@
 	return p + 2;
 }
 
-/* smb_setup_header_exclusive waits on server->lock and locks the
-   server, when it's free. You have to unlock it manually when you're
-   finished with server->packet! */
-
-static byte *
-smb_setup_header_exclusive(struct smb_server *server,
-			   byte command, word wct, word bcc)
-{
-	smb_lock_server(server);
-	return smb_setup_header(server, command, wct, bcc);
-}
-
 static void
-smb_setup_bcc(struct smb_server *server, byte * p)
+smb_setup_bcc(struct smb_sb_info *server, __u8 * p)
 {
 	__u8 *packet = server->packet;
 	__u8 *pbcc = packet + SMB_HEADER_LEN + 2 * SMB_WCT(packet);
@@ -557,101 +504,118 @@
 }
 
 
-/*****************************************************************************/
-/*                                                                           */
-/*  File operation section.                                                  */
-/*                                                                           */
-/*****************************************************************************/
+/*
+ * We're called with the server locked, and we leave it that way. We
+ * try maximum permissions.
+ */
 
-int
-smb_proc_open(struct smb_server *server,
-	      struct smb_inode_info *dir, const char *name, int len,
-	      struct smb_dirent *entry)
+static int
+smb_proc_open(struct inode *ino)
 {
+	struct smb_sb_info *server = SMB_SERVER(ino);
 	int error;
 	char *p;
-	char *buf;
-	const word o_attr = aSYSTEM | aHIDDEN | aDIR;
-
-	DPRINTK("smb_proc_open: name=%s\n", name);
-
-	smb_lock_server(server);
 
-	if (entry->opened != 0)
-	{
-		/* Somebody else opened the file while we slept */
-		smb_unlock_server(server);
-		return 0;
-	}
       retry:
-	buf = server->packet;
 	p = smb_setup_header(server, SMBopen, 2, 0);
-	WSET(buf, smb_vwv0, 0x42);	/* read/write */
-	WSET(buf, smb_vwv1, o_attr);
+	WSET(server->packet, smb_vwv0, 0x42);	/* read/write */
+	WSET(server->packet, smb_vwv1, aSYSTEM | aHIDDEN | aDIR);
 	*p++ = 4;
-	p = smb_encode_path(server, p, dir, name, len);
+	p = smb_encode_path(server, p, ino, NULL);
 	smb_setup_bcc(server, p);
 
 	if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0)
 	{
-
 		if (smb_retry(server))
-		{
 			goto retry;
-		}
+
 		if ((error != -EACCES) && (error != -ETXTBSY)
 		    && (error != -EROFS))
-		{
-			smb_unlock_server(server);
 			return error;
-		}
+
 		p = smb_setup_header(server, SMBopen, 2, 0);
-		WSET(buf, smb_vwv0, 0x40);	/* read only */
-		WSET(buf, smb_vwv1, o_attr);
+		WSET(server->packet, smb_vwv0, 0x40);	/* read only */
+		WSET(server->packet, smb_vwv1, aSYSTEM | aHIDDEN | aDIR);
 		*p++ = 4;
-		p = smb_encode_path(server, p, dir, name, len);
+		p = smb_encode_path(server, p, ino, NULL);
 		smb_setup_bcc(server, p);
 
 		if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0)
 		{
 			if (smb_retry(server))
-			{
 				goto retry;
-			}
-			smb_unlock_server(server);
+
 			return error;
 		}
 	}
 	/* We should now have data in vwv[0..6]. */
 
-	entry->fileid = WVAL(buf, smb_vwv0);
-	entry->attr = WVAL(buf, smb_vwv1);
-	entry->f_ctime = entry->f_atime =
-	    entry->f_mtime = local2utc(DVAL(buf, smb_vwv2));
-	entry->f_size = DVAL(buf, smb_vwv4);
-	entry->access = WVAL(buf, smb_vwv6);
-
-	entry->opened = 1;
-	entry->access &= 3;
+	ino->u.smbfs_i.fileid = WVAL(server->packet, smb_vwv0);
+	ino->u.smbfs_i.attr = WVAL(server->packet, smb_vwv1);
+	ino->u.smbfs_i.access = WVAL(server->packet, smb_vwv6);
+	ino->u.smbfs_i.access &= 3;
 
-	smb_unlock_server(server);
+	ino->u.smbfs_i.open = server->generation;
 
-	DPRINTK("smb_proc_open: entry->access = %d\n", entry->access);
+	pr_debug("smb_proc_open: entry->access = %d\n", ino->u.smbfs_i.access);
 	return 0;
 }
 
 int
-smb_proc_close(struct smb_server *server,
-	       __u16 fileid, __u32 mtime)
+smb_open(struct inode *i, int wish)
 {
-	char *buf;
+	struct smb_sb_info *server = SMB_SERVER(i);
+	int result = -EACCES;
 
-	smb_setup_header_exclusive(server, SMBclose, 3, 0);
-	buf = server->packet;
-	WSET(buf, smb_vwv0, fileid);
-	DSET(buf, smb_vwv1, utc2local(mtime));
+	smb_lock_server(server);
+
+	if (!smb_is_open(i)) {
+		int error = smb_proc_open(i);
+		if (error) {
+			smb_unlock_server(server);
+			return error;
+		}
+	}
+
+	if (((wish == O_RDONLY) && ((i->u.smbfs_i.access == O_RDONLY)
+				     || (i->u.smbfs_i.access == O_RDWR)))
+	    || ((wish == O_WRONLY) && ((i->u.smbfs_i.access == O_WRONLY)
+					|| (i->u.smbfs_i.access == O_RDWR)))
+	    || ((wish == O_RDWR) && (i->u.smbfs_i.access == O_RDWR)))
+		result = 0;
 
-	return smb_request_ok_unlock(server, SMBclose, 0, 0);
+	smb_unlock_server(server);
+	return result;
+}
+
+/* We're called with the server locked */
+
+static int smb_proc_close(struct smb_sb_info *server,
+			  __u16 fileid, __u32 mtime)
+{
+	smb_setup_header(server, SMBclose, 3, 0);
+	WSET(server->packet, smb_vwv0, fileid);
+	DSET(server->packet, smb_vwv1, mtime);
+	return smb_request_ok(server, SMBclose, 0, 0);
+}
+	
+
+int smb_close(struct inode *ino)
+{
+	struct smb_sb_info *server = SMB_SERVER(ino);
+	int result;
+
+	smb_lock_server(server);
+
+	if (!smb_is_open(ino)) {
+		smb_unlock_server(server);
+		return 0;
+	}
+
+	result = smb_proc_close(server, ino->u.smbfs_i.fileid, ino->i_mtime);
+	ino->u.smbfs_i.open = 0;
+	smb_unlock_server(server);
+	return result;
 }
 
 /* In smb_proc_read and smb_proc_write we do not retry, because the
@@ -661,17 +625,18 @@
    copy_to_user. */
 
 int
-smb_proc_read(struct smb_server *server, struct smb_dirent *finfo,
-	      off_t offset, long count, char *data, int fs)
+smb_proc_read(struct inode *ino, off_t offset, long count, char *data)
 {
-	word returned_count, data_len;
+	struct smb_sb_info *server = SMB_SERVER(ino);
+	__u16 returned_count, data_len;
 	char *buf;
 	int error;
 
-	smb_setup_header_exclusive(server, SMBread, 5, 0);
+	smb_lock_server(server);
+	smb_setup_header(server, SMBread, 5, 0);
 	buf = server->packet;
 
-	WSET(buf, smb_vwv0, finfo->fileid);
+	WSET(buf, smb_vwv0, ino->u.smbfs_i.fileid);
 	WSET(buf, smb_vwv1, count);
 	DSET(buf, smb_vwv2, offset);
 	WSET(buf, smb_vwv4, 0);
@@ -683,56 +648,56 @@
 	}
 	returned_count = WVAL(buf, smb_vwv0);
 
-	smb_decode_data(SMB_BUF(server->packet), data, &data_len, fs);
+	buf = SMB_BUF(server->packet);
+	data_len = WVAL(buf, 1);
+
+	memcpy(data, buf+3, data_len);
 
 	smb_unlock_server(server);
 
 	if (returned_count != data_len)
 	{
-		printk("smb_proc_read: Warning, returned_count != data_len\n");
-		printk("smb_proc_read: ret_c=%d, data_len=%d\n",
+		printk(KERN_NOTICE "smb_proc_read: returned != data_len\n");
+		printk(KERN_NOTICE "smb_proc_read: ret_c=%d, data_len=%d\n",
 		       returned_count, data_len);
 	}
 	return data_len;
 }
 
 int
-smb_proc_write(struct smb_server *server, struct smb_dirent *finfo,
-	       off_t offset, int count, const char *data)
+smb_proc_write(struct inode *ino, off_t offset, int count, const char *data)
 {
+	struct smb_sb_info *server = SMB_SERVER(ino);
 	int res = 0;
-	char *buf;
-	byte *p;
+	__u8 *p;
 
-	p = smb_setup_header_exclusive(server, SMBwrite, 5, count + 3);
-	buf = server->packet;
-	WSET(buf, smb_vwv0, finfo->fileid);
-	WSET(buf, smb_vwv1, count);
-	DSET(buf, smb_vwv2, offset);
-	WSET(buf, smb_vwv4, 0);
+	smb_lock_server(server);
+	p = smb_setup_header(server, SMBwrite, 5, count + 3);
+	WSET(server->packet, smb_vwv0, ino->u.smbfs_i.fileid);
+	WSET(server->packet, smb_vwv1, count);
+	DSET(server->packet, smb_vwv2, offset);
+	WSET(server->packet, smb_vwv4, 0);
 
 	*p++ = 1;
 	WSET(p, 0, count);
-	copy_from_user(p + 2, data, count);
+	memcpy(p+2, data, count);
 
 	if ((res = smb_request_ok(server, SMBwrite, 1, 0)) >= 0)
-	{
-		res = WVAL(buf, smb_vwv0);
-	}
+		res = WVAL(server->packet, smb_vwv0);
+
 	smb_unlock_server(server);
 
 	return res;
 }
 
 int
-smb_proc_create(struct inode *dir, const char *name, int len,
-		word attr, time_t ctime)
+smb_proc_create(struct inode *dir, struct qstr *name,
+		__u16 attr, time_t ctime)
 {
 	int error;
 	char *p;
-	struct smb_server *server = SMB_SERVER(dir);
+	struct smb_sb_info *server = SMB_SERVER(dir);
 	char *buf;
-	__u16 fileid;
 
 	smb_lock_server(server);
       retry:
@@ -741,7 +706,7 @@
 	WSET(buf, smb_vwv0, attr);
 	DSET(buf, smb_vwv1, utc2local(ctime));
 	*p++ = 4;
-	p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
+	p = smb_encode_path(server, p, dir, name);
 	smb_setup_bcc(server, p);
 
 	if ((error = smb_request_ok(server, SMBcreate, 1, 0)) < 0)
@@ -753,20 +718,18 @@
 		smb_unlock_server(server);
 		return error;
 	}
-	fileid = WVAL(buf, smb_vwv0);
+	smb_proc_close(server, WVAL(buf, smb_vwv0), CURRENT_TIME);
 	smb_unlock_server(server);
 
-	smb_proc_close(server, fileid, CURRENT_TIME);
-
 	return 0;
 }
 
 int
-smb_proc_mv(struct inode *odir, const char *oname, const int olen,
-	    struct inode *ndir, const char *nname, const int nlen)
+smb_proc_mv(struct inode *odir, struct qstr *oname,
+	    struct inode *ndir, struct qstr *nname)
 {
 	char *p;
-	struct smb_server *server = SMB_SERVER(odir);
+	struct smb_sb_info *server = SMB_SERVER(odir);
 	int result;
 
 	smb_lock_server(server);
@@ -775,9 +738,9 @@
 	p = smb_setup_header(server, SMBmv, 1, 0);
 	WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN);
 	*p++ = 4;
-	p = smb_encode_path(server, p, SMB_INOP(odir), oname, olen);
+	p = smb_encode_path(server, p, odir, oname);
 	*p++ = 4;
-	p = smb_encode_path(server, p, SMB_INOP(ndir), nname, nlen);
+	p = smb_encode_path(server, p, ndir, nname);
 	smb_setup_bcc(server, p);
 
 	if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0)
@@ -792,18 +755,18 @@
 }
 
 int
-smb_proc_mkdir(struct inode *dir, const char *name, const int len)
+smb_proc_mkdir(struct inode *dir, struct qstr *name)
 {
 	char *p;
 	int result;
-	struct smb_server *server = SMB_SERVER(dir);
+	struct smb_sb_info *server = SMB_SERVER(dir);
 
 	smb_lock_server(server);
 
       retry:
 	p = smb_setup_header(server, SMBmkdir, 0, 0);
 	*p++ = 4;
-	p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
+	p = smb_encode_path(server, p, dir, name);
 	smb_setup_bcc(server, p);
 
 	if ((result = smb_request_ok(server, SMBmkdir, 0, 0)) < 0)
@@ -818,18 +781,18 @@
 }
 
 int
-smb_proc_rmdir(struct inode *dir, const char *name, const int len)
+smb_proc_rmdir(struct inode *dir, struct qstr *name)
 {
 	char *p;
 	int result;
-	struct smb_server *server = SMB_SERVER(dir);
+	struct smb_sb_info *server = SMB_SERVER(dir);
 
 	smb_lock_server(server);
 
       retry:
 	p = smb_setup_header(server, SMBrmdir, 0, 0);
 	*p++ = 4;
-	p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
+	p = smb_encode_path(server, p, dir, name);
 	smb_setup_bcc(server, p);
 
 	if ((result = smb_request_ok(server, SMBrmdir, 0, 0)) < 0)
@@ -844,10 +807,10 @@
 }
 
 int
-smb_proc_unlink(struct inode *dir, const char *name, const int len)
+smb_proc_unlink(struct inode *dir, struct qstr *name)
 {
 	char *p;
-	struct smb_server *server = SMB_SERVER(dir);
+	struct smb_sb_info *server = SMB_SERVER(dir);
 	int result;
 
 	smb_lock_server(server);
@@ -856,7 +819,7 @@
 	p = smb_setup_header(server, SMBunlink, 1, 0);
 	WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN);
 	*p++ = 4;
-	p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
+	p = smb_encode_path(server, p, dir, name);
 	smb_setup_bcc(server, p);
 
 	if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0)
@@ -871,7 +834,7 @@
 }
 
 int
-smb_proc_trunc(struct smb_server *server, word fid, dword length)
+smb_proc_trunc(struct smb_sb_info *server, __u16 fid, __u32 length)
 {
 	char *p;
 	char *buf;
@@ -886,7 +849,8 @@
 	WSET(buf, smb_vwv1, 0);
 	DSET(buf, smb_vwv2, length);
 	WSET(buf, smb_vwv4, 0);
-	p = smb_encode_ascii(p, "", 0);
+	*p++ = 4;
+	*p++ = 0;
 	smb_setup_bcc(server, p);
 
 	if ((result = smb_request_ok(server, SMBwrite, 1, 0)) < 0)
@@ -901,59 +865,60 @@
 }
 
 static void
-smb_init_dirent(struct smb_server *server, struct smb_dirent *entry)
+smb_init_dirent(struct smb_sb_info *server, struct smb_fattr *fattr)
 {
-	memset(entry, 0, sizeof(struct smb_dirent));
+	memset(fattr, 0, sizeof(*fattr));
 
-	entry->f_nlink = 1;
-	entry->f_uid = server->m.uid;
-	entry->f_gid = server->m.gid;
-	entry->f_blksize = 512;
+	fattr->f_nlink = 1;
+	fattr->f_uid = server->m.uid;
+	fattr->f_gid = server->m.gid;
+	fattr->f_blksize = 512;
 }
 
 static void
-smb_finish_dirent(struct smb_server *server, struct smb_dirent *entry)
+smb_finish_dirent(struct smb_sb_info *server, struct smb_fattr *fattr)
 {
-	if ((entry->attr & aDIR) != 0)
+	if (fattr->attr & aDIR)
 	{
-		entry->f_mode = server->m.dir_mode;
-		entry->f_size = 512;
+		fattr->f_mode = server->m.dir_mode;
+		fattr->f_size = 512;
 	} else
 	{
-		entry->f_mode = server->m.file_mode;
+		fattr->f_mode = server->m.file_mode;
 	}
 
-	if ((entry->f_blksize != 0) && (entry->f_size != 0))
+	if ((fattr->f_blksize != 0) && (fattr->f_size != 0))
 	{
-		entry->f_blocks =
-		    (entry->f_size - 1) / entry->f_blksize + 1;
+		fattr->f_blocks =
+		    (fattr->f_size - 1) / fattr->f_blksize + 1;
 	} else
 	{
-		entry->f_blocks = 0;
+		fattr->f_blocks = 0;
 	}
 	return;
 }
 
 void
-smb_init_root_dirent(struct smb_server *server, struct smb_dirent *entry)
+smb_init_root_dirent(struct smb_sb_info *server, struct smb_fattr *fattr)
 {
-	smb_init_dirent(server, entry);
-	entry->attr = aDIR;
-	entry->f_ino = 1;
-	smb_finish_dirent(server, entry);
+	smb_init_dirent(server, fattr);
+	fattr->attr = aDIR;
+	fattr->f_ino = 1;
+	smb_finish_dirent(server, fattr);
 }
 
 
-static char *
-smb_decode_dirent(struct smb_server *server, char *p, struct smb_dirent *entry)
+static __u8 *
+smb_decode_dirent(struct smb_sb_info *server, __u8 *p,
+		  struct smb_dirent *entry)
 {
-	smb_init_dirent(server, entry);
+	smb_init_dirent(server, &(entry->attr));
 
 	p += SMB_STATUS_SIZE;	/* reserved (search_status) */
-	entry->attr = BVAL(p, 0);
-	entry->f_mtime = entry->f_atime = entry->f_ctime =
+	entry->attr.attr = *p;
+	entry->attr.f_mtime = entry->attr.f_atime = entry->attr.f_ctime =
 	    date_dos2unix(WVAL(p, 1), WVAL(p, 3));
-	entry->f_size = DVAL(p, 5);
+	entry->attr.f_size = DVAL(p, 5);
 	entry->len = strlen(p + 9);
 	if (entry->len > 12)
 	{
@@ -970,28 +935,28 @@
 			entry->name[entry->len] = '\0';
 		}
 	}
-	switch (server->case_handling)
+	switch (server->opt.case_handling)
 	{
-	case CASE_UPPER:
+	case SMB_CASE_UPPER:
 		str_upper(entry->name);
 		break;
-	case CASE_LOWER:
+	case SMB_CASE_LOWER:
 		str_lower(entry->name);
 		break;
 	default:
 		break;
 	}
-	DPRINTK("smb_decode_dirent: name = %s\n", entry->name);
-	smb_finish_dirent(server, entry);
+	pr_debug("smb_decode_dirent: name = %s\n", entry->name);
+	smb_finish_dirent(server, &(entry->attr));
 	return p + 22;
 }
 
 /* This routine is used to read in directory entries from the network.
    Note that it is for short directory name seeks, i.e.: protocol <
-   PROTOCOL_LANMAN2 */
+   SMB_PROTOCOL_LANMAN2 */
 
 static int
-smb_proc_readdir_short(struct smb_server *server, struct inode *dir, int fpos,
+smb_proc_readdir_short(struct smb_sb_info *server, struct inode *dir, int fpos,
 		       int cache_size, struct smb_dirent *entry)
 {
 	char *p;
@@ -1001,12 +966,14 @@
 	int i;
 	int first, total_count;
 	struct smb_dirent *current_entry;
-	word bcc;
-	word count;
+	__u16 bcc;
+	__u16 count;
 	char status[SMB_STATUS_SIZE];
-	int entries_asked = (server->max_xmit - 100) / SMB_DIRINFO_SIZE;
+	int entries_asked = (server->opt.max_xmit - 100) / SMB_DIRINFO_SIZE;
+
+	static struct qstr mask = { "*.*", 3, 0 };
 
-	DPRINTK("SMB call  readdir %d @ %d\n", cache_size, fpos);
+	pr_debug("SMB call  readdir %d @ %d\n", cache_size, fpos);
 
 	smb_lock_server(server);
 
@@ -1024,7 +991,7 @@
 			WSET(buf, smb_vwv0, entries_asked);
 			WSET(buf, smb_vwv1, aDIR);
 			*p++ = 4;
-			p = smb_encode_path(server, p, SMB_INOP(dir), "*.*", 3);
+			p = smb_encode_path(server, p, dir, &mask);
 			*p++ = 5;
 			WSET(p, 0, 0);
 			p += 2;
@@ -1033,7 +1000,8 @@
 			p = smb_setup_header(server, SMBsearch, 2, 0);
 			WSET(buf, smb_vwv0, entries_asked);
 			WSET(buf, smb_vwv1, aDIR);
-			p = smb_encode_ascii(p, "", 0);
+			*p++ = 4;
+			*p++ = 0;
 			*p++ = 5;
 			WSET(p, 0, SMB_STATUS_SIZE);
 			p += 2;
@@ -1061,8 +1029,8 @@
 			}
 		}
 		p = SMB_VWV(server->packet);
-		p = smb_decode_word(p, &count);
-		p = smb_decode_word(p, &bcc);
+		count = WVAL(p, 0);
+		bcc = WVAL(p, 2);
 
 		first = 0;
 
@@ -1076,8 +1044,7 @@
 			result = -EIO;
 			goto unlock_return;
 		}
-		p += 3;		/* Skipping VBLOCK header
-				   (5, length lo, length hi). */
+		p += 7;
 
 		/* Read the last entry into the status field. */
 		memcpy(status,
@@ -1092,8 +1059,8 @@
 			if (total_count < fpos)
 			{
 				p += SMB_DIRINFO_SIZE;
-				DDPRINTK("smb_proc_readdir: skipped entry.\n");
-				DDPRINTK("                  total_count = %d\n"
+				pr_debug("smb_proc_readdir: skipped entry.\n");
+				pr_debug("                  total_count = %d\n"
 					 "                i = %d, fpos = %d\n",
 					 total_count, i, fpos);
 			} else if (total_count >= fpos + cache_size)
@@ -1105,8 +1072,8 @@
 				p = smb_decode_dirent(server, p,
 						      current_entry);
 				current_entry->f_pos = total_count;
-				DDPRINTK("smb_proc_readdir: entry->f_pos = "
-					 "%lu\n", entry->f_pos);
+				pr_debug("smb_proc_readdir: entry->f_pos = "
+					 "%u\n", entry->f_pos);
 				current_entry += 1;
 			}
 			total_count += 1;
@@ -1123,52 +1090,52 @@
    is used by OS/2. */
 
 static char *
-smb_decode_long_dirent(struct smb_server *server, char *p,
+smb_decode_long_dirent(struct smb_sb_info *server, char *p,
 		       struct smb_dirent *entry, int level)
 {
 	char *result;
 
-	smb_init_dirent(server, entry);
+	smb_init_dirent(server, &(entry->attr));
 
 	switch (level)
 	{
 		/* We might add more levels later... */
 	case 1:
-		entry->len = BVAL(p, 26);
+		entry->len = *(p+26);
 		strncpy(entry->name, p + 27, entry->len);
 		entry->name[entry->len] = '\0';
-		entry->f_size = DVAL(p, 16);
-		entry->attr = BVAL(p, 24);
+		entry->attr.f_size = DVAL(p, 16);
+		entry->attr.attr = *(p+24);
 
-		entry->f_ctime = date_dos2unix(WVAL(p, 6), WVAL(p, 4));
-		entry->f_atime = date_dos2unix(WVAL(p, 10), WVAL(p, 8));
-		entry->f_mtime = date_dos2unix(WVAL(p, 14), WVAL(p, 12));
-		result = p + 28 + BVAL(p, 26);
+		entry->attr.f_ctime = date_dos2unix(WVAL(p, 6), WVAL(p, 4));
+		entry->attr.f_atime = date_dos2unix(WVAL(p, 10), WVAL(p, 8));
+		entry->attr.f_mtime = date_dos2unix(WVAL(p, 14), WVAL(p, 12));
+		result = p + 28 + *(p+26);
 		break;
 
 	default:
-		DPRINTK("Unknown long filename format %d\n", level);
+		pr_debug("Unknown long filename format %d\n", level);
 		result = p + WVAL(p, 0);
 	}
 
-	switch (server->case_handling)
+	switch (server->opt.case_handling)
 	{
-	case CASE_UPPER:
+	case SMB_CASE_UPPER:
 		str_upper(entry->name);
 		break;
-	case CASE_LOWER:
+	case SMB_CASE_LOWER:
 		str_lower(entry->name);
 		break;
 	default:
 		break;
 	}
 
-	smb_finish_dirent(server, entry);
+	smb_finish_dirent(server, &(entry->attr));
 	return result;
 }
 
-int
-smb_proc_readdir_long(struct smb_server *server, struct inode *dir, int fpos,
+static int
+smb_proc_readdir_long(struct smb_sb_info *server, struct inode *dir, int fpos,
 		      int cache_size, struct smb_dirent *cache)
 {
 	/* NT uses 260, OS/2 uses 2. Both accept 1. */
@@ -1199,16 +1166,17 @@
 
 	char param[SMB_MAXPATHLEN + 2 + 12];
 	int mask_len;
-	unsigned char *mask = &(param[12]);
+	char *mask = &(param[12]);
+
+	static struct qstr star = { "*", 1, 0 };
 
-	mask_len = smb_encode_path(server, mask,
-				   SMB_INOP(dir), "*", 1) - mask;
+	mask_len = smb_encode_path(server, mask, dir, &star) - mask;
 
 	mask[mask_len] = 0;
 	mask[mask_len + 1] = 0;
 
-	DPRINTK("smb_readdir_long cache=%d, fpos=%d, mask=%s\n",
-		cache_size, fpos, mask);
+	pr_debug("smb_readdir_long cache=%d, fpos=%d, mask=%s\n",
+		 cache_size, fpos, mask);
 
 	smb_lock_server(server);
 
@@ -1223,7 +1191,7 @@
 		loop_count += 1;
 		if (loop_count > 200)
 		{
-			printk("smb_proc_readdir_long: "
+			printk(KERN_WARNING "smb_proc_readdir_long: "
 			       "Looping in FIND_NEXT??\n");
 			break;
 		}
@@ -1240,8 +1208,9 @@
 		} else
 		{
 			command = TRANSACT2_FINDNEXT;
-			DPRINTK("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
-			     ff_dir_handle, ff_resume_key, ff_lastname, mask);
+			pr_debug("hand=0x%X resume=%d ff_lastnm=%d mask=%s\n",
+				 ff_dir_handle, ff_resume_key, ff_lastname,
+				 mask);
 			WSET(param, 0, ff_dir_handle);
 			WSET(param, 2, max_matches);	/* max count */
 			WSET(param, 4, info_level);
@@ -1270,8 +1239,8 @@
 			{
 				goto retry;
 			}
-			DPRINTK("smb_proc_readdir_long: "
-				"got error from trans2_request\n");
+			pr_debug("smb_proc_readdir_long: "
+				 "got error from trans2_request\n");
 			break;
 		}
 		if (server->rcls != 0)
@@ -1314,7 +1283,7 @@
 				break;
 			case 1:
 				lastname = p + ff_lastname + 1;
-				lastname_len = BVAL(p, ff_lastname);
+				lastname_len = *(p+ff_lastname);
 				ff_resume_key = 0;
 				break;
 			}
@@ -1332,7 +1301,7 @@
 			p = smb_decode_long_dirent(server, p,
 						   entry, info_level);
 
-			DDPRINTK("smb_readdir_long: got %s\n", entry->name);
+			pr_debug("smb_readdir_long: got %s\n", entry->name);
 
 			if ((entry->name[0] == '.')
 			    && ((entry->name[1] == '\0')
@@ -1354,8 +1323,8 @@
 			entries_seen += 1;
 		}
 
-		DPRINTK("received %d entries (eos=%d resume=%d)\n",
-			ff_searchcount, ff_eos, ff_resume_key);
+		pr_debug("received %d entries (eos=%d resume=%d)\n",
+			 ff_searchcount, ff_eos, ff_resume_key);
 
 		first = 0;
 	}
@@ -1366,10 +1335,12 @@
 }
 
 int
-smb_proc_readdir(struct smb_server *server, struct inode *dir, int fpos,
+smb_proc_readdir(struct inode *dir, int fpos,
 		 int cache_size, struct smb_dirent *entry)
 {
-	if (server->protocol >= PROTOCOL_LANMAN2)
+	struct smb_sb_info *server = SMB_SERVER(dir);
+
+	if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
 		return smb_proc_readdir_long(server, dir, fpos, cache_size,
 					     entry);
 	else
@@ -1378,23 +1349,21 @@
 }
 
 static int
-smb_proc_getattr_core(struct inode *dir, const char *name, int len,
-		      struct smb_dirent *entry)
+smb_proc_getattr_core(struct inode *dir, struct qstr *name,
+		      struct smb_fattr *attr)
 {
 	int result;
 	char *p;
-	struct smb_server *server = SMB_SERVER(dir);
+	struct smb_sb_info *server = SMB_SERVER(dir);
 	char *buf;
 
 	smb_lock_server(server);
 
-	DDPRINTK("smb_proc_getattr: %s\n", name);
-
       retry:
 	buf = server->packet;
 	p = smb_setup_header(server, SMBgetatr, 0, 0);
 	*p++ = 4;
-	p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
+	p = smb_encode_path(server, p, dir, name);
 	smb_setup_bcc(server, p);
 
 	if ((result = smb_request_ok(server, SMBgetatr, 10, 0)) < 0)
@@ -1406,20 +1375,20 @@
 		smb_unlock_server(server);
 		return result;
 	}
-	entry->attr = WVAL(buf, smb_vwv0);
-	entry->f_ctime = entry->f_atime =
-	    entry->f_mtime = local2utc(DVAL(buf, smb_vwv1));
+	attr->attr = WVAL(buf, smb_vwv0);
+	attr->f_ctime = attr->f_atime =
+	    attr->f_mtime = local2utc(DVAL(buf, smb_vwv1));
 
-	entry->f_size = DVAL(buf, smb_vwv3);
+	attr->f_size = DVAL(buf, smb_vwv3);
 	smb_unlock_server(server);
 	return 0;
 }
 
 static int
-smb_proc_getattr_trans2(struct inode *dir, const char *name, int len,
-			struct smb_dirent *entry)
+smb_proc_getattr_trans2(struct inode *dir, struct qstr *name,
+			struct smb_fattr *attr)
 {
-	struct smb_server *server = SMB_SERVER(dir);
+	struct smb_sb_info *server = SMB_SERVER(dir);
 	char param[SMB_MAXPATHLEN + 20];
 	char *p;
 	int result;
@@ -1431,7 +1400,7 @@
 
 	WSET(param, 0, 1);	/* Info level SMB_INFO_STANDARD */
 	DSET(param, 2, 0);
-	p = smb_encode_path(server, param + 6, SMB_INOP(dir), name, len);
+	p = smb_encode_path(server, param + 6, dir, name);
 
 	smb_lock_server(server);
       retry:
@@ -1459,41 +1428,34 @@
 		smb_unlock_server(server);
 		return -ENOENT;
 	}
-	entry->f_ctime = date_dos2unix(WVAL(resp_data, 2),
-				       WVAL(resp_data, 0));
-	entry->f_atime = date_dos2unix(WVAL(resp_data, 6),
-				       WVAL(resp_data, 4));
-	entry->f_mtime = date_dos2unix(WVAL(resp_data, 10),
-				       WVAL(resp_data, 8));
-	entry->f_size = DVAL(resp_data, 12);
-	entry->attr = WVAL(resp_data, 20);
+	attr->f_ctime = date_dos2unix(WVAL(resp_data, 2),
+				      WVAL(resp_data, 0));
+	attr->f_atime = date_dos2unix(WVAL(resp_data, 6),
+				      WVAL(resp_data, 4));
+	attr->f_mtime = date_dos2unix(WVAL(resp_data, 10),
+				      WVAL(resp_data, 8));
+	attr->f_size = DVAL(resp_data, 12);
+	attr->attr = WVAL(resp_data, 20);
 	smb_unlock_server(server);
 
 	return 0;
 }
 
-int
-smb_proc_getattr(struct inode *dir, const char *name, int len,
-		 struct smb_dirent *entry)
+int smb_proc_getattr(struct inode *dir, struct qstr *name,
+		     struct smb_fattr *fattr)
 {
-	struct smb_server *server = SMB_SERVER(dir);
+	struct smb_sb_info *server = SMB_SERVER(dir);
 	int result = 0;
 
-	smb_init_dirent(server, entry);
+	smb_init_dirent(server, fattr);
 
-	if (server->protocol >= PROTOCOL_LANMAN2)
-	{
-		result = smb_proc_getattr_trans2(dir, name, len, entry);
-	}
-	if ((server->protocol < PROTOCOL_LANMAN2) || (result < 0))
-	{
-		result = smb_proc_getattr_core(dir, name, len, entry);
-	}
-	smb_finish_dirent(server, entry);
+	if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
+		result = smb_proc_getattr_trans2(dir, name, fattr);
 
-	entry->len = len;
-	memcpy(entry->name, name, len);
-	/* entry->name is null terminated from smb_init_dirent */
+	if ((server->opt.protocol < SMB_PROTOCOL_LANMAN2) || (result < 0))
+		result = smb_proc_getattr_core(dir, name, fattr);
+
+	smb_finish_dirent(server, fattr);
 
 	return result;
 }
@@ -1502,8 +1464,8 @@
 /* In core protocol, there is only 1 time to be set, we use
    entry->f_mtime, to make touch work. */
 static int
-smb_proc_setattr_core(struct smb_server *server,
-		      struct inode *i, struct smb_dirent *new_finfo)
+smb_proc_setattr_core(struct smb_sb_info *server,
+		      struct inode *i, struct smb_fattr *fattr)
 {
 	char *p;
 	char *buf;
@@ -1514,29 +1476,25 @@
       retry:
 	buf = server->packet;
 	p = smb_setup_header(server, SMBsetatr, 8, 0);
-	WSET(buf, smb_vwv0, new_finfo->attr);
-	DSET(buf, smb_vwv1, utc2local(new_finfo->f_mtime));
+	WSET(buf, smb_vwv0, fattr->attr);
+	DSET(buf, smb_vwv1, utc2local(fattr->f_mtime));
+	*p++ = 4;
+	p = smb_encode_path(server, p, i, NULL);
 	*p++ = 4;
-	p = smb_encode_path(server, p,
-			    SMB_INOP(i)->dir, SMB_INOP(i)->finfo.name,
-			    SMB_INOP(i)->finfo.len);
-	p = smb_encode_ascii(p, "", 0);
+	*p++ = 0;
 
 	smb_setup_bcc(server, p);
 	if ((result = smb_request_ok(server, SMBsetatr, 0, 0)) < 0)
-	{
 		if (smb_retry(server))
-		{
 			goto retry;
-		}
-	}
+
 	smb_unlock_server(server);
 	return result;
 }
 
 static int
-smb_proc_setattr_trans2(struct smb_server *server,
-			struct inode *i, struct smb_dirent *new_finfo)
+smb_proc_setattr_trans2(struct smb_sb_info *server,
+			struct inode *i, struct smb_fattr *fattr)
 {
 	char param[SMB_MAXPATHLEN + 20];
 	char data[26];
@@ -1550,16 +1508,14 @@
 
 	WSET(param, 0, 1);	/* Info level SMB_INFO_STANDARD */
 	DSET(param, 2, 0);
-	p = smb_encode_path(server, param + 6,
-			    SMB_INOP(i)->dir, SMB_INOP(i)->finfo.name,
-			    SMB_INOP(i)->finfo.len);
-
-	date_unix2dos(new_finfo->f_ctime, &(data[0]), &(data[2]));
-	date_unix2dos(new_finfo->f_atime, &(data[4]), &(data[6]));
-	date_unix2dos(new_finfo->f_mtime, &(data[8]), &(data[10]));
-	DSET(data, 12, new_finfo->f_size);
-	DSET(data, 16, new_finfo->f_blksize);
-	WSET(data, 20, new_finfo->attr);
+	p = smb_encode_path(server, param + 6, i, NULL);
+
+	date_unix2dos(fattr->f_ctime, &(data[0]), &(data[2]));
+	date_unix2dos(fattr->f_atime, &(data[4]), &(data[6]));
+	date_unix2dos(fattr->f_mtime, &(data[8]), &(data[10]));
+	DSET(data, 12, fattr->f_size);
+	DSET(data, 16, fattr->f_blksize);
+	WSET(data, 20, fattr->attr);
 	WSET(data, 22, 0);
 
 	smb_lock_server(server);
@@ -1575,39 +1531,34 @@
 		return -smb_errno(server->rcls, server->err);
 	}
 	if (result < 0)
-	{
 		if (smb_retry(server))
-		{
 			goto retry;
-		}
-	}
+
 	smb_unlock_server(server);
 	return 0;
 }
 
 int
-smb_proc_setattr(struct smb_server *server, struct inode *inode,
-		 struct smb_dirent *new_finfo)
+smb_proc_setattr(struct smb_sb_info *server, struct inode *inode,
+		 struct smb_fattr *fattr)
 {
 	int result;
 
-	if (server->protocol >= PROTOCOL_LANMAN2)
-	{
-		result = smb_proc_setattr_trans2(server, inode, new_finfo);
-	}
-	if ((server->protocol < PROTOCOL_LANMAN2) || (result < 0))
-	{
-		result = smb_proc_setattr_core(server, inode, new_finfo);
-	}
+	if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
+		result = smb_proc_setattr_trans2(server, inode, fattr);
+
+	if ((server->opt.protocol < SMB_PROTOCOL_LANMAN2) || (result < 0))
+		result = smb_proc_setattr_core(server, inode, fattr);
+
 	return result;
 }
 
 int
-smb_proc_dskattr(struct super_block *super, struct smb_dskattr *attr)
+smb_proc_dskattr(struct super_block *sb, struct statfs *attr)
 {
 	int error;
 	char *p;
-	struct smb_server *server = &(SMB_SBP(super)->s_server);
+	struct smb_sb_info *server = &(sb->u.smbfs_sb);
 
 	smb_lock_server(server);
 
@@ -1617,351 +1568,26 @@
 	if ((error = smb_request_ok(server, SMBdskattr, 5, 0)) < 0)
 	{
 		if (smb_retry(server))
-		{
 			goto retry;
-		}
+
 		smb_unlock_server(server);
 		return error;
 	}
 	p = SMB_VWV(server->packet);
-	p = smb_decode_word(p, &attr->total);
-	p = smb_decode_word(p, &attr->allocblocks);
-	p = smb_decode_word(p, &attr->blocksize);
-	p = smb_decode_word(p, &attr->free);
+	attr->f_bsize = WVAL(p, 2) * WVAL(p, 4);
+	attr->f_blocks = WVAL(p, 0);
+	attr->f_bavail = attr->f_bfree = WVAL(p, 6);
 	smb_unlock_server(server);
 	return 0;
 }
 
-/*****************************************************************************/
-/*                                                                           */
-/*  Mount/umount operations.                                                 */
-/*                                                                           */
-/*****************************************************************************/
-
-struct smb_prots
-{
-	enum smb_protocol prot;
-	const char *name;
-};
-
-/* smb_proc_reconnect: We expect the server to be locked, so that you
-   can call the routine from within smb_retry. The socket must be
-   created, like after a user-level socket()-call. It may not be
-   connected. */
-
-int
-smb_proc_reconnect(struct smb_server *server)
-{
-	struct smb_prots prots[] =
-	{
-		{PROTOCOL_CORE, "PC NETWORK PROGRAM 1.0"},
-		{PROTOCOL_COREPLUS, "MICROSOFT NETWORKS 1.03"},
-#ifdef LANMAN1
-		{PROTOCOL_LANMAN1, "MICROSOFT NETWORKS 3.0"},
-		{PROTOCOL_LANMAN1, "LANMAN1.0"},
-#endif
-#ifdef LANMAN2
-		{PROTOCOL_LANMAN2, "LM1.2X002"},
-#endif
-#ifdef NT1
-		{PROTOCOL_NT1, "NT LM 0.12"},
-		{PROTOCOL_NT1, "NT LANMAN 1.0"},
-#endif
-		{-1, NULL}};
-	char dev[] = "A:";
-	int i, plength;
-	int max_xmit = 1024;	/* Space needed for first request. */
-	int given_max_xmit = server->m.max_xmit;
-	int result;
-	byte *p;
-
-	if ((result = smb_connect(server)) < 0)
-	{
-		DPRINTK("smb_proc_reconnect: could not smb_connect\n");
-		goto fail;
-	}
-	/* Here we assume that the connection is valid */
-	server->state = CONN_VALID;
-
-	if (server->packet != NULL)
-	{
-		smb_vfree(server->packet);
-		server->packet_size = 0;
-	}
-	server->packet = smb_vmalloc(max_xmit);
-
-	if (server->packet == NULL)
-	{
-		printk("smb_proc_connect: No memory! Bailing out.\n");
-		result = -ENOMEM;
-		goto fail;
-	}
-	server->packet_size = server->max_xmit = max_xmit;
-
-	/*
-	 * Start with an RFC1002 session request packet.
-	 */
-	p = server->packet + 4;
-
-	p = smb_name_mangle(p, server->m.server_name);
-	p = smb_name_mangle(p, server->m.client_name);
-
-	smb_encode_smb_length(server->packet,
-			      (void *) p - (void *) (server->packet));
-
-	server->packet[0] = 0x81;	/* SESSION REQUEST */
-
-	if (smb_catch_keepalive(server) < 0)
-	{
-		printk("smb_proc_connect: could not catch_keepalives\n");
-	}
-	if ((result = smb_request(server)) < 0)
-	{
-		DPRINTK("smb_proc_connect: Failed to send SESSION REQUEST.\n");
-		smb_dont_catch_keepalive(server);
-		goto fail;
-	}
-	if (server->packet[0] != 0x82)
-	{
-		printk("smb_proc_connect: Did not receive positive response "
-		       "(err = %x)\n",
-		       server->packet[0]);
-		smb_dont_catch_keepalive(server);
-		result = -EIO;
-		goto fail;
-	}
-	DPRINTK("smb_proc_connect: Passed SESSION REQUEST.\n");
-
-	/* Now we are ready to send a SMB Negotiate Protocol packet. */
-	memset(server->packet, 0, SMB_HEADER_LEN);
-
-	plength = 0;
-	for (i = 0; prots[i].name != NULL; i++)
-	{
-		plength += strlen(prots[i].name) + 2;
-	}
-
-	smb_setup_header(server, SMBnegprot, 0, plength);
-
-	p = SMB_BUF(server->packet);
-
-	for (i = 0; prots[i].name != NULL; i++)
-	{
-		*p++ = 2;
-		strcpy(p, prots[i].name);
-		p += strlen(prots[i].name) + 1;
-	}
-
-	if ((result = smb_request_ok(server, SMBnegprot, 1, -1)) < 0)
-	{
-		DPRINTK("smb_proc_connect: Failure requesting SMBnegprot\n");
-		smb_dont_catch_keepalive(server);
-		goto fail;
-	} else
-	{
-		DDPRINTK("smb_proc_connect: Request SMBnegprot..");
-	}
-
-	DDPRINTK("Verified!\n");
-
-	p = SMB_VWV(server->packet);
-	p = smb_decode_word(p, (word *) & i);
-	server->protocol = prots[i].prot;
-
-	DPRINTK("smb_proc_connect: Server wants %s protocol.\n",
-		prots[i].name);
-
-	if (server->protocol >= PROTOCOL_LANMAN1)
-	{
-
-		word passlen = strlen(server->m.password);
-		word userlen = strlen(server->m.username);
-
-		DPRINTK("smb_proc_connect: password = %s\n",
-			server->m.password);
-		DPRINTK("smb_proc_connect: usernam = %s\n",
-			server->m.username);
-		DPRINTK("smb_proc_connect: blkmode = %d\n",
-			WVAL(server->packet, smb_vwv5));
-
-		if (server->protocol >= PROTOCOL_NT1)
-		{
-			server->max_xmit = DVAL(server->packet, smb_vwv3 + 1);
-			server->maxmux = WVAL(server->packet, smb_vwv1 + 1);
-			server->maxvcs = WVAL(server->packet, smb_vwv2 + 1);
-			server->blkmode = DVAL(server->packet, smb_vwv9 + 1);
-			server->sesskey = DVAL(server->packet, smb_vwv7 + 1);
-		} else
-		{
-			server->max_xmit = WVAL(server->packet, smb_vwv2);
-			server->maxmux = WVAL(server->packet, smb_vwv3);
-			server->maxvcs = WVAL(server->packet, smb_vwv4);
-			server->blkmode = WVAL(server->packet, smb_vwv5);
-			server->sesskey = DVAL(server->packet, smb_vwv6);
-		}
-
-		if (server->max_xmit < given_max_xmit)
-		{
-			/* We do not distinguish between the client
-			   requests and the server response. */
-			given_max_xmit = server->max_xmit;
-		}
-		if (server->protocol >= PROTOCOL_NT1)
-		{
-			char *workgroup = server->m.domain;
-			char *OS_id = "Unix";
-			char *client_id = "ksmbfs";
-
-			smb_setup_header(server, SMBsesssetupX, 13,
-					 5 + userlen + passlen +
-					 strlen(workgroup) + strlen(OS_id) +
-					 strlen(client_id));
-
-			WSET(server->packet, smb_vwv0, 0x00ff);
-			WSET(server->packet, smb_vwv1, 0);
-			WSET(server->packet, smb_vwv2, given_max_xmit);
-			WSET(server->packet, smb_vwv3, 2);
-			WSET(server->packet, smb_vwv4, server->pid);
-			DSET(server->packet, smb_vwv5, server->sesskey);
-			WSET(server->packet, smb_vwv7, passlen + 1);
-			WSET(server->packet, smb_vwv8, 0);
-			WSET(server->packet, smb_vwv9, 0);
-
-			p = SMB_BUF(server->packet);
-			strcpy(p, server->m.password);
-			p += passlen + 1;
-			strcpy(p, server->m.username);
-			p += userlen + 1;
-			strcpy(p, workgroup);
-			p += strlen(p) + 1;
-			strcpy(p, OS_id);
-			p += strlen(p) + 1;
-			strcpy(p, client_id);
-		} else
-		{
-			smb_setup_header(server, SMBsesssetupX, 10,
-					 2 + userlen + passlen);
-
-			WSET(server->packet, smb_vwv0, 0x00ff);
-			WSET(server->packet, smb_vwv1, 0);
-			WSET(server->packet, smb_vwv2, given_max_xmit);
-			WSET(server->packet, smb_vwv3, 2);
-			WSET(server->packet, smb_vwv4, server->pid);
-			DSET(server->packet, smb_vwv5, server->sesskey);
-			WSET(server->packet, smb_vwv7, passlen + 1);
-			WSET(server->packet, smb_vwv8, 0);
-			WSET(server->packet, smb_vwv9, 0);
-
-			p = SMB_BUF(server->packet);
-			strcpy(p, server->m.password);
-			p += passlen + 1;
-			strcpy(p, server->m.username);
-		}
-
-		if ((result = smb_request_ok(server, SMBsesssetupX, 3, 0)) < 0)
-		{
-			DPRINTK("smb_proc_connect: SMBsessetupX failed\n");
-			smb_dont_catch_keepalive(server);
-			goto fail;
-		}
-		smb_decode_word(server->packet + 32, &(server->server_uid));
-	} else
-	{
-		server->max_xmit = 0;
-		server->maxmux = 0;
-		server->maxvcs = 0;
-		server->blkmode = 0;
-		server->sesskey = 0;
-	}
-
-	/* Fine! We have a connection, send a tcon message. */
-
-	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));
-	p = smb_encode_ascii(p, dev, strlen(dev));
-
-	if ((result = smb_request_ok(server, SMBtcon, 2, 0)) < 0)
-	{
-		DPRINTK("smb_proc_connect: SMBtcon not verified.\n");
-		smb_dont_catch_keepalive(server);
-		goto fail;
-	}
-	DDPRINTK("OK! Managed to set up SMBtcon!\n");
-
-	p = SMB_VWV(server->packet);
-
-	if (server->protocol <= PROTOCOL_COREPLUS)
-	{
-		word max_xmit;
-
-		p = smb_decode_word(p, &max_xmit);
-		server->max_xmit = max_xmit;
-
-		if (server->max_xmit > given_max_xmit)
-		{
-			server->max_xmit = given_max_xmit;
-		}
-	} else
-	{
-		p += 2;
-	}
-
-	p = smb_decode_word(p, &server->tid);
-
-	/* Ok, everything is fine. max_xmit does not include */
-	/* the TCP-SMB header of 4 bytes. */
-	server->max_xmit += 4;
-
-	DPRINTK("max_xmit = %d, tid = %d\n", server->max_xmit, server->tid);
-
-	/* Now make a new packet with the correct size. */
-	smb_vfree(server->packet);
-
-	server->packet = smb_vmalloc(server->max_xmit);
-	if (server->packet == NULL)
-	{
-		printk("smb_proc_connect: No memory left in end of "
-		       "connection phase :-(\n");
-		smb_dont_catch_keepalive(server);
-		goto fail;
-	}
-	server->packet_size = server->max_xmit;
-
-	DPRINTK("smb_proc_connect: Normal exit\n");
-	return 0;
-
-      fail:
-	server->state = CONN_INVALID;
-	return result;
-}
-
-/* smb_proc_reconnect: server->packet is allocated with
-   server->max_xmit bytes if and only if we return >= 0 */
 int
-smb_proc_connect(struct smb_server *server)
+smb_proc_disconnect(struct smb_sb_info *server)
 {
 	int result;
 	smb_lock_server(server);
-
-	result = smb_proc_reconnect(server);
-
-	if ((result < 0) && (server->packet != NULL))
-	{
-		smb_vfree(server->packet);
-		server->packet = NULL;
-	}
+	smb_setup_header(server, SMBtdis, 0, 0);
+	result = smb_request_ok(server, SMBtdis, 0, 0);
 	smb_unlock_server(server);
 	return result;
-}
-
-int
-smb_proc_disconnect(struct smb_server *server)
-{
-	smb_setup_header_exclusive(server, SMBtdis, 0, 0);
-	return smb_request_ok_unlock(server, SMBtdis, 0, 0);
 }
diff -u --recursive --new-file v2.1.51/linux/fs/smbfs/sock.c linux/fs/smbfs/sock.c
--- v2.1.51/linux/fs/smbfs/sock.c	Mon Aug 18 18:19:46 1997
+++ linux/fs/smbfs/sock.c	Fri Aug 22 10:04:33 1997
@@ -2,6 +2,7 @@
  *  sock.c
  *
  *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1997 by Volker Lendecke
  *
  */
 
@@ -99,8 +100,7 @@
 			result = _recvfrom(sock, (void *) peek_buf, 4,
 					   MSG_DONTWAIT);
 
-			DDPRINTK("smb_data_callback:"
-				 " got SESSION KEEP ALIVE\n");
+			pr_debug("smb_data_callback: got SESSION KEEPALIVE\n");
 
 			if (result == -EAGAIN)
 			{
@@ -119,7 +119,7 @@
 }
 
 int
-smb_catch_keepalive(struct smb_server *server)
+smb_catch_keepalive(struct smb_sb_info *server)
 {
 	struct file *file;
 	struct inode *inode;
@@ -131,7 +131,7 @@
 	    || ((inode = file->f_dentry->d_inode) == NULL)
 	    || (!S_ISSOCK(inode->i_mode)))
 	{
-		printk("smb_catch_keepalive: did not get valid server!\n");
+		pr_debug("smb_catch_keepalive: did not get valid server!\n");
 		server->data_ready = NULL;
 		return -EINVAL;
 	}
@@ -139,7 +139,7 @@
 
 	if (sock->type != SOCK_STREAM)
 	{
-		printk("smb_catch_keepalive: did not get SOCK_STREAM\n");
+		pr_debug("smb_catch_keepalive: did not get SOCK_STREAM\n");
 		server->data_ready = NULL;
 		return -EINVAL;
 	}
@@ -147,17 +147,17 @@
 
 	if (sk == NULL)
 	{
-		printk("smb_catch_keepalive: sk == NULL");
+		pr_debug("smb_catch_keepalive: sk == NULL");
 		server->data_ready = NULL;
 		return -EINVAL;
 	}
-	DDPRINTK("smb_catch_keepalive.: sk->d_r = %x, server->d_r = %x\n",
+	pr_debug("smb_catch_keepalive.: sk->d_r = %x, server->d_r = %x\n",
 		 (unsigned int) (sk->data_ready),
 		 (unsigned int) (server->data_ready));
 
 	if (sk->data_ready == smb_data_callback)
 	{
-		printk("smb_catch_keepalive: already done\n");
+		printk(KERN_ERR "smb_catch_keepalive: already done\n");
 		return -EINVAL;
 	}
 	server->data_ready = sk->data_ready;
@@ -166,7 +166,7 @@
 }
 
 int
-smb_dont_catch_keepalive(struct smb_server *server)
+smb_dont_catch_keepalive(struct smb_sb_info *server)
 {
 	struct file *file;
 	struct inode *inode;
@@ -208,7 +208,7 @@
 		       "sk->data_callback != smb_data_callback\n");
 		return -EINVAL;
 	}
-	DDPRINTK("smb_dont_catch_keepalive: sk->d_r = %x, server->d_r = %x\n",
+	pr_debug("smb_dont_catch_keepalive: sk->d_r = %x, server->d_r = %x\n",
 		 (unsigned int) (sk->data_ready),
 		 (unsigned int) (server->data_ready));
 
@@ -235,8 +235,8 @@
 		}
 		if (result < 0)
 		{
-			DPRINTK("smb_send_raw: sendto error = %d\n",
-				-result);
+			pr_debug("smb_send_raw: sendto error = %d\n",
+				 -result);
 			return result;
 		}
 		already_sent += result;
@@ -262,8 +262,8 @@
 		}
 		if (result < 0)
 		{
-			DPRINTK("smb_receive_raw: recvfrom error = %d\n",
-				-result);
+			pr_debug("smb_receive_raw: recvfrom error = %d\n",
+				 -result);
 			return result;
 		}
 		already_read += result;
@@ -286,7 +286,7 @@
 
 	if (result < 0)
 	{
-		DPRINTK("smb_get_length: recv error = %d\n", -result);
+		pr_debug("smb_get_length: recv error = %d\n", -result);
 		return result;
 	}
 	switch (peek_buf[0])
@@ -296,11 +296,11 @@
 		break;
 
 	case 0x85:
-		DPRINTK("smb_get_length: Got SESSION KEEP ALIVE\n");
+		pr_debug("smb_get_length: Got SESSION KEEP ALIVE\n");
 		goto re_recv;
 
 	default:
-		printk("smb_get_length: Invalid NBT packet\n");
+		pr_debug("smb_get_length: Invalid NBT packet\n");
 		return -EIO;
 	}
 
@@ -313,7 +313,7 @@
 }
 
 static struct socket *
-server_sock(struct smb_server *server)
+server_sock(struct smb_sb_info *server)
 {
 	struct file *file;
 	struct inode *inode;
@@ -332,7 +332,7 @@
  * fs points to the correct segment
  */
 static int
-smb_receive(struct smb_server *server)
+smb_receive(struct smb_sb_info *server)
 {
 	struct socket *sock = server_sock(server);
 	int len;
@@ -349,7 +349,7 @@
 	{
 		/* Some servers do not care about our max_xmit. They
 		   send larger packets */
-		DPRINTK("smb_receive: Increase packet size from %d to %d\n",
+		pr_debug("smb_receive: Increase packet size from %d to %d\n",
 			server->packet_size, len + 4);
 		smb_vfree(server->packet);
 		server->packet_size = 0;
@@ -365,22 +365,22 @@
 
 	if (result < 0)
 	{
-		printk("smb_receive: receive error: %d\n", result);
+		pr_debug("smb_receive: receive error: %d\n", result);
 		return result;
 	}
-	server->rcls = BVAL(server->packet, 9);
+	server->rcls = *(server->packet+9);
 	server->err = WVAL(server->packet, 11);
 
 	if (server->rcls != 0)
 	{
-		DPRINTK("smb_receive: rcls=%d, err=%d\n",
-			server->rcls, server->err);
+		pr_debug("smb_receive: rcls=%d, err=%d\n",
+			 server->rcls, server->err);
 	}
 	return result;
 }
 
 static int
-smb_receive_trans2(struct smb_server *server,
+smb_receive_trans2(struct smb_sb_info *server,
 		   int *ldata, unsigned char **data,
 		   int *lparam, unsigned char **param)
 {
@@ -405,12 +405,12 @@
 	total_data = WVAL(server->packet, smb_tdrcnt);
 	total_param = WVAL(server->packet, smb_tprcnt);
 
-	DDPRINTK("smb_receive_trans2: td=%d,tp=%d\n", total_data, total_param);
+	pr_debug("smb_receive_trans2: td=%d,tp=%d\n", total_data, total_param);
 
 	if ((total_data > TRANS2_MAX_TRANSFER)
 	    || (total_param > TRANS2_MAX_TRANSFER))
 	{
-		DPRINTK("smb_receive_trans2: data/param too long\n");
+		pr_debug("smb_receive_trans2: data/param too long\n");
 		return -EIO;
 	}
 	buf_len = total_data + total_param;
@@ -420,7 +420,7 @@
 	}
 	if ((rcv_buf = smb_vmalloc(buf_len)) == NULL)
 	{
-		DPRINTK("smb_receive_trans2: could not alloc data area\n");
+		pr_debug("smb_receive_trans2: could not alloc data area\n");
 		return -ENOMEM;
 	}
 	*param = rcv_buf;
@@ -433,7 +433,7 @@
 		if (WVAL(inbuf, smb_prdisp) + WVAL(inbuf, smb_prcnt)
 		    > total_param)
 		{
-			DPRINTK("smb_receive_trans2: invalid parameters\n");
+			pr_debug("smb_receive_trans2: invalid parameters\n");
 			result = -EIO;
 			goto fail;
 		}
@@ -445,14 +445,11 @@
 		if (WVAL(inbuf, smb_drdisp) + WVAL(inbuf, smb_drcnt)
 		    > total_data)
 		{
-			DPRINTK("smb_receive_trans2: invalid data block\n");
+			pr_debug("smb_receive_trans2: invalid data block\n");
 			result = -EIO;
 			goto fail;
 		}
-		DDPRINTK("target: %X\n", *data + WVAL(inbuf, smb_drdisp));
-		DDPRINTK("source: %X\n",
-			 smb_base(inbuf) + WVAL(inbuf, smb_droff));
-		DDPRINTK("disp: %d, off: %d, cnt: %d\n",
+		pr_debug("disp: %d, off: %d, cnt: %d\n",
 			 WVAL(inbuf, smb_drdisp), WVAL(inbuf, smb_droff),
 			 WVAL(inbuf, smb_drcnt));
 
@@ -464,7 +461,7 @@
 		if ((WVAL(inbuf, smb_tdrcnt) > total_data)
 		    || (WVAL(inbuf, smb_tprcnt) > total_param))
 		{
-			printk("smb_receive_trans2: data/params grew!\n");
+			pr_debug("smb_receive_trans2: data/params grew!\n");
 			result = -EIO;
 			goto fail;
 		}
@@ -499,50 +496,8 @@
 	return result;
 }
 
-extern struct net_proto_family inet_family_ops;
-
-int
-smb_release(struct smb_server *server)
-{
-	struct socket *sock = server_sock(server);
-	int result;
-
-	if (sock == NULL)
-	{
-		return -EINVAL;
-	}
-	result = sock->ops->release(sock, NULL);
-	DPRINTK("smb_release: sock->ops->release = %d\n", result);
-
-	/* inet_release does not set sock->state.  Maybe someone is
-	   confused about sock->state being SS_CONNECTED while there
-	   is nothing behind it, so I set it to SS_UNCONNECTED. */
-	sock->state = SS_UNCONNECTED;
-
-	result = inet_family_ops.create(sock, 0);
-	DPRINTK("smb_release: inet_create = %d\n", result);
-	return result;
-}
-
-int
-smb_connect(struct smb_server *server)
-{
-	struct socket *sock = server_sock(server);
-	if (sock == NULL)
-	{
-		return -EINVAL;
-	}
-	if (sock->state != SS_UNCONNECTED)
-	{
-		DPRINTK("smb_connect: socket is not unconnected: %d\n",
-			sock->state);
-	}
-	return sock->ops->connect(sock, (struct sockaddr *) &(server->m.addr),
-				  sizeof(struct sockaddr_in), 0);
-}
-
 int
-smb_request(struct smb_server *server)
+smb_request(struct smb_sb_info *server)
 {
 	unsigned long old_mask;
 	unsigned short fs;
@@ -552,7 +507,7 @@
 
 	if (buffer == NULL)
 	{
-		printk("smb_request: Bad server!\n");
+		pr_debug("smb_request: Bad server!\n");
 		return -EBADF;
 	}
 	if (server->state != CONN_VALID)
@@ -562,12 +517,12 @@
 	if ((result = smb_dont_catch_keepalive(server)) != 0)
 	{
 		server->state = CONN_INVALID;
-		smb_invalidate_all_inodes(server);
+		smb_invalidate_inodes(server);
 		return result;
 	}
 	len = smb_len(buffer) + 4;
 
-	DDPRINTK("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]);
+	pr_debug("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]);
 
 	old_mask = current->blocked;
 	current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
@@ -595,16 +550,16 @@
 	if (result < 0)
 	{
 		server->state = CONN_INVALID;
-		smb_invalidate_all_inodes(server);
+		smb_invalidate_inodes(server);
 	}
-	DDPRINTK("smb_request: result = %d\n", result);
+	pr_debug("smb_request: result = %d\n", result);
 
 	return result;
 }
 
 #define ROUND_UP(x) (((x)+3) & ~3)
 static int
-smb_send_trans2(struct smb_server *server, __u16 trans2_command,
+smb_send_trans2(struct smb_sb_info *server, __u16 trans2_command,
 		int ldata, unsigned char *data,
 		int lparam, unsigned char *param)
 {
@@ -632,7 +587,7 @@
 	struct iovec iov[4];
 	struct msghdr msg;
 
-	if ((bcc + oparam) > server->max_xmit)
+	if ((bcc + oparam) > server->opt.max_xmit)
 	{
 		return -ENOMEM;
 	}
@@ -687,7 +642,7 @@
  * one packet to send.
  */
 int
-smb_trans2_request(struct smb_server *server, __u16 trans2_command,
+smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,
 		   int ldata, unsigned char *data,
 		   int lparam, unsigned char *param,
 		   int *lrdata, unsigned char **rdata,
@@ -697,7 +652,7 @@
 	unsigned short fs;
 	int result;
 
-	DDPRINTK("smb_trans2_request: com=%d, ld=%d, lp=%d\n",
+	pr_debug("smb_trans2_request: com=%d, ld=%d, lp=%d\n",
 		 trans2_command, ldata, lparam);
 
 	if (server->state != CONN_VALID)
@@ -707,7 +662,7 @@
 	if ((result = smb_dont_catch_keepalive(server)) != 0)
 	{
 		server->state = CONN_INVALID;
-		smb_invalidate_all_inodes(server);
+		smb_invalidate_inodes(server);
 		return result;
 	}
 	old_mask = current->blocked;
@@ -738,9 +693,9 @@
 	if (result < 0)
 	{
 		server->state = CONN_INVALID;
-		smb_invalidate_all_inodes(server);
+		smb_invalidate_inodes(server);
 	}
-	DDPRINTK("smb_trans2_request: result = %d\n", result);
+	pr_debug("smb_trans2_request: result = %d\n", result);
 
 	return result;
 }
diff -u --recursive --new-file v2.1.51/linux/fs/super.c linux/fs/super.c
--- v2.1.51/linux/fs/super.c	Mon Aug 18 18:19:46 1997
+++ linux/fs/super.c	Mon Sep  1 12:24:18 1997
@@ -553,7 +553,7 @@
 static int d_umount(struct super_block * sb)
 {
 	struct dentry * root = sb->s_root;
-	struct dentry * covers = root->d_covers;
+	struct dentry * covered = root->d_covers;
 
 	if (root->d_count != 1)
 		return -EBUSY;
@@ -563,22 +563,23 @@
 
 	sb->s_root = NULL;
 
-	covers->d_mounts = covers;
-	root->d_covers = root;
-
-	dput(covers);
+	if (covered != root) {
+		root->d_covers = root;
+		covered->d_mounts = covered;
+		dput(covered);
+	}
 	dput(root);
 	return 0;
 }
 
-static void d_mount(struct dentry *covers, struct dentry *dentry)
+static void d_mount(struct dentry *covered, struct dentry *dentry)
 {
-	if (covers->d_mounts != covers) {
+	if (covered->d_mounts != covered) {
 		printk("VFS: mount - already mounted\n");
 		return;
 	}
-	covers->d_mounts = dentry;
-	dentry->d_covers = covers;
+	covered->d_mounts = dentry;
+	dentry->d_covers = covered;
 }
 
 static int do_umount(kdev_t dev,int unmount_root)
@@ -1124,6 +1125,15 @@
 	}
 	ROOT_DEV = new_root_dev;
 	do_mount_root();
+	dput(old_root);
+	dput(old_pwd);
+#if 1
+	shrink_dcache();
+	printk("do_change_root: old root has d_count=%d\n", old_root->d_count);
+#endif
+	/*
+	 * Get the new mount directory
+	 */
 	dir_d = lookup_dentry(put_old, NULL, 1);
 	if (IS_ERR(dir_d)) {
 		error = PTR_ERR(dir_d);
@@ -1141,20 +1151,18 @@
 		dput(dir_d);
 		error = -ENOTDIR;
 	}
-	printk("do_change_root: old root d_count=%d\n", old_root->d_count);
-	dput(old_root);
-	dput(old_pwd);
 	if (error) {
 		int umount_error;
 
 		printk(KERN_NOTICE "Trying to unmount old root ... ");
 		umount_error = do_umount(old_root_dev,1);
-		if (umount_error) printk(KERN_ERR "error %d\n",umount_error);
-		else {
+		if (!umount_error) {
 			printk("okay\n");
 			invalidate_buffers(old_root_dev);
+			return 0;
 		}
-		return umount_error ? error : 0;
+		printk(KERN_ERR "error %d\n",umount_error);
+		return error;
 	}
 	remove_vfsmnt(old_root_dev);
 	vfsmnt = add_vfsmnt(old_root_dev,"/dev/root.old",put_old);
@@ -1165,7 +1173,6 @@
 		return 0;
 	}
 	printk(KERN_CRIT "Trouble: add_vfsmnt failed\n");
-	dput(old_root);
 	return -ENOMEM;
 }
 
diff -u --recursive --new-file v2.1.51/linux/include/asm-i386/string.h linux/include/asm-i386/string.h
--- v2.1.51/linux/include/asm-i386/string.h	Thu Jun 12 15:28:32 1997
+++ linux/include/asm-i386/string.h	Wed Aug 27 18:32:47 1997
@@ -23,7 +23,8 @@
  * set, making the functions fast and clean. String instructions have been
  * used through-out, making for "slightly" unclear code :-)
  *
- *		Copyright (C) 1991, 1992 Linus Torvalds
+ *		NO Copyright (C) 1991, 1992 Linus Torvalds,
+ *		consider these trivial functions to be PD.
  */
 
 #define __HAVE_ARCH_STRCPY
diff -u --recursive --new-file v2.1.51/linux/include/linux/dcache.h linux/include/linux/dcache.h
--- v2.1.51/linux/include/linux/dcache.h	Mon Aug 18 18:19:47 1997
+++ linux/include/linux/dcache.h	Sat Aug 23 16:47:12 1997
@@ -46,7 +46,6 @@
 	struct dentry * d_mounts;	/* mount information */
 	struct dentry * d_covers;
 	struct list_head d_hash;	/* lookup hash list */
-	struct list_head d_alias;	/* inode alias list */
 	struct list_head d_lru;		/* d_count = 0 LRU list */
 	struct qstr d_name;
 	unsigned long d_time;		/* used by d_revalidate */
@@ -57,6 +56,7 @@
 	int (*d_revalidate)(struct dentry *);
 	int (*d_hash) (struct dentry *,struct qstr *);
 	int (*d_compare) (struct dentry *,struct qstr *, struct qstr *);
+	void (*d_delete)(struct dentry *);
 };
 
 /* the dentry parameter passed to d_hash and d_compare is the parent
@@ -70,6 +70,10 @@
 
 /* d_flags entries */
 #define DCACHE_AUTOFS_PENDING 0x0001    /* autofs: "under construction" */
+#define DCACHE_NFSFS_RENAMED  0x0002    /* this dentry has been "silly
+					 * renamed" and has to be
+					 * deleted on the last dput()
+					 */
 
 /*
  * d_drop() unhashes the entry from the parent
@@ -132,13 +136,5 @@
 }
 
 extern void dput(struct dentry *);
-
-/*
- * This is ugly. The inode:dentry relationship is a 1:n
- * relationship, so we have to return one (random) dentry
- * from the alias list. We select the first one..
- */
-#define i_dentry(inode) \
-	list_entry((inode)->i_dentry.next, struct dentry, d_alias)
 
 #endif	/* __LINUX_DCACHE_H */
diff -u --recursive --new-file v2.1.51/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.1.51/linux/include/linux/fs.h	Mon Aug 18 18:19:47 1997
+++ linux/include/linux/fs.h	Mon Sep  1 12:43:13 1997
@@ -250,6 +250,7 @@
 #include <linux/affs_fs_i.h>
 #include <linux/ufs_fs_i.h>
 #include <linux/romfs_fs_i.h>
+#include <linux/smb_fs_i.h>
 
 /*
  * Attribute flags.  These should be or-ed together to figure out what
@@ -327,8 +328,6 @@
 	struct page		*i_pages;
 	struct dquot		*i_dquot[MAXQUOTAS];
 
-	struct list_head	i_dentry;
-
 	unsigned long		i_state;
 
 	unsigned int		i_flags;
@@ -350,6 +349,7 @@
 		struct affs_inode_info		affs_i;
 		struct ufs_inode_info		ufs_i;
 		struct romfs_inode_info		romfs_i;
+		struct smb_inode_info		smbfs_i;
 		struct socket			socket_i;
 		void				*generic_ip;
 	} u;
@@ -481,6 +481,7 @@
 #include <linux/affs_fs_sb.h>
 #include <linux/ufs_fs_sb.h>
 #include <linux/romfs_fs_sb.h>
+#include <linux/smb_fs_sb.h>
 
 struct super_block {
 	kdev_t			s_dev;
@@ -514,6 +515,7 @@
 		struct affs_sb_info	affs_sb;
 		struct ufs_sb_info	ufs_sb;
 		struct romfs_sb_info	romfs_sb;
+		struct smb_sb_info	smbfs_sb;
 		void			*generic_sbp;
 	} u;
 };
diff -u --recursive --new-file v2.1.51/linux/include/linux/lp.h linux/include/linux/lp.h
--- v2.1.51/linux/include/linux/lp.h	Sun Jul 27 12:11:01 1997
+++ linux/include/linux/lp.h	Tue Aug 26 14:52:45 1997
@@ -123,6 +123,7 @@
 	unsigned int lastcall;
 	unsigned int runchars;
 	unsigned int waittime;
+	unsigned int should_relinquish;
 	struct lp_stats stats;
 };
 
diff -u --recursive --new-file v2.1.51/linux/include/linux/nfs_fs_i.h linux/include/linux/nfs_fs_i.h
--- v2.1.51/linux/include/linux/nfs_fs_i.h	Thu Jun 12 15:28:32 1997
+++ linux/include/linux/nfs_fs_i.h	Sat Aug 23 16:47:12 1997
@@ -47,13 +47,6 @@
 	unsigned long		attrtimeo;
 
 	/*
-	 * This is to support the clandestine rename on unlink.
-	 * Instead of the directory inode, we might as well keep
-	 * its NFS FH, but that requires a kmalloc.
-	 */
-	struct inode *		silly_inode;
-
-	/*
 	 * This is the list of dirty unwritten pages.
 	 * NFSv3 will want to add a list for written but uncommitted
 	 * pages.
diff -u --recursive --new-file v2.1.51/linux/include/linux/parport.h linux/include/linux/parport.h
--- v2.1.51/linux/include/linux/parport.h	Mon Aug  4 16:25:40 1997
+++ linux/include/linux/parport.h	Mon Sep  1 12:43:52 1997
@@ -81,6 +81,9 @@
 	void (*enable_irq)(struct parport *);
 	void (*disable_irq)(struct parport *);
 	int (*examine_irq)(struct parport *);
+
+	void (*inc_use_count)(void);
+	void (*dec_use_count)(void);
 };
 
 #define PARPORT_CONTROL_STROBE    0x1
diff -u --recursive --new-file v2.1.51/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.1.51/linux/include/linux/sched.h	Mon Aug  4 16:25:40 1997
+++ linux/include/linux/sched.h	Mon Sep  1 12:43:13 1997
@@ -471,6 +471,16 @@
 	return 0;
 }
 
+/*
+ * Routines for handling mm_structs
+ */
+extern struct mm_struct * mm_alloc(void);
+static inline void mmget(struct mm_struct * mm)
+{
+	mm->count++;
+}
+extern void mmput(struct mm_struct *);
+
 extern int  copy_thread(int, unsigned long, unsigned long, struct task_struct *, struct pt_regs *);
 extern void flush_thread(void);
 extern void exit_thread(void);
diff -u --recursive --new-file v2.1.51/linux/include/linux/smb.h linux/include/linux/smb.h
--- v2.1.51/linux/include/linux/smb.h	Sun Dec  1 08:21:33 1996
+++ linux/include/linux/smb.h	Fri Aug 22 10:04:33 1997
@@ -1,119 +1,76 @@
 /*
  *  smb.h
  *
- *  Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1997 by Volker Lendecke
  *
  */
 
 #ifndef _LINUX_SMB_H
 #define _LINUX_SMB_H
 
-#define SMB_PORT 139
-#define SMB_MAXNAMELEN 255
-#define SMB_MAXPATHLEN 1024
-
-#define SMB_DEF_MAX_XMIT 32768
-
-/* Allocate max. 1 page */
-#define TRANS2_MAX_TRANSFER (4096-17)
-
-#include <asm/types.h>
-#ifdef __KERNEL__
-typedef u8  byte;
-typedef u16 word;
-typedef u32 dword;
-#else
-typedef unsigned char byte;
-typedef unsigned short word;
-typedef unsigned long dword;
-#endif
-
-/* The following macros have been taken directly from Samba. Thanks,
-   Andrew! */
-
-#undef CAREFUL_ALIGNMENT
+#include <linux/types.h>
 
-/* we know that the 386 can handle misalignment and has the "right" 
-   byteorder */
-#if defined(__i386__)
-#define CAREFUL_ALIGNMENT 0
-#endif
-
-#ifndef CAREFUL_ALIGNMENT
-#define CAREFUL_ALIGNMENT 1
-#endif
+enum smb_protocol { 
+	SMB_PROTOCOL_NONE, 
+	SMB_PROTOCOL_CORE, 
+	SMB_PROTOCOL_COREPLUS, 
+	SMB_PROTOCOL_LANMAN1, 
+	SMB_PROTOCOL_LANMAN2, 
+	SMB_PROTOCOL_NT1 
+};
 
-#define BVAL(buf,pos) (((u8 *)(buf))[pos])
-#define PVAL(buf,pos) ((unsigned)BVAL(buf,pos))
-#define BSET(buf,pos,val) (BVAL(buf,pos) = (val))
-
-
-#if CAREFUL_ALIGNMENT
-#define WVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
-#define DVAL(buf,pos) (WVAL(buf,pos)|WVAL(buf,(pos)+2)<<16)
-
-#define SSVALX(buf,pos,val) (BVAL(buf,pos)=(val)&0xFF,BVAL(buf,pos+1)=(val)>>8)
-#define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
-#define WSET(buf,pos,val) { word __val = (val); \
-	SSVALX((buf),(pos),((word)(__val))); }
-#define DSET(buf,pos,val) { dword __val = (val); \
-	SIVALX((buf),(pos),((dword)(__val))); }
-#else
-/* this handles things for architectures like the 386 that can handle
-   alignment errors */
-/*
-   WARNING: This section is dependent on the length of word and dword
-   being correct 
-*/
-#define WVAL(buf,pos) (*(word *)((char *)(buf) + (pos)))
-#define DVAL(buf,pos) (*(dword *)((char *)(buf) + (pos)))
-#define WSET(buf,pos,val) WVAL(buf,pos)=((word)(val))
-#define DSET(buf,pos,val) DVAL(buf,pos)=((dword)(val))
-#endif
+enum smb_case_hndl {
+	SMB_CASE_DEFAULT,
+	SMB_CASE_LOWER,
+	SMB_CASE_UPPER
+};
 
+struct smb_dskattr {
+        __u16 total;
+        __u16 allocblocks;
+        __u16 blocksize;
+        __u16 free;
+};
 
-/* where to find the base of the SMB packet proper */
-#define smb_base(buf) ((byte *)(((byte *)(buf))+4))
+struct smb_conn_opt {
 
-#define LANMAN1
-#define LANMAN2
-#define NT1
+        /* The socket */
+	unsigned int fd;
 
-enum smb_protocol { 
-	PROTOCOL_NONE, 
-	PROTOCOL_CORE, 
-	PROTOCOL_COREPLUS, 
-	PROTOCOL_LANMAN1, 
-	PROTOCOL_LANMAN2, 
-	PROTOCOL_NT1 
-};
+	enum smb_protocol protocol;
+	enum smb_case_hndl case_handling;
 
-enum smb_case_hndl {
-	CASE_DEFAULT,
-	CASE_LOWER,
-	CASE_UPPER
+	/* Connection-Options */
+
+	__u32              max_xmit;
+	__u16              server_uid;
+	__u16              tid;
+
+        /* The following are LANMAN 1.0 options */
+        __u16              secmode;
+        __u16              maxmux;
+        __u16              maxvcs;
+        __u16              rawmode;
+        __u32              sesskey;
+
+	/* The following are NT LM 0.12 options */
+	__u32              maxraw;
+	__u32              capabilities;
+	__u16              serverzone;
 };
 
 #ifdef __KERNEL__
 
-enum smb_conn_state {
-        CONN_VALID,             /* everything's fine */
-        CONN_INVALID,           /* Something went wrong, but did not
-                                   try to reconnect yet. */
-        CONN_RETRIED            /* Tried a reconnection, but was refused */
-};
-
-struct smb_dskattr {
-        word total;
-        word allocblocks;
-        word blocksize;
-        word free;
-};
+#define SMB_MAXNAMELEN 255
+#define SMB_MAXPATHLEN 1024
 
 /*
  * Contains all relevant data on a SMB networked file.
  */
-struct smb_dirent {
+struct smb_fattr {
+
+	__u16 attr;
 
 	unsigned long	f_ino;
 	umode_t		f_mode;
@@ -127,16 +84,40 @@
 	time_t		f_ctime;
 	unsigned long	f_blksize;
 	unsigned long	f_blocks;
-	
-        int             opened; /* is it open on the fileserver? */
-	word            fileid;	/* What id to handle a file with? */
-	word            attr;	/* Attribute fields, DOS value */
-
-	unsigned short  access;	/* Access bits. */
-        unsigned long   f_pos;	/* File position. (For readdir.) */
-	unsigned char   name[SMB_MAXNAMELEN+1];
-	int             len;	/* namelength */
 };
 
-#endif  /* __KERNEL__ */
-#endif  /* _LINUX_SMB_H */
+struct smb_dirent {
+	struct smb_fattr attr;
+
+	int f_pos;
+	int len;
+	__u8 name[SMB_MAXNAMELEN];
+};
+
+enum smb_conn_state {
+        CONN_VALID,             /* everything's fine */
+        CONN_INVALID,           /* Something went wrong, but did not
+                                   try to reconnect yet. */
+        CONN_RETRIED            /* Tried a reconnection, but was refused */
+};
+
+/*
+ * The readdir cache size controls how many directory entries are cached.
+ */
+#define SMB_READDIR_CACHE_SIZE        64
+
+#define SMB_SUPER_MAGIC               0x517B
+
+#define SMB_SERVER(inode)    (&(inode->i_sb->u.smbfs_sb))
+#define SMB_INOP(inode)      (&(inode->u.smbfs_i))
+
+#define SMB_HEADER_LEN   37     /* includes everything up to, but not
+                                 * including smb_bcc */
+#define SMB_DEF_MAX_XMIT 32768
+#define SMB_INITIAL_PACKET_SIZE 4000
+
+/* Allocate max. 1 page */
+#define TRANS2_MAX_TRANSFER (4096-17)
+
+#endif
+#endif
diff -u --recursive --new-file v2.1.51/linux/include/linux/smb_fs.h linux/include/linux/smb_fs.h
--- v2.1.51/linux/include/linux/smb_fs.h	Mon Jul  7 16:04:00 1997
+++ linux/include/linux/smb_fs.h	Mon Sep  1 12:44:45 1997
@@ -2,6 +2,7 @@
  *  smb_fs.h
  *
  *  Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1997 by Volker Lendecke
  *
  */
 
@@ -9,72 +10,37 @@
 #define _LINUX_SMB_FS_H
 
 #include <linux/smb.h>
-#include <linux/fs.h>
-#include <linux/in.h>
-#include <linux/types.h>
-#include <linux/vmalloc.h>
-
-#include <linux/smb_mount.h>
-#include <linux/smb_fs_sb.h>
-#include <linux/smb_fs_i.h>
 
 /*
  * ioctl commands
  */
 #define	SMB_IOC_GETMOUNTUID		_IOR('u', 1, uid_t)
+#define SMB_IOC_NEWCONN                 _IOW('u', 2, struct smb_conn_opt)
 
 #ifdef __KERNEL__
 
-/*
- * The readdir cache size controls how many directory entries are cached.
- */
-#define SMB_READDIR_CACHE_SIZE        64
-
-/*
- * This defines the number of filenames cached in memory to avoid 
- * constructing filenames from \
- */
-#define SMB_CACHE_TABLE_SIZE          64
-
-#define SMB_SUPER_MAGIC               0x517B
+#include <asm/unaligned.h>
 
+#define WVAL(buf,pos) \
+(le16_to_cpu(get_unaligned((__u16 *)((__u8 *)(buf) + (pos)))))
+#define DVAL(buf,pos) \
+(le32_to_cpu(get_unaligned((__u32 *)((__u8 *)(buf) + (pos)))))
+#define WSET(buf,pos,val) \
+put_unaligned(cpu_to_le16((__u16)(val)), (__u16 *)((__u8 *)(buf) + (pos)))
+#define DSET(buf,pos,val) \
+put_unaligned(cpu_to_le32((__u32)(val)), (__u32 *)((__u8 *)(buf) + (pos)))
 
+/* where to find the base of the SMB packet proper */
+#define smb_base(buf) ((__u8 *)(((__u8 *)(buf))+4))
 
-#define SMB_SBP(sb)          ((struct smb_sb_info *)(sb->u.generic_sbp))
-#define SMB_INOP(inode)      ((struct smb_inode_info *)(inode->u.generic_ip))
-
-#define SMB_SERVER(inode)    (&(SMB_SBP(inode->i_sb)->s_server))
-#define SMB_SERVATTR(inode)  (&(SMB_SBP(inode->i_sb)->s_attr))
-
-#define SMB_FINFO(inode)     (&(SMB_INOP(inode)->finfo))
-
-#define SMB_HEADER_LEN   37     /* includes everything up to, but not
-                                 * including smb_bcc */
+#include <linux/vmalloc.h>
 
 #ifdef DEBUG_SMB_MALLOC
 
-#include <linux/malloc.h>
-
 extern int smb_malloced;
-extern int smb_current_kmalloced;
 extern int smb_current_vmalloced;
 
 static inline void *
-smb_kmalloc(unsigned int size, int priority)
-{
-        smb_malloced += 1;
-        smb_current_kmalloced += 1;
-        return kmalloc(size, priority);
-}
-
-static inline void
-smb_kfree_s(void *obj, int size)
-{
-        smb_current_kmalloced -= 1;
-        kfree_s(obj, size);
-}
-
-static inline void *
 smb_vmalloc(unsigned int size)
 {
         smb_malloced += 1;
@@ -98,47 +64,20 @@
 
 #endif /* DEBUG_SMB_MALLOC */
 
-#if DEBUG_SMB > 0
-#define DPRINTK(format, args...) printk(format , ## args)
-#else
-#define DPRINTK(format, args...)
-#endif
-
-#if DEBUG_SMB > 1
-#define DDPRINTK(format, args...) printk(format , ## args)
-#else
-#define DDPRINTK(format, args...)
-#endif
-
-
-static inline ino_t
-smb_info_ino(struct smb_inode_info *info)
-{
-#if 0
-	return (ino_t) info;
-#else
-	if (info != NULL)
-	{
-		return info->finfo.f_ino;
-	}
-	return 1;
-#endif
-}
+struct smb_sb_info;
 
 /* linux/fs/smbfs/file.c */
 extern struct inode_operations smb_file_inode_operations;
-int smb_make_open(struct inode *i, int right);
 
 /* linux/fs/smbfs/dir.c */
 extern struct inode_operations smb_dir_inode_operations;
-struct smb_inode_info *smb_find_inode(struct smb_server *server, ino_t ino);
+struct smb_inode_info *smb_find_inode(struct smb_sb_info *server, ino_t ino);
 void smb_free_inode_info(struct smb_inode_info *i);
-void smb_free_all_inodes(struct smb_server *server);
-void smb_init_root(struct smb_server *server);
-int  smb_stat_root(struct smb_server *server);
+void smb_free_all_inodes(struct smb_sb_info *server);
+void smb_init_root(struct smb_sb_info *server);
+int  smb_stat_root(struct smb_sb_info *server);
 void smb_init_dir_cache(void);
 void smb_invalid_dir_cache(unsigned long ino);
-void smb_invalidate_all_inodes(struct smb_server *server);
 void smb_free_dir_cache(void);
 
 /* linux/fs/smbfs/ioctl.c */
@@ -149,63 +88,63 @@
 struct super_block *smb_read_super(struct super_block *sb,
                                    void *raw_data, int silent);
 extern int init_smb_fs(void);
+void smb_invalidate_inodes(struct smb_sb_info *server);
+int smb_revalidate_inode(struct inode *i);
+int smb_refresh_inode(struct inode *i);
 int smb_notify_change(struct inode *inode, struct iattr *attr);
-void smb_invalidate_connection(struct smb_server *server);
-int smb_conn_is_valid(struct smb_server *server);
+void smb_invalidate_connection(struct smb_sb_info *server);
+int smb_conn_is_valid(struct smb_sb_info *server);
+unsigned long smb_invent_inos(unsigned long n);
+struct inode *smb_iget(struct super_block *, struct smb_fattr *);
 
 /* linux/fs/smbfs/proc.c */
-dword smb_len(unsigned char *packet);
-byte *smb_encode_smb_length(byte *p, dword len);
-__u8 *smb_setup_header(struct smb_server *server, byte command,
-		       word wct, word bcc);
-void smb_init_root_dirent(struct smb_server *server, struct smb_dirent *entry);
-int smb_proc_open(struct smb_server *server,
-		  struct smb_inode_info *dir, const char *name, int len,
-		  struct smb_dirent *entry);
-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, 
-                      off_t offset, long count, char *data);
-int smb_proc_write(struct smb_server *server, struct smb_dirent *finfo,
-		   off_t offset, int count, const char *data);
-int smb_proc_write_raw(struct smb_server *server, struct smb_dirent *finfo, 
-                       off_t offset, long count, const char *data);
-int smb_proc_create(struct inode *dir, const char *name, int len,
-		    word attr, time_t ctime);
-int smb_proc_mv(struct inode *odir, const char *oname, const int olen,
-		struct inode *ndir, const char *nname, const int nlen);
-int smb_proc_mkdir(struct inode *dir, const char *name, const int len);
-int smb_proc_rmdir(struct inode *dir, const char *name, const int len);
-int smb_proc_unlink(struct inode *dir, const char *name, const int len);
-int smb_proc_readdir(struct smb_server *server, struct inode *dir,
+__u32 smb_len(unsigned char *packet);
+__u8 *smb_encode_smb_length(__u8 *p, __u32 len);
+__u8 *smb_setup_header(struct smb_sb_info *server, __u8 command,
+		       __u16 wct, __u16 bcc);
+int smb_offerconn(struct smb_sb_info *server);
+int smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt);
+int smb_close(struct inode *);
+int smb_open(struct inode *, int);
+static inline int
+smb_is_open(struct inode *i)
+{
+	return (i->u.smbfs_i.open == SMB_SERVER(i)->generation);
+}
+
+int smb_proc_read(struct inode *, off_t, long, char *);
+int smb_proc_write(struct inode *, off_t, int, const char *);
+int smb_proc_create(struct inode *, struct qstr *, __u16, time_t);
+int smb_proc_mv(struct inode *, struct qstr *, struct inode *, struct qstr *);
+int smb_proc_mkdir(struct inode *, struct qstr *);
+int smb_proc_rmdir(struct inode *, struct qstr *);
+int smb_proc_unlink(struct inode *dir, struct qstr *);
+int smb_proc_readdir(struct inode *dir,
                      int fpos, int cache_size, 
 		     struct smb_dirent *entry);
-int smb_proc_getattr(struct inode *dir, const char *name, int len,
-		     struct smb_dirent *entry);
-int smb_proc_setattr(struct smb_server *server,
+int smb_proc_getattr(struct inode *dir, struct qstr *name,
+		     struct smb_fattr *entry);
+int smb_proc_setattr(struct smb_sb_info *server,
                      struct inode *ino,
-                     struct smb_dirent *new_finfo);
-int smb_proc_chkpath(struct smb_server *server, char *path, int len,
-                     int *result);
-int smb_proc_dskattr(struct super_block *super, struct smb_dskattr *attr);
-int smb_proc_reconnect(struct smb_server *server);
-int smb_proc_connect(struct smb_server *server);
-int smb_proc_disconnect(struct smb_server *server);
-int smb_proc_trunc(struct smb_server *server, word fid, dword length);
+                     struct smb_fattr *new_finfo);
+int smb_proc_dskattr(struct super_block *sb, struct statfs *attr);
+int smb_proc_reconnect(struct smb_sb_info *server);
+int smb_proc_connect(struct smb_sb_info *server);
+int smb_proc_disconnect(struct smb_sb_info *server);
+int smb_proc_trunc(struct smb_sb_info *server, __u16 fid, __u32 length);
+void smb_init_root_dirent(struct smb_sb_info *server, struct smb_fattr *);
 
 /* linux/fs/smbfs/sock.c */
-int smb_release(struct smb_server *server);
-int smb_connect(struct smb_server *server);
-int smb_request(struct smb_server *server);
-int smb_request_read_raw(struct smb_server *server,
+int smb_release(struct smb_sb_info *server);
+int smb_connect(struct smb_sb_info *server);
+int smb_request(struct smb_sb_info *server);
+int smb_request_read_raw(struct smb_sb_info *server,
                          unsigned char *target, int max_len);
-int smb_request_write_raw(struct smb_server *server,
+int smb_request_write_raw(struct smb_sb_info *server,
                           unsigned const char *source, int length);
-int smb_catch_keepalive(struct smb_server *server);
-int smb_dont_catch_keepalive(struct smb_server *server);
-int smb_trans2_request(struct smb_server *server, __u16 trans2_command,
+int smb_catch_keepalive(struct smb_sb_info *server);
+int smb_dont_catch_keepalive(struct smb_sb_info *server);
+int smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,
 		       int ldata, unsigned char *data,
 		       int lparam, unsigned char *param,
 		       int *lrdata, unsigned char **rdata,
diff -u --recursive --new-file v2.1.51/linux/include/linux/smb_fs_i.h linux/include/linux/smb_fs_i.h
--- v2.1.51/linux/include/linux/smb_fs_i.h	Sun Dec  1 08:59:35 1996
+++ linux/include/linux/smb_fs_i.h	Fri Aug 22 10:04:33 1997
@@ -2,6 +2,7 @@
  *  smb_fs_i.h
  *
  *  Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1997 by Volker Lendecke
  *
  */
 
@@ -9,25 +10,22 @@
 #define _LINUX_SMB_FS_I
 
 #ifdef __KERNEL__
-#include <linux/smb.h>
-
-enum smb_inode_state {
-        SMB_INODE_VALID = 19,	/* Inode currently in use */
-        SMB_INODE_LOOKED_UP,	/* directly before iget */
-        SMB_INODE_CACHED,	/* in a path to an inode which is in use */
-        SMB_INODE_INVALID
-};
+#include <linux/types.h>
 
 /*
  * smb fs inode data (in memory only)
  */
 struct smb_inode_info {
-        enum smb_inode_state state;
-        int nused;              /* for directories:
-                                   number of references in memory */
-        struct smb_inode_info *dir;
-        struct smb_inode_info *next, *prev;
-        struct smb_dirent finfo;
+
+	/*
+	 * file handles are local to a connection. A file is open if
+	 * (open == generation).
+	 */
+        unsigned int open;
+	__u16 fileid;		/* What id to handle a file with? */
+	__u16 attr;		/* Attribute fields, DOS value */
+
+	__u16 access;		/* Access bits. */
 };
 
 #endif
diff -u --recursive --new-file v2.1.51/linux/include/linux/smb_fs_sb.h linux/include/linux/smb_fs_sb.h
--- v2.1.51/linux/include/linux/smb_fs_sb.h	Mon Jul  7 16:04:00 1997
+++ linux/include/linux/smb_fs_sb.h	Fri Aug 22 10:04:33 1997
@@ -2,76 +2,41 @@
  *  smb_fs_sb.h
  *
  *  Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1997 by Volker Lendecke
  *
  */
 
 #ifndef _SMB_FS_SB
 #define _SMB_FS_SB
 
+#ifdef __KERNEL__
+
+#include <linux/types.h>
 #include <linux/smb.h>
-#include <linux/smb_fs_i.h>
 #include <linux/smb_mount.h>
-#include <linux/types.h>
 
-#ifdef __KERNEL__
+struct smb_sb_info {
+        enum smb_conn_state state;
+	struct file * sock_file;
 
-struct smb_server {
-	enum smb_protocol  protocol;       /* The protocol this
-                                              connection accepts. */
-	enum smb_case_hndl case_handling;
-	struct file *      sock_file;	   /* The socket we transfer
-                                              data on. */
-	int                lock;       	   /* To prevent mismatch in
-                                              protocols. */
-	struct wait_queue *wait;
-
-	__u32              max_xmit;
-	char               hostname[256];
-	word               pid;
-	word               server_uid;
-	word               mid;
-	word               tid;
-
-        struct smb_mount_data m; /* We store the complete information here
-                                  * to be able to reconnect.
-                                  */
+        struct smb_mount_data m;
 
-        unsigned short     rcls; /* The error codes we received */
-        unsigned short     err;
+	/* Connections are counted. Each time a new socket arrives,
+	 * generation is incremented.
+	 */
+	unsigned int generation;
+	pid_t conn_pid;
+	struct smb_conn_opt opt;
+
+	struct semaphore sem;
 
 	__u32              packet_size;
 	unsigned char *    packet;
-
-        enum smb_conn_state state;
-        unsigned long reconnect_time; /* The time of the last attempt */
-
-        /* The following are LANMAN 1.0 options transferred to us in
-           SMBnegprot */
-        word   secmode;
-        word   maxmux;
-        word   maxvcs;
-        word   blkmode;
-        dword  sesskey;
+        unsigned short     rcls; /* The error codes we received */
+        unsigned short     err;
 
         /* We use our on data_ready callback, but need the original one */
         void *data_ready;
-
-        /* We do not have unique numbers for files in the smb protocol
-           like NFS-filehandles. (SMB was designed for DOS, not for
-           UNIX!) So we have to create our own inode numbers. We keep
-           a complete path of smb_inode_info's to each active
-           inode. The inode number is then created by the address of
-           this structure. */
-        struct smb_inode_info root;
-};
-
-/*
- * This is the part of the super-block (in memory) for the SMB file system.
- */
-
-struct smb_sb_info {
-	struct smb_server  s_server;
-	struct smb_dskattr s_attr;
 };
 
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.1.51/linux/include/linux/smb_mount.h linux/include/linux/smb_mount.h
--- v2.1.51/linux/include/linux/smb_mount.h	Mon Jul  7 16:03:54 1997
+++ linux/include/linux/smb_mount.h	Fri Aug 22 10:04:33 1997
@@ -2,6 +2,7 @@
  *  smb_mount.h
  *
  *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1997 by Volker Lendecke
  *
  */
 
@@ -9,26 +10,12 @@
 #define _LINUX_SMB_MOUNT_H
 
 #include <linux/types.h>
-#include <linux/in.h>
 
-#define SMB_MOUNT_VERSION 5
+#define SMB_MOUNT_VERSION 6
 
 struct smb_mount_data {
 	int version;
-	unsigned int fd;
         uid_t mounted_uid;      /* Who may umount() this filesystem? */
-	struct sockaddr_in addr;
-
-	char server_name[17];
-        char client_name[17];
-	char service[64];
-        char root_path[64];
-
-        char username[64];
-	char password[64];
-	char domain[64];
-
-	unsigned short max_xmit;
 
         uid_t uid;
         gid_t gid;
diff -u --recursive --new-file v2.1.51/linux/kernel/exit.c linux/kernel/exit.c
--- v2.1.51/linux/kernel/exit.c	Mon Aug  4 16:25:40 1997
+++ linux/kernel/exit.c	Mon Sep  1 12:10:04 1997
@@ -446,13 +446,7 @@
 		tsk->mm = &init_mm;
 		tsk->swappable = 0;
 		SET_PAGE_DIR(tsk, swapper_pg_dir);
-
-		/* free the old state - not used any more */
-		if (!--mm->count) {
-			exit_mmap(mm);
-			free_page_tables(mm);
-			kmem_cache_free(mm_cachep, mm);
-		}
+		mmput(mm);
 	}
 }
 
@@ -504,7 +498,8 @@
 
 		p->p_pptr = p->p_opptr;
 		p->p_osptr = p->p_pptr->p_cptr;
-		p->p_osptr->p_ysptr = p;
+		if (p->p_osptr)
+			p->p_osptr->p_ysptr = p;
 		p->p_pptr->p_cptr = p;
 		if (p->state == TASK_ZOMBIE)
 			notify_parent(p, p->exit_signal);
diff -u --recursive --new-file v2.1.51/linux/kernel/fork.c linux/kernel/fork.c
--- v2.1.51/linux/kernel/fork.c	Mon Aug 18 18:19:47 1997
+++ linux/kernel/fork.c	Mon Sep  1 12:10:04 1997
@@ -258,36 +258,62 @@
 	return 0;
 
 fail_nomem:
-	exit_mmap(mm);
 	flush_tlb_mm(current->mm);
 	return retval;
 }
 
+/*
+ * Allocate and initialize an mm_struct.
+ */
+struct mm_struct * mm_alloc(void)
+{
+	struct mm_struct * mm;
+
+	mm = kmem_cache_alloc(mm_cachep, SLAB_KERNEL);
+	if (mm) {
+		*mm = *current->mm;
+		init_new_context(mm);
+		mm->count = 1;
+		mm->def_flags = 0;
+		mm->mmap_sem = MUTEX;
+		mm->pgd = NULL;
+		mm->mmap = mm->mmap_cache = NULL;
+
+		/* It has not run yet, so cannot be present in anyone's
+		 * cache or tlb.
+		 */
+		mm->cpu_vm_mask = 0;
+	}
+	return mm;
+}
+
+/*
+ * Decrement the use count and release all resources for an mm.
+ */
+void mmput(struct mm_struct *mm)
+{
+	if (!--mm->count) {
+		exit_mmap(mm);
+		free_page_tables(mm);
+		kmem_cache_free(mm_cachep, mm);
+	}
+}
+
 static inline int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
 {
 	struct mm_struct * mm;
 	int retval;
 
 	if (clone_flags & CLONE_VM) {
-		current->mm->count++;
+		mmget(current->mm);
 		SET_PAGE_DIR(tsk, current->mm->pgd);
 		return 0;
 	}
 
 	retval = -ENOMEM;
-	mm = kmem_cache_alloc(mm_cachep, SLAB_KERNEL);
+	mm = mm_alloc();
 	if (!mm)
 		goto fail_nomem;
-	*mm = *current->mm;
-	init_new_context(mm);
-	mm->count = 1;
-	mm->def_flags = 0;
-	mm->mmap_sem = MUTEX;
-
-	/* It has not run yet, so cannot be present in anyone's
-	 * cache or tlb.
-	 */
-	mm->cpu_vm_mask = 0;
 
 	tsk->mm = mm;
 	tsk->min_flt = tsk->maj_flt = 0;
@@ -298,14 +324,12 @@
 		goto free_mm;
 	retval = dup_mmap(mm);
 	if (retval)
-		goto free_pt;
+		goto free_mm;
 	return 0;
 
-free_pt:
-	free_page_tables(mm);
 free_mm:
 	tsk->mm = NULL;
-	kmem_cache_free(mm_cachep, mm);
+	mmput(mm);
 fail_nomem:
 	return retval;
 }
diff -u --recursive --new-file v2.1.51/linux/mm/filemap.c linux/mm/filemap.c
--- v2.1.51/linux/mm/filemap.c	Mon Aug  4 16:25:40 1997
+++ linux/mm/filemap.c	Mon Sep  1 12:27:06 1997
@@ -952,11 +952,14 @@
 	file.f_reada = 0;
 
 	/*
-	 * WSH: could vm_area struct (and inode) be released while writing?
+	 * If a task terminates while we're swapping the page, the vma and
+	 * and dentry could be released ... increment the count to be safe.
 	 */
+	dget(dentry);
 	down(&inode->i_sem);
 	result = do_write_page(inode, &file, (const char *) page, offset);
 	up(&inode->i_sem);
+	dput(dentry);
 	return result;
 }
 
diff -u --recursive --new-file v2.1.51/linux/mm/memory.c linux/mm/memory.c
--- v2.1.51/linux/mm/memory.c	Mon Aug 18 18:19:47 1997
+++ linux/mm/memory.c	Mon Sep  1 12:10:04 1997
@@ -143,8 +143,7 @@
 
 /*
  * This function frees up all page tables of a process when it exits. It
- * is the same as "clear_page_tables()", except it also changes the process'
- * page table directory to the kernel page tables and then frees the old
+ * is the same as "clear_page_tables()", except it also frees the old
  * page table directory.
  */
 void free_page_tables(struct mm_struct * mm)
@@ -153,13 +152,15 @@
 	pgd_t * page_dir;
 
 	page_dir = mm->pgd;
-	if (!page_dir || page_dir == swapper_pg_dir) {
-		printk("Trying to free kernel page-directory: not good\n");
-		return;
+	if (page_dir) {
+		if (page_dir == swapper_pg_dir) {
+			printk("free_page_tables: Trying to free kernel pgd\n");
+			return;
+		}
+		for (i = 0 ; i < USER_PTRS_PER_PGD ; i++)
+			free_one_pgd(page_dir + i);
+		pgd_free(page_dir);
 	}
-	for (i = 0 ; i < USER_PTRS_PER_PGD ; i++)
-		free_one_pgd(page_dir + i);
-	pgd_free(page_dir);
 }
 
 int new_page_tables(struct task_struct * tsk)
diff -u --recursive --new-file v2.1.51/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.1.51/linux/mm/swapfile.c	Thu Jul 17 10:06:09 1997
+++ linux/mm/swapfile.c	Mon Sep  1 12:25:18 1997
@@ -21,6 +21,7 @@
 #include <linux/malloc.h>
 #include <linux/blkdev.h> /* for blk_size */
 #include <linux/vmalloc.h>
+#include <linux/dcache.h>
 
 #include <asm/dma.h>
 #include <asm/system.h> /* for cli()/sti() */
@@ -169,7 +170,7 @@
  * from the beginning for this process..
  */
 static inline int unuse_pte(struct vm_area_struct * vma, unsigned long address,
-	pte_t *dir, unsigned int type, unsigned long page)
+	pte_t *dir, unsigned long entry, unsigned long page)
 {
 	pte_t pte = *dir;
 
@@ -178,24 +179,24 @@
 	if (pte_present(pte)) {
 		struct page *pg;
 		unsigned long page_nr = MAP_NR(pte_page(pte));
+		unsigned long pg_swap_entry;
+
 		if (page_nr >= max_mapnr)
 			return 0;
 		pg = mem_map + page_nr;
-		if (!in_swap_cache(pg))
+		if (!(pg_swap_entry = in_swap_cache(pg)))
 			return 0;
-		if (SWP_TYPE(in_swap_cache(pg)) != type)
+		if (SWP_TYPE(pg_swap_entry) != SWP_TYPE(entry))
 			return 0;
 		delete_from_swap_cache(pg);
 		set_pte(dir, pte_mkdirty(pte));
-		return 0;
-	}
-	if (SWP_TYPE(pte_val(pte)) != type)
-		return 0;
-	read_swap_page(pte_val(pte), (char *) page);
-	if (pte_val(*dir) != pte_val(pte)) {
+		if (pg_swap_entry != entry)
+			return 0;
 		free_page(page);
 		return 1;
 	}
+	if (pte_val(pte) != entry)
+		return 0;
 	set_pte(dir, pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))));
 	flush_tlb_page(vma, address);
 	++vma->vm_mm->rss;
@@ -205,7 +206,7 @@
 
 static inline int unuse_pmd(struct vm_area_struct * vma, pmd_t *dir,
 	unsigned long address, unsigned long size, unsigned long offset,
-	unsigned int type, unsigned long page)
+	unsigned long entry, unsigned long page)
 {
 	pte_t * pte;
 	unsigned long end;
@@ -224,7 +225,8 @@
 	if (end > PMD_SIZE)
 		end = PMD_SIZE;
 	do {
-		if (unuse_pte(vma, offset+address-vma->vm_start, pte, type, page))
+		if (unuse_pte(vma, offset+address-vma->vm_start, pte, entry, 
+				page))
 			return 1;
 		address += PAGE_SIZE;
 		pte++;
@@ -234,7 +236,7 @@
 
 static inline int unuse_pgd(struct vm_area_struct * vma, pgd_t *dir,
 	unsigned long address, unsigned long size,
-	unsigned int type, unsigned long page)
+	unsigned long entry, unsigned long page)
 {
 	pmd_t * pmd;
 	unsigned long offset, end;
@@ -253,7 +255,8 @@
 	if (end > PGDIR_SIZE)
 		end = PGDIR_SIZE;
 	do {
-		if (unuse_pmd(vma, pmd, address, end - address, offset, type, page))
+		if (unuse_pmd(vma, pmd, address, end - address, offset, entry,
+				 page))
 			return 1;
 		address = (address + PMD_SIZE) & PMD_MASK;
 		pmd++;
@@ -262,11 +265,12 @@
 }
 
 static int unuse_vma(struct vm_area_struct * vma, pgd_t *pgdir,
-	unsigned long start, unsigned long end,
-	unsigned int type, unsigned long page)
+			unsigned long entry, unsigned long page)
 {
+	unsigned long start = vma->vm_start, end = vma->vm_end;
+
 	while (start < end) {
-		if (unuse_pgd(vma, pgdir, start, end - start, type, page))
+		if (unuse_pgd(vma, pgdir, start, end - start, entry, page))
 			return 1;
 		start = (start + PGDIR_SIZE) & PGDIR_MASK;
 		pgdir++;
@@ -274,7 +278,8 @@
 	return 0;
 }
 
-static int unuse_process(struct mm_struct * mm, unsigned int type, unsigned long page)
+static int unuse_process(struct mm_struct * mm, unsigned long entry, 
+			unsigned long page)
 {
 	struct vm_area_struct* vma;
 
@@ -283,43 +288,70 @@
 	 */
 	if (!mm || mm == &init_mm)
 		return 0;
-	vma = mm->mmap;
-	while (vma) {
+	for (vma = mm->mmap; vma; vma = vma->vm_next) {
 		pgd_t * pgd = pgd_offset(mm, vma->vm_start);
-		if (unuse_vma(vma, pgd, vma->vm_start, vma->vm_end, type, page))
+		if (unuse_vma(vma, pgd, entry, page))
 			return 1;
-		vma = vma->vm_next;
+	}
+	return 0;
+}
+
+static unsigned long find_swap_entry(int type)
+{
+	struct swap_info_struct * p = &swap_info[type];
+	int i;
+
+	for (i = 1 ; i < p->max ; i++) {
+		if (p->swap_map[i] > 0 && p->swap_map[i] != 0x80)
+			return SWP_ENTRY(type, i);
 	}
 	return 0;
 }
 
 /*
- * To avoid races, we repeat for each process after having
- * swapped something in. That gets rid of a few pesky races,
- * and "swapoff" isn't exactly timing critical.
+ * We completely avoid races by reading each swap page in advance,
+ * and then search for the process using it.  All the necessary
+ * page table adjustments can then be made atomically.
  */
 static int try_to_unuse(unsigned int type)
 {
-	unsigned long page = get_free_page(GFP_KERNEL);
+	unsigned long page = 0;
 	struct task_struct *p;
+	unsigned long entry;
 
-	if (!page)
-		return -ENOMEM;
-again:
-	read_lock(&tasklist_lock);
-	for_each_task(p) {
-		read_unlock(&tasklist_lock);
-		if(unuse_process(p->mm, type, page)) {
-			page = get_free_page(GFP_KERNEL);
-			if(!page)
+	/*
+	 * Find all swap entries in use ...
+	 */
+	while ((entry = find_swap_entry(type)) != 0) {
+		if (!page) {
+			page = __get_free_page(GFP_KERNEL);
+			if (!page)
 				return -ENOMEM;
-			goto again;
 		}
+
+		/*
+		 * Read in the page, and then free the swap page.
+		 */
+		read_swap_page(entry, (char *) page);
+
 		read_lock(&tasklist_lock);
+		for_each_task(p) {
+			if (unuse_process(p->mm, entry, page)) {
+				page = 0;
+				goto unlock;
+			}
+		}
+	unlock:
+		read_unlock(&tasklist_lock);
+		if (page) {
+			printk("try_to_unuse: didn't find entry %8lx\n",
+				entry);
+			swap_free(entry);
+		}
 	}
-	read_unlock(&tasklist_lock);
 
-	free_page(page);
+	if (page)
+		free_page(page);
 	return 0;
 }
 
@@ -415,18 +447,25 @@
 
 int get_swaparea_info(char *buf)
 {
+	char * page = (char *) __get_free_page(GFP_KERNEL);
 	struct swap_info_struct *ptr = swap_info;
 	int i, j, len = 0, usedswap;
 
+	if (!page)
+		return -ENOMEM;
+
 	len += sprintf(buf, "Filename\t\t\tType\t\tSize\tUsed\tPriority\n");
-	for (i = 0 ; i < nr_swapfiles ; i++, ptr++)
+	for (i = 0 ; i < nr_swapfiles ; i++, ptr++) {
 		if (ptr->flags & SWP_USED) {
-			len += sprintf(buf + len, "%-31s ", ptr->swap_file->d_name.name);
+			char * path = d_path(ptr->swap_file, page, PAGE_SIZE);
 
-			if (ptr->swap_file)
+			len += sprintf(buf + len, "%-31s ", path);
+
+			if (!ptr->swap_device)
 				len += sprintf(buf + len, "file\t\t");
 			else
 				len += sprintf(buf + len, "partition\t");
+
 			usedswap = 0;
 			for (j = 0; j < ptr->max; ++j)
 				switch (ptr->swap_map[j]) {
@@ -439,6 +478,8 @@
 			len += sprintf(buf + len, "%d\t%d\t%d\n", ptr->pages << (PAGE_SHIFT - 10), 
 				usedswap << (PAGE_SHIFT - 10), ptr->prio);
 		}
+	}
+	free_page((unsigned long) page);
 	return len;
 }
 
diff -u --recursive --new-file v2.1.51/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.1.51/linux/mm/vmscan.c	Sun Jul 27 12:11:01 1997
+++ linux/mm/vmscan.c	Wed Sep  3 11:44:50 1997
@@ -269,74 +269,78 @@
 	return 0;
 }
 
+/*
+ * Select the task with maximal swap_cnt and try to swap out a page.
+ * N.B. This function returns only 0 or 1.  Return values != 1 from
+ * the lower level routines result in continued processing.
+ */
 static int swap_out(unsigned int priority, int dma, int wait)
 {
-	static int skip_factor = 0;
-	int limit = nr_tasks - 1;
-	int loop, counter, i;
-	struct task_struct *p;
+	struct task_struct * p, * pbest;
+	int counter, assign, max_cnt;
 
+	/* 
+	 * We make one or two passes through the task list, indexed by 
+	 * assign = {0, 1}:
+	 *   Pass 1: select the swappable task with maximal swap_cnt.
+	 *   Pass 2: assign new swap_cnt values, then select as above.
+	 * With this approach, there's no need to remember the last task
+	 * swapped out.  If the swap-out fails, we clear swap_cnt so the 
+	 * task won't be selected again until all others have been tried.
+	 */
 	counter = ((PAGEOUT_WEIGHT * nr_tasks) >> 10) >> priority;
-	if(skip_factor > nr_tasks)
-		skip_factor = 0;
-
-	read_lock(&tasklist_lock);
-	p = init_task.next_task;
-	i = skip_factor;
-	while(i--)
-		p = p->next_task;
-	for(; counter >= 0; counter--) {
-		/* Check if task is suitable for swapping. */
-		loop = 0;
-		while(1) {
-			if(!--limit) {
-				limit = nr_tasks - 1;
-				/* See if all processes are unswappable or
-				 * already swapped out.
+	for (; counter >= 0; counter--) {
+		assign = 0;
+		max_cnt = 0;
+		pbest = NULL;
+	select:
+		read_lock(&tasklist_lock);
+		p = init_task.next_task;
+		for (; p != &init_task; p = p->next_task) {
+			if (!p->swappable)
+				continue;
+	 		if (p->mm->rss <= 0)
+				continue;
+			if (assign) {
+				/* 
+				 * If we didn't select a task on pass 1, 
+				 * assign each task a new swap_cnt.
+				 * Normalise the number of pages swapped
+				 * by multiplying by (RSS / 1MB)
 				 */
-				if (loop)
-					goto out;
-				loop = 1;
+				p->swap_cnt = AGE_CLUSTER_SIZE(p->mm->rss);
+			}
+			if (p->swap_cnt > max_cnt) {
+				max_cnt = p->swap_cnt;
+				pbest = p;
 			}
-			if (p->swappable && p->mm->rss)
-				break;
-			if((p = p->next_task) == &init_task)
-				p = p->next_task;
-		}
-		skip_factor++;
-
-		/* Determine the number of pages to swap from this process. */
-		if (!p->swap_cnt) {
-			/* Normalise the number of pages swapped by
-			   multiplying by (RSS / 1MB) */
-			p->swap_cnt = AGE_CLUSTER_SIZE(p->mm->rss);
 		}
-		if (!--p->swap_cnt)
-			skip_factor++;
 		read_unlock(&tasklist_lock);
+		if (!pbest) {
+			if (!assign) {
+				assign = 1;
+				goto select;
+			}
+			goto out;
+		}
+		pbest->swap_cnt--;
 
-		switch (swap_out_process(p, dma, wait)) {
+		switch (swap_out_process(pbest, dma, wait)) {
 		case 0:
-			if (p->swap_cnt)
-				skip_factor++;
+			/*
+			 * Clear swap_cnt so we don't look at this task
+			 * again until we've tried all of the others.
+			 * (We didn't block, so the task is still here.)
+			 */
+			pbest->swap_cnt = 0;
 			break;
 		case 1:
 			return 1;
 		default:
 			break;
 		};
-
-		/* Whoever we swapped may not even exist now, in fact we cannot
-		 * assume anything about the list we were searching previously.
-		 */
-		read_lock(&tasklist_lock);
-		p = init_task.next_task;
-		i = skip_factor;
-		while(i--)
-			p = p->next_task;
 	}
 out:
-	read_unlock(&tasklist_lock);
 	return 0;
 }
 
@@ -362,9 +366,6 @@
 				return 1;
 			state = 1;
 		case 1:
-			shrink_dcache();
-			state = 2;
-		case 2:
 			/*
 			 * We shouldn't have a priority here:
 			 * If we're low on memory we should
@@ -373,11 +374,11 @@
 			 */
 			if (kmem_cache_reap(0, dma, wait))
 				return 1;
-			state = 3;
-		case 3:
+			state = 2;
+		case 2:
 			if (shm_swap(i, dma))
 				return 1;
-			state = 4;
+			state = 3;
 		default:
 			if (swap_out(i, dma, wait))
 				return 1;
@@ -477,31 +478,23 @@
 
 void swap_tick(void)
 {
-	int	want_wakeup = 0;
-	static int	last_wakeup_low = 0;
+	int want_wakeup = 0, memory_low = 0;
+	int pages = nr_free_pages + atomic_read(&nr_async_pages);
 
-	if ((nr_free_pages + atomic_read(&nr_async_pages)) < free_pages_low) {
-		if (last_wakeup_low)
-			want_wakeup = jiffies >= next_swap_jiffies;
-		else
-			last_wakeup_low = want_wakeup = 1;
-	}
-	else if (((nr_free_pages + atomic_read(&nr_async_pages)) < free_pages_high) && 
-	         jiffies >= next_swap_jiffies) {
-		last_wakeup_low = 0;
+	if (pages < free_pages_low)
+		memory_low = want_wakeup = 1;
+	else if (pages < free_pages_high && jiffies >= next_swap_jiffies)
 		want_wakeup = 1;
-	}
 
 	if (want_wakeup) { 
 		if (!kswapd_awake) {
 			wake_up(&kswapd_wait);
 			need_resched = 1;
 		}
-		/* low on memory, we need to start swapping soon */
-		if(last_wakeup_low) 
-			next_swap_jiffies = jiffies;
-		else  
-			next_swap_jiffies = jiffies + swapout_interval;
+		/* Set the next wake-up time */
+		next_swap_jiffies = jiffies;
+		if (!memory_low) 
+			next_swap_jiffies += swapout_interval;
 	}
 	timer_active |= (1<<SWAP_TIMER);
 }
diff -u --recursive --new-file v2.1.51/linux/net/bridge/br.c linux/net/bridge/br.c
--- v2.1.51/linux/net/bridge/br.c	Wed Apr 23 19:01:29 1997
+++ linux/net/bridge/br.c	Tue Aug 26 11:06:08 1997
@@ -1567,7 +1567,7 @@
 		return;
 	}
 		
-	bpdu = (Tcn_bpdu *)skb->data + ETH_HLEN;
+	bpdu = (Tcn_bpdu *) (skb->data + ETH_HLEN);
 	switch (bpdu->type) {
 		case BPDU_TYPE_CONFIG:
 			received_config_bpdu(port, (Config_bpdu *)bpdu);
