diff -u --recursive --new-file v2.0.26/linux/CREDITS linux/CREDITS
--- v2.0.26/linux/CREDITS	Fri Nov 22 16:25:53 1996
+++ linux/CREDITS	Fri Nov 29 12:10:18 1996
@@ -108,8 +108,8 @@
 N: Randolph Bentson
 E: bentson@grieg.seaslug.org
 D: author of driver for Cyclades Cyclom-Y async mux
-S: 2500 Gilman Dr W, #404
-S: Seattle, Washington 98119-2102
+S: 2322 37th Ave SW
+S: Seattle, Washington 98126-2010
 S: USA
 
 N: Stephen R. van den Berg (AKA BuGless)
@@ -960,7 +960,7 @@
 S: USA
 
 N: Rick Miller
-E: rdmiller@execpc.com
+E: rick@digalogsys.com
 D: Original Linux Device Registrar (Major/minor numbers), au-play, bwBASIC
 S: S78 W16203 Woods Road
 S: Muskego, Wisconsin 53150
diff -u --recursive --new-file v2.0.26/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.0.26/linux/Documentation/Configure.help	Fri Nov 22 16:25:54 1996
+++ linux/Documentation/Configure.help	Sun Dec  1 15:58:05 1996
@@ -1641,10 +1641,10 @@
 EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support
 CONFIG_SCSI_EATA
   This driver supports all the EATA/DMA-compliant SCSI host adapters
-  and does not need any BIOS32 or PCI BIOS service.
-  Only ISA (0x1F0, 0x170, 0x230, 0x330) and EISA (0x1C88 through 0xFC88)
-  addresses are probed. In order to detect a generic EATA PCI board you
-  can force on it any unused EISA address.
+  and does not need any BIOS32 service.
+  DPT ISA and all EISA i/o addresses are probed looking for the "EATA"
+  signature. If "PCI bios support" is enabled, the addresses of all the
+  PCI SCSI controllers reported by BIOS32 are probed as well.
   Note that there is also another driver for the same hardware:
   "EATA-DMA support". You should enable only one of them.
   You want to read the start of drivers/scsi/eata.c and the
@@ -3121,15 +3121,12 @@
   removed from the running kernel whenever you want), say M here and
   read Documentation/modules.txt. Most people say N, however.
 
-SMB long filename support (EXPERIMENTAL)
-CONFIG_SMB_LONG
-  SMBFS was designed to support long filenames using the LanManager
-  2.0 protocol. I had to find out that the support for long filenames
-  sometimes causes problems, which can even result in kernel OOPSes. I
-  did not yet find out what the problem is, but hopefully I will find
-  this bug eventually. As many people seem to run long filenames with
-  no problems, I leave this support in the kernel as an option. The
-  careful among you should say N here.
+SMB Win95 bug work-around
+CONFIG_SMB_WIN95
+  If you want to connect to a share exported by Windows 95, you should
+  say Y here. The Windows 95 server contains a bug that makes listing
+  directories unreliable. This option slows down the listing of
+  directories. This makes the Windows 95 server a bit more stable.
 
 NCP filesystem support (to mount NetWare volumes)
 CONFIG_NCP_FS
diff -u --recursive --new-file v2.0.26/linux/Makefile linux/Makefile
--- v2.0.26/linux/Makefile	Fri Nov 22 16:25:55 1996
+++ linux/Makefile	Fri Nov 22 16:25:41 1996
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 0
-SUBLEVEL = 26
+SUBLEVEL = 27
 
 ARCH = i386
 
diff -u --recursive --new-file v2.0.26/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c
--- v2.0.26/linux/arch/alpha/kernel/bios32.c	Fri Nov 22 16:25:55 1996
+++ linux/arch/alpha/kernel/bios32.c	Sat Nov 30 11:14:51 1996
@@ -693,6 +693,7 @@
 
 static inline void alphapc164_fixup(void)
 {
+	extern int SMCInit(void);
 	char irq_tab[7][5] = {
 	  /*
 	   *      int   intA  intB   intC   intD
@@ -708,6 +709,8 @@
 	};
 
 	common_fixup(5, 11, 5, irq_tab, 0);
+
+	SMCInit();
 }
 
 /*
@@ -1279,4 +1282,262 @@
 	}
         return err;
 }
+#ifdef CONFIG_ALPHA_PC164
+
+/* device "activate" register contents */
+#define DEVICE_ON		1
+#define DEVICE_OFF		0
+
+/* configuration on/off keys */
+#define CONFIG_ON_KEY		0x55
+#define CONFIG_OFF_KEY		0xaa
+
+/* configuration space device definitions */
+#define FDC			0
+#define IDE1			1
+#define IDE2			2
+#define PARP			3
+#define SER1			4
+#define SER2			5
+#define RTCL			6
+#define KYBD			7
+#define AUXIO			8
+
+/* Chip register offsets from base */
+#define CONFIG_CONTROL		0x02
+#define INDEX_ADDRESS		0x03
+#define LOGICAL_DEVICE_NUMBER	0x07
+#define DEVICE_ID		0x20
+#define DEVICE_REV		0x21
+#define POWER_CONTROL		0x22
+#define POWER_MGMT		0x23
+#define OSC			0x24
+
+#define ACTIVATE		0x30
+#define ADDR_HI			0x60
+#define ADDR_LO			0x61
+#define INTERRUPT_SEL		0x70
+#define INTERRUPT_SEL_2		0x72 /* KYBD/MOUS only */
+#define DMA_CHANNEL_SEL		0x74 /* FDC/PARP only */
+
+#define FDD_MODE_REGISTER	0x90
+#define FDD_OPTION_REGISTER	0x91
+
+/* values that we read back that are expected ... */
+#define VALID_DEVICE_ID		2
+
+/* default device addresses */
+#define KYBD_INTERRUPT		1
+#define MOUS_INTERRUPT		12
+#define COM2_BASE		0x2f8
+#define COM2_INTERRUPT		3
+#define COM1_BASE		0x3f8
+#define COM1_INTERRUPT		4
+#define PARP_BASE		0x3bc
+#define PARP_INTERRUPT		7
+
+#define SMC_DEBUG 0
+
+unsigned long SMCConfigState( unsigned long baseAddr )
+{
+    unsigned char devId;
+    unsigned char devRev;
+
+    unsigned long configPort;
+    unsigned long indexPort;
+    unsigned long dataPort;
+
+    configPort = indexPort = baseAddr;
+    dataPort = ( unsigned long )( ( char * )configPort + 1 );
+
+    outb(CONFIG_ON_KEY, configPort);
+    outb(CONFIG_ON_KEY, configPort);
+    outb(DEVICE_ID, indexPort);
+    devId = inb(dataPort);
+    if ( devId == VALID_DEVICE_ID ) {
+        outb(DEVICE_REV, indexPort);
+        devRev = inb(dataPort);
+    }
+    else {
+        baseAddr = 0;
+    }
+    return( baseAddr );
+}
+
+void SMCRunState( unsigned long baseAddr )
+{
+    outb(CONFIG_OFF_KEY, baseAddr);
+}
+
+unsigned long SMCDetectUltraIO(void)
+{
+    unsigned long baseAddr;
+
+    baseAddr = 0x3F0;
+    if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x3F0 ) {
+        return( baseAddr );
+    }
+    baseAddr = 0x370;
+    if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x370 ) {
+        return( baseAddr );
+    }
+    return( ( unsigned long )0 );
+}
+
+void SMCEnableDevice( unsigned long baseAddr,
+		      unsigned long device,
+		      unsigned long portaddr,
+		      unsigned long interrupt)
+{
+    unsigned long indexPort;
+    unsigned long dataPort;
+
+    indexPort = baseAddr;
+    dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
+
+    outb(LOGICAL_DEVICE_NUMBER, indexPort);
+    outb(device, dataPort);
+
+    outb(ADDR_LO, indexPort);
+    outb(( portaddr & 0xFF ), dataPort);
+
+    outb(ADDR_HI, indexPort);
+    outb(( ( portaddr >> 8 ) & 0xFF ), dataPort);
+
+    outb(INTERRUPT_SEL, indexPort);
+    outb(interrupt, dataPort);
+
+    outb(ACTIVATE, indexPort);
+    outb(DEVICE_ON, dataPort);
+}
+
+void SMCEnableKYBD( unsigned long baseAddr )
+{
+    unsigned long indexPort;
+    unsigned long dataPort;
+
+    indexPort = baseAddr;
+    dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
+
+    outb(LOGICAL_DEVICE_NUMBER, indexPort);
+    outb(KYBD, dataPort);
+
+    outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */
+    outb(KYBD_INTERRUPT, dataPort);
+
+    outb(INTERRUPT_SEL_2, indexPort);/* Secondary interrupt select */
+    outb(MOUS_INTERRUPT, dataPort);
+
+    outb(ACTIVATE, indexPort);
+    outb(DEVICE_ON, dataPort);
+}
+
+void SMCEnableFDC( unsigned long baseAddr )
+{
+    unsigned long indexPort;
+    unsigned long dataPort;
+
+    unsigned char oldValue;
+
+    indexPort = baseAddr;
+    dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
+
+    outb(LOGICAL_DEVICE_NUMBER, indexPort);
+    outb(FDC, dataPort);
+
+    outb(FDD_MODE_REGISTER, indexPort);
+    oldValue = inb(dataPort);
+
+    oldValue |= 0x0E;                   /* Enable burst mode */
+    outb(oldValue, dataPort);
+
+    outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */
+    outb(0x06, dataPort );
+
+    outb(DMA_CHANNEL_SEL, indexPort);  /* DMA channel select */
+    outb(0x02, dataPort);
+
+    outb(ACTIVATE, indexPort);
+    outb(DEVICE_ON, dataPort);
+}
+
+#if SMC_DEBUG
+void SMCReportDeviceStatus( unsigned long baseAddr )
+{
+    unsigned long indexPort;
+    unsigned long dataPort;
+    unsigned char currentControl;
+
+    indexPort = baseAddr;
+    dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
+
+    outb(POWER_CONTROL, indexPort);
+    currentControl = inb(dataPort);
+
+    if ( currentControl & ( 1 << FDC ) )
+        printk( "\t+FDC Enabled\n" );
+    else
+        printk( "\t-FDC Disabled\n" );
+
+    if ( currentControl & ( 1 << IDE1 ) )
+        printk( "\t+IDE1 Enabled\n" );
+    else
+        printk( "\t-IDE1 Disabled\n" );
+
+    if ( currentControl & ( 1 << IDE2 ) )
+        printk( "\t+IDE2 Enabled\n" );
+    else
+        printk( "\t-IDE2 Disabled\n" );
+
+    if ( currentControl & ( 1 << PARP ) )
+        printk( "\t+PARP Enabled\n" );
+    else
+        printk( "\t-PARP Disabled\n" );
+
+    if ( currentControl & ( 1 << SER1 ) )
+        printk( "\t+SER1 Enabled\n" );
+    else
+        printk( "\t-SER1 Disabled\n" );
+
+    if ( currentControl & ( 1 << SER2 ) )
+        printk( "\t+SER2 Enabled\n" );
+    else
+        printk( "\t-SER2 Disabled\n" );
+
+    printk( "\n" );
+}
+#endif
+
+int SMCInit(void)
+{
+    unsigned long SMCUltraBase;
+
+    if ( ( SMCUltraBase = SMCDetectUltraIO( ) ) != ( unsigned long )0 ) {
+        printk( "SMC FDC37C93X Ultra I/O Controller found @ 0x%lx\n",
+		SMCUltraBase );
+#if SMC_DEBUG
+        SMCReportDeviceStatus( SMCUltraBase );
+#endif
+        SMCEnableDevice( SMCUltraBase, SER1, COM1_BASE, COM1_INTERRUPT );
+        SMCEnableDevice( SMCUltraBase, SER2, COM2_BASE, COM2_INTERRUPT );
+        SMCEnableDevice( SMCUltraBase, PARP, PARP_BASE, PARP_INTERRUPT );
+	/* on PC164, IDE on the SMC is not enabled; CMD646 (PCI) on MB */
+        SMCEnableKYBD( SMCUltraBase );
+        SMCEnableFDC( SMCUltraBase );
+#if SMC_DEBUG
+        SMCReportDeviceStatus( SMCUltraBase );
+#endif
+        SMCRunState( SMCUltraBase );
+        return( 1 );
+    }
+    else {
+#if SMC_DEBUG
+        printk( "No SMC FDC37C93X Ultra I/O Controller found\n" );
+#endif
+        return( 0 );
+    }
+}
+
+#endif /* CONFIG_ALPHA_PC164 */
+
 #endif /* CONFIG_PCI */
diff -u --recursive --new-file v2.0.26/linux/drivers/isdn/teles/proto.h linux/drivers/isdn/teles/proto.h
--- v2.0.26/linux/drivers/isdn/teles/proto.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/isdn/teles/proto.h	Fri Nov 29 11:10:13 1996
@@ -0,0 +1,18 @@
+/* $Id: proto.h,v 1.1 1996/09/23 01:53:52 fritz Exp $
+ *
+ * not much now - just the l3 proto discriminator
+ *
+ * $Log: proto.h,v $
+ * Revision 1.1  1996/09/23 01:53:52  fritz
+ * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
+ *
+ */
+
+#ifndef	PROTO_H
+#define	PROTO_H
+
+#define	PROTO_EURO		0x08
+#define	PROTO_DIS_N0	0x40
+#define	PROTO_DIS_N1	0x41
+
+#endif
diff -u --recursive --new-file v2.0.26/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c
--- v2.0.26/linux/drivers/net/wavelan.c	Wed Aug 21 09:18:08 1996
+++ linux/drivers/net/wavelan.c	Fri Nov 29 12:00:05 1996
@@ -69,7 +69,7 @@
 
 extern int		wavelan_probe(device *);	/* See Space.c */
 
-static const char	*version	= "wavelan.c:v8 96/8/18\n";
+static const char	*version	= "wavelan.c:v9 96/11/17\n";
 
 /*
  * Entry point forward declarations.
@@ -881,7 +881,11 @@
 		||
 		psa.psa_univ_mac_addr[1] != SA_ADDR1
 		||
-		psa.psa_univ_mac_addr[2] != SA_ADDR2
+		(
+			psa.psa_univ_mac_addr[2] != SA_ADDR2
+			&&
+			psa.psa_univ_mac_addr[2] != SA_ALT_ADDR2
+		)
 	)
 	{
 		if (wavelan_debug > 0)
diff -u --recursive --new-file v2.0.26/linux/drivers/net/wavelan.h linux/drivers/net/wavelan.h
--- v2.0.26/linux/drivers/net/wavelan.h	Sun Jul  2 10:30:38 1995
+++ linux/drivers/net/wavelan.h	Fri Nov 29 12:00:05 1996
@@ -2,6 +2,7 @@
 #define SA_ADDR0		0x08	/* First octet of WaveLAN MAC addresses */
 #define SA_ADDR1		0x00	/* Second octet of WaveLAN MAC addresses */
 #define SA_ADDR2		0x0E	/* Third octet of WaveLAN MAC addresses */
+#define SA_ALT_ADDR2		0x6A	/* Alternate third octet of WaveLAN MAC addresses */
 #define WAVELAN_MTU		1500	/* Maximum size of WaveLAN packet */
 
 /*
diff -u --recursive --new-file v2.0.26/linux/drivers/scsi/BusLogic.c linux/drivers/scsi/BusLogic.c
--- v2.0.26/linux/drivers/scsi/BusLogic.c	Thu Oct 31 12:08:52 1996
+++ linux/drivers/scsi/BusLogic.c	Sun Dec  1 09:43:49 1996
@@ -25,7 +25,7 @@
 
 
 #define BusLogic_DriverVersion		"2.0.6"
-#define BusLogic_DriverDate		"19 October 1996"
+#define BusLogic_DriverDate		"1 December 1996"
 
 
 #include <linux/module.h>
@@ -763,7 +763,7 @@
 					     *HostAdapter)
 {
   boolean TraceHardReset = (BusLogic_GlobalOptions & BusLogic_TraceHardReset);
-  int TimeoutCounter = loops_per_sec >> 2;
+  int TimeoutCounter = loops_per_sec;
   unsigned char StatusRegister = 0;
   /*
     Issue a Hard Reset Command to the Host Adapter.  The Host Adapter should
diff -u --recursive --new-file v2.0.26/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c
--- v2.0.26/linux/drivers/scsi/eata.c	Fri Nov 22 16:26:03 1996
+++ linux/drivers/scsi/eata.c	Sat Nov 23 15:28:23 1996
@@ -1,6 +1,14 @@
 /*
  *      eata.c - Low-level driver for EATA/DMA SCSI host adapters.
  *
+ *      22 Nov 1996 rev. 2.30 for linux 2.1.12 and 2.0.26
+ *          When CONFIG_PCI is defined, BIOS32 is used to include in the
+ *          list of i/o ports to be probed all the PCI SCSI controllers.
+ *          The list of i/o ports to be probed can be overwritten by the
+ *          "eata=port0, port1,...." boot command line option.
+ *          Scatter/gather lists are now allocated by a number of kmalloc
+ *          calls, in order to avoid the previous size limit of 64Kb.
+ *
  *      16 Nov 1996 rev. 2.20 for linux 2.1.10 and 2.0.25
  *          Added support for EATA 2.0C, PCI, multichannel and wide SCSI.
  *
@@ -79,6 +87,11 @@
  *
  *  Copyright (C) 1994, 1995, 1996 Dario Ballabio (dario@milano.europe.dg.com)
  *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that redistributions of source
+ *  code retain the above copyright notice and this comment without
+ *  modification.
+ *
  */
 
 /*
@@ -103,9 +116,10 @@
  *  supported by this driver.
  *
  *  This code has been tested with up to 3 Distributed Processing Technology 
- *  PM2122A/9X (DPT SCSI BIOS v002.D1, firmware v05E.0) eisa controllers,
+ *  PM2122A/9X (DPT SCSI BIOS v002.D1, firmware v05E.0) EISA controllers,
  *  in any combination of private and shared IRQ.
- *  PCI support has been tested using a DPT PM3224W (firmware v07G.0).
+ *  PCI support has been tested using up to 2 DPT PM3224W (DPT SCSI BIOS 
+ *  v003.D0, firmware v07G.0).
  *
  *  Multiple ISA, EISA and PCI boards can be configured in the same system.
  *  It is suggested to put all the EISA boards on the same IRQ level, all
@@ -116,16 +130,32 @@
  *  be _level_ triggered (not _edge_ triggered).
  *
  *  This driver detects EATA boards by probes at fixed port addresses,
- *  so no BIOS32 or PCI BIOS support is used or required.
+ *  so no BIOS32 or PCI BIOS support is required.
  *  The suggested way to detect a generic EATA PCI board is to force on it
  *  any unused EISA address, even if there are other controllers on the EISA
  *  bus, or even if you system has no EISA bus at all.
  *  Do not force any ISA address on EATA PCI boards.
  *
+ *  If PCI bios support is configured into the kernel, BIOS32 is used to 
+ *  include in the list of i/o ports to be probed all the PCI SCSI controllers.
+ *
+ *  Due to a DPT BIOS "feature", it might not be possible to force an EISA
+ *  address on more then a single DPT PCI board, so in this case you have to
+ *  let the PCI BIOS assign the addresses.
+ *
  *  The sequence of detection probes is:
+ *
  *  - ISA 0x1F0; 
+ *  - PCI SCSI controllers (only if BIOS32 is available);
  *  - EISA/PCI 0x1C88 through 0xFC88 (corresponding to EISA slots 1 to 15);
  *  - ISA  0x170, 0x230, 0x330.
+ * 
+ *  The above list of detection probes can be totally replaced by the
+ *  boot command line option: "eata=port0, port1, port2,...", where the
+ *  port0, port1... arguments are ISA/EISA/PCI addresses to be probed.
+ *  For example using "eata=0x7410, 0x7450, 0x230", the driver probes
+ *  only the two PCI addresses 0x7410 and 0x7450 and the ISA address 0x230,
+ *  in this order; "eata=0" totally disables this driver.
  *
  *  The boards are named EATA0, EATA1,... according to the detection order.
  *
@@ -152,9 +182,11 @@
 #include "sd.h"
 #include <asm/dma.h>
 #include <asm/irq.h>
-#include "linux/in.h"
 #include "eata.h"
 #include<linux/stat.h>
+#include<linux/config.h>
+#include<linux/bios32.h>
+#include<linux/pci.h>
 
 struct proc_dir_entry proc_scsi_eata2x = {
     PROC_SCSI_EATA2X, 6, "eata2x",
@@ -172,17 +204,22 @@
 #undef  DEBUG_STATISTICS
 #undef  DEBUG_RESET
 
+#define MAX_ISA 4
+#define MAX_VESA 0 
+#define MAX_EISA 15
+#define MAX_PCI 16
+#define MAX_BOARDS (MAX_ISA + MAX_VESA + MAX_EISA + MAX_PCI)
 #define MAX_CHANNEL 4
 #define MAX_LUN 32
 #define MAX_TARGET 32
 #define MAX_IRQ 16
-#define MAX_BOARDS 18
 #define MAX_MAILBOXES 64
 #define MAX_SGLIST 64
 #define MAX_LARGE_SGLIST 252
 #define MAX_INTERNAL_RETRIES 64
 #define MAX_CMD_PER_LUN 2
 
+#define SKIP 1
 #define FALSE 0
 #define TRUE 1
 #define FREE 0
@@ -190,7 +227,6 @@
 #define LOCKED   2
 #define IN_RESET 3
 #define IGNORE   4
-#define NO_IRQ  0xff
 #define NO_DMA  0xff
 #define MAXLOOP 200000
 
@@ -205,7 +241,8 @@
 #define REG_MID         4
 #define REG_MSB         5
 #define REGION_SIZE     9
-#define EISA_RANGE      0x1000
+#define ISA_RANGE       0x0fff
+#define EISA_RANGE      0xfc88
 #define BSY_ASSERTED      0x80
 #define DRQ_ASSERTED      0x08
 #define ABSY_ASSERTED     0x01
@@ -261,13 +298,18 @@
    /* Structure extension defined in EATA 2.0B */
    unchar  isaena:1,    /* ISA i/o addressing is disabled/enabled */
 	 forcaddr:1,    /* Port address has been forced */
-		 :6;
+         large_sg:1,    /* 1 if large SG lists are supported */
+             res1:1,
+		 :4;
    unchar  max_id:5,    /* Max SCSI target ID number */
 	 max_chan:3;    /* Max SCSI channel number on this board */
 
    /* Structure extension defined in EATA 2.0C */
    unchar   max_lun;    /* Max SCSI LUN number */
-   unchar   notused[3];
+   unchar        :6,
+              pci:1,    /* This board is PCI */
+             eisa:1;    /* This board is EISA */
+   unchar   notused[2];
 
    ushort ipad[247];
    };
@@ -294,6 +336,11 @@
    char mess[12];
    };
 
+struct sg_list {
+   unsigned int address;                /* Segment Address */
+   unsigned int num_bytes;              /* Segment Length */
+   };
+
 /* MailBox SCSI Command Packet */
 struct mscp {
    unchar  sreset:1,     /* SCSI Bus Reset Signal should be asserted */
@@ -317,17 +364,12 @@
    unchar mess[3];       /* Massage to/from Target */
    unchar cdb[12];       /* Command Descriptor Block */
    ulong  data_len;      /* If sg=0 Data Length, if sg=1 sglist length */
-   Scsi_Cmnd *SCpnt;     /* Address to be returned is sp */
+   Scsi_Cmnd *SCpnt;     /* Address to be returned in sp */
    ulong  data_address;  /* If sg=0 Data Address, if sg=1 sglist address */
    ulong  sp_addr;       /* Address where sp is DMA'ed when cp completes */
    ulong  sense_addr;    /* Address where Sense Data is DMA'ed on error */
-
-   struct sg_list {
-      unsigned int address;     /* Segment Address */
-      unsigned int num_bytes;   /* Segment Length */
-      } sglist[MAX_SGLIST];
-
    unsigned int index;   /* cp index */
+   struct sg_list *sglist;
    };
 
 struct hostdata {
@@ -353,6 +395,26 @@
 static const char *driver_name = "EATA";
 static unsigned int irqlist[MAX_IRQ], calls[MAX_IRQ];
 
+static unsigned int io_port[MAX_BOARDS + 1] = { 
+
+   /* First ISA */
+   0x1f0,
+
+   /* Space for MAX_PCI ports possibly reported by PCI_BIOS */
+    SKIP,    SKIP,   SKIP,   SKIP,   SKIP,   SKIP,   SKIP,   SKIP,
+    SKIP,    SKIP,   SKIP,   SKIP,   SKIP,   SKIP,   SKIP,   SKIP,
+
+   /* MAX_EISA ports */
+   0x1c88, 0x2c88, 0x3c88, 0x4c88, 0x5c88, 0x6c88, 0x7c88, 0x8c88,
+   0x9c88, 0xac88, 0xbc88, 0xcc88, 0xdc88, 0xec88, 0xfc88, 
+
+   /* Other (MAX_ISA - 1) ports */
+   0x170,  0x230,  0x330,
+ 
+   /* End of list */
+   0x0
+   };
+
 #define HD(board) ((struct hostdata *) &sh[board]->hostdata)
 #define BN(board) (HD(board)->board_name)
 
@@ -363,6 +425,7 @@
 
 static void eata2x_interrupt_handler(int, void *, struct pt_regs *);
 static int do_trace = FALSE;
+static int setup_done = FALSE;
 
 static inline int wait_on_busy(unsigned int iobase) {
    unsigned int loop = MAXLOOP;
@@ -404,11 +467,12 @@
    return FALSE;
 }
 
-static inline int port_detect(unsigned int *port_base, unsigned int j, 
+static inline int port_detect(unsigned int port_base, unsigned int j, 
 			      Scsi_Host_Template *tpnt) {
-   unsigned char irq, dma_channel, subversion, c;
+   unsigned char irq, dma_channel, subversion, i;
    unsigned char protocol_rev;
    struct eata_info info;
+   char *bus_type;
 
    /* Allowed DMA channels for ISA (0 indicates reserved) */
    unsigned char dma_channel_table[4] = { 5, 6, 7, 0 };
@@ -417,16 +481,15 @@
 
    sprintf(name, "%s%d", driver_name, j);
 
-   if(check_region(*port_base, REGION_SIZE)) {
-      printk("%s: address 0x%03x in use, skipping probe.\n", 
-	     name, *port_base);
+   if(check_region(port_base, REGION_SIZE)) {
+      printk("%s: address 0x%03x in use, skipping probe.\n", name, port_base);
       return FALSE;
       }
 
-   if (do_dma(*port_base, 0, READ_CONFIG_PIO)) return FALSE;
+   if (do_dma(port_base, 0, READ_CONFIG_PIO)) return FALSE;
 
    /* Read the info structure */
-   if (read_pio(*port_base, (ushort *)&info, (ushort *)&info.ipad[0])) 
+   if (read_pio(port_base, (ushort *)&info, (ushort *)&info.ipad[0])) 
       return FALSE;
 
    /* Check the controller "EATA" signature */
@@ -446,7 +509,7 @@
 
    irq = info.irq;
 
-   if (*port_base >= EISA_RANGE) {
+   if (port_base > ISA_RANGE) {
 
       if (!info.haaval || info.ata || info.drqvld) {
 	 printk("%s: unusable EISA/PCI board found (%d%d%d), detaching.\n", 
@@ -477,8 +540,8 @@
 	     name, irq);
 
    /* Board detected, allocate its IRQ if not already done */
-   if ((irq >= MAX_IRQ) || ((irqlist[irq] == NO_IRQ) && request_irq
-       (irq, eata2x_interrupt_handler, SA_INTERRUPT, driver_name, NULL))) {
+   if ((irq >= MAX_IRQ) || (!irqlist[irq] && request_irq(irq,
+              eata2x_interrupt_handler, SA_INTERRUPT, driver_name, NULL))) {
       printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq);
       return FALSE;
       }
@@ -499,7 +562,7 @@
    config.len = (ushort) htons((ushort)510);
    config.ocena = TRUE;
 
-   if (do_dma(*port_base, (unsigned int)&config, SET_CONFIG_DMA)) {
+   if (do_dma(port_base, (unsigned int)&config, SET_CONFIG_DMA)) {
       printk("%s: busy timeout sending configuration, detaching.\n", name);
       return FALSE;
       }
@@ -511,15 +574,15 @@
    if (sh[j] == NULL) {
       printk("%s: unable to register host, detaching.\n", name);
 
-      if (irqlist[irq] == NO_IRQ) free_irq(irq, NULL);
+      if (!irqlist[irq]) free_irq(irq, NULL);
 
       if (subversion == ISA) free_dma(dma_channel);
 
       return FALSE;
       }
 
-   sh[j]->io_port = *port_base;
-   sh[j]->unique_id = *port_base;
+   sh[j]->io_port = port_base;
+   sh[j]->unique_id = port_base;
    sh[j]->n_io_port = REGION_SIZE;
    sh[j]->dma_channel = dma_channel;
    sh[j]->irq = irq;
@@ -529,13 +592,13 @@
    sh[j]->cmd_per_lun = MAX_CMD_PER_LUN;
 
    /* Register the I/O space that we use */
-   request_region(sh[j]->io_port, REGION_SIZE, driver_name);
+   request_region(sh[j]->io_port, sh[j]->n_io_port, driver_name);
 
    memset(HD(j), 0, sizeof(struct hostdata));
    HD(j)->subversion = subversion;
    HD(j)->protocol_rev = protocol_rev;
    HD(j)->board_number = j;
-   irqlist[irq] = j;
+   irqlist[irq]++;
 
    if (HD(j)->subversion == ESA)
       sh[j]->unchecked_isa_dma = FALSE;
@@ -548,66 +611,138 @@
       enable_dma(dma_channel);
       }
 
-   if (protocol_rev != 'A' && info.max_chan > 0 && info.max_chan < MAX_CHANNEL)
-      sh[j]->max_channel = info.max_chan;
-
-   if (protocol_rev != 'A' && info.max_id > 7 && info.max_id < MAX_TARGET)
-      sh[j]->max_id = info.max_id + 1;
-
-   if (protocol_rev == 'C' && info.max_lun > 7 && info.max_lun < MAX_LUN)
-      sh[j]->max_lun = info.max_lun + 1;
-
    strcpy(BN(j), name);
 
-   printk("%s: rev. 2.0%c, PORT 0x%03x, IRQ %u, DMA %u, SG %d, "\
-	  "Mbox %d, CmdLun %d.\n", BN(j), HD(j)->protocol_rev,
-	   sh[j]->io_port, sh[j]->irq, sh[j]->dma_channel,
-	   sh[j]->sg_tablesize, sh[j]->can_queue, sh[j]->cmd_per_lun);
-
    /* DPT PM2012 does not allow to detect sg_tablesize correctly */
    if (sh[j]->sg_tablesize > MAX_SGLIST || sh[j]->sg_tablesize < 2) {
-      printk("%s: detect, forcing to use %d SG lists.\n", BN(j), MAX_SGLIST);
+      printk("%s: detect, wrong n. of SG lists %d, fixed.\n",
+             BN(j), sh[j]->sg_tablesize);
       sh[j]->sg_tablesize = MAX_SGLIST;
       }
 
    /* DPT PM2012 does not allow to detect can_queue correctly */
    if (sh[j]->can_queue > MAX_MAILBOXES || sh[j]->can_queue  < 2) {
-      printk("%s: detect, forcing to use %d Mbox.\n", BN(j), MAX_MAILBOXES);
+      printk("%s: detect, wrong n. of Mbox %d, fixed.\n",
+             BN(j), sh[j]->can_queue);
       sh[j]->can_queue = MAX_MAILBOXES;
       }
 
+   if (protocol_rev != 'A') {
+
+      if (info.max_chan > 0 && info.max_chan < MAX_CHANNEL)
+         sh[j]->max_channel = info.max_chan;
+
+      if (info.max_id > 7 && info.max_id < MAX_TARGET)
+         sh[j]->max_id = info.max_id + 1;
+
+      if (info.large_sg && sh[j]->sg_tablesize == MAX_SGLIST)
+         sh[j]->sg_tablesize = MAX_LARGE_SGLIST;
+      }
+
+   if (protocol_rev == 'C') {
+
+      if (info.max_lun > 7 && info.max_lun < MAX_LUN)
+         sh[j]->max_lun = info.max_lun + 1;
+      }
+
+   if (subversion == ESA && protocol_rev == 'C' && info.pci) bus_type = "PCI";
+   else if (sh[j]->io_port > EISA_RANGE) bus_type = "PCI";
+   else if (subversion == ESA) bus_type = "EISA";
+   else bus_type = "ISA";
+
+   for (i = 0; i < sh[j]->can_queue; i++)
+      if (! ((&HD(j)->cp[i])->sglist = kmalloc(
+            sh[j]->sg_tablesize * sizeof(struct sg_list), 
+            (sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) {
+         printk("%s: kmalloc SGlist failed, mbox %d, detaching.\n", BN(j), i);
+         eata2x_release(sh[j]);
+         return FALSE;
+         }
+      
+   printk("%s: rev. 2.0%c, %s, PORT 0x%03x, IRQ %u, DMA %u, SG %d, "\
+	  "Mbox %d, CmdLun %d.\n", BN(j), HD(j)->protocol_rev, bus_type,
+	   sh[j]->io_port, sh[j]->irq, sh[j]->dma_channel,
+	   sh[j]->sg_tablesize, sh[j]->can_queue, sh[j]->cmd_per_lun);
+
    if (sh[j]->max_id > 8 || sh[j]->max_lun > 8)
       printk("%s: wide SCSI support enabled, max_id %u, max_lun %u.\n",
              BN(j), sh[j]->max_id, sh[j]->max_lun);
 
-   for (c = 0; c <= sh[j]->max_channel; c++)
+   for (i = 0; i <= sh[j]->max_channel; i++)
       printk("%s: SCSI channel %u enabled, host target ID %u.\n",
-             BN(j), c, info.host_addr[3 - c]);
+             BN(j), i, info.host_addr[3 - i]);
 
 #if defined (DEBUG_DETECT)
-   if (protocol_rev != 'A')
-      printk("%s: EATA 2.0%c, isaena %u, forcaddr %u, max_id %u,"\
-	     " max_chan %u, max_lun %u.\n", name, protocol_rev, info.isaena, 
-	     info.forcaddr, info.max_id, info.max_chan, info.max_lun);
-
-   printk("%s: Vers. 0x%x, SYNC 0x%x, sec. %u, infol %ld, cpl %ld spl %ld.\n", 
-	  name, info.version, info.sync, info.second, DEV2H(info.data_len), 
-	  DEV2H(info.cp_len), DEV2H(info.sp_len));
+   printk("%s: Vers. 0x%x, ocs %u, tar %u, SYNC 0x%x, sec. %u, "\
+          "infol %ld, cpl %ld spl %ld.\n", name, info.version,
+          info.ocsena, info.tarsup, info.sync, info.second,
+          DEV2H(info.data_len), DEV2H(info.cp_len), DEV2H(info.sp_len));
+
+   if (protocol_rev == 'B' || protocol_rev == 'C')
+      printk("%s: isaena %u, forcaddr %u, max_id %u, max_chan %u, "\
+             "large_sg %u, res1 %u.\n", name, info.isaena, info.forcaddr,
+             info.max_id, info.max_chan, info.large_sg, info.res1);
+
+   if (protocol_rev == 'C')
+      printk("%s: max_lun %u, pci %u, eisa %u.\n", name, 
+             info.max_lun, info.pci, info.eisa);
 #endif
 
    return TRUE;
 }
 
-int eata2x_detect(Scsi_Host_Template *tpnt) {
-   unsigned int j = 0, k, flags;
+void eata2x_setup(char *str, int *ints) {
+   int i, argc = ints[0];
 
-   unsigned int io_port[] = { 
-      0x1f0,  0x1c88, 0x2c88, 0x3c88, 0x4c88, 0x5c88, 0x6c88, 0x7c88,
-      0x8c88, 0x9c88, 0xac88, 0xbc88, 0xcc88, 0xdc88, 0xec88, 0xfc88, 
-      0x170,  0x230,  0x330,  0x0
-      };
+   if (argc <= 0) return;
 
-   unsigned int *port_base = io_port;
+   if (argc > MAX_BOARDS) argc = MAX_BOARDS;
+
+   for (i = 0; i < argc; i++) io_port[i] = ints[i + 1]; 
+   
+   io_port[i] = 0;
+   setup_done = TRUE;
+   return;
+}
+
+static void add_pci_ports(void) {
+
+#if defined(CONFIG_PCI)
+
+   unsigned short i = 0;
+   unsigned char bus, devfn;
+   unsigned int addr, k;
+
+   if (!pcibios_present()) return;
+
+   for (k = 0; k < MAX_PCI; k++) {
+
+      if (pcibios_find_class(PCI_CLASS_STORAGE_SCSI << 8, i++, &bus, &devfn)
+             != PCIBIOS_SUCCESSFUL) break;
+
+      if (pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &addr)
+             != PCIBIOS_SUCCESSFUL) continue;
+
+#if defined(DEBUG_DETECT)
+      printk("%s: detect, seq. %d, bus %d, devfn 0x%x, addr 0x%x.\n",
+             driver_name, k, bus, devfn, addr);
+#endif
+
+      if ((addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+             continue;
+
+      /* Reverse the returned address order */
+      io_port[MAX_PCI - k] = 
+             (addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0;
+      }
+#endif
+
+   return;
+}
+
+int eata2x_detect(Scsi_Host_Template *tpnt) {
+   unsigned long flags;
+   unsigned int j = 0, k;
 
    tpnt->proc_dir = &proc_scsi_eata2x;
 
@@ -615,17 +750,19 @@
    cli();
 
    for (k = 0; k < MAX_IRQ; k++) {
-      irqlist[k] = NO_IRQ;
+      irqlist[k] = 0;
       calls[k] = 0;
       }
 
    for (k = 0; k < MAX_BOARDS + 1; k++) sh[k] = NULL;
 
-   while (*port_base) {
+   if (!setup_done) add_pci_ports();
 
-      if (j < MAX_BOARDS && port_detect(port_base, j, tpnt)) j++;
+   for (k = 0; io_port[k]; k++) {
 
-      port_base++;
+      if (io_port[k] == SKIP) continue;
+
+      if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt)) j++;
       }
 
    if (j > 0) 
@@ -651,7 +788,8 @@
 }
 
 int eata2x_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
-   unsigned int i, j, k, flags;
+   unsigned long flags;
+   unsigned int i, j, k;
    struct mscp *cpp;
    struct mssp *spp;
 
@@ -702,7 +840,7 @@
    /* Set pointer to control packet structure */
    cpp = &HD(j)->cp[i];
 
-   memset(cpp, 0, sizeof(struct mscp));
+   memset(cpp, 0, sizeof(struct mscp) - sizeof(struct sg_list *));
 
    /* Set pointer to status packet structure */
    spp = &HD(j)->sp[i];
@@ -766,7 +904,8 @@
 }
 
 int eata2x_abort(Scsi_Cmnd *SCarg) {
-   unsigned int i, j, flags;
+   unsigned long flags;
+   unsigned int i, j;
 
    save_flags(flags);
    cli();
@@ -805,6 +944,9 @@
 	 panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
 	       BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
 
+      if (inb(sh[j]->io_port + REG_AUX_STATUS) & IRQ_ASSERTED)
+         printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i);
+
       restore_flags(flags);
       return SCSI_ABORT_SNOOZE;
       }
@@ -825,7 +967,8 @@
 }
 
 int eata2x_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
-   unsigned int i, j, flags, time, k, c, limit = 0;
+   unsigned long flags;
+   unsigned int i, j, time, k, c, limit = 0;
    int arg_done = FALSE;
    Scsi_Cmnd *SCpnt;
 
@@ -944,14 +1087,15 @@
 static void eata2x_interrupt_handler(int irq, void *dev_id,
                                      struct pt_regs *regs) {
    Scsi_Cmnd *SCpnt;
-   unsigned int i, j, k, c, flags, status, tstatus, loops, total_loops = 0;
+   unsigned long flags;
+   unsigned int i, j, k, c, status, tstatus, loops, total_loops = 0;
    struct mssp *spp;
    struct mscp *cpp;
 
    save_flags(flags);
    cli();
 
-   if (irqlist[irq] == NO_IRQ) {
+   if (!irqlist[irq]) {
       printk("%s, ihdlr, irq %d, unexpected interrupt.\n", driver_name, irq);
       restore_flags(flags);
       return;
@@ -1158,6 +1302,31 @@
 
    restore_flags(flags);
    return;
+}
+
+int eata2x_release(struct Scsi_Host *shpnt) {
+   unsigned long flags;
+   unsigned int i, j;
+
+   save_flags(flags);
+   cli();
+
+   for (j = 0; sh[j] != NULL && sh[j] != shpnt; j++);
+    
+   if (sh[j] == NULL) panic("%s: release, invalid Scsi_Host pointer.\n",
+                            driver_name);
+
+   for (i = 0; i < sh[j]->can_queue; i++) 
+      if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist);
+
+   if (! --irqlist[sh[j]->irq]) free_irq(sh[j]->irq, NULL);
+
+   if (sh[j]->dma_channel != NO_DMA) free_dma(sh[j]->dma_channel);
+
+   release_region(sh[j]->io_port, sh[j]->n_io_port);
+   scsi_unregister(sh[j]);
+   restore_flags(flags);
+   return FALSE;
 }
 
 #if defined(MODULE)
diff -u --recursive --new-file v2.0.26/linux/drivers/scsi/eata.h linux/drivers/scsi/eata.h
--- v2.0.26/linux/drivers/scsi/eata.h	Fri Nov 22 16:26:03 1996
+++ linux/drivers/scsi/eata.h	Sat Nov 23 15:28:23 1996
@@ -7,11 +7,12 @@
 #include <scsi/scsicam.h>
 
 int eata2x_detect(Scsi_Host_Template *);
+int eata2x_release(struct Scsi_Host *);
 int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int eata2x_abort(Scsi_Cmnd *);
 int eata2x_reset(Scsi_Cmnd *, unsigned int);
 
-#define EATA_VERSION "2.20.00"
+#define EATA_VERSION "2.30.00"
 
 
 #define EATA {                                                 \
@@ -21,7 +22,7 @@
 		NULL,                                          \
 		"EATA/DMA 2.0x rev. " EATA_VERSION " ",        \
 		eata2x_detect,				       \
-		NULL, /* Release */     		       \
+		eata2x_release,          		       \
 		NULL,					       \
 		NULL,    			       	       \
 		eata2x_queuecommand,			       \
diff -u --recursive --new-file v2.0.26/linux/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c
--- v2.0.26/linux/drivers/scsi/u14-34f.c	Fri Nov 22 16:26:04 1996
+++ linux/drivers/scsi/u14-34f.c	Sat Nov 23 15:28:23 1996
@@ -1,6 +1,12 @@
 /*
  *      u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
  *
+ *      21 Nov 1996 rev. 2.30 for linux 2.1.11 and 2.0.25
+ *          The list of i/o ports to be probed can be overwritten by the
+ *          "u14-34f=port0, port1,...." boot command line option.
+ *          Scatter/gather lists are now allocated by a number of kmalloc
+ *          calls, in order to avoid the previous size limit of 64Kb.
+ *
  *      16 Nov 1996 rev. 2.20 for linux 2.1.10 and 2.0.25
  *          Added multichannel support.
  *
@@ -74,6 +80,11 @@
  *
  *  Copyright (C) 1994, 1995, 1996 Dario Ballabio (dario@milano.europe.dg.com)
  *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that redistributions of source
+ *  code retain the above copyright notice and this comment without
+ *  modification.
+ *
  *      WARNING: if your 14/34F board has an old firmware revision (see below)
  *               you must change "#undef" into "#define" in the following
  *               statement.
@@ -149,6 +160,15 @@
  *  the latest firmware prom is 28008-006. Older firmware 28008-005 has
  *  problems when using more then 16 scatter/gather lists.
  *
+ *  The list of i/o ports to be probed can be totally replaced by the
+ *  boot command line option: "u14-34f=port0, port1, port2,...", where the
+ *  port0, port1... arguments are ISA/VESA addresses to be probed.
+ *  For example using "u14-34f=0x230, 0x340", the driver probes only the two
+ *  addresses 0x230 and 0x340 in this order; "u14-34f=0" totally disables
+ *  this driver.
+ *
+ *  The boards are named Ux4F0, Ux4F1,... according to the detection order.
+ *
  *  In order to support multiple ISA boards in a reliable way,
  *  the driver sets host->wish_block = TRUE for all ISA boards.
  */
@@ -205,11 +225,15 @@
 #undef  DEBUG_STATISTICS
 #undef  DEBUG_RESET
 
+#define MAX_ISA 3
+#define MAX_VESA 1 
+#define MAX_EISA 0
+#define MAX_PCI 0
+#define MAX_BOARDS (MAX_ISA + MAX_VESA + MAX_EISA + MAX_PCI)
 #define MAX_CHANNEL 1
 #define MAX_LUN 8
 #define MAX_TARGET 8
 #define MAX_IRQ 16
-#define MAX_BOARDS 4
 #define MAX_MAILBOXES 16
 #define MAX_SGLIST 32
 #define MAX_SAFE_SGLIST 16
@@ -223,7 +247,6 @@
 #define LOCKED   2
 #define IN_RESET 3
 #define IGNORE   4
-#define NO_IRQ  0xff
 #define NO_DMA  0xff
 #define MAXLOOP 200000
 
@@ -251,6 +274,11 @@
 
 #define PACKED          __attribute__((packed))
 
+struct sg_list {
+   unsigned int address;                /* Segment Address */
+   unsigned int num_bytes;              /* Segment Length */
+   };
+
 /* MailBox SCSI Command Packet */
 struct mscp {
    unsigned char opcode: 3;             /* type of command */
@@ -272,15 +300,9 @@
    unsigned char adapter_status;        /* non-zero indicates HA error */
    unsigned char target_status;         /* non-zero indicates target error */
    unsigned int sense_addr PACKED;
-
    Scsi_Cmnd *SCpnt;
-
-   struct sg_list {
-      unsigned int address;             /* Segment Address */
-      unsigned int num_bytes;           /* Segment Length */
-      } sglist[MAX_SGLIST];
-
-   unsigned int index;   /* cp index */
+   unsigned int index;                  /* cp index */
+   struct sg_list *sglist;
    };
 
 struct hostdata {
@@ -309,6 +331,13 @@
 static const char *driver_name = "Ux4F";
 static unsigned int irqlist[MAX_IRQ], calls[MAX_IRQ];
 
+static unsigned int io_port[] = {
+      0x330, 0x340, 0x230, 0x240, 0x210, 0x130, 0x140,
+
+      /* End of list */
+      0x0
+      };
+
 #define HD(board) ((struct hostdata *) &sh[board]->hostdata)
 #define BN(board) (HD(board)->board_name)
 
@@ -328,6 +357,7 @@
 
 static void u14_34f_interrupt_handler(int, void *, struct pt_regs *);
 static int do_trace = FALSE;
+static int setup_done = FALSE;
 
 static inline int wait_on_busy(unsigned int iobase) {
    unsigned int loop = MAXLOOP;
@@ -381,9 +411,9 @@
    return FALSE;
 }
 
-static inline int port_detect(unsigned int *port_base, unsigned int j, 
-			      Scsi_Host_Template *tpnt) {
-   unsigned char irq, dma_channel, subversion, c;
+static inline int port_detect(unsigned int port_base, unsigned int j, 
+                              Scsi_Host_Template *tpnt) {
+   unsigned char irq, dma_channel, subversion, i;
    unsigned char in_byte;
 
    /* Allowed BIOS base addresses (NULL indicates reserved) */
@@ -425,28 +455,27 @@
 
    sprintf(name, "%s%d", driver_name, j);
 
-   if(check_region(*port_base, REGION_SIZE)) {
-      printk("%s: address 0x%03x in use, skipping probe.\n", 
-	     name, *port_base);
+   if(check_region(port_base, REGION_SIZE)) {
+      printk("%s: address 0x%03x in use, skipping probe.\n", name, port_base);
       return FALSE;
       }
 
-   if (inb(*port_base + REG_PRODUCT_ID1) != PRODUCT_ID1) return FALSE;
+   if (inb(port_base + REG_PRODUCT_ID1) != PRODUCT_ID1) return FALSE;
 
-   in_byte = inb(*port_base + REG_PRODUCT_ID2);
+   in_byte = inb(port_base + REG_PRODUCT_ID2);
 
    if ((in_byte & 0xf0) != PRODUCT_ID2) return FALSE;
 
-   *(char *)&config_1 = inb(*port_base + REG_CONFIG1);
-   *(char *)&config_2 = inb(*port_base + REG_CONFIG2);
+   *(char *)&config_1 = inb(port_base + REG_CONFIG1);
+   *(char *)&config_2 = inb(port_base + REG_CONFIG2);
 
    irq = interrupt_table[config_1.interrupt];
    dma_channel = dma_channel_table[config_1.dma_channel];
    subversion = (in_byte & 0x0f);
 
    /* Board detected, allocate its IRQ if not already done */
-   if ((irq >= MAX_IRQ) || ((irqlist[irq] == NO_IRQ) && request_irq
-       (irq, u14_34f_interrupt_handler, SA_INTERRUPT, driver_name, NULL))) {
+   if ((irq >= MAX_IRQ) || (!irqlist[irq] && request_irq(irq,
+              u14_34f_interrupt_handler, SA_INTERRUPT, driver_name, NULL))) {
       printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq);
       return FALSE;
       }
@@ -463,15 +492,15 @@
    if (sh[j] == NULL) {
       printk("%s: unable to register host, detaching.\n", name);
 
-      if (irqlist[irq] == NO_IRQ) free_irq(irq, NULL);
+      if (!irqlist[irq]) free_irq(irq, NULL);
 
       if (subversion == ISA) free_dma(dma_channel);
 
       return FALSE;
       }
 
-   sh[j]->io_port = *port_base;
-   sh[j]->unique_id = *port_base;
+   sh[j]->io_port = port_base;
+   sh[j]->unique_id = port_base;
    sh[j]->n_io_port = REGION_SIZE;
    sh[j]->base = bios_segment_table[config_1.bios_segment];
    sh[j]->irq = irq;
@@ -494,14 +523,14 @@
    if (sh[j]->base == 0) outb(CMD_ENA_INTR, sh[j]->io_port + REG_SYS_MASK);
 
    /* Register the I/O space that we use */
-   request_region(sh[j]->io_port, REGION_SIZE, driver_name);
+   request_region(sh[j]->io_port, sh[j]->n_io_port, driver_name);
 
    memset(HD(j), 0, sizeof(struct hostdata));
    HD(j)->heads = mapping_table[config_2.mapping_mode].heads;
    HD(j)->sectors = mapping_table[config_2.mapping_mode].sectors;
    HD(j)->subversion = subversion;
    HD(j)->board_number = j;
-   irqlist[irq] = j;
+   irqlist[irq]++;
 
    if (HD(j)->subversion == ESA) {
 
@@ -546,6 +575,15 @@
 	 }
       }
 
+   for (i = 0; i < sh[j]->can_queue; i++)
+      if (! ((&HD(j)->cp[i])->sglist = kmalloc(
+            sh[j]->sg_tablesize * sizeof(struct sg_list), 
+            (sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) {
+         printk("%s: kmalloc SGlist failed, mbox %d, detaching.\n", BN(j), i);
+         u14_34f_release(sh[j]);
+         return FALSE;
+         }
+      
    printk("%s: PORT 0x%03x, BIOS 0x%05x, IRQ %u, DMA %u, SG %d, "\
 	  "Mbox %d, CmdLun %d, C%d.\n", BN(j), sh[j]->io_port, 
 	  (int)sh[j]->base, sh[j]->irq, sh[j]->dma_channel,
@@ -556,21 +594,30 @@
       printk("%s: wide SCSI support enabled, max_id %u, max_lun %u.\n",
              BN(j), sh[j]->max_id, sh[j]->max_lun);
 
-   for (c = 0; c <= sh[j]->max_channel; c++)
+   for (i = 0; i <= sh[j]->max_channel; i++)
       printk("%s: SCSI channel %u enabled, host target ID %u.\n",
-             BN(j), c, sh[j]->this_id);
+             BN(j), i, sh[j]->this_id);
 
    return TRUE;
 }
 
-int u14_34f_detect(Scsi_Host_Template *tpnt) {
-   unsigned int j = 0, k, flags;
+void u14_34f_setup(char *str, int *ints) {
+   int i, argc = ints[0];
 
-   unsigned int io_port[] = {
-      0x330, 0x340, 0x230, 0x240, 0x210, 0x130, 0x140, 0x0
-      };
+   if (argc <= 0) return;
 
-   unsigned int *port_base = io_port;
+   if (argc > MAX_BOARDS) argc = MAX_BOARDS;
+
+   for (i = 0; i < argc; i++) io_port[i] = ints[i + 1]; 
+   
+   io_port[i] = 0;
+   setup_done = TRUE;
+   return;
+}
+
+int u14_34f_detect(Scsi_Host_Template *tpnt) {
+   unsigned long flags;
+   unsigned int j = 0, k;
 
    tpnt->proc_dir = &proc_scsi_u14_34f;
 
@@ -578,18 +625,14 @@
    cli();
 
    for (k = 0; k < MAX_IRQ; k++) {
-      irqlist[k] = NO_IRQ;
+      irqlist[k] = 0;
       calls[k] = 0;
       }
 
    for (k = 0; k < MAX_BOARDS + 1; k++) sh[k] = NULL;
 
-   while (*port_base) {
-
-      if (j < MAX_BOARDS && port_detect(port_base, j, tpnt)) j++;
-
-      port_base++;
-      }
+   for (k = 0; io_port[k]; k++)
+      if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt)) j++;
 
    if (j > 0) 
       printk("UltraStor 14F/34F: Copyright (C) 1994, 1995, 1996 Dario Ballabio.\n");
@@ -616,7 +659,8 @@
 }
 
 int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
-   unsigned int i, j, k, flags;
+   unsigned long flags;
+   unsigned int i, j, k;
    struct mscp *cpp;
 
    static const unsigned char data_out_cmds[] = {
@@ -666,7 +710,7 @@
    /* Set pointer to control packet structure */
    cpp = &HD(j)->cp[i];
 
-   memset(cpp, 0, sizeof(struct mscp));
+   memset(cpp, 0, sizeof(struct mscp) - sizeof(struct sg_list *));
    SCpnt->scsi_done = done;
    cpp->index = i;
    SCpnt->host_scribble = (unsigned char *) &cpp->index;
@@ -726,7 +770,8 @@
 }
 
 int u14_34f_abort(Scsi_Cmnd *SCarg) {
-   unsigned int i, j, flags;
+   unsigned long flags;
+   unsigned int i, j;
 
    save_flags(flags);
    cli();
@@ -765,6 +810,9 @@
 	 panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
 	       BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
 
+      if (inb(sh[j]->io_port + REG_SYS_INTR) & IRQ_ASSERTED)
+         printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i);
+
       restore_flags(flags);
       return SCSI_ABORT_SNOOZE;
       }
@@ -785,7 +833,8 @@
 }
 
 int u14_34f_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
-   unsigned int i, j, flags, time, k, c, limit = 0;
+   unsigned long flags;
+   unsigned int i, j, time, k, c, limit = 0;
    int arg_done = FALSE;
    Scsi_Cmnd *SCpnt;
 
@@ -909,19 +958,20 @@
    dkinfo[0] = HD(j)->heads;
    dkinfo[1] = HD(j)->sectors;
    dkinfo[2] = size / (HD(j)->heads * HD(j)->sectors);
-   return 0;
+   return FALSE;
 }
 
 static void u14_34f_interrupt_handler(int irq, void *dev_id,
                                       struct pt_regs *regs) {
    Scsi_Cmnd *SCpnt;
-   unsigned int i, j, k, c, flags, status, tstatus, loops, total_loops = 0;
+   unsigned long flags;
+   unsigned int i, j, k, c, status, tstatus, loops, total_loops = 0;
    struct mscp *spp;
 
    save_flags(flags);
    cli();
 
-   if (irqlist[irq] == NO_IRQ) {
+   if (!irqlist[irq]) {
       printk("%s, ihdlr, irq %d, unexpected interrupt.\n", driver_name, irq);
       restore_flags(flags);
       return;
@@ -1122,6 +1172,31 @@
 
    restore_flags(flags);
    return;
+}
+
+int u14_34f_release(struct Scsi_Host *shpnt) {
+   unsigned long flags;
+   unsigned int i, j;
+
+   save_flags(flags);
+   cli();
+
+   for (j = 0; sh[j] != NULL && sh[j] != shpnt; j++);
+    
+   if (sh[j] == NULL) panic("%s: release, invalid Scsi_Host pointer.\n",
+                            driver_name);
+
+   for (i = 0; i < sh[j]->can_queue; i++) 
+      if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist);
+
+   if (! --irqlist[sh[j]->irq]) free_irq(sh[j]->irq, NULL);
+
+   if (sh[j]->dma_channel != NO_DMA) free_dma(sh[j]->dma_channel);
+
+   release_region(sh[j]->io_port, sh[j]->n_io_port);
+   scsi_unregister(sh[j]);
+   restore_flags(flags);
+   return FALSE;
 }
 
 #if defined(MODULE)
diff -u --recursive --new-file v2.0.26/linux/drivers/scsi/u14-34f.h linux/drivers/scsi/u14-34f.h
--- v2.0.26/linux/drivers/scsi/u14-34f.h	Fri Nov 22 16:26:05 1996
+++ linux/drivers/scsi/u14-34f.h	Sat Nov 23 15:28:23 1996
@@ -5,12 +5,13 @@
 #define _U14_34F_H
 
 int u14_34f_detect(Scsi_Host_Template *);
+int u14_34f_release(struct Scsi_Host *);
 int u14_34f_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int u14_34f_abort(Scsi_Cmnd *);
 int u14_34f_reset(Scsi_Cmnd *, unsigned int);
 int u14_34f_biosparam(Disk *, kdev_t, int *);
 
-#define U14_34F_VERSION "2.20.00"
+#define U14_34F_VERSION "2.30.00"
 
 #define ULTRASTOR_14_34F {                                            \
 		NULL, /* Ptr for modules */                           \
@@ -19,7 +20,7 @@
 		NULL,		                                      \
 		"UltraStor 14F/34F rev. " U14_34F_VERSION " ",        \
 		u14_34f_detect,                                       \
-		NULL, /* Release */                                   \
+		u14_34f_release,                                      \
 		NULL,						      \
 		NULL,                                                 \
 		u14_34f_queuecommand,                                 \
diff -u --recursive --new-file v2.0.26/linux/fs/Config.in linux/fs/Config.in
--- v2.0.26/linux/fs/Config.in	Wed Jun  5 13:24:45 1996
+++ linux/fs/Config.in	Sun Dec  1 15:58:05 1996
@@ -28,8 +28,8 @@
     fi
   fi
   tristate 'SMB filesystem support (to mount WfW shares etc..)' CONFIG_SMB_FS
-  if [ "$CONFIG_SMB_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    bool 'SMB long filename support (EXPERIMENTAL)' CONFIG_SMB_LONG
+  if [ "$CONFIG_SMB_FS" != "n" ]; then
+    bool 'SMB Win95 bug work-around' CONFIG_SMB_WIN95
   fi
 fi
 if [ "$CONFIG_IPX" != "n" ]; then
diff -u --recursive --new-file v2.0.26/linux/fs/fat/inode.c linux/fs/fat/inode.c
--- v2.0.26/linux/fs/fat/inode.c	Mon Aug  5 10:13:54 1996
+++ linux/fs/fat/inode.c	Sat Nov 30 12:27:38 1996
@@ -48,13 +48,12 @@
 	}
 	inode->i_size = 0;
 	fat_truncate(inode);
-	clear_inode(inode);
 	if (depend) {
 		if (MSDOS_I(depend)->i_old != inode) {
 			printk("Invalid link (0x%p): expected 0x%p, got 0x%p\n",
 			    depend, inode, MSDOS_I(depend)->i_old);
 			fat_fs_panic(sb,"...");
-			return;
+			goto done;
 		}
 		MSDOS_I(depend)->i_old = NULL;
 		iput(depend);
@@ -64,11 +63,13 @@
 			printk("Invalid link (0x%p): expected 0x%p, got 0x%p\n",
 			    linked, inode, MSDOS_I(linked)->i_oldlink);
 			fat_fs_panic(sb,"...");
-			return;
+			goto done;
 		}
 		MSDOS_I(linked)->i_oldlink = NULL;
 		iput(linked);
 	}
+done:
+	clear_inode(inode);
 }
 
 
diff -u --recursive --new-file v2.0.26/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c
--- v2.0.26/linux/fs/smbfs/dir.c	Wed Sep 11 17:57:16 1996
+++ linux/fs/smbfs/dir.c	Sun Dec  1 15:58:05 1996
@@ -1,7 +1,7 @@
 /*
  *  dir.c
  *
- *  Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
  *
  */
 
@@ -12,98 +12,69 @@
 #include <linux/malloc.h>
 #include <linux/mm.h>
 #include <linux/smb_fs.h>
+#include <linux/smbno.h>
 #include <asm/segment.h>
+#include <asm/semaphore.h>
 #include <linux/errno.h>
 
-#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
-#define ROUND_UP(x) (((x)+3) & ~3)
-
-static int 
-smb_dir_read(struct inode *inode, struct file *filp, char *buf, int count);
-
-static int 
-smb_readdir(struct inode *inode, struct file *filp,
-            void *dirent, filldir_t filldir);
-
-static int 
-get_pname(struct inode *dir, const char *name, int len,
-          char **res_path, int *res_len);
-
 static int
-get_pname_static(struct inode *dir, const char *name, int len,
-                 char *path, int *res_len);
+ smb_dir_read(struct inode *inode, struct file *filp, char *buf, int count);
 
-static void 
-put_pname(char *path);
+static int
+ smb_readdir(struct inode *inode, struct file *filp,
+	     void *dirent, filldir_t filldir);
 
 static struct smb_inode_info *
-smb_find_inode(struct smb_server *server, const char *path);
+ 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);
+ 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_create(struct inode *dir, const char *name, int len, int mode,
+	    struct inode **result);
 
-static int 
-smb_rmdir(struct inode *dir, const char *name, int len);
+static int
+ smb_mkdir(struct inode *dir, const char *name, int len, int mode);
 
 static int
-smb_unlink(struct inode *dir, const char *name, int len);
+ smb_rmdir(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,
-           int must_be_dir);
+ smb_unlink(struct inode *dir, const char *name, int len);
 
-static inline void str_upper(char *name)
-{
-	while (*name) {
-		if (*name >= 'a' && *name <= 'z')
-			*name -= ('a' - 'A');
-		name++;
-	}
-}
+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,
+	    int must_be_dir);
 
-static inline void str_lower(char *name)
+static struct file_operations smb_dir_operations =
 {
-	while (*name) {
-		if (*name >= 'A' && *name <= 'Z')
-			*name += ('a' - 'A');
-		name ++;
-	}
-}
-
-static struct file_operations smb_dir_operations = {
-        NULL,			/* lseek - default */
+	NULL,			/* lseek - default */
 	smb_dir_read,		/* read - bad */
 	NULL,			/* write - bad */
 	smb_readdir,		/* readdir */
 	NULL,			/* select - default */
 	smb_ioctl,		/* ioctl - default */
-	NULL,                   /* mmap */
+	NULL,			/* mmap */
 	NULL,			/* no special open code */
 	NULL,			/* no special release code */
 	NULL			/* fsync */
 };
 
-struct inode_operations smb_dir_inode_operations = 
+struct inode_operations smb_dir_inode_operations =
 {
 	&smb_dir_operations,	/* default directory file ops */
 	smb_create,		/* create */
-	smb_lookup,    		/* lookup */
+	smb_lookup,		/* lookup */
 	NULL,			/* link */
-	smb_unlink,    		/* unlink */
+	smb_unlink,		/* unlink */
 	NULL,			/* symlink */
-	smb_mkdir,     		/* mkdir */
-	smb_rmdir,     		/* rmdir */
+	smb_mkdir,		/* mkdir */
+	smb_rmdir,		/* rmdir */
 	NULL,			/* mknod */
-	smb_rename,    		/* rename */
+	smb_rename,		/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
 	NULL,			/* readpage */
@@ -111,336 +82,301 @@
 	NULL,			/* bmap */
 	NULL,			/* truncate */
 	NULL,			/* permission */
-	NULL                    /* smap */
+	NULL			/* smap */
 };
 
-
-static int 
-smb_dir_read(struct inode *inode, struct file *filp, char *buf, int count)
+static int
+strncasecmp(const char *s1, const char *s2, int len)
 {
-	return -EISDIR;
-}
+	int result = 0;
 
-/*
- * Description:
- *  smb_readdir provides a listing in the form of filling the dirent structure.
- *  Note that dirent resides in the user space. This is to support reading of a
- *  directory "stream". 
- * Notes:
- *     Since we want to reduce directory lookups we revert into a
- *     dircache. It is taken rather directly out of the nfs_readdir.
- */
+	for (; len > 0; len -= 1)
+	{
+		char c1, c2;
 
-/* In smbfs, we have unique inodes across all mounted filesystems, for
-   all inodes that are in memory. That's why it's enough to index the
-   directory cache by the inode number. */
-
-static unsigned long      c_ino = 0;
-static int                c_size;
-static int                c_seen_eof;
-static int                c_last_returned_index;
-static struct smb_dirent* c_entry = NULL;
+		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
-smb_readdir(struct inode *inode, struct file *filp,
-            void *dirent, filldir_t filldir)
+compare_filename(const struct smb_server *server,
+		 const char *s1, int len, struct smb_dirent *entry)
 {
-	int result, i = 0;
-        int index = 0;
-	struct smb_dirent *entry = NULL;
-        struct smb_server *server = SMB_SERVER(inode);
-
-	DDPRINTK("smb_readdir: filp->f_pos = %d\n", (int)filp->f_pos);
-	DDPRINTK("smb_readdir: inode->i_ino = %ld, c_ino = %ld\n",
-		 inode->i_ino, c_ino);
-
-	if (!inode || !S_ISDIR(inode->i_mode)) {
-		printk("smb_readdir: inode is NULL or not a directory\n");
-		return -EBADF;
+	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;
 
-	if (c_entry == NULL) 
+	do
 	{
-		i = sizeof (struct smb_dirent) * SMB_READDIR_CACHE_SIZE;
-		c_entry = (struct smb_dirent *) smb_kmalloc(i, GFP_KERNEL);
-		if (c_entry == NULL) {
-			printk("smb_readdir: no MEMORY for cache\n");
-			return -ENOMEM;
-		}
-		for (i = 0; i < SMB_READDIR_CACHE_SIZE; i++) {
-			c_entry[i].path =
-                                (char *) smb_kmalloc(SMB_MAXNAMELEN + 1,
-                                                     GFP_KERNEL);
-                        if (c_entry[i].path == NULL) {
-                                DPRINTK("smb_readdir: could not alloc path\n");
-				while (--i>=0)
-					kfree(c_entry[i].path);
-				kfree(c_entry);
-				c_entry = NULL;
-				return -ENOMEM;
-                        }
-                }
-	}
-
-        if (filp->f_pos == 0) {
-                smb_invalid_dir_cache(inode->i_ino);
-        }
-
-	if (inode->i_ino == c_ino) {
-		for (i = 0; i < c_size; i++) {
-			if (filp->f_pos == c_entry[i].f_pos) {
-                                entry = &c_entry[i];
-                                c_last_returned_index = i;
-                                index = i;
-                                break;
-			}
+		if (ino == smb_info_ino(this))
+		{
+			return this;
 		}
-                if ((entry == NULL) && c_seen_eof)
-                        return 0;
+		this = this->next;
 	}
+	while (this != root);
 
-	if (entry == NULL) {
-		DPRINTK("smb_readdir: Not found in cache.\n");
-		result = smb_proc_readdir(server, inode,
-                                          filp->f_pos, SMB_READDIR_CACHE_SIZE,
-                                          c_entry);
+	return NULL;
+}
 
-		if (result < 0) {
-			c_ino = 0;
-			return result;
-		}
+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;
 
-		if (result > 0) {
-                        c_seen_eof = (result < SMB_READDIR_CACHE_SIZE);
-			c_ino  = inode->i_ino;
-			c_size = result;
-			entry = c_entry;
-                        c_last_returned_index = 0;
-                        index = 0;
-                        for (i = 0; i < c_size; i++) {
-
-                                switch (server->case_handling) 
-                                {
-                                case CASE_UPPER:
-                                        str_upper(c_entry[i].path); break;
-                                case CASE_LOWER:
-                                        str_lower(c_entry[i].path); break;
-                                case CASE_DEFAULT:
-                                        break;
-                                }
-                        }
+      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);
 
-        if (entry == NULL) {
-                /* Nothing found, even from a smb call */
-                return 0;
-        }
-
-        while (index < 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..) */ 
-
-                int path_len;
-                int len;
-                struct smb_inode_info *ino_info;
-                char complete_path[SMB_MAXPATHLEN];
-
-		len = strlen(entry->path);
-                if ((result = get_pname_static(inode, entry->path, len,
-                                               complete_path,
-                                               &path_len)) < 0)
-                        return result;
-
-                ino_info = smb_find_inode(server, complete_path);
-
-                /* Some programs seem to be confused about a zero
-                   inode number, so we set it to one.  Thanks to
-                   Gordon Chaffee for this one. */
-                if (ino_info == NULL) {
-                        ino_info = (struct smb_inode_info *) 1;
-                }
-
-		DDPRINTK("smb_readdir: entry->path = %s\n", entry->path);
-		DDPRINTK("smb_readdir: entry->f_pos = %ld\n", entry->f_pos);
+	seed += no;
 
-                if (filldir(dirent, entry->path, len,
-                            entry->f_pos, (ino_t)ino_info) < 0) {
-                        break;
-                }
-
-                if (   (inode->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;
-                index += 1;
-                entry += 1;
-	}
-	return 0;
+	return seed - no;
 }
 
-void
-smb_init_dir_cache(void)
+static int
+smb_dir_read(struct inode *inode, struct file *filp, char *buf, int count)
 {
-        c_ino   = 0;
-        c_entry = NULL;
+	return -EISDIR;
 }
 
-void
-smb_invalid_dir_cache(unsigned long ino)
+
+static unsigned long c_ino = 0;
+static kdev_t c_dev;
+static int c_size;
+static int c_seen_eof;
+static int c_last_returned_index;
+static struct smb_dirent *c_entry = NULL;
+
+static struct smb_dirent *
+smb_search_in_cache(struct inode *dir, unsigned long f_pos)
 {
-	if (ino == c_ino) {
-                c_ino = 0;
-                c_seen_eof = 0;
-        }
+	int i;
+
+	if ((dir->i_dev != c_dev) || (dir->i_ino != c_ino))
+	{
+		return NULL;
+	}
+	for (i = 0; i < c_size; i++)
+	{
+		if (f_pos == c_entry[i].f_pos)
+		{
+			c_last_returned_index = i;
+			return &(c_entry[i]);
+		}
+	}
+	return NULL;
 }
 
-void
-smb_free_dir_cache(void)
+static int
+smb_refill_dir_cache(struct smb_server *server, struct inode *dir,
+		     unsigned long f_pos)
 {
-        int i;
+	int result;
+	static struct semaphore sem = MUTEX;
+	int i;
+	ino_t ino;
 
-        DPRINTK("smb_free_dir_cache: enter\n");
-        
-        if (c_entry == NULL)
-                return;
+	do
+	{
+		down(&sem);
+		result = smb_proc_readdir(server, dir, f_pos,
+					  SMB_READDIR_CACHE_SIZE, c_entry);
 
-        for (i = 0; i < SMB_READDIR_CACHE_SIZE; i++) {
-                smb_kfree_s(c_entry[i].path, NAME_MAX + 1);
-        }
+		if (result <= 0)
+		{
+			smb_invalid_dir_cache(dir->i_ino);
+			up(&sem);
+			return result;
+		}
+		c_seen_eof = (result < SMB_READDIR_CACHE_SIZE);
+		c_dev = dir->i_dev;
+		c_ino = dir->i_ino;
+		c_size = result;
+		c_last_returned_index = 0;
 
-        smb_kfree_s(c_entry,
-                    sizeof(struct smb_dirent) * SMB_READDIR_CACHE_SIZE);
-        c_entry = NULL;
+		ino = smb_fresh_inodes(server, c_size);
+		for (i = 0; i < c_size; i++)
+		{
+			c_entry[i].f_ino = ino;
+			ino += 1;
+		}
 
-        DPRINTK("smb_free_dir_cache: exit\n");
-}
+		up(&sem);
 
+	}
+	while ((c_dev != dir->i_dev) || (c_ino != dir->i_ino));
 
-/* get_pname_static: it expects the res_path to be a preallocated
-   string of len SMB_MAXPATHLEN. */
+	return result;
+}
 
 static int
-get_pname_static(struct inode *dir, const char *name, int len,
-                 char *path, int *res_len)
+smb_readdir(struct inode *dir, struct file *filp,
+	    void *dirent, filldir_t filldir)
 {
-        char *parentname = SMB_INOP(dir)->finfo.path;
-        int   parentlen  = SMB_INOP(dir)->finfo.len;
-
-#if 1
-        if (parentlen != strlen(parentname)) {
-                printk("get_pname: parent->finfo.len = %d instead of %d\n",
-                       parentlen, strlen(parentname));
-                parentlen = strlen(parentname);
-        }
-	
-#endif
-	DDPRINTK("get_pname_static: parentname = %s, len = %d\n",
-                 parentname, parentlen);
-	
-        if (len > SMB_MAXNAMELEN) {
-                return -ENAMETOOLONG;
-        }
+	int result, i = 0;
+	struct smb_dirent *entry = NULL;
+	struct smb_server *server = SMB_SERVER(dir);
 
-	/* Fast cheat for . */
-	if (len == 0 || (len == 1 && name[0] == '.')) {
+	DPRINTK("smb_readdir: filp->f_pos = %d\n", (int) filp->f_pos);
+	DDPRINTK("smb_readdir: dir->i_ino = %ld, c_ino = %ld\n",
+		 dir->i_ino, c_ino);
 
-		memcpy(path, parentname, parentlen + 1);
-		*res_len = parentlen;
-		return 0;
+	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)
+	{
+		i = sizeof(struct smb_dirent) * SMB_READDIR_CACHE_SIZE;
+		c_entry = (struct smb_dirent *) smb_vmalloc(i);
+		if (c_entry == NULL)
+		{
+			printk("smb_readdir: no MEMORY for cache\n");
+			return -ENOMEM;
+		}
 	}
-	
-	/* Hmm, what about .. ? */
-	if (len == 2 && name[0] == '.' && name[1] == '.') {
-
-		char *pos = strrchr(parentname, '\\');
-
-                if (   (pos == NULL)
-                    && (parentlen == 0)) {
-
-                        /* We're at the top */
-
-                        path[0] = '\\';
-                        path[1] = '\0';
-                        *res_len  = 2;
-                        return 0;
-                }
-                        
-                
-		if (pos == NULL) {
-			printk("smb_make_name: Bad parent SMB-name: %s",
-                               parentname);
-			return -ENODATA;
-		}
-		
-		len = pos - parentname;
+	if (filp->f_pos == 0)
+	{
+		c_ino = 0;
+		c_dev = 0;
+		c_seen_eof = 0;
 
-	        memcpy(path, parentname, len);
-		path[len] = '\0';
+		if (filldir(dirent, ".", 1, filp->f_pos,
+			    smb_info_ino(SMB_INOP(dir))) < 0)
+		{
+			return 0;
+		}
+		filp->f_pos += 1;
 	}
-	else
+	if (filp->f_pos == 1)
 	{
-		if (len + parentlen + 2 > SMB_MAXPATHLEN) 
-			return -ENAMETOOLONG;
-				
-		memcpy(path, parentname, parentlen);
-		path[parentlen] = '\\';
-		memcpy(path + parentlen + 1, name, len);
-		path[parentlen + 1 + len] = '\0';
-		len = parentlen + len + 1;
-	}
-
-	switch (SMB_SERVER(dir)->case_handling) 
-	{
-        case CASE_UPPER: 
-                str_upper(path); 
-                break;
-        case CASE_LOWER: 
-                str_lower(path); 
-                break;
-        case CASE_DEFAULT: 
-                break;
+		if (filldir(dirent, "..", 2, filp->f_pos,
+			    smb_info_ino(SMB_INOP(dir)->dir)) < 0)
+		{
+			return 0;
+		}
+		filp->f_pos += 1;
 	}
+	entry = smb_search_in_cache(dir, filp->f_pos);
 
-	*res_len = len;
+	if (entry == NULL)
+	{
+		if (c_seen_eof)
+		{
+			/* End of directory */
+			return 0;
+		}
+		result = smb_refill_dir_cache(server, dir, filp->f_pos);
+		if (result <= 0)
+		{
+			return result;
+		}
+		entry = c_entry;
+	}
+	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..) */
 
-	DDPRINTK("get_pname: path = %s, *pathlen = %d\n",
-                 path, *res_len);
+		struct smb_inode_info *ino_info
+		= smb_find_dir_inode(dir, entry->name, entry->len);
+
+		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);
+
+		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;
+	}
 	return 0;
 }
-        
-static int 
-get_pname(struct inode *dir, const char *name, int len,
-          char **res_path, int *res_len)
-{
-        char result[SMB_MAXPATHLEN];
-        int  result_len;
-        int  res;
 
-        if ((res = get_pname_static(dir,name,len,result,&result_len) != 0)) {
-                return res;
-        }
-
-        if ((*res_path = smb_kmalloc(result_len+1, GFP_KERNEL)) == NULL) {
-                printk("get_pname: Out of memory while allocating name.");
-                return -ENOMEM;
-        }
+void
+smb_init_dir_cache(void)
+{
+	c_ino = 0;
+	c_dev = 0;
+	c_entry = NULL;
+}
 
-        strcpy(*res_path, result);
-        *res_len = result_len;
-        return 0;
+void
+smb_invalid_dir_cache(unsigned long ino)
+{
+	/* TODO: check for dev as well */
+	if (ino == c_ino)
+	{
+		c_ino = 0;
+		c_seen_eof = 0;
+	}
 }
 
-static void
-put_pname(char *path)
+void
+smb_free_dir_cache(void)
 {
-	smb_kfree_s(path, 0);
+	if (c_entry != NULL)
+	{
+		smb_vfree(c_entry);
+	}
+	c_entry = NULL;
 }
 
 /* Insert a NEW smb_inode_info into the inode tree of our filesystem,
@@ -448,45 +384,35 @@
    assume that path is allocated for us. */
 
 static struct inode *
-smb_iget(struct inode *dir, char *path, struct smb_dirent *finfo,
-	 struct smb_inode_info *new_inode_info)
+smb_iget(struct inode *dir, struct smb_inode_info *new_inode_info)
 {
 	struct inode *inode;
-	int len;
-        struct smb_inode_info *root;
+	struct smb_inode_info *root;
 
-	if (   (dir == NULL) || (path == NULL) || (finfo == NULL)
-	    || (new_inode_info == NULL))
+	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);
 
-        len = strlen(path);
+	new_inode_info->prev = root;
+	new_inode_info->next = root->next;
+	root->next->prev = new_inode_info;
+	root->next = new_inode_info;
 
-        new_inode_info->state = SMB_INODE_LOOKED_UP;
-        new_inode_info->nused = 0;
-        new_inode_info->dir   = SMB_INOP(dir);
-
-        new_inode_info->finfo        = *finfo;
-        new_inode_info->finfo.opened = 0;
-        new_inode_info->finfo.path   = path;
-        new_inode_info->finfo.len    = len;
-
-        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, (int)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;
@@ -494,337 +420,327 @@
 		printk("smb_iget: iget failed!");
 		return NULL;
 	}
-
 	return inode;
 }
 
 void
 smb_free_inode_info(struct smb_inode_info *i)
 {
-        if (i == NULL) {
-                printk("smb_free_inode: i == NULL\n");
-                return;
-        }
-
-        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;
+	if (i == NULL)
+	{
+		printk("smb_free_inode: i == NULL\n");
+		return;
+	}
+	i->state = SMB_INODE_CACHED;
+	while ((i->nused == 0) && (i->state == SMB_INODE_CACHED))
+	{
+		struct smb_inode_info *dir = i->dir;
 
-                smb_kfree_s(i->finfo.path, i->finfo.len+1);
-                smb_kfree_s(i, sizeof(struct smb_inode_info));
+		i->next->prev = i->prev;
+		i->prev->next = i->next;
 
-                if (dir == NULL) return;
+		smb_kfree_s(i, sizeof(struct smb_inode_info));
 
-                (dir->nused)--;
-                i = dir;
-        }
+		if (dir == NULL)
+		{
+			return;
+		}
+		dir->nused -= 1;
+		i = dir;
+	}
 }
-        
+
 void
 smb_init_root(struct smb_server *server)
 {
-        struct smb_inode_info *root = &(server->root);
+	struct smb_inode_info *root = &(server->root);
 
-        root->finfo.path = server->m.root_path;
-        root->finfo.len  = strlen(root->finfo.path);
-        root->finfo.opened = 0;
-
-        root->state = SMB_INODE_LOOKED_UP;
-        root->nused = 1;
-        root->dir   = NULL;
-        root->next = root->prev = root;
-        return;
-}
-
-int
-smb_stat_root(struct smb_server *server)
-{
-        struct smb_inode_info *root = &(server->root);
-        int result;
-
-        if (root->finfo.len == 0) {
-                result = smb_proc_getattr(server, "\\", 1, &(root->finfo));
-        }
-        else
-        {
-                result = smb_proc_getattr(server, 
-                                          root->finfo.path, root->finfo.len,
-                                          &(root->finfo));
-        }
-        return result;
+	root->state = SMB_INODE_LOOKED_UP;
+	root->nused = 1;
+	root->dir = NULL;
+	root->next = root->prev = root;
+
+	return;
 }
 
 void
 smb_free_all_inodes(struct smb_server *server)
 {
-        /* 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 */
+	/* 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_inode_info *root = &(server->root);
 
-        if (root->next != root) {
-                printk("smb_free_all_inodes: INODES LEFT!!!\n");
-        }
-
-        while (root->next != root) {
-                printk("smb_free_all_inodes: freeing inode\n");
-                smb_free_inode_info(root->next);
-                /* In case we have an endless loop.. */
-                schedule();
-        }
-#endif        
-        
-        return;
+	if (root->next != root)
+	{
+		printk("smb_free_all_inodes: INODES LEFT!!!\n");
+	}
+	while (root->next != root)
+	{
+		printk("smb_free_all_inodes: freeing inode\n");
+		smb_free_inode_info(root->next);
+		/* In case we have an endless loop.. */
+		schedule();
+	}
+#endif
+
+	return;
 }
 
 /* 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);
+	struct smb_inode_info *ino = &(server->root);
+
+	do
+	{
+		ino->finfo.opened = 0;
+		ino = ino->next;
+	}
+	while (ino != &(server->root));
 
-        do {
-                ino->finfo.opened = 0;
-                ino = ino->next;
-        } while (ino != &(server->root));
-        
-        return;
+	return;
 }
-        
 
 /* 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_inode(struct smb_server *server, const char *path)
+smb_find_dir_inode(struct inode *parent, const char *name, int len)
 {
-        struct smb_inode_info *result = &(server->root);
-
-        if (path == NULL)
-                return NULL;
-
-        do {
-                if (strcmp(result->finfo.path, path) == 0)
-                        return result;
-                result = result->next;
+	struct smb_server *server = SMB_SERVER(parent);
+	struct smb_inode_info *dir = SMB_INOP(parent);
+	struct smb_inode_info *result = &(server->root);
 
-        } while (result != &(server->root));
+	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));
 
-        return NULL;
+	return NULL;
 }
 
-
-static int 
-smb_lookup(struct inode *dir, const char *__name, int len,
-           struct inode **result)
+static int
+smb_lookup(struct inode *dir, const char *name, int len,
+	   struct inode **result)
 {
-	char *name = NULL;
 	struct smb_dirent finfo;
-        struct smb_inode_info *result_info;
+	struct smb_inode_info *result_info;
 	int error;
-        int found_in_cache;
+	int found_in_cache;
 
 	struct smb_inode_info *new_inode_info = NULL;
 
 	*result = NULL;
 
-	if (!dir || !S_ISDIR(dir->i_mode)) {
+	if (!dir || !S_ISDIR(dir->i_mode))
+	{
 		printk("smb_lookup: inode is NULL or not a directory.\n");
 		iput(dir);
 		return -ENOENT;
 	}
-
-        DDPRINTK("smb_lookup: %s\n", __name);
+	DDPRINTK("smb_lookup: %s\n", name);
 
 	/* Fast cheat for . */
-	if (len == 0 || (len == 1 && __name[0] == '.')) {
+	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;
 
-	/* Now we will have to build up an SMB filename. */
-	if ((error = get_pname(dir, __name, len, &name, &len)) < 0) {
+		if (parent->state == SMB_INODE_CACHED)
+		{
+			parent->state = SMB_INODE_LOOKED_UP;
+		}
+		*result = iget(dir->i_sb, smb_info_ino(parent));
 		iput(dir);
-		return error;
+		if (*result == 0)
+		{
+			return -EACCES;
+		}
+		return 0;
 	}
+	result_info = smb_find_dir_inode(dir, name, len);
 
-        result_info = smb_find_inode(SMB_SERVER(dir), name);
-
-in_tree:
-        if (result_info != NULL) {
-                if (result_info->state == SMB_INODE_CACHED)
-                        result_info->state = SMB_INODE_LOOKED_UP;
-
-                /* Here we convert the inode_info address into an
-                   inode number */
-
-                *result = iget(dir->i_sb, (int)result_info);
+      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));
 		}
-			
-                put_pname(name);
-                iput(dir);
-
-		if (*result == NULL) {
+		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;
 
-	/* Ok, now we have made our name. We have to build a new
-           smb_inode_info struct and insert it into the tree, if it is
-           a name that exists on the server */
-
-        /* If the file is in the dir cache, we do not have to ask the
-           server. */
-
-        found_in_cache = 0;
-        
-        if (dir->i_ino == c_ino) {
-                int first = c_last_returned_index;
-                int i;
-
-                i = first;
-                do {
-                        DDPRINTK("smb_lookup: trying index: %d, name: %s\n",
-                                i, c_entry[i].path);
-                        if (strcmp(c_entry[i].path, __name) == 0) {
-                                DPRINTK("smb_lookup: found in cache!\n");
-                                finfo = c_entry[i];
-                                finfo.path = NULL; /* It's not ours! */
-                                found_in_cache = 1;
-                                break;
-                        }
-                        i = (i + 1) % c_size;
-                        DDPRINTK("smb_lookup: index %d, name %s failed\n",
-                                 i, c_entry[i].path);
-                } while (i != first);
-        }
-
-        if (found_in_cache == 0) {
-                error = smb_proc_getattr(SMB_SERVER(dir), name, len, &finfo);
-                if (error < 0) {
-                        put_pname(name);
-                        iput(dir);
-                        return error;
-                }
-        }
+	if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino) && (c_size != 0))
+	{
+		int first = c_last_returned_index;
+		int i;
 
+		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);
 
 	/* Here somebody else might have inserted the inode */
-	result_info = smb_find_inode(SMB_SERVER(dir), name);
+
+	result_info = smb_find_dir_inode(dir, name, len);
 	if (result_info != NULL)
 	{
 		goto in_tree;
 	}
+	new_inode_info->finfo = finfo;
+
+	DPRINTK("attr: %x\n", finfo.attr);
 
-	if ((*result = smb_iget(dir, name, &finfo, new_inode_info)) == NULL)
+	if ((*result = smb_iget(dir, new_inode_info)) == NULL)
 	{
 		smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info));
-		put_pname(name);
 		iput(dir);
 		return -EACCES;
 	}
-
-        DDPRINTK("smb_lookup: %s => %lu\n", name, (unsigned long)result_info);
+	DDPRINTK("smb_lookup: %s => %lu\n", name, (unsigned long) result_info);
 	iput(dir);
 	return 0;
 }
 
-static int 
+static int
 smb_create(struct inode *dir, const char *name, int len, int mode,
-           struct inode **result)
+	   struct inode **result)
 {
 	int error;
-	char *path = NULL;
 	struct smb_dirent entry;
 	struct smb_inode_info *new_inode_info;
 
 	*result = NULL;
 
-	if (!dir || !S_ISDIR(dir->i_mode)) {
+	if (!dir || !S_ISDIR(dir->i_mode))
+	{
 		printk("smb_create: inode is NULL or not a directory\n");
 		iput(dir);
 		return -ENOENT;
 	}
-
-	/* Now we will have to build up an SMB filename. */
-	if ((error = get_pname(dir, name, len, &path, &len)) < 0) {
-		iput(dir);
-		return error;
-	}
-
 	new_inode_info = smb_kmalloc(sizeof(struct smb_inode_info),
 				     GFP_KERNEL);
 	if (new_inode_info == NULL)
 	{
-		put_pname(path);
 		iput(dir);
 		return -ENOMEM;
 	}
+	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);
 
-        entry.attr  = 0;
-        entry.ctime = CURRENT_TIME;
-        entry.atime = CURRENT_TIME;
-        entry.mtime = CURRENT_TIME;
-        entry.size  = 0;
-
-        error = smb_proc_create(SMB_SERVER(dir), path, len, &entry);
-	if (error < 0) {
+	if ((error = smb_proc_getattr(dir, name, len, &entry)) < 0)
+	{
 		smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info));
-		put_pname(path);
 		iput(dir);
 		return error;
 	}
+	entry.f_ino = smb_fresh_inodes(SMB_SERVER(dir), 1);
 
-        smb_invalid_dir_cache(dir->i_ino);
+	new_inode_info->finfo = entry;
 
-	if ((*result = smb_iget(dir, path, &entry, new_inode_info)) == NULL)
+	if ((*result = smb_iget(dir, new_inode_info)) == NULL)
 	{
 		smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info));
-		put_pname(path);
 		iput(dir);
 		return error;
 	}
 	iput(dir);
-	return 0;	
+	return 0;
 }
 
 static int
 smb_mkdir(struct inode *dir, const char *name, int len, int mode)
 {
 	int error;
-	char path[SMB_MAXPATHLEN];
 
-	if (!dir || !S_ISDIR(dir->i_mode)) {
-		printk("smb_mkdir: inode is NULL or not a directory\n");
+	if (!dir || !S_ISDIR(dir->i_mode))
+	{
 		iput(dir);
-		return -ENOENT;
+		return -EINVAL;
 	}
-
-	/* Now we will have to build up an SMB filename. */
-	if ((error = get_pname_static(dir, name, len, path, &len)) < 0) {
-		iput(dir);
-		return error;
+	if ((error = smb_proc_mkdir(dir, name, len)) == 0)
+	{
+		smb_invalid_dir_cache(dir->i_ino);
 	}
-
-	if ((error = smb_proc_mkdir(SMB_SERVER(dir), path, len)) == 0) {
-                smb_invalid_dir_cache(dir->i_ino);
-        }
-
 	iput(dir);
 	return error;
 }
@@ -833,23 +749,23 @@
 smb_rmdir(struct inode *dir, const char *name, int len)
 {
 	int error;
-        char path[SMB_MAXPATHLEN];
 
-	if (!dir || !S_ISDIR(dir->i_mode)) {
+	if (!dir || !S_ISDIR(dir->i_mode))
+	{
 		printk("smb_rmdir: inode is NULL or not a directory\n");
 		iput(dir);
 		return -ENOENT;
 	}
-	if ((error = get_pname_static(dir, name, len, path, &len)) < 0) {
-		iput(dir);
-		return error;
+	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);
+		}
 	}
-        if (smb_find_inode(SMB_SERVER(dir), path) != NULL) {
-                error = -EBUSY;
-        } else {
-                if ((error = smb_proc_rmdir(SMB_SERVER(dir), path, len)) == 0)
-                        smb_invalid_dir_cache(dir->i_ino);
-        }
 	iput(dir);
 	return error;
 }
@@ -858,82 +774,72 @@
 smb_unlink(struct inode *dir, const char *name, int len)
 {
 	int error;
-	char path[SMB_MAXPATHLEN];
 
-	if (!dir || !S_ISDIR(dir->i_mode)) {
+	if (!dir || !S_ISDIR(dir->i_mode))
+	{
 		printk("smb_unlink: inode is NULL or not a directory\n");
 		iput(dir);
 		return -ENOENT;
 	}
-	if ((error = get_pname_static(dir, name, len, path, &len)) < 0) {
-		iput(dir);
-		return error;
+	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);
+		}
 	}
-        if (smb_find_inode(SMB_SERVER(dir), path) != NULL) {
-                error = -EBUSY;
-        } else {
-                if ((error = smb_proc_unlink(SMB_SERVER(dir), path, len)) == 0)
-                        smb_invalid_dir_cache(dir->i_ino);
-        }
 	iput(dir);
 	return error;
 }
 
 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,
-           int must_be_dir)
+	   struct inode *new_dir, const char *new_name, int new_len,
+	   int must_be_dir)
 {
 	int res;
-	char old_path[SMB_MAXPATHLEN], new_path[SMB_MAXPATHLEN];
 
-	if (!old_dir || !S_ISDIR(old_dir->i_mode)) {
+	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;
+		res = -ENOENT;
+		goto finished;
 	}
-
-	if (!new_dir || !S_ISDIR(new_dir->i_mode)) {
+	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;
-	}
-
-        res = get_pname_static(old_dir, old_name, old_len, old_path, &old_len);
-        if (res < 0) {
-                goto finished;
+		res = -ENOENT;
+		goto finished;
 	}
-
-        res = get_pname_static(new_dir, new_name, new_len, new_path, &new_len);
-	if (res < 0) {
-                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;
 	}
-	
-        if (   (smb_find_inode(SMB_SERVER(old_dir), old_path) != NULL)
-            || (smb_find_inode(SMB_SERVER(new_dir), new_path) != NULL)) {
-                res = -EBUSY;
-                goto finished;
-        }
+	res = smb_proc_mv(old_dir, old_name, old_len,
+			  new_dir, new_name, new_len);
 
-	res = smb_proc_mv(SMB_SERVER(old_dir), old_path, old_len,
-                          new_path, new_len);
+	if (res == -EEXIST)
+	{
+		int res1 = smb_proc_unlink(old_dir, new_name, new_len);
 
-	if (res == -EEXIST) {
-		int res1;
-		res1 = smb_proc_unlink(SMB_SERVER(old_dir), new_path, new_len);
-		if (res1 == 0) {
-			res = smb_proc_mv(SMB_SERVER(old_dir), old_path,
-					  old_len, new_path, new_len);
+		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);
-        }		
-	
- finished:
-	iput(old_dir); 
+	if (res == 0)
+	{
+		smb_invalid_dir_cache(old_dir->i_ino);
+		smb_invalid_dir_cache(new_dir->i_ino);
+	}
+      finished:
+	iput(old_dir);
 	iput(new_dir);
 	return res;
 }
diff -u --recursive --new-file v2.0.26/linux/fs/smbfs/file.c linux/fs/smbfs/file.c
--- v2.0.26/linux/fs/smbfs/file.c	Wed Sep 11 17:57:16 1996
+++ linux/fs/smbfs/file.c	Sun Dec  1 15:58:05 1996
@@ -1,7 +1,7 @@
 /*
  *  file.c
  *
- *  Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
  *
  */
 
@@ -17,12 +17,13 @@
 #include <linux/smb_fs.h>
 #include <linux/malloc.h>
 
-static inline int min(int a, int b)
+static inline int
+min(int a, int b)
 {
-	return a<b ? a : b;
+	return a < b ? a : b;
 }
 
-static int 
+static int
 smb_fsync(struct inode *inode, struct file *file)
 {
 	return 0;
@@ -31,142 +32,136 @@
 int
 smb_make_open(struct inode *i, int right)
 {
-        struct smb_dirent *dirent;
+	struct smb_dirent *dirent;
 
-        if (i == NULL) {
-                printk("smb_make_open: got NULL inode\n");
-                return -EINVAL;
-        }
-
-        dirent = &(SMB_INOP(i)->finfo);
+	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);
+	DDPRINTK("smb_make_open: dirent->opened = %d\n", dirent->opened);
 
-        if ((dirent->opened) == 0) {
-                /* tries max. rights */
+	if ((dirent->opened) == 0)
+	{
+		/* tries max. rights */
 		int open_result = smb_proc_open(SMB_SERVER(i),
-						dirent->path, dirent->len,
+						SMB_INOP(i)->dir,
+						dirent->name, dirent->len,
 						dirent);
-                if (open_result)
+		if (open_result)
 		{
-                        return 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;
+	}
+	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;
 
-        return -EACCES;
+	return -EACCES;
 }
 
-static int 
+static int
 smb_file_read(struct inode *inode, struct file *file, char *buf, int count)
 {
 	int result, bufsize, to_read, already_read;
 	off_t pos;
-        int errno;
+	int errno;
+
+	DPRINTK("smb_file_read: enter %s\n", SMB_FINFO(inode)->name);
 
-        DPRINTK("smb_file_read: enter %s\n", SMB_FINFO(inode)->path);
-        
-	if (!inode) {
+	if (!inode)
+	{
 		DPRINTK("smb_file_read: inode = NULL\n");
 		return -EINVAL;
 	}
-
-	if (!S_ISREG(inode->i_mode)) {
+	if (!S_ISREG(inode->i_mode))
+	{
 		DPRINTK("smb_file_read: read from non-file, mode %07o\n",
-                        inode->i_mode);
+			inode->i_mode);
 		return -EINVAL;
 	}
+	if ((errno = smb_make_open(inode, O_RDONLY)) != 0)
+		return errno;
 
-        if ((errno = smb_make_open(inode, O_RDONLY)) != 0)
-                return errno;
-        
 	pos = file->f_pos;
 
 	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;
 
-        already_read = 0;
+	already_read = 0;
 
 	/* First read in as much as possible for each bufsize. */
-        while (already_read < count) {
-
-                result = 0;
-                to_read = 0;
-                
-                if ((SMB_SERVER(inode)->blkmode & 1) != 0) {
-                        to_read = min(65535, count - already_read);
-                        DPRINTK("smb_file_read: Raw %d bytes\n", to_read);
-                        result = smb_proc_read_raw(SMB_SERVER(inode),
-                                                   SMB_FINFO(inode),
-                                                   pos, to_read, buf);
-                        DPRINTK("smb_file_read: returned %d\n", result);
-                }
-
-                if (result <= 0) {
-                        to_read = min(bufsize, count - already_read);
-                        result = smb_proc_read(SMB_SERVER(inode),
-                                               SMB_FINFO(inode),
-                                               pos, to_read, buf, 1);
-                }
-
+	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;
+		already_read += result;
 
-		if (result < to_read) {
-                        break;
+		if (result < to_read)
+		{
+			break;
 		}
 	}
 
-        file->f_pos = pos;
+	file->f_pos = pos;
 
-	if (!IS_RDONLY(inode)) inode->i_atime = CURRENT_TIME;
+	if (!IS_RDONLY(inode))
+		inode->i_atime = CURRENT_TIME;
 	inode->i_dirt = 1;
 
-        DPRINTK("smb_file_read: exit %s\n", SMB_FINFO(inode)->path);
+	DPRINTK("smb_file_read: exit %s\n", SMB_FINFO(inode)->name);
 
-        return already_read;
+	return already_read;
 }
 
-static int 
+static int
 smb_file_write(struct inode *inode, struct file *file, const char *buf,
 	       int count)
 {
 	int result, bufsize, to_write, already_written;
-        off_t pos;
-        int errno;
-			  
-	if (!inode) {
+	off_t pos;
+	int errno;
+
+	if (!inode)
+	{
 		DPRINTK("smb_file_write: inode = NULL\n");
 		return -EINVAL;
 	}
-
-	if (!S_ISREG(inode->i_mode)) {
+	if (!S_ISREG(inode->i_mode))
+	{
 		DPRINTK("smb_file_write: write to non-file, mode %07o\n",
-                       inode->i_mode);
+			inode->i_mode);
 		return -EINVAL;
 	}
-
-        DPRINTK("smb_file_write: enter %s\n", SMB_FINFO(inode)->path);
+	DPRINTK("smb_file_write: enter %s\n", SMB_FINFO(inode)->name);
 
 	if (count <= 0)
+	{
 		return 0;
-
-        if ((errno = smb_make_open(inode, O_RDWR)) != 0)
-                return errno;
-        
+	}
+	if ((errno = smb_make_open(inode, O_RDWR)) != 0)
+	{
+		return errno;
+	}
 	pos = file->f_pos;
 
 	if (file->f_flags & O_APPEND)
@@ -174,41 +169,28 @@
 
 	bufsize = SMB_SERVER(inode)->max_xmit - SMB_HEADER_LEN - 5 * 2 - 5;
 
-        already_written = 0;
+	already_written = 0;
 
-        DPRINTK("smb_write_file: blkmode = %d, blkmode & 2 = %d\n",
-                SMB_SERVER(inode)->blkmode,
-                SMB_SERVER(inode)->blkmode & 2);
-        
-        while (already_written < count) {
-
-                result = 0;
-                to_write = 0;
-
-                if ((SMB_SERVER(inode)->blkmode & 2) != 0) {
-                        to_write = min(65535, count - already_written);
-                        DPRINTK("smb_file_write: Raw %d bytes\n", to_write);
-                        result = smb_proc_write_raw(SMB_SERVER(inode),
-                                                    SMB_FINFO(inode), 
-                                                    pos, to_write, buf);
-                        DPRINTK("smb_file_write: returned %d\n", result);
-                }
-
-                if (result <= 0) {
-                        to_write = min(bufsize, count - already_written);
-                        result = smb_proc_write(SMB_SERVER(inode),
-                                                SMB_FINFO(inode), 
-                                                pos, to_write, buf);
-                }
+	DPRINTK("smb_write_file: blkmode = %d, blkmode & 2 = %d\n",
+		SMB_SERVER(inode)->blkmode,
+		SMB_SERVER(inode)->blkmode & 2);
+
+	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);
 
 		if (result < 0)
+		{
 			return result;
-
+		}
 		pos += result;
 		buf += result;
-                already_written += result;
+		already_written += result;
 
-		if (result < to_write) {
+		if (result < to_write)
+		{
 			break;
 		}
 	}
@@ -218,29 +200,31 @@
 
 	file->f_pos = pos;
 
-        if (pos > inode->i_size) {
-                inode->i_size = pos;
-        }
-
-        DPRINTK("smb_file_write: exit %s\n", SMB_FINFO(inode)->path);
+	if (pos > inode->i_size)
+	{
+		inode->i_size = pos;
+	}
+	DPRINTK("smb_file_write: exit %s\n", SMB_FINFO(inode)->name);
 
 	return already_written;
 }
 
-static struct file_operations smb_file_operations = {
+static struct file_operations smb_file_operations =
+{
 	NULL,			/* lseek - default */
 	smb_file_read,		/* read */
 	smb_file_write,		/* write */
 	NULL,			/* readdir - bad */
 	NULL,			/* select - default */
 	smb_ioctl,		/* ioctl */
-	smb_mmap,               /* mmap */
-	NULL,                   /* open */
-	NULL,                   /* release */
+	smb_mmap,		/* mmap */
+	NULL,			/* open */
+	NULL,			/* release */
 	smb_fsync,		/* fsync */
 };
 
-struct inode_operations smb_file_inode_operations = {
+struct inode_operations smb_file_inode_operations =
+{
 	&smb_file_operations,	/* default file operations */
 	NULL,			/* create */
 	NULL,			/* lookup */
diff -u --recursive --new-file v2.0.26/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- v2.0.26/linux/fs/smbfs/inode.c	Wed Nov 13 11:26:23 1996
+++ linux/fs/smbfs/inode.c	Sun Dec  1 15:58:05 1996
@@ -1,7 +1,7 @@
 /*
  *  inode.c
  *
- *  Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
  *
  */
 
@@ -29,16 +29,17 @@
 static void smb_put_super(struct super_block *);
 static void smb_statfs(struct super_block *, struct statfs *, int bufsiz);
 
-static struct super_operations smb_sops = {
-	smb_read_inode,         /* read inode */
-	smb_notify_change,      /* notify change */
+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_put_super,		/* put superblock */
 	NULL,			/* write superblock */
 	smb_statfs,		/* stat filesystem */
 	NULL
-        };
+};
 
 /* smb_read_inode: Called from iget, it only traverses the allocated
    smb_inode_info's and initializes the inode from the data found
@@ -47,187 +48,205 @@
 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. The address of this information is the
-           inode->i_ino. Just to make sure everything went well, we
-           check it's there. */
-
-        struct smb_inode_info *inode_info
-                = (struct smb_inode_info *)(inode->i_ino);
-
-#if 1
-        struct smb_inode_info *root = &(SMB_SERVER(inode)->root);
-        struct smb_inode_info *check_info = root;
-
-        do {
-                if (inode_info == check_info) {
-                        if (check_info->state == SMB_INODE_LOOKED_UP) {
-                                DDPRINTK("smb_read_inode: found it!\n");
-                                goto good;
-                        }
-                        else {
-                                printk("smb_read_inode: "
-                                       "state != SMB_INODE_LOOKED_UP\n");
-                                return;
-                        }
-                }
-                check_info = check_info->next;
-        } while (check_info != root);
-
-        /* 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");
-        return;
-
- good:
-#endif
-        inode_info->state = SMB_INODE_VALID;
+	/* 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);
 
-        SMB_INOP(inode) = inode_info;
+	if (inode_info == NULL)
+	{
+		/* 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");
+		return;
+	}
+	inode_info->state = SMB_INODE_VALID;
 
-        if (SMB_INOP(inode)->finfo.attr & aDIR)
-                inode->i_mode = SMB_SERVER(inode)->m.dir_mode;
-        else
-                inode->i_mode = SMB_SERVER(inode)->m.file_mode;
-
-        DDPRINTK("smb_read_inode: inode->i_mode = %u\n", inode->i_mode);
-
-        inode->i_nlink   = 1;
-        inode->i_uid     = SMB_SERVER(inode)->m.uid;
-        inode->i_gid     = SMB_SERVER(inode)->m.gid;
-        inode->i_size    = SMB_INOP(inode)->finfo.size;
-        inode->i_blksize = 1024;
-        inode->i_rdev    = 0;
-        if ((inode->i_blksize != 0) && (inode->i_size != 0))
-                inode->i_blocks =
-                        (inode->i_size - 1) / inode->i_blksize + 1;
-        else
-                inode->i_blocks = 0;
-
-        inode->i_mtime = SMB_INOP(inode)->finfo.mtime;
-        inode->i_ctime = SMB_INOP(inode)->finfo.ctime;
-        inode->i_atime = SMB_INOP(inode)->finfo.atime;
-
-        if (S_ISREG(inode->i_mode))
-                inode->i_op = &smb_file_inode_operations;
-        else if (S_ISDIR(inode->i_mode))
-                inode->i_op = &smb_dir_inode_operations;
-        else
-                inode->i_op = NULL;
+	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;
 
+	if (S_ISREG(inode->i_mode))
+	{
+		inode->i_op = &smb_file_inode_operations;
+	} else if (S_ISDIR(inode->i_mode))
+	{
+		inode->i_op = &smb_dir_inode_operations;
+	} else
+	{
+		inode->i_op = NULL;
+	}
 }
 
 static void
 smb_put_inode(struct inode *inode)
 {
-        struct smb_dirent *finfo  = SMB_FINFO(inode);
+	struct smb_dirent *finfo = SMB_FINFO(inode);
 	struct smb_server *server = SMB_SERVER(inode);
 	struct smb_inode_info *info = SMB_INOP(inode);
 
-	int opened        = finfo->opened;
-	int mtime         = inode->i_mtime;
-	int file_id       = finfo->fileid;
-	int isdir         = S_ISDIR(inode->i_mode);
-	unsigned long ino = inode->i_ino;
-
-	/* Remove the inode before closing the file, because the close
-           will sleep. This hopefully removes a race condition. */
-
-	clear_inode(inode);
-        smb_free_inode_info(info);
-
-        if (isdir)
+	if (S_ISDIR(inode->i_mode))
 	{
-                DDPRINTK("smb_put_inode: put directory %ld\n",
-                         inode->i_ino);
-                smb_invalid_dir_cache(ino);
-        }                
-
-        if (opened != 0)
+		smb_invalid_dir_cache(inode->i_ino);
+	}
+	if (finfo->opened != 0)
 	{
-                if (smb_proc_close(server, file_id, mtime))
+		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");
-                }
-        }
+			/* We can't do anything but complain. */
+			DPRINTK("smb_put_inode: could not close\n");
+		}
+	}
+	smb_free_inode_info(info);
+	clear_inode(inode);
 }
 
 static void
 smb_put_super(struct super_block *sb)
 {
-        struct smb_server *server = &(SMB_SBP(sb)->s_server);
+	struct smb_server *server = &(SMB_SBP(sb)->s_server);
 
-        smb_proc_disconnect(server);
+	smb_proc_disconnect(server);
 	smb_dont_catch_keepalive(server);
 	close_fp(server->sock_file);
 
 	lock_super(sb);
 
-        smb_free_all_inodes(server);
+	smb_free_all_inodes(server);
 
-        smb_kfree_s(server->packet, server->max_xmit);
+	smb_vfree(server->packet);
+	server->packet = NULL;
 
 	sb->s_dev = 0;
-        smb_kfree_s(SMB_SBP(sb), sizeof(struct smb_sb_info));
+	smb_kfree_s(SMB_SBP(sb), sizeof(struct smb_sb_info));
 
 	unlock_super(sb);
 
-        MOD_DEC_USE_COUNT;
+	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;
+}
 
-/* Hmm, should we do this like the NFS mount command does? Guess so.. */
 struct super_block *
 smb_read_super(struct super_block *sb, void *raw_data, int silent)
 {
-	struct smb_mount_data *data = (struct smb_mount_data *) raw_data;
+	struct smb_mount_data data;
 	struct smb_server *server;
-        struct smb_sb_info *smb_sb;
+	struct smb_sb_info *smb_sb;
 	unsigned int fd;
 	struct file *filp;
 	kdev_t dev = sb->s_dev;
 	int error;
 
-	if (!data) {
-		printk("smb_read_super: missing data argument\n");
+	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 (data->version != SMB_MOUNT_VERSION) {
-		printk("smb warning: mount version %s than kernel\n",
-		       (data->version < SMB_MOUNT_VERSION) ?
-                       "older" : "newer");
-	}
-	if (fd >= NR_OPEN || !(filp = current->files->fd[fd])) {
+	fd = data.fd;
+	if (fd >= NR_OPEN || !(filp = current->files->fd[fd]))
+	{
 		printk("smb_read_super: invalid file descriptor\n");
 		sb->s_dev = 0;
 		return NULL;
 	}
-	if (!S_ISSOCK(filp->f_inode->i_mode)) {
+	if (!S_ISSOCK(filp->f_inode->i_mode))
+	{
 		printk("smb_read_super: not a socket!\n");
 		sb->s_dev = 0;
 		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);
 
-        /* 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) {
-                printk("smb_read_super: could not alloc smb_sb_info\n");
-                return NULL;
-        }
-
-	filp->f_count += 1; 
+	if (smb_sb == NULL)
+	{
+		printk("smb_read_super: could not alloc smb_sb_info\n");
+		return NULL;
+	}
+	filp->f_count += 1;
 
 	lock_super(sb);
 
-        SMB_SBP(sb) = smb_sb;
-        
-	sb->s_blocksize = 1024; /* Eh...  Is this correct? */
+	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;
@@ -237,100 +256,90 @@
 	server->sock_file = filp;
 	server->lock = 0;
 	server->wait = NULL;
-        server->packet = NULL;
-	server->max_xmit = data->max_xmit;
+	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 = 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);
-
-        /*
-         * Make the connection to the server
-         */
-        
+			       (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);
+
 	error = smb_proc_connect(server);
 
 	unlock_super(sb);
 
-	if (error < 0) {
+	if (error < 0)
+	{
 		sb->s_dev = 0;
-		printk("smb_read_super: Failed connection, bailing out "
-                       "(error = %d).\n", -error);
-                goto fail;
+		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_dev = 0;
-		printk("smb_read_super: could not get super block "
-                       "attributes\n");
-                smb_kfree_s(server->packet, server->max_xmit);
-                goto fail;
+	if (server->protocol >= PROTOCOL_LANMAN2)
+	{
+		server->case_handling = CASE_DEFAULT;
+	} else
+	{
+		server->case_handling = CASE_LOWER;
 	}
 
-	if ((error = smb_stat_root(server)) < 0) {
+	if ((error = smb_proc_dskattr(sb, &(SMB_SBP(sb)->s_attr))) < 0)
+	{
 		sb->s_dev = 0;
-		printk("smb_read_super: could not get root dir attributes\n");
-                smb_kfree_s(server->packet, server->max_xmit);
-                goto fail;
+		printk("smb_read_super: could not get super block "
+		       "attributes\n");
+		goto fail;
 	}
+	smb_init_root_dirent(server, &(server->root.finfo));
 
-	DPRINTK("smb_read_super : %u %u %u %u\n",
-                SMB_SBP(sb)->s_attr.total,
-                SMB_SBP(sb)->s_attr.blocksize,
-                SMB_SBP(sb)->s_attr.allocblocks,
-                SMB_SBP(sb)->s_attr.free);
-
-        DPRINTK("smb_read_super: SMB_SBP(sb) = %x\n", (int)SMB_SBP(sb));
-
-	if (!(sb->s_mounted = iget(sb, (int)&(server->root)))) {
+	if (!(sb->s_mounted = iget(sb, smb_info_ino(&(server->root)))))
+	{
 		sb->s_dev = 0;
 		printk("smb_read_super: get root inode failed\n");
-                smb_kfree_s(server->packet, server->max_xmit);
-                goto fail;
+		goto fail;
 	}
-
-        MOD_INC_USE_COUNT;
+	MOD_INC_USE_COUNT;
 	return sb;
 
- fail:
-	filp->f_count -= 1; 
+      fail:
+	if (server->packet != NULL)
+	{
+		smb_vfree(server->packet);
+		server->packet = NULL;
+	}
+	filp->f_count -= 1;
 	smb_dont_catch_keepalive(server);
-        smb_kfree_s(SMB_SBP(sb), sizeof(struct smb_sb_info));
-        return NULL;
+	smb_kfree_s(SMB_SBP(sb), sizeof(struct smb_sb_info));
+	return NULL;
 }
 
-static void 
+static void
 smb_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
 {
 	int error;
 	struct smb_dskattr attr;
 	struct statfs tmp;
-	
+
 	error = smb_proc_dskattr(sb, &attr);
 
-	if (error) {
+	if (error)
+	{
 		printk("smb_statfs: dskattr error = %d\n", -error);
 		attr.total = attr.allocblocks = attr.blocksize =
-                        attr.free = 0;
+		    attr.free = 0;
 	}
-
 	tmp.f_type = SMB_SUPER_MAGIC;
-	tmp.f_bsize = attr.blocksize*attr.allocblocks;
+	tmp.f_bsize = attr.blocksize * attr.allocblocks;
 	tmp.f_blocks = attr.total;
 	tmp.f_bfree = attr.free;
 	tmp.f_bavail = attr.free;
@@ -340,7 +349,6 @@
 	memcpy_tofs(buf, &tmp, bufsiz);
 }
 
-/* DO MORE */
 int
 smb_notify_change(struct inode *inode, struct iattr *attr)
 {
@@ -349,93 +357,101 @@
 	if ((error = inode_change_ok(inode, attr)) < 0)
 		return error;
 
-	if (((attr->ia_valid & ATTR_UID) && 
+	if (((attr->ia_valid & ATTR_UID) &&
 	     (attr->ia_uid != SMB_SERVER(inode)->m.uid)))
 		return -EPERM;
 
-	if (((attr->ia_valid & ATTR_GID) && 
+	if (((attr->ia_valid & ATTR_GID) &&
 	     (attr->ia_uid != SMB_SERVER(inode)->m.gid)))
-                return -EPERM;
+		return -EPERM;
 
 	if (((attr->ia_valid & ATTR_MODE) &&
-	     (attr->ia_mode & ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO))))
+	(attr->ia_mode & ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO))))
 		return -EPERM;
 
-        if ((attr->ia_valid & ATTR_SIZE) != 0) {
-
-                if ((error = smb_make_open(inode, O_WRONLY)) < 0)
-                        goto fail;
-
-                if ((error = smb_proc_trunc(SMB_SERVER(inode),
-                                            SMB_FINFO(inode)->fileid,
-                                            attr->ia_size)) < 0)
-                        goto fail;
-
-        }
-
-        if ((attr->ia_valid & (ATTR_CTIME | ATTR_MTIME | ATTR_ATIME)) != 0) {
-
-                struct smb_dirent finfo;
+	if ((attr->ia_valid & ATTR_SIZE) != 0)
+	{
 
-                finfo.attr  = 0;
+		if ((error = smb_make_open(inode, O_WRONLY)) < 0)
+			goto fail;
 
-                if ((attr->ia_valid & ATTR_CTIME) != 0)
-                        finfo.ctime = attr->ia_ctime;
-                else
-                        finfo.ctime = inode->i_ctime;
+		if ((error = smb_proc_trunc(SMB_SERVER(inode),
+					    SMB_FINFO(inode)->fileid,
+					    attr->ia_size)) < 0)
+			goto fail;
 
-                if ((attr->ia_valid & ATTR_MTIME) != 0)
-                        finfo.mtime = attr->ia_mtime;
-                else
-                        finfo.mtime = inode->i_mtime;
+	}
+	if ((attr->ia_valid & (ATTR_CTIME | ATTR_MTIME | ATTR_ATIME)) != 0)
+	{
 
-                if ((attr->ia_valid & ATTR_ATIME) != 0)
-                        finfo.atime = attr->ia_atime;
-                else
-                        finfo.atime = inode->i_atime;
+		struct smb_dirent finfo;
 
-                if ((error = smb_proc_setattr(SMB_SERVER(inode),
-                                              inode, &finfo)) >= 0) {
-                        inode->i_ctime = finfo.ctime;
-                        inode->i_mtime = finfo.mtime;
-                        inode->i_atime = finfo.atime;
-                }
-        }
+		finfo.attr = 0;
+		finfo.f_size = inode->i_size;
+		finfo.f_blksize = inode->i_blksize;
+
+		if ((attr->ia_valid & ATTR_CTIME) != 0)
+			finfo.f_ctime = attr->ia_ctime;
+		else
+			finfo.f_ctime = inode->i_ctime;
+
+		if ((attr->ia_valid & ATTR_MTIME) != 0)
+			finfo.f_mtime = attr->ia_mtime;
+		else
+			finfo.f_mtime = inode->i_mtime;
+
+		if ((attr->ia_valid & ATTR_ATIME) != 0)
+			finfo.f_atime = attr->ia_atime;
+		else
+			finfo.f_atime = inode->i_atime;
 
- fail:
-        smb_invalid_dir_cache((unsigned long)(SMB_INOP(inode)->dir));
+		if ((error = smb_proc_setattr(SMB_SERVER(inode),
+					      inode, &finfo)) >= 0)
+		{
+			inode->i_ctime = finfo.f_ctime;
+			inode->i_mtime = finfo.f_mtime;
+			inode->i_atime = finfo.f_atime;
+		}
+	}
+      fail:
+	smb_invalid_dir_cache(smb_info_ino(SMB_INOP(inode)->dir));
 
 	return error;
 }
 
-		
+
 #ifdef DEBUG_SMB_MALLOC
 int smb_malloced;
-int smb_current_malloced;
+int smb_current_kmalloced;
+int smb_current_vmalloced;
 #endif
 
-static struct file_system_type smb_fs_type = {
-        smb_read_super, "smbfs", 0, NULL
-        };
+static struct file_system_type smb_fs_type =
+{
+	smb_read_super, "smbfs", 0, NULL
+};
 
-int init_smb_fs(void)
+int
+init_smb_fs(void)
 {
-        return register_filesystem(&smb_fs_type);
+	return register_filesystem(&smb_fs_type);
 }
 
 #ifdef MODULE
-int init_module(void)
+int
+init_module(void)
 {
 	int status;
 
-        DPRINTK("smbfs: init_module called\n");
+	DPRINTK("smbfs: init_module called\n");
 
 #ifdef DEBUG_SMB_MALLOC
-        smb_malloced = 0;
-        smb_current_malloced = 0;
+	smb_malloced = 0;
+	smb_current_kmalloced = 0;
+	smb_current_vmalloced = 0;
 #endif
 
-        smb_init_dir_cache();
+	smb_init_dir_cache();
 
 	if ((status = init_smb_fs()) == 0)
 		register_symtab(0);
@@ -445,12 +461,13 @@
 void
 cleanup_module(void)
 {
-        DPRINTK("smbfs: cleanup_module called\n");
-        smb_free_dir_cache();
-        unregister_filesystem(&smb_fs_type);
+	DPRINTK("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_malloced: %d\n", smb_current_malloced);
+	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);
 #endif
 }
 
diff -u --recursive --new-file v2.0.26/linux/fs/smbfs/ioctl.c linux/fs/smbfs/ioctl.c
--- v2.0.26/linux/fs/smbfs/ioctl.c	Wed Jun  5 13:22:48 1996
+++ linux/fs/smbfs/ioctl.c	Sun Dec  1 15:58:05 1996
@@ -1,7 +1,7 @@
 /*
  *  ioctl.c
  *
- *  Copyright (C) 1995 by Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Volker Lendecke
  *
  */
 
@@ -14,20 +14,22 @@
 #include <linux/mm.h>
 
 int
-smb_ioctl (struct inode * inode, struct file * filp,
-           unsigned int cmd, unsigned long arg)
+smb_ioctl(struct inode *inode, struct file *filp,
+	  unsigned int cmd, unsigned long arg)
 {
 	int result;
 
-	switch (cmd) {
-        case SMB_IOC_GETMOUNTUID:
-                if ((result = verify_area(VERIFY_WRITE, (uid_t*) arg,
-                                          sizeof(uid_t))) != 0) {
-                        return result;
-                }
-                put_fs_word(SMB_SERVER(inode)->m.mounted_uid, (uid_t*) arg);
-                return 0;
-        default:
+	switch (cmd)
+	{
+	case SMB_IOC_GETMOUNTUID:
+		if ((result = verify_area(VERIFY_WRITE, (uid_t *) arg,
+					  sizeof(uid_t))) != 0)
+		{
+			return result;
+		}
+		put_fs_word(SMB_SERVER(inode)->m.mounted_uid, (uid_t *) arg);
+		return 0;
+	default:
 		return -EINVAL;
 	}
 }
diff -u --recursive --new-file v2.0.26/linux/fs/smbfs/mmap.c linux/fs/smbfs/mmap.c
--- v2.0.26/linux/fs/smbfs/mmap.c	Wed Jun  5 13:22:48 1996
+++ linux/fs/smbfs/mmap.c	Sun Dec  1 15:58:05 1996
@@ -1,7 +1,7 @@
 /*
  *  mmap.c
  *
- *  Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
  *
  */
 
@@ -23,11 +23,11 @@
 /*
  * Fill in the supplied page for mmap
  */
-static unsigned long 
-smb_file_mmap_nopage(struct vm_area_struct * area,
+static unsigned long
+smb_file_mmap_nopage(struct vm_area_struct *area,
 		     unsigned long address, int no_share)
 {
-	struct inode * inode = area->vm_inode;
+	struct inode *inode = area->vm_inode;
 	unsigned long page;
 	unsigned int clear;
 	unsigned long tmp;
@@ -42,50 +42,54 @@
 	pos = address - area->vm_start + area->vm_offset;
 
 	clear = 0;
-	if (address + PAGE_SIZE > area->vm_end) {
+	if (address + PAGE_SIZE > area->vm_end)
+	{
 		clear = address + PAGE_SIZE - area->vm_end;
 	}
-
-        /* what we can read in one go */
+	/* 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;
-                        }
-                }
-        }
+	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;
+	while (clear--)
+	{
+		*(char *) --tmp = 0;
 	}
 	return page;
 }
 
-struct vm_operations_struct smb_file_mmap = {
+struct vm_operations_struct smb_file_mmap =
+{
 	NULL,			/* open */
 	NULL,			/* close */
 	NULL,			/* unmap */
@@ -101,20 +105,20 @@
 
 /* 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)
+smb_mmap(struct inode *inode, struct file *file, struct vm_area_struct *vma)
 {
-        DPRINTK("smb_mmap: called\n");
+	DPRINTK("smb_mmap: called\n");
 
-        /* only PAGE_COW or read-only supported now */
-	if (vma->vm_flags & VM_SHARED)	
+	/* 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)) {
+	if (!IS_RDONLY(inode))
+	{
 		inode->i_atime = CURRENT_TIME;
 		inode->i_dirt = 1;
 	}
-
 	vma->vm_inode = inode;
 	inode->i_count++;
 	vma->vm_ops = &smb_file_mmap;
diff -u --recursive --new-file v2.0.26/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c
--- v2.0.26/linux/fs/smbfs/proc.c	Wed Sep 11 17:57:16 1996
+++ linux/fs/smbfs/proc.c	Sun Dec  1 15:58:06 1996
@@ -1,7 +1,7 @@
 /*
  *  proc.c
  *
- *  Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
  *
  *  28/06/96 - Fixed long file name support (smb_proc_readdir_long) by Yuri Per
  */
@@ -18,25 +18,43 @@
 #include <asm/segment.h>
 #include <asm/string.h>
 
-#define ARCH i386
 #define SMB_VWV(packet)  ((packet) + SMB_HEADER_LEN)
-#define SMB_CMD(packet)  ((packet)[8])
-#define SMB_WCT(packet)  ((packet)[SMB_HEADER_LEN - 1])
+#define SMB_CMD(packet)  (BVAL(packet,8))
+#define SMB_WCT(packet)  (BVAL(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
 
-#define HI_WORD(l) ((word)(l >> 16))
-#define LO_WORD(l) ((word)(l % 0xFFFF))
-
-void smb_printerr(int class, int num);
 static int smb_request_ok(struct smb_server *s, int command, int wct, int bcc);
 
-static inline int min(int a, int b)
+static inline int
+min(int a, int b)
+{
+	return a < b ? a : b;
+}
+
+static void
+str_upper(char *name)
+{
+	while (*name)
+	{
+		if (*name >= 'a' && *name <= 'z')
+			*name -= ('a' - 'A');
+		name++;
+	}
+}
+
+static void
+str_lower(char *name)
 {
-	return a<b ? a : b;
+	while (*name)
+	{
+		if (*name >= 'A' && *name <= 'Z')
+			*name += ('a' - 'A');
+		name++;
+	}
 }
 
 /*****************************************************************************/
@@ -45,94 +63,105 @@
 /*                                                                           */
 /*****************************************************************************/
 
-static byte *
-smb_encode_word(byte *p, word data)
-{
-#if (ARCH == i386)
-        *((word *)p) = data;
-#else
-	p[0] = data & 0x00ffU;
-	p[1] = (data & 0xff00U) >> 8;
-#error "Non-Intel"
-#endif
-	return &p[2];
-}
-
-static byte *
-smb_decode_word(byte *p, word *data)
+static inline byte *
+smb_decode_word(byte * p, word * data)
 {
-#if (ARCH == i386)
-	*data = *(word *)p;
-#else
-	*data = (word) p[0] | p[1] << 8;
-#endif 
-	return &p[2];
+	*data = WVAL(p, 0);
+	return p + 2;
 }
 
 byte *
-smb_encode_smb_length(byte *p, dword len)
+smb_encode_smb_length(byte * p, dword len)
 {
-	p[0] = p[1] = 0;
-	p[2] = (len & 0xFF00) >> 8;
-	p[3] = (len & 0xFF);
+	BSET(p, 0, 0);
+	BSET(p, 1, 0);
+	BSET(p, 2, (len & 0xFF00) >> 8);
+	BSET(p, 3, (len & 0xFF));
 	if (len > 0xFFFF)
-		p[1] |= 0x01;
-	return &p[4];
+	{
+		BSET(p, 1, 1);
+	}
+	return p + 4;
 }
 
 static byte *
-smb_encode_dialect(byte *p, const byte *name, int len)
+smb_encode_ascii(byte * p, const byte * name, int len)
 {
-	*p ++ = 2;
+	*p++ = 4;
 	strcpy(p, name);
 	return p + len + 1;
 }
 
 static byte *
-smb_encode_ascii(byte *p, const byte *name, int len)
+smb_encode_this_name(byte * p, const char *name, const int len)
 {
-	*p ++ = 4;
-	strcpy(p, name);
-	return p + len + 1;
+	*p++ = '\\';
+	strncpy(p, name, len);
+	return p + len;
 }
 
+/* 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_vblock(byte *p, const byte *data, word len, int fs)
+smb_encode_parents(byte * p, struct smb_inode_info *ino)
 {
-	*p ++ = 5;
-	p = smb_encode_word(p, len);
-	if (fs)
-		memcpy_fromfs(p, data, len);
-	else
-		memcpy(p, data, len);
-	return p + len;
+	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;
+	}
+	return smb_encode_this_name(q, ino->finfo.name, ino->finfo.len);
 }
 
 static byte *
-smb_decode_data(byte *p, byte *data, word *data_len, int fs)
-{
-        word len;
+smb_encode_path(struct smb_server *server,
+		byte * p, struct smb_inode_info *dir,
+		const char *name, const int len)
+{
+	byte *start = p;
+	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;
+}
 
-	if (!(*p == 1 || *p == 5)) {
-                printk("smb_decode_data: Warning! Data block not starting "
-                       "with 1 or 5\n");
-        }
+static byte *
+smb_decode_data(byte * p, byte * data, word * data_len, int fs)
+{
+	word len;
 
-        len = WVAL(p, 1);
-        p += 3;
+	if (!(*p == 1 || *p == 5))
+	{
+		printk("smb_decode_data: Warning! Data block not starting "
+		       "with 1 or 5\n");
+	}
+	len = WVAL(p, 1);
+	p += 3;
 
-        if (fs)
-                memcpy_tofs(data, p, len);
-        else
-                memcpy(data, p, len);
+	if (fs)
+		memcpy_tofs(data, p, len);
+	else
+		memcpy(data, p, len);
 
-        *data_len = len;
+	*data_len = len;
 
-        return p + len;
+	return p + len;
 }
 
 static byte *
-smb_name_mangle(byte *p, const byte *name)
+smb_name_mangle(byte * p, const byte * name)
 {
 	int len, pad = 0;
 
@@ -141,19 +170,21 @@
 	if (len < 16)
 		pad = 16 - len;
 
-	*p ++ = 2 * (len + pad);
+	*p++ = 2 * (len + pad);
 
-	while (*name) {
-		*p ++ = (*name >> 4) + 'A';
-		*p ++ = (*name & 0x0F) + 'A';
-		name ++;
-	}
-	while (pad --) {
-		*p ++ = 'C';
-		*p ++ = 'A';
+	while (*name)
+	{
+		*p++ = (*name >> 4) + 'A';
+		*p++ = (*name & 0x0F) + 'A';
+		name++;
+	}
+	while (pad--)
+	{
+		*p++ = 'C';
+		*p++ = 'A';
 	}
 	*p++ = '\0';
-	
+
 	return p;
 }
 
@@ -161,7 +192,8 @@
 
 /* Linear day numbers of the respective 1sts in non-leap years. */
 
-static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
+static int day_n[] =
+{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
 		  /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
 
 
@@ -170,28 +202,28 @@
 static int
 utc2local(int time)
 {
-        return time - sys_tz.tz_minuteswest*60;
+	return time - sys_tz.tz_minuteswest * 60;
 }
 
 static int
 local2utc(int time)
 {
-        return time + sys_tz.tz_minuteswest*60;
+	return time + sys_tz.tz_minuteswest * 60;
 }
 
 /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
 
 static int
-date_dos2unix(unsigned short time,unsigned short date)
+date_dos2unix(unsigned short time, unsigned short date)
 {
-	int month,year,secs;
+	int month, year, secs;
 
-	month = ((date >> 5) & 15)-1;
+	month = ((date >> 5) & 15) - 1;
 	year = date >> 9;
-	secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
-	    ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
-	    month < 2 ? 1 : 0)+3653);
-			/* days since 1.1.70 plus 80's leap day */
+	secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 + 86400 *
+	    ((date & 31) - 1 + day_n[month] + (year / 4) + year * 365 - ((year & 3) == 0 &&
+						   month < 2 ? 1 : 0) + 3653);
+	/* days since 1.1.70 plus 80's leap day */
 	return local2utc(secs);
 }
 
@@ -199,27 +231,32 @@
 /* Convert linear UNIX date to a MS-DOS time/date pair. */
 
 static void
-date_unix2dos(int unix_date,unsigned short *time, unsigned short *date)
+date_unix2dos(int unix_date, byte * date, byte * time)
 {
-	int day,year,nl_day,month;
+	int day, year, nl_day, month;
 
 	unix_date = utc2local(unix_date);
-	*time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
-	    (((unix_date/3600) % 24) << 11);
-	day = unix_date/86400-3652;
-	year = day/365;
-	if ((year+3)/4+365*year > day) year--;
-	day -= (year+3)/4+365*year;
-	if (day == 59 && !(year & 3)) {
+	WSET(time, 0,
+	     (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
+	     (((unix_date / 3600) % 24) << 11));
+	day = unix_date / 86400 - 3652;
+	year = day / 365;
+	if ((year + 3) / 4 + 365 * year > day)
+		year--;
+	day -= (year + 3) / 4 + 365 * year;
+	if (day == 59 && !(year & 3))
+	{
 		nl_day = day;
 		month = 2;
-	}
-	else {
-		nl_day = (year & 3) || day <= 59 ? day : day-1;
+	} else
+	{
+		nl_day = (year & 3) || day <= 59 ? day : day - 1;
 		for (month = 0; month < 12; month++)
-			if (day_n[month] > nl_day) break;
+			if (day_n[month] > nl_day)
+				break;
 	}
-	*date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
+	WSET(date, 0,
+	     nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9));
 }
 
 
@@ -231,43 +268,39 @@
 /*****************************************************************************/
 
 dword
-smb_len(byte *packet) 
+smb_len(byte * p)
 {
-	return ((packet[1] & 0x1) << 16L) | (packet[2] << 8L) | (packet[3]);
+	return ((BVAL(p, 1) & 0x1) << 16L) | (BVAL(p, 2) << 8L) | (BVAL(p, 3));
 }
 
 static word
-smb_bcc(byte *packet)
+smb_bcc(byte * packet)
 {
 	int pos = SMB_HEADER_LEN + SMB_WCT(packet) * sizeof(word);
-#if (ARCH == i386)
-	return *((word *)((byte *)packet + pos));
-#else
-	return packet[pos] | packet[pos+1] << 8;
-#endif
+	return WVAL(packet, pos);
 }
 
 /* smb_valid_packet: We check if packet fulfills the basic
    requirements of a smb packet */
 
 static int
-smb_valid_packet(byte *packet)
+smb_valid_packet(byte * packet)
 {
-        DDPRINTK("len: %ld, wct: %d, bcc: %d\n",
-                 smb_len(packet), SMB_WCT(packet), SMB_BCC(packet));
-	return (   packet[4] == 0xff
-                && packet[5] == 'S'
-                && packet[6] == 'M'
-                && packet[7] == 'B'
-                && (smb_len(packet) + 4 == SMB_HEADER_LEN
-                    + SMB_WCT(packet) * 2 + SMB_BCC(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'
+		&& packet[7] == 'B'
+		&& (smb_len(packet) + 4 == SMB_HEADER_LEN
+		    + SMB_WCT(packet) * 2 + SMB_BCC(packet)));
 }
 
 /* smb_verify: We check if we got the answer we expected, and if we
    got enough data. If bcc == -1, we don't care. */
 
 static int
-smb_verify(byte *packet, int command, int wct, int bcc)
+smb_verify(byte * packet, int command, int wct, int bcc)
 {
 	return (SMB_CMD(packet) == command &&
 		SMB_WCT(packet) >= wct &&
@@ -277,119 +310,100 @@
 static int
 smb_errno(int errcls, int error)
 {
-
-#if DEBUG_SMB > 1
-	if (errcls) {
-		printk("smb_errno: ");
-		smb_printerr(errcls, error);
-		printk("\n");
-	}
-#endif
-
-	if (errcls == ERRDOS) 
-		switch (error) {
-			case ERRbadfunc:    return EINVAL;
-			case ERRbadfile:    return ENOENT;
-			case ERRbadpath:    return ENOENT;
-			case ERRnofids:     return EMFILE;
-			case ERRnoaccess:   return EACCES;
-			case ERRbadfid:     return EBADF;
-			case ERRbadmcb:     return EREMOTEIO;
-			case ERRnomem:      return ENOMEM;
-			case ERRbadmem:     return EFAULT;
-			case ERRbadenv:     return EREMOTEIO;
-			case ERRbadformat:  return EREMOTEIO;
-			case ERRbadaccess:  return EACCES;
-			case ERRbaddata:    return E2BIG;
-			case ERRbaddrive:   return ENXIO;
-			case ERRremcd:      return EREMOTEIO;
-			case ERRdiffdevice: return EXDEV;
-			case ERRnofiles:    return 0;
-			case ERRbadshare:   return ETXTBSY;
-			case ERRlock:       return EDEADLK;
-			case ERRfilexists:  return EEXIST;
-			case 87:            return 0; /* Unknown error!! */
+	if (errcls == ERRDOS)
+		switch (error)
+		{
+		case ERRbadfunc:
+			return EINVAL;
+		case ERRbadfile:
+			return ENOENT;
+		case ERRbadpath:
+			return ENOENT;
+		case ERRnofids:
+			return EMFILE;
+		case ERRnoaccess:
+			return EACCES;
+		case ERRbadfid:
+			return EBADF;
+		case ERRbadmcb:
+			return EREMOTEIO;
+		case ERRnomem:
+			return ENOMEM;
+		case ERRbadmem:
+			return EFAULT;
+		case ERRbadenv:
+			return EREMOTEIO;
+		case ERRbadformat:
+			return EREMOTEIO;
+		case ERRbadaccess:
+			return EACCES;
+		case ERRbaddata:
+			return E2BIG;
+		case ERRbaddrive:
+			return ENXIO;
+		case ERRremcd:
+			return EREMOTEIO;
+		case ERRdiffdevice:
+			return EXDEV;
+		case ERRnofiles:
+			return 0;
+		case ERRbadshare:
+			return ETXTBSY;
+		case ERRlock:
+			return EDEADLK;
+		case ERRfilexists:
+			return EEXIST;
+		case 87:
+			return 0;	/* Unknown error!! */
 			/* This next error seems to occur on an mv when
 			 * the destination exists */
-			case 183:	    return EEXIST;
-			default:            return EIO;
-		}
-	else if (errcls == ERRSRV) 
-		switch (error) {
-			case ERRerror: return ENFILE;
-			case ERRbadpw: return EINVAL;
-			case ERRbadtype: return EIO;
-			case ERRaccess: return EACCES;
-			default: return EIO;
-		}
-	else if (errcls == ERRHRD) 
-		switch (error) {
-			case ERRnowrite: return EROFS; 
-			case ERRbadunit: return ENODEV;
-			case ERRnotready: return EUCLEAN;
-			case ERRbadcmd: return EIO;
-			case ERRdata: return EIO;
-			case ERRbadreq: return ERANGE;
-			case ERRbadshare: return ETXTBSY;
-			case ERRlock: return EDEADLK;
-			default: return EIO;
-		}
-	else if (errcls == ERRCMD) 
-	        return EIO;
+		case 183:
+			return EEXIST;
+		default:
+			return EIO;
+	} else if (errcls == ERRSRV)
+		switch (error)
+		{
+		case ERRerror:
+			return ENFILE;
+		case ERRbadpw:
+			return EINVAL;
+		case ERRbadtype:
+			return EIO;
+		case ERRaccess:
+			return EACCES;
+		default:
+			return EIO;
+	} else if (errcls == ERRHRD)
+		switch (error)
+		{
+		case ERRnowrite:
+			return EROFS;
+		case ERRbadunit:
+			return ENODEV;
+		case ERRnotready:
+			return EUCLEAN;
+		case ERRbadcmd:
+			return EIO;
+		case ERRdata:
+			return EIO;
+		case ERRbadreq:
+			return ERANGE;
+		case ERRbadshare:
+			return ETXTBSY;
+		case ERRlock:
+			return EDEADLK;
+		default:
+			return EIO;
+	} else if (errcls == ERRCMD)
+		return EIO;
 	return 0;
 }
 
-#if DEBUG_SMB > 0
-static char
-print_char(char c)
-{
-	if ((c < ' ') || (c > '~'))
-		return '.';
-	return c;
-}
-
-static void
-smb_dump_packet(byte *packet) {
-	int i, j, len;
-        int errcls, error;
-
-        errcls = (int)packet[9];
-        error  = (int)(int)(packet[11]|packet[12]<<8);
-
-	printk("smb_len = %d  valid = %d    \n", 
-	       len = smb_len(packet), smb_valid_packet(packet));
-	printk("smb_cmd = %d  smb_wct = %d  smb_bcc = %d\n", 
-	       packet[8], SMB_WCT(packet), SMB_BCC(packet)); 
-	printk("smb_rcls = %d smb_err = %d\n", errcls, error);
-
-	if (errcls) {
-		smb_printerr(errcls, error);
-		printk("\n");
-	}
-
-        if (len > 100)
-                len = 100;
-	
-	for (i = 0; i < len; i += 10) {
-		printk("%03d:", i);
-		for (j = i; j < i+10; j++)
-			if (j < len)
-				printk("%02x ", packet[j]);
-			else
-				printk("   ");
-		printk(": ");
-	        for (j = i; j < i+10; j++)
-			if (j < len)
-				printk("%c", print_char(packet[j]));
-		printk("\n");
-	}
-}
-#endif
-
 static void
 smb_lock_server(struct smb_server *server)
 {
-        while (server->lock)
+	while (server->lock)
 		sleep_on(&server->wait);
 	server->lock = 1;
 }
@@ -397,14 +411,14 @@
 static void
 smb_unlock_server(struct smb_server *server)
 {
-        if (server->lock != 1) {
-                printk("smb_unlock_server: was not locked!\n");
-        }
-
-        server->lock = 0;
-        wake_up(&server->wait);
+	if (server->lock != 1)
+	{
+		printk("smb_unlock_server: was not locked!\n");
+	}
+	server->lock = 0;
+	wake_up(&server->wait);
 }
-        
+
 /* smb_request_ok: We expect the server to be locked. Then we do the
    request and check the answer completely. When smb_request_ok
    returns 0, you can be quite sure that everything went well. When
@@ -413,27 +427,27 @@
 static int
 smb_request_ok(struct smb_server *s, int command, int wct, int bcc)
 {
-        int result = 0;
-        s->rcls = 0;
-        s->err  = 0;
-
-        if (smb_request(s) < 0) {
-                DPRINTK("smb_request failed\n");
-                result = -EIO;
-        }
-        else if (smb_valid_packet(s->packet) != 0) {
-                DPRINTK("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");
-                result = -EIO;
-        }
+	int result = 0;
+	s->rcls = 0;
+	s->err = 0;
 
-        return result;
+	if (smb_request(s) < 0)
+	{
+		DPRINTK("smb_request failed\n");
+		result = -EIO;
+	} else if (smb_valid_packet(s->packet) != 0)
+	{
+		DPRINTK("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");
+		result = -EIO;
+	}
+	return result;
 }
 
 /* smb_retry: This function should be called when smb_request_ok has
@@ -445,72 +459,73 @@
 static int
 smb_retry(struct smb_server *server)
 {
-        if (server->state != CONN_INVALID) {
-                return 0;
-        }
-        
-        if (smb_release(server) < 0) {
-                DPRINTK("smb_retry: smb_release failed\n");
-                server->state = CONN_RETRIED;
-                return 0;
-        }
-        if(smb_proc_reconnect(server) < 0) {
-                DPRINTK("smb_proc_reconnect failed\n");
-                server->state = CONN_RETRIED;
-                return 0;
-        }
-
-        server->state = CONN_VALID;
-        return 1;
+	if (server->state != CONN_INVALID)
+	{
+		return 0;
+	}
+	if (smb_release(server) < 0)
+	{
+		DPRINTK("smb_retry: smb_release failed\n");
+		server->state = CONN_RETRIED;
+		return 0;
+	}
+	if (smb_proc_reconnect(server) < 0)
+	{
+		DPRINTK("smb_proc_reconnect failed\n");
+		server->state = CONN_RETRIED;
+		return 0;
+	}
+	server->state = CONN_VALID;
+	return 1;
 }
 
 static int
 smb_request_ok_unlock(struct smb_server *s, int command, int wct, int bcc)
 {
-        int result = smb_request_ok(s, command, wct, bcc);
+	int result = smb_request_ok(s, command, wct, bcc);
 
-        smb_unlock_server(s);
+	smb_unlock_server(s);
 
-        return result;
+	return result;
 }
-        
+
 /* smb_setup_header: We completely set up the packet. You only have to
    insert the command-specific fields */
 
-static byte *
-smb_setup_header(struct smb_server *server, byte command, word wct, word bcc)
+__u8 *
+smb_setup_header(struct smb_server * server, byte command, word wct, word bcc)
 {
 	dword xmit_len = SMB_HEADER_LEN + wct * sizeof(word) + bcc + 2;
 	byte *p = server->packet;
-        byte *buf = server->packet;
+	byte *buf = server->packet;
 
-	p = smb_encode_smb_length(p, xmit_len);
+	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);
+	BSET(p, 0, 0xff);
+	BSET(p, 1, 'S');
+	BSET(p, 2, 'M');
+	BSET(p, 3, 'B');
+	BSET(p, 4, command);
 
-        p += 5;
+	p += 5;
 	memset(p, '\0', 19);
 	p += 19;
-        p += 8;
+	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);
-
-        if (server->protocol > PROTOCOL_CORE) {
-                BSET(buf, smb_flg, 0x8);
-                WSET(buf, smb_flg2, 0x3);
-        }
-        
+	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);
+
+	if (server->protocol > PROTOCOL_CORE)
+	{
+		BSET(buf, smb_flg, 0x8);
+		WSET(buf, smb_flg2, 0x3);
+	}
 	*p++ = wct;		/* wct */
-        p += 2*wct;
-        WSET(p, 0, bcc);
-        return p+2;
+	p += 2 * wct;
+	WSET(p, 0, bcc);
+	return p + 2;
 }
 
 /* smb_setup_header_exclusive waits on server->lock and locks the
@@ -519,10 +534,22 @@
 
 static byte *
 smb_setup_header_exclusive(struct smb_server *server,
-                           byte command, word wct, word bcc)
+			   byte command, word wct, word bcc)
 {
-        smb_lock_server(server);
-        return smb_setup_header(server, command, wct, bcc);
+	smb_lock_server(server);
+	return smb_setup_header(server, command, wct, bcc);
+}
+
+static void
+smb_setup_bcc(struct smb_server *server, byte * p)
+{
+	__u8 *packet = server->packet;
+	__u8 *pbcc = packet + SMB_HEADER_LEN + 2 * SMB_WCT(packet);
+	__u16 bcc = p - (pbcc + 2);
+
+	WSET(pbcc, 0, bcc);
+	smb_encode_smb_length(packet,
+			      SMB_HEADER_LEN + 2 * SMB_WCT(packet) - 2 + bcc);
 }
 
 
@@ -533,17 +560,19 @@
 /*****************************************************************************/
 
 int
-smb_proc_open(struct smb_server *server, const char *pathname, int len,
-              struct smb_dirent *entry)
+smb_proc_open(struct smb_server *server,
+	      struct smb_inode_info *dir, const char *name, int len,
+	      struct smb_dirent *entry)
 {
 	int error;
-	char* p;
-        char* buf = server->packet;
+	char *p;
+	char *buf;
 	const word o_attr = aSYSTEM | aHIDDEN | aDIR;
 
-        DPRINTK("smb_proc_open: path=%s\n", pathname);
+	DPRINTK("smb_proc_open: name=%s\n", name);
 
-        smb_lock_server(server);
+	smb_lock_server(server);
+	buf = server->packet;
 
 	if (entry->opened != 0)
 	{
@@ -551,69 +580,74 @@
 		smb_unlock_server(server);
 		return 0;
 	}
+      retry:
+	p = smb_setup_header(server, SMBopen, 2, 0);
+	WSET(buf, smb_vwv0, 0x42);	/* read/write */
+	WSET(buf, smb_vwv1, o_attr);
+	*p++ = 4;
+	p = smb_encode_path(server, p, dir, name, len);
+	smb_setup_bcc(server, p);
 
- retry:
-        p = smb_setup_header(server, SMBopen, 2, 2 + len);
-        WSET(buf, smb_vwv0, 0x42); /* read/write */
-        WSET(buf, smb_vwv1, o_attr);
-        smb_encode_ascii(p, pathname, len);
-
-        if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0) {
-
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-                
-                if (error != -EACCES) {
-                        smb_unlock_server(server);
-                        return error;
-                }
-
-                p = smb_setup_header(server, SMBopen, 2, 2 + len);
-                WSET(buf, smb_vwv0, 0x40); /* read only */
-                WSET(buf, smb_vwv1, o_attr);
-                smb_encode_ascii(p, pathname, len);
-
-                if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0) {
-                        if (smb_retry(server)) {
-                                goto retry;
-                        }
-                        smb_unlock_server(server);
-                        return error;
-                }
-        }
+	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);
+		*p++ = 4;
+		p = smb_encode_path(server, p, dir, name, len);
+		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->ctime = entry->atime =
-                entry->mtime = local2utc(DVAL(buf, smb_vwv2));
-        entry->size   = DVAL(buf, smb_vwv4);
-        entry->access = WVAL(buf, smb_vwv6);
+	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;
 
-        smb_unlock_server(server);
+	smb_unlock_server(server);
 
-        DPRINTK("smb_proc_open: entry->access = %d\n", entry->access);
+	DPRINTK("smb_proc_open: entry->access = %d\n", entry->access);
 	return 0;
 }
 
-/* smb_proc_close: in finfo->mtime we can send a modification time to
-   the server */
 int
 smb_proc_close(struct smb_server *server,
 	       __u16 fileid, __u32 mtime)
 {
-        char *buf = server->packet;
+	char *buf;
 
 	smb_setup_header_exclusive(server, SMBclose, 3, 0);
-        WSET(buf, smb_vwv0, fileid);
-        DSET(buf, smb_vwv1, utc2local(mtime));
+	buf = server->packet;
+	WSET(buf, smb_vwv0, fileid);
+	DSET(buf, smb_vwv1, utc2local(mtime));
 
-        return smb_request_ok_unlock(server, SMBclose, 0, 0);
+	return smb_request_ok_unlock(server, SMBclose, 0, 0);
 }
 
 /* In smb_proc_read and smb_proc_write we do not retry, because the
@@ -623,311 +657,333 @@
    memcpy_tofs. */
 
 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 smb_server *server, struct smb_dirent *finfo,
+	      off_t offset, long count, char *data, int fs)
 {
 	word returned_count, data_len;
-        char *buf = server->packet;
-        int error;
+	char *buf;
+	int error;
 
 	smb_setup_header_exclusive(server, SMBread, 5, 0);
+	buf = server->packet;
 
-        WSET(buf, smb_vwv0, finfo->fileid);
-        WSET(buf, smb_vwv1, count);
-        DSET(buf, smb_vwv2, offset);
-        WSET(buf, smb_vwv4, 0);
-	
-	if ((error = smb_request_ok(server, SMBread, 5, -1)) < 0) {
-                smb_unlock_server(server);
-		return error;
-        }
+	WSET(buf, smb_vwv0, finfo->fileid);
+	WSET(buf, smb_vwv1, count);
+	DSET(buf, smb_vwv2, offset);
+	WSET(buf, smb_vwv4, 0);
 
+	if ((error = smb_request_ok(server, SMBread, 5, -1)) < 0)
+	{
+		smb_unlock_server(server);
+		return error;
+	}
 	returned_count = WVAL(buf, smb_vwv0);
-	
+
 	smb_decode_data(SMB_BUF(server->packet), data, &data_len, fs);
 
-        smb_unlock_server(server);
+	smb_unlock_server(server);
 
-	if (returned_count != data_len) {
+	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",
-                       returned_count, data_len);
-        }
-
-        return data_len;
-}
-
-/* count must be <= 65535. No error number is returned.  A result of 0
-   indicates an error, which has to be investigated by a normal read
-   call. */
-int
-smb_proc_read_raw(struct smb_server *server, struct smb_dirent *finfo, 
-                  off_t offset, long count, char *data)
-{
-        char *buf = server->packet;
-        int result;
-
-        if ((count <= 0) || (count > 65535)) {
-                return -EINVAL;
-        }
-
-	smb_setup_header_exclusive(server, SMBreadbraw, 8, 0);
-
-        WSET(buf, smb_vwv0, finfo->fileid);
-        DSET(buf, smb_vwv1, offset);
-        WSET(buf, smb_vwv3, count);
-        WSET(buf, smb_vwv4, 0);
-        DSET(buf, smb_vwv5, 0);
-
-        result = smb_request_read_raw(server, data, count);
-        smb_unlock_server(server);
-        return result;
+		printk("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)
+	       off_t offset, int count, const char *data)
 {
-        int res = 0;
-        char *buf = server->packet;
-        byte *p;
+	int res = 0;
+	char *buf;
+	byte *p;
 
 	p = smb_setup_header_exclusive(server, SMBwrite, 5, count + 3);
-        WSET(buf, smb_vwv0, finfo->fileid);
-        WSET(buf, smb_vwv1, count);
-        DSET(buf, smb_vwv2, offset);
-        WSET(buf, smb_vwv4, 0);
-
-        *p++ = 1;
-        WSET(p, 0, count);
-        memcpy_fromfs(p+2, data, count);
-
-	if ((res = smb_request_ok(server, SMBwrite, 1, 0)) >= 0) {
-                res = WVAL(buf, smb_vwv0);
-        }
+	buf = server->packet;
+	WSET(buf, smb_vwv0, finfo->fileid);
+	WSET(buf, smb_vwv1, count);
+	DSET(buf, smb_vwv2, offset);
+	WSET(buf, smb_vwv4, 0);
+
+	*p++ = 1;
+	WSET(p, 0, count);
+	memcpy_fromfs(p + 2, data, count);
 
-        smb_unlock_server(server);
+	if ((res = smb_request_ok(server, SMBwrite, 1, 0)) >= 0)
+	{
+		res = WVAL(buf, smb_vwv0);
+	}
+	smb_unlock_server(server);
 
 	return res;
 }
 
-/* count must be <= 65535 */
 int
-smb_proc_write_raw(struct smb_server *server, struct smb_dirent *finfo, 
-                   off_t offset, long count, const char *data)
+smb_proc_create(struct inode *dir, const char *name, int len,
+		word attr, time_t ctime)
 {
-        char *buf = server->packet;
-        int result;
+	int error;
+	char *p;
+	struct smb_server *server = SMB_SERVER(dir);
+	char *buf;
+	__u16 fileid;
 
-        if ((count <= 0) || (count > 65535)) {
-                return -EINVAL;
-        }
-
-	smb_setup_header_exclusive(server, SMBwritebraw, 11, 0);
-
-        WSET(buf, smb_vwv0, finfo->fileid);
-        WSET(buf, smb_vwv1, count);
-        WSET(buf, smb_vwv2, 0); /* reserved */
-        DSET(buf, smb_vwv3, offset);
-        DSET(buf, smb_vwv5, 0); /* timeout */
-        WSET(buf, smb_vwv7, 1); /* send final result response */
-        DSET(buf, smb_vwv8, 0); /* reserved */
-        WSET(buf, smb_vwv10, 0); /* no data in this buf */
-        WSET(buf, smb_vwv11, 0); /* no data in this buf */
-
-        result = smb_request_ok(server, SMBwritebraw, 1, 0);
-
-        DPRINTK("smb_proc_write_raw: first request returned %d\n", result);
-        
-        if (result < 0) {
-                smb_unlock_server(server);
-                return result;
-        }
-        
-        result = smb_request_write_raw(server, data, count);
-
-        DPRINTK("smb_proc_write_raw: raw request returned %d\n", result);
-        
-        if (result > 0) {
-                /* We have to do the checks of smb_request_ok here as well */
-                if (smb_valid_packet(server->packet) != 0) {
-                        DPRINTK("not a valid packet!\n");
-                        result = -EIO;
-                } else if (server->rcls != 0) {
-                        result = -smb_errno(server->rcls, server->err);
-                } else if (smb_verify(server->packet, SMBwritec,1,0) != 0) {
-                        DPRINTK("smb_verify failed\n");
-                        result = -EIO;
-                }
-        }
+	smb_lock_server(server);
+	buf = server->packet;
+      retry:
+	p = smb_setup_header(server, SMBcreate, 3, 0);
+	WSET(buf, smb_vwv0, attr);
+	DSET(buf, smb_vwv1, utc2local(ctime));
+	*p++ = 4;
+	p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
+	smb_setup_bcc(server, p);
 
-        smb_unlock_server(server);
-        return result;
-}
+	if ((error = smb_request_ok(server, SMBcreate, 1, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+		smb_unlock_server(server);
+		return error;
+	}
+	fileid = WVAL(buf, smb_vwv0);
+	smb_unlock_server(server);
 
+	smb_proc_close(server, fileid, CURRENT_TIME);
 
-/* smb_proc_create: We expect entry->attr & entry->ctime to be set. */
+	return 0;
+}
 
 int
-smb_proc_create(struct smb_server *server, const char *path, int len, 
-		struct smb_dirent *entry)
+smb_proc_mv(struct inode *odir, const char *oname, const int olen,
+	    struct inode *ndir, const char *nname, const int nlen)
 {
-	int error;
 	char *p;
-        char *buf = server->packet;
-	__u16 fileid;
+	struct smb_server *server = SMB_SERVER(odir);
+	char *buf;
+	int result;
 
 	smb_lock_server(server);
- retry:
-	p = smb_setup_header(server, SMBcreate, 3, len + 2);
-        WSET(buf, smb_vwv0, entry->attr);
-        DSET(buf, smb_vwv1, utc2local(entry->ctime));
-	smb_encode_ascii(p, path, len);
-
-	if ((error = smb_request_ok(server, SMBcreate, 1, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-                smb_unlock_server(server);
-		return error;
-        }
-
-        entry->opened = 0;
-        fileid = WVAL(buf, smb_vwv0);
-        smb_unlock_server(server);
+	buf = server->packet;
 
-        smb_proc_close(server, fileid, 0);
+      retry:
+	p = smb_setup_header(server, SMBmv, 1, 0);
+	WSET(buf, smb_vwv0, aSYSTEM | aHIDDEN);
+	*p++ = 4;
+	p = smb_encode_path(server, p, SMB_INOP(odir), oname, olen);
+	*p++ = 4;
+	p = smb_encode_path(server, p, SMB_INOP(ndir), nname, nlen);
+	smb_setup_bcc(server, p);
 
-	return 0;
+	if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+	}
+	smb_unlock_server(server);
+	return result;
 }
 
 int
-smb_proc_mv(struct smb_server *server, 
-            const char *opath, const int olen,
-            const char *npath, const int nlen)
+smb_proc_mkdir(struct inode *dir, const char *name, const int len)
 {
 	char *p;
-        char *buf = server->packet;
-        int result;
+	int result;
+	struct smb_server *server = SMB_SERVER(dir);
+
+	smb_lock_server(server);
 
-        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);
+	smb_setup_bcc(server, p);
 
- retry:
-	p = smb_setup_header(server, SMBmv, 1, olen + nlen + 4);
-        WSET(buf, smb_vwv0, 0);
-	p = smb_encode_ascii(p, opath, olen);
-	smb_encode_ascii(p, npath, olen);
-
-        if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-        }
-        smb_unlock_server(server);
-        return result;
+	if ((result = smb_request_ok(server, SMBmkdir, 0, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+	}
+	smb_unlock_server(server);
+	return result;
 }
 
 int
-smb_proc_mkdir(struct smb_server *server, const char *path, const int len)
+smb_proc_rmdir(struct inode *dir, const char *name, const int len)
 {
 	char *p;
-        int result;
+	int result;
+	struct smb_server *server = SMB_SERVER(dir);
+
+	smb_lock_server(server);
+
 
-        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);
+	smb_setup_bcc(server, p);
 
- retry:
-	p = smb_setup_header(server, SMBmkdir, 0, 2 + len);
-	smb_encode_ascii(p, path, len);
-
-        if ((result = smb_request_ok(server, SMBmkdir, 0, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-        }
-        smb_unlock_server(server);
-        return result;
+	if ((result = smb_request_ok(server, SMBrmdir, 0, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+	}
+	smb_unlock_server(server);
+	return result;
 }
 
 int
-smb_proc_rmdir(struct smb_server *server, const char *path, const int len)
+smb_proc_unlink(struct inode *dir, const char *name, const int len)
 {
 	char *p;
-        int result;
+	struct smb_server *server = SMB_SERVER(dir);
+	char *buf;
+	int result;
+
+	smb_lock_server(server);
+	buf = server->packet;
 
-        smb_lock_server(server);
+      retry:
+	p = smb_setup_header(server, SMBunlink, 1, 0);
+	WSET(buf, smb_vwv0, aSYSTEM | aHIDDEN);
+	*p++ = 4;
+	p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
+	smb_setup_bcc(server, p);
 
- retry:
-	p = smb_setup_header(server, SMBrmdir, 0, 2 + len);
-	smb_encode_ascii(p, path, len);
-
-        if ((result = smb_request_ok(server, SMBrmdir, 0, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-        }
-        smb_unlock_server(server);
-        return result;
+	if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+	}
+	smb_unlock_server(server);
+	return result;
 }
 
 int
-smb_proc_unlink(struct smb_server *server, const char *path, const int len)
+smb_proc_trunc(struct smb_server *server, word fid, dword length)
 {
 	char *p;
-        char *buf = server->packet;
-        int result;
+	char *buf;
+	int result;
 
-        smb_lock_server(server);
+	smb_lock_server(server);
+	buf = server->packet;
 
- retry:
-	p = smb_setup_header(server, SMBunlink, 1, 2 + len);
-        WSET(buf, smb_vwv0, 0);
-	smb_encode_ascii(p, path, len);
-
-        if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-        }
-        smb_unlock_server(server);
-        return result;
+      retry:
+	p = smb_setup_header(server, SMBwrite, 5, 0);
+	WSET(buf, smb_vwv0, fid);
+	WSET(buf, smb_vwv1, 0);
+	DSET(buf, smb_vwv2, length);
+	WSET(buf, smb_vwv4, 0);
+	p = smb_encode_ascii(p, "", 0);
+	smb_setup_bcc(server, p);
+
+	if ((result = smb_request_ok(server, SMBwrite, 1, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+	}
+	smb_unlock_server(server);
+	return result;
 }
 
-int
-smb_proc_trunc(struct smb_server *server, word fid, dword length)
+static void
+smb_init_dirent(struct smb_server *server, struct smb_dirent *entry)
 {
-        char *p;
-        char *buf = server->packet;
-        int result;
-
-        smb_lock_server(server);
-
- retry:
-        p = smb_setup_header(server, SMBwrite, 5, 3);
-        WSET(buf, smb_vwv0, fid);
-        WSET(buf, smb_vwv1, 0);
-        DSET(buf, smb_vwv2, length);
-        WSET(buf, smb_vwv4, 0);
-	smb_encode_ascii(p, "", 0);
-	
-        if ((result = smb_request_ok(server, SMBwrite, 1, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-        }
-        smb_unlock_server(server);
-        return result;
+	memset(entry, 0, sizeof(struct smb_dirent));
+
+	entry->f_nlink = 1;
+	entry->f_uid = server->m.uid;
+	entry->f_gid = server->m.gid;
+	entry->f_blksize = 512;
 }
 
+static void
+smb_finish_dirent(struct smb_server *server, struct smb_dirent *entry)
+{
+	if ((entry->attr & aDIR) != 0)
+	{
+		entry->f_mode = server->m.dir_mode;
+		entry->f_size = 512;
+	} else
+	{
+		entry->f_mode = server->m.file_mode;
+	}
+
+	if ((entry->f_blksize != 0) && (entry->f_size != 0))
+	{
+		entry->f_blocks =
+		    (entry->f_size - 1) / entry->f_blksize + 1;
+	} else
+	{
+		entry->f_blocks = 0;
+	}
+	return;
+}
+
+void
+smb_init_root_dirent(struct smb_server *server, struct smb_dirent *entry)
+{
+	smb_init_dirent(server, entry);
+	entry->attr = aDIR;
+	entry->f_ino = 1;
+	smb_finish_dirent(server, entry);
+}
+
+
 static char *
-smb_decode_dirent(char *p, struct smb_dirent *entry)
+smb_decode_dirent(struct smb_server *server, char *p, struct smb_dirent *entry)
 {
-	p += SMB_STATUS_SIZE;                  /* reserved (search_status) */
-        entry->attr = BVAL(p, 0);
-        entry->mtime = entry->atime = entry->ctime =
-                date_dos2unix(WVAL(p, 1), WVAL(p, 3));
-        entry->size = DVAL(p, 5);
-        memcpy(entry->path, p+9, 13);
-	DDPRINTK("smb_decode_dirent: path = %s\n", entry->path);
+	smb_init_dirent(server, entry);
+
+	p += SMB_STATUS_SIZE;	/* reserved (search_status) */
+	entry->attr = BVAL(p, 0);
+	entry->f_mtime = entry->f_atime = entry->f_ctime =
+	    date_dos2unix(WVAL(p, 1), WVAL(p, 3));
+	entry->f_size = DVAL(p, 5);
+	entry->len = strlen(p + 9);
+	if (entry->len > 12)
+	{
+		entry->len = 12;
+	}
+	memcpy(entry->name, p + 9, entry->len);
+	entry->name[entry->len] = '\0';
+	while (entry->len > 2)
+	{
+		/* Pathworks fills names with spaces */
+		entry->len -= 1;
+		if (entry->name[entry->len] == ' ')
+		{
+			entry->name[entry->len] = '\0';
+		}
+	}
+	switch (server->case_handling)
+	{
+	case CASE_UPPER:
+		str_upper(entry->name);
+		break;
+	case CASE_LOWER:
+		str_lower(entry->name);
+		break;
+	default:
+		break;
+	}
+	DPRINTK("smb_decode_dirent: name = %s\n", entry->name);
+	smb_finish_dirent(server, entry);
 	return p + 22;
 }
 
@@ -940,118 +996,126 @@
 		       int cache_size, struct smb_dirent *entry)
 {
 	char *p;
-        char *buf;
+	char *buf;
 	int error;
-        int result;
+	int result;
 	int i;
 	int first, total_count;
-        struct smb_dirent *current_entry;
+	struct smb_dirent *current_entry;
 	word bcc;
 	word count;
 	char status[SMB_STATUS_SIZE];
 	int entries_asked = (server->max_xmit - 100) / SMB_DIRINFO_SIZE;
-	int dirlen = strlen(SMB_FINFO(dir)->path);
-	char mask[dirlen + 5];
-
-	strcpy(mask, SMB_FINFO(dir)->path);
-	strcat(mask, "\\*.*");
-
- 	DPRINTK("SMB call  readdir %d @ %d\n", cache_size, fpos);        
-	DPRINTK("          mask = %s\n", mask);
 
-        buf = server->packet;
+	DPRINTK("SMB call  readdir %d @ %d\n", cache_size, fpos);
 
-        smb_lock_server(server);
+	smb_lock_server(server);
+	buf = server->packet;
 
- retry:
+      retry:
 	first = 1;
-        total_count = 0;
-        current_entry = entry;
-	
-	while (1) {
-		if (first == 1) {
-			p = smb_setup_header(server, SMBsearch, 2,
-                                             5 + strlen(mask));
-                        WSET(buf, smb_vwv0, entries_asked);
-                        WSET(buf, smb_vwv1, aDIR);
-			p = smb_encode_ascii(p, mask, strlen(mask));
-			*p ++ = 5;
-		        p = smb_encode_word(p, 0);
-		} else {
-			p = smb_setup_header(server, SMBsearch, 2,
-                                             5 + SMB_STATUS_SIZE);
-                        WSET(buf, smb_vwv0, entries_asked);
-                        WSET(buf, smb_vwv1, aDIR);
+	total_count = 0;
+	current_entry = entry;
+
+	while (1)
+	{
+		if (first == 1)
+		{
+			p = smb_setup_header(server, SMBsearch, 2, 0);
+			WSET(buf, smb_vwv0, entries_asked);
+			WSET(buf, smb_vwv1, aDIR);
+			*p++ = 4;
+			p = smb_encode_path(server, p, SMB_INOP(dir), "*.*", 3);
+			*p++ = 5;
+			WSET(p, 0, 0);
+			p += 2;
+		} else
+		{
+			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 = smb_encode_vblock(p, status, SMB_STATUS_SIZE, 0);
+			*p++ = 5;
+			WSET(p, 0, SMB_STATUS_SIZE);
+			p += 2;
+			memcpy(p, status, SMB_STATUS_SIZE);
+			p += SMB_STATUS_SIZE;
 		}
-		
-		if ((error = smb_request_ok(server, SMBsearch, 1, -1)) < 0) {
-                        if (   (server->rcls == ERRDOS)
-                            && (server->err  == ERRnofiles)) {
-                                result = total_count - fpos;
-                                goto unlock_return;
-                        }
-                        else
-                        {
-                                if (smb_retry(server)) {
-                                        goto retry;
-                                }
-                                result = error;
-                                goto unlock_return;
-                        }
-                }
 
+		smb_setup_bcc(server, p);
+
+		if ((error = smb_request_ok(server, SMBsearch, 1, -1)) < 0)
+		{
+			if ((server->rcls == ERRDOS)
+			    && (server->err == ERRnofiles))
+			{
+				result = total_count - fpos;
+				goto unlock_return;
+			} else
+			{
+				if (smb_retry(server))
+				{
+					goto retry;
+				}
+				result = error;
+				goto unlock_return;
+			}
+		}
 		p = SMB_VWV(server->packet);
-		p = smb_decode_word(p, &count); /* vwv[0] = count-returned */
-		p = smb_decode_word(p, &bcc);           
-		
+		p = smb_decode_word(p, &count);
+		p = smb_decode_word(p, &bcc);
+
 		first = 0;
-		
-		if (count <= 0) {
+
+		if (count <= 0)
+		{
 			result = total_count - fpos;
-                        goto unlock_return;
-                }
-		if (bcc != count * SMB_DIRINFO_SIZE + 3) {
+			goto unlock_return;
+		}
+		if (bcc != count * SMB_DIRINFO_SIZE + 3)
+		{
 			result = -EIO;
-                        goto unlock_return;
-                }
-
-		p += 3; /* Skipping VBLOCK header (5, length lo, length hi). */
+			goto unlock_return;
+		}
+		p += 3;		/* Skipping VBLOCK header
+				   (5, length lo, length hi). */
 
 		/* Read the last entry into the status field. */
 		memcpy(status,
-                       SMB_BUF(server->packet) + 3 +
-                       (count - 1) * SMB_DIRINFO_SIZE, 
-                       SMB_STATUS_SIZE);
+		       SMB_BUF(server->packet) + 3 +
+		       (count - 1) * SMB_DIRINFO_SIZE,
+		       SMB_STATUS_SIZE);
 
 		/* Now we are ready to parse smb directory entries. */
-		
-		for (i = 0; i < count; i ++) {
-			if (total_count < fpos) {
+
+		for (i = 0; i < count; i++)
+		{
+			if (total_count < fpos)
+			{
 				p += SMB_DIRINFO_SIZE;
 				DDPRINTK("smb_proc_readdir: skipped entry.\n");
 				DDPRINTK("                  total_count = %d\n"
-                                         "                i = %d, fpos = %d\n",
-                                         total_count, i, fpos);
-                        }
-                        else if (total_count >= fpos + cache_size) {
-                                result = total_count - fpos;
-                                goto unlock_return;
-			}
-			else {
-				p = smb_decode_dirent(p, current_entry);
+					 "                i = %d, fpos = %d\n",
+					 total_count, i, fpos);
+			} else if (total_count >= fpos + cache_size)
+			{
+				result = total_count - fpos;
+				goto unlock_return;
+			} else
+			{
+				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);	
+					 "%lu\n", entry->f_pos);
 				current_entry += 1;
 			}
 			total_count += 1;
 		}
 	}
- unlock_return:
-        smb_unlock_server(server);
-        return result;
+      unlock_return:
+	smb_unlock_server(server);
+	return result;
 }
 
 /* interpret a long filename structure - this is mostly guesses at the
@@ -1060,524 +1124,483 @@
    is used by OS/2. */
 
 static char *
-smb_decode_long_dirent(char *p, struct smb_dirent *finfo, int level)
+smb_decode_long_dirent(struct smb_server *server, char *p,
+		       struct smb_dirent *entry, int level)
 {
-        char *result;
+	char *result;
 
-        if (finfo) {
-                /* I have to set times to 0 here, because I do not
-                   have specs about this for all info levels. */
-                finfo->ctime = finfo->mtime = finfo->atime = 0;
-        }
-
-        switch (level)
-        {
-        case 1:                 /* OS/2 understands this */
-                if (finfo)
-                {
-                        DPRINTK("received entry\n");
-                        strcpy(finfo->path,p+27);
-                        finfo->len  = strlen(finfo->path);
-                        finfo->size = DVAL(p,16);
-                        finfo->attr = BVAL(p,24);
-
-                        finfo->ctime = date_dos2unix(WVAL(p, 6), WVAL(p, 4));
-                        finfo->atime = date_dos2unix(WVAL(p, 10), WVAL(p, 8));
-                        finfo->mtime = date_dos2unix(WVAL(p, 14), WVAL(p, 12));
-                }
-                result = p + 28 + BVAL(p,26);
-                break;
-
-        case 2:                 /* this is what OS/2 uses */
-                if (finfo)
-                {
-                        strcpy(finfo->path,p+31);
-                        finfo->len  = strlen(finfo->path);
-                        finfo->size = DVAL(p,16);
-                        finfo->attr = BVAL(p,24);
-#if 0
-                        finfo->atime = make_unix_date2(p+8);
-                        finfo->mtime = make_unix_date2(p+12);
-#endif
-                }
-                result = p + 32 + BVAL(p,30);
-                break;
-
-        case 260:               /* NT uses this, but also accepts 2 */
-                result = p + WVAL(p,0);
-                if (finfo)
-                {
-                        int namelen;
-                        p += 4; /* next entry offset */
-                        p += 4; /* fileindex */
-                        /* finfo->ctime = interpret_filetime(p);*/
-                        p += 8;
-                        /* finfo->atime = interpret_filetime(p);*/
-                        p += 8;
-                        p += 8; /* write time */
-                        /* finfo->mtime = interpret_filetime(p);*/
-                        p += 8;
-                        finfo->size = DVAL(p,0);
-                        p += 8;
-                        p += 8; /* alloc size */
-                        finfo->attr = BVAL(p,0);
-                        p += 4;
-                        namelen = min(DVAL(p,0), SMB_MAXNAMELEN);
-                        p += 4;
-                        p += 4; /* EA size */
-                        p += 2; /* short name len? */
-                        p += 24; /* short name? */	  
-                        strncpy(finfo->path,p,namelen);
-                        finfo->len = namelen;
-                }
-                break;
-
-        default:
-                DPRINTK("Unknown long filename format %d\n",level);
-                result = p + WVAL(p,0);
-        }
-        return result;
+	smb_init_dirent(server, entry);
+
+	switch (level)
+	{
+		/* We might add more levels later... */
+	case 1:
+		entry->len = BVAL(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->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);
+		break;
+
+	default:
+		DPRINTK("Unknown long filename format %d\n", level);
+		result = p + WVAL(p, 0);
+	}
+
+	switch (server->case_handling)
+	{
+	case CASE_UPPER:
+		str_upper(entry->name);
+		break;
+	case CASE_LOWER:
+		str_lower(entry->name);
+		break;
+	default:
+		break;
+	}
+
+	smb_finish_dirent(server, entry);
+	return result;
 }
 
 int
 smb_proc_readdir_long(struct smb_server *server, struct inode *dir, int fpos,
-                      int cache_size, struct smb_dirent *entry)
+		      int cache_size, struct smb_dirent *cache)
 {
-        int max_matches = 64; /* this should actually be based on the 
-				 maxxmit */
-  
-        /* NT uses 260, OS/2 uses 2. Both accept 1. */
-        int info_level = 1;
+	/* NT uses 260, OS/2 uses 2. Both accept 1. */
+	const int info_level = 1;
+	const int max_matches = 512;
 
 	char *p;
 	char *lastname;
-	int   lastname_len;
+	int lastname_len;
 	int i;
-	int first, total_count;
-        struct smb_dirent *current_entry;
+	int first, entries, entries_seen;
 
-        char *resp_data;
-        char *resp_param;
-        int resp_data_len = 0;
-        int resp_param_len=0;
+	unsigned char *resp_data = NULL;
+	unsigned char *resp_param = NULL;
+	int resp_data_len = 0;
+	int resp_param_len = 0;
 
-        int attribute = aSYSTEM | aHIDDEN | aDIR;
-        int result;
+	__u16 command;
 
-        int ff_resume_key = 0;
-        int ff_searchcount=0;
-        int ff_eos=0;
-        int ff_lastname=0;
-        int ff_dir_handle=0;
-        int loop_count = 0;
+	int result;
 
-	int dirlen = strlen(SMB_FINFO(dir)->path) + 3;
-	char *mask;
+	int ff_resume_key = 0;
+	int ff_searchcount = 0;
+	int ff_eos = 0;
+	int ff_lastname = 0;
+	int ff_dir_handle = 0;
+	int loop_count = 0;
+
+	char param[SMB_MAXPATHLEN + 2 + 12];
+	int mask_len;
+	unsigned char *mask = &(param[12]);
 
-	mask = smb_kmalloc(dirlen, GFP_KERNEL);
-	if (mask == NULL)
-	{
-		printk("smb_proc_readdir_long: Memory allocation failed\n");
-		return -ENOMEM;
-	}
-	strcpy(mask, SMB_FINFO(dir)->path);
-	strcat(mask, "\\*");
+	mask_len = smb_encode_path(server, mask,
+				   SMB_INOP(dir), "*", 1) - mask;
 
- 	DPRINTK("SMB call lreaddir %d @ %d\n", cache_size, fpos);        
-	DPRINTK("          mask = %s\n", mask);
+	mask[mask_len] = 0;
+	mask[mask_len + 1] = 0;
 
-        resp_param = NULL;
-        resp_data  = NULL;
+	DPRINTK("smb_readdir_long cache=%d, fpos=%d, mask=%s\n",
+		cache_size, fpos, mask);
 
-        smb_lock_server(server);
+	smb_lock_server(server);
 
- retry:
+      retry:
 
 	first = 1;
-        total_count = 0;
-        current_entry = entry;
-	
-        while (ff_eos == 0)
-        {
-                int masklen = strlen(mask);
-                unsigned char *outbuf = server->packet;
-                
-                loop_count += 1;
-                if (loop_count > 200)
-                {
-                        printk("smb_proc_readdir_long: "
-                               "Looping in FIND_NEXT??\n");
-                        break;
-                }
-
-                smb_setup_header(server, SMBtrans2, 15,
-                                 5 + 12 + masklen + 1);
-
-                WSET(outbuf,smb_tpscnt,12 + masklen +1);
-                WSET(outbuf,smb_tdscnt,0);
-                WSET(outbuf,smb_mprcnt,10); 
-                WSET(outbuf,smb_mdrcnt,TRANS2_MAX_TRANSFER);
-                WSET(outbuf,smb_msrcnt,0);
-                WSET(outbuf,smb_flags,0); 
-                DSET(outbuf,smb_timeout,0);
-                WSET(outbuf,smb_pscnt,WVAL(outbuf,smb_tpscnt));
-                WSET(outbuf,smb_psoff,((SMB_BUF(outbuf)+3) - outbuf)-4);
-                WSET(outbuf,smb_dscnt,0);
-                WSET(outbuf,smb_dsoff,0);
-                WSET(outbuf,smb_suwcnt,1);
-                WSET(outbuf,smb_setup0,
-                     first == 1 ? TRANSACT2_FINDFIRST : TRANSACT2_FINDNEXT);
-
-                p = SMB_BUF(outbuf);
-                *p++=0;         /* put in a null smb_name */
-                *p++='D'; *p++ = ' '; /* this was added because OS/2 does it */
-
-                if (first != 0)
-                {
-                        WSET(p,0,attribute); /* attribute */
-                        WSET(p,2,max_matches); /* max count */
-                        WSET(p,4,8+4+2); /* resume required + close on end +
-                                            continue */
-                        WSET(p,6,info_level); 
-                        DSET(p,8,0);
-                        p += 12;
-                        strncpy(p, mask, masklen);
-                        p += masklen;
-                        *p++ = 0; *p++ = 0;
-                }
-                else
-                {
-                        DPRINTK("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
-                                ff_dir_handle,ff_resume_key,ff_lastname,mask);
-                        WSET(p,0,ff_dir_handle);
-                        WSET(p,2,max_matches); /* max count */
-                        WSET(p,4,info_level); 
-                        DSET(p,6,ff_resume_key); /* ff_resume_key */
-                        WSET(p,10,8+4+2); /* resume required + close on end +
-                                             continue */
-                        p += 12;
-                        strncpy(p, mask, masklen);
-                        p += masklen;
-                        *p++ = 0; *p++ = 0;
-                }
-
-                result = smb_trans2_request(server,
-                                            &resp_data_len,&resp_param_len,
-                                            &resp_data,&resp_param);
-
-                if (result < 0) {
-                        if (smb_retry(server)) {
-                                goto retry;
-                        }
-                        DPRINTK("smb_proc_readdir_long: "
-                                "got error from trans2_request\n");
-                        break;
-                }
-
-                if (server->rcls != 0)
-                {
-                        result = -EIO;
-                        break;
-                }
-
-                /* parse out some important return info */
-                p = resp_param;
-                if (first != 0)
-                {
-                        ff_dir_handle  = WVAL(p,0);
-                        ff_searchcount = WVAL(p,2);
-                        ff_eos         = WVAL(p,4);
-                        ff_lastname    = WVAL(p,8);
-                }
-                else
-                {
-                        ff_searchcount = WVAL(p,0);
-                        ff_eos         = WVAL(p,2);
-                        ff_lastname    = WVAL(p,6);
-                }
+	entries = 0;
+	entries_seen = 2;
+
+	while (ff_eos == 0)
+	{
+		loop_count += 1;
+		if (loop_count > 200)
+		{
+			printk("smb_proc_readdir_long: "
+			       "Looping in FIND_NEXT??\n");
+			break;
+		}
+		if (first != 0)
+		{
+			command = TRANSACT2_FINDFIRST;
+			WSET(param, 0, aSYSTEM | aHIDDEN | aDIR);
+			WSET(param, 2, max_matches);	/* max count */
+			WSET(param, 4, 8 + 4 + 2);	/* resume required +
+							   close on end +
+							   continue */
+			WSET(param, 6, info_level);
+			DSET(param, 8, 0);
+		} 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);
+			WSET(param, 0, ff_dir_handle);
+			WSET(param, 2, max_matches);	/* max count */
+			WSET(param, 4, info_level);
+			DSET(param, 6, ff_resume_key);	/* ff_resume_key */
+			WSET(param, 10, 8 + 4 + 2);	/* resume required +
+							   close on end +
+							   continue */
+#ifdef CONFIG_SMB_WIN95
+			/* Windows 95 is not able to deliver answers
+			   to FIND_NEXT fast enough, so sleep 0.2 seconds */
+			current->timeout = jiffies + HZ / 5;
+			current->state = TASK_INTERRUPTIBLE;
+			schedule();
+			current->timeout = 0;
+#endif
+		}
 
-                if (ff_searchcount == 0) 
-                        break;
+		result = smb_trans2_request(server, command,
+					    0, NULL, 12 + mask_len + 2, param,
+					    &resp_data_len, &resp_data,
+					    &resp_param_len, &resp_param);
+
+		if (result < 0)
+		{
+			if (smb_retry(server))
+			{
+				goto retry;
+			}
+			DPRINTK("smb_proc_readdir_long: "
+				"got error from trans2_request\n");
+			break;
+		}
+		if (server->rcls != 0)
+		{
+			result = -EIO;
+			break;
+		}
+		/* parse out some important return info */
+		if (first != 0)
+		{
+			ff_dir_handle = WVAL(resp_param, 0);
+			ff_searchcount = WVAL(resp_param, 2);
+			ff_eos = WVAL(resp_param, 4);
+			ff_lastname = WVAL(resp_param, 8);
+		} else
+		{
+			ff_searchcount = WVAL(resp_param, 0);
+			ff_eos = WVAL(resp_param, 2);
+			ff_lastname = WVAL(resp_param, 6);
+		}
 
-                /* point to the data bytes */
-                p = resp_data;
+		if (ff_searchcount == 0)
+		{
+			break;
+		}
+		/* point to the data bytes */
+		p = resp_data;
 
-                /* we might need the lastname for continuations */
+		/* we might need the lastname for continuations */
 		lastname = "";
 		lastname_len = 0;
-                if (ff_lastname > 0)
-                {
-                        switch(info_level)
-                        {
-                        case 260:
+		if (ff_lastname > 0)
+		{
+			switch (info_level)
+			{
+			case 260:
 				lastname = p + ff_lastname;
 				lastname_len = resp_data_len - ff_lastname;
 				ff_resume_key = 0;
-                                break;
-                        case 1:
+				break;
+			case 1:
 				lastname = p + ff_lastname + 1;
-				lastname_len = strlen(lastname);
-                                ff_resume_key = 0;
-                                break;
-                        }
-                }
-  
-		/* Increase size of mask, if it is too small */
-		i = strlen(lastname) + 1;
-		if (i > dirlen)
-		{
-			smb_kfree_s(mask,  0);
-			dirlen = i;
-			mask = smb_kmalloc(dirlen, GFP_KERNEL);
-			if (mask == NULL)
-			{
-				printk("smb_proc_readdir_long: "
-				       "Memory allocation failed\n");
-				result = -ENOMEM;
+				lastname_len = BVAL(p, ff_lastname);
+				ff_resume_key = 0;
 				break;
 			}
 		}
+		lastname_len = min(lastname_len, 256);
 		strncpy(mask, lastname, lastname_len);
 		mask[lastname_len] = '\0';
-  
+
 		/* Now we are ready to parse smb directory entries. */
-		
-		for (i = 0; i < ff_searchcount; i ++) {
-			if (total_count < fpos) {
-				p = smb_decode_long_dirent(p, NULL,
-                                                           info_level);
-				DPRINTK("smb_proc_readdir: skipped entry.\n");
-				DDPRINTK("                  total_count = %d\n"
-                                         "                i = %d, fpos = %d\n",
-                                         total_count, i, fpos);
-                        }
-                        else if (total_count >= fpos + cache_size) {
-                                goto finished;
+
+		for (i = 0; i < ff_searchcount; i++)
+		{
+			struct smb_dirent *entry = &(cache[entries]);
+
+			p = smb_decode_long_dirent(server, p,
+						   entry, info_level);
+
+			DDPRINTK("smb_readdir_long: got %s\n", entry->name);
+
+			if ((entry->name[0] == '.')
+			    && ((entry->name[1] == '\0')
+				|| ((entry->name[1] == '.')
+				    && (entry->name[2] == '\0'))))
+			{
+				/* ignore . and .. from the server */
+				continue;
 			}
-			else {
-				p = smb_decode_long_dirent(p, current_entry,
-                                                           info_level);
-				current_entry->f_pos = total_count;
-				DDPRINTK("smb_proc_readdir: entry->f_pos = "
-                                         "%lu\n", entry->f_pos);	
-				current_entry += 1;
+			if (entries_seen >= fpos)
+			{
+				entry->f_pos = entries_seen;
+				entries += 1;
 			}
-			total_count += 1;
+			if (entries >= cache_size)
+			{
+				goto finished;
+			}
+			entries_seen += 1;
 		}
 
-                if (resp_data != NULL) {
-                        smb_kfree_s(resp_data,  0);
-                        resp_data = NULL;
-                }
-                if (resp_param != NULL) {
-                        smb_kfree_s(resp_param, 0);
-                        resp_param = NULL;
-                }
-
-                DPRINTK("received %d entries (eos=%d resume=%d)\n",
-                        ff_searchcount,ff_eos,ff_resume_key);
-
-                first = 0;
-        }
-
- finished:
- 	if (mask != NULL)
-		smb_kfree_s(mask,  0);
-
-        if (resp_data != NULL) {
-                smb_kfree_s(resp_data,  0);
-                resp_data = NULL;
-        }
-        if (resp_param != NULL) {
-                smb_kfree_s(resp_param, 0);
-                resp_param = NULL;
-        }
+		DPRINTK("received %d entries (eos=%d resume=%d)\n",
+			ff_searchcount, ff_eos, ff_resume_key);
 
-        smb_unlock_server(server);
+		first = 0;
+	}
 
-        return total_count - fpos;
+      finished:
+	smb_unlock_server(server);
+	return entries;
 }
 
 int
 smb_proc_readdir(struct smb_server *server, struct inode *dir, int fpos,
 		 int cache_size, struct smb_dirent *entry)
 {
-        if (server->protocol >= PROTOCOL_LANMAN2)
-                return smb_proc_readdir_long(server, dir, fpos, cache_size,
-                                             entry);
-        else
-                return smb_proc_readdir_short(server, dir, fpos, cache_size,
-                                              entry);
+	if (server->protocol >= PROTOCOL_LANMAN2)
+		return smb_proc_readdir_long(server, dir, fpos, cache_size,
+					     entry);
+	else
+		return smb_proc_readdir_short(server, dir, fpos, cache_size,
+					      entry);
 }
-		
+
 static int
-smb_proc_getattr_core(struct smb_server *server, const char *path, int len, 
-                      struct smb_dirent *entry)
+smb_proc_getattr_core(struct inode *dir, const char *name, int len,
+		      struct smb_dirent *entry)
 {
 	int result;
 	char *p;
-        char *buf = server->packet;
+	struct smb_server *server = SMB_SERVER(dir);
+	char *buf;
 
-        smb_lock_server(server);
+	smb_lock_server(server);
+	buf = server->packet;
 
-        DDPRINTK("smb_proc_getattr: %s\n", path);
+	DDPRINTK("smb_proc_getattr: %s\n", name);
 
- retry:
-	p = smb_setup_header(server, SMBgetatr, 0, 2 + len);
-	smb_encode_ascii(p, path, len);
-	
-	if ((result = smb_request_ok(server, SMBgetatr, 10, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-                smb_unlock_server(server);
-		return result;
-        }
+      retry:
+	p = smb_setup_header(server, SMBgetatr, 0, 0);
+	*p++ = 4;
+	p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
+	smb_setup_bcc(server, p);
 
-        entry->attr         = WVAL(buf, smb_vwv0);
-        entry->ctime = entry->atime = /* The server only tells us 1 time */
-                entry->mtime = local2utc(DVAL(buf, smb_vwv1));
+	if ((result = smb_request_ok(server, SMBgetatr, 10, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+		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));
 
-        entry->size         = DVAL(buf, smb_vwv3);
-        smb_unlock_server(server);
+	entry->f_size = DVAL(buf, smb_vwv3);
+	smb_unlock_server(server);
 	return 0;
 }
 
-/* smb_proc_getattrE: entry->fid must be valid */
-
 static int
-smb_proc_getattrE(struct smb_server *server, struct smb_dirent *entry)
+smb_proc_getattr_trans2(struct inode *dir, const char *name, int len,
+			struct smb_dirent *entry)
 {
-        char* buf = server->packet;
-        int result;
+	struct smb_server *server = SMB_SERVER(dir);
+	char param[SMB_MAXPATHLEN + 20];
+	char *p;
+	int result;
 
-        smb_setup_header_exclusive(server, SMBgetattrE, 1, 0);
-        WSET(buf, smb_vwv0, entry->fileid);
+	unsigned char *resp_data = NULL;
+	unsigned char *resp_param = NULL;
+	int resp_data_len = 0;
+	int resp_param_len = 0;
+
+	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);
 
-        if ((result = smb_request_ok(server, SMBgetattrE, 11, 0)) != 0) {
-                smb_unlock_server(server);
-                return result;
-        }
-
-        entry->ctime = date_dos2unix(WVAL(buf, smb_vwv1), WVAL(buf, smb_vwv0));
-        entry->atime = date_dos2unix(WVAL(buf, smb_vwv3), WVAL(buf, smb_vwv2));
-        entry->mtime = date_dos2unix(WVAL(buf, smb_vwv5), WVAL(buf, smb_vwv4));
-        entry->size  = DVAL(buf, smb_vwv6);
-        entry->attr  = WVAL(buf, smb_vwv10);
+	smb_lock_server(server);
+      retry:
+	result = smb_trans2_request(server, TRANSACT2_QPATHINFO,
+				    0, NULL, p - param, param,
+				    &resp_data_len, &resp_data,
+				    &resp_param_len, &resp_param);
 
-        smb_unlock_server(server);
-        return 0;
+	if (server->rcls != 0)
+	{
+		smb_unlock_server(server);
+		return -smb_errno(server->rcls, server->err);
+	}
+	if (result < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+		smb_unlock_server(server);
+		return result;
+	}
+	if (resp_data_len < 22)
+	{
+		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);
+	smb_unlock_server(server);
+
+	return 0;
 }
 
 int
-smb_proc_getattr(struct smb_server *server, const char *path, int len, 
-                 struct smb_dirent *entry)
+smb_proc_getattr(struct inode *dir, const char *name, int len,
+		 struct smb_dirent *entry)
 {
-        if (server->protocol >= PROTOCOL_LANMAN1) {
+	struct smb_server *server = SMB_SERVER(dir);
+	int result = 0;
 
-                int result = 0;
-                struct smb_dirent temp_entry;
+	smb_init_dirent(server, entry);
 
-		memset(&temp_entry, 0, sizeof(temp_entry));
-
-                if ((result=smb_proc_open(server,path,len,
-                                          &temp_entry)) < 0) {
-                        /* We cannot open directories, so we try to use the
-                           core variant */
-                        return smb_proc_getattr_core(server,path,len,entry);
-                }
-
-                if ((result=smb_proc_getattrE(server, &temp_entry)) >= 0) {
-                        entry->attr  = temp_entry.attr;
-                        entry->atime = temp_entry.atime;
-                        entry->mtime = temp_entry.mtime;
-                        entry->ctime = temp_entry.ctime;
-                        entry->size  = temp_entry.size;
-                }
-
-                smb_proc_close(server, temp_entry.fileid, temp_entry.mtime);
-                return result;
-
-        } else {
-                return smb_proc_getattr_core(server, path, len, entry);
-        }
+	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);
+
+	entry->len = len;
+	memcpy(entry->name, name, len);
+	/* entry->name is null terminated from smb_init_dirent */
+
+	return result;
 }
 
 
 /* In core protocol, there is only 1 time to be set, we use
-   entry->mtime, to make touch work. */
+   entry->f_mtime, to make touch work. */
 static int
 smb_proc_setattr_core(struct smb_server *server,
-                      const char *path, int len,
-                      struct smb_dirent *new_finfo)
+		      struct inode *i, struct smb_dirent *new_finfo)
 {
-        char *p;
-        char *buf = server->packet;
-        int result;
-
-        smb_lock_server(server);
-
- retry:
-        p = smb_setup_header(server, SMBsetatr, 8, 4 + len);
-        WSET(buf, smb_vwv0, new_finfo->attr);
-        DSET(buf, smb_vwv1, utc2local(new_finfo->mtime));
-        p = smb_encode_ascii(p, path, len);
-        p = smb_encode_ascii(p, "", 0);
-
-        if ((result = smb_request_ok(server, SMBsetatr, 0, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-        }
-        smb_unlock_server(server);
-        return result;
+	char *p;
+	char *buf;
+	int result;
+
+	smb_lock_server(server);
+	buf = server->packet;
+
+      retry:
+	p = smb_setup_header(server, SMBsetatr, 8, 0);
+	WSET(buf, smb_vwv0, new_finfo->attr);
+	DSET(buf, smb_vwv1, utc2local(new_finfo->f_mtime));
+	*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);
+
+	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;
 }
 
-/* smb_proc_setattrE: we do not retry here, because we rely on fid,
-   which would not be valid after a retry. */
 static int
-smb_proc_setattrE(struct smb_server *server, word fid,
-                  struct smb_dirent *new_entry)
+smb_proc_setattr_trans2(struct smb_server *server,
+			struct inode *i, struct smb_dirent *new_finfo)
 {
-        char *buf = server->packet;
-        word date, time;
-
-        smb_setup_header_exclusive(server, SMBsetattrE, 7, 0);
+	char param[SMB_MAXPATHLEN + 20];
+	char data[26];
+	char *p;
+	int result;
 
-        WSET(buf, smb_vwv0, fid);
+	unsigned char *resp_data = NULL;
+	unsigned char *resp_param = NULL;
+	int resp_data_len = 0;
+	int resp_param_len = 0;
+
+	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);
+	WSET(data, 22, 0);
 
-        date_unix2dos(new_entry->ctime, &time, &date);
-        WSET(buf, smb_vwv1, date);
-        WSET(buf, smb_vwv2, time);
-        
-        date_unix2dos(new_entry->atime, &time, &date);
-        WSET(buf, smb_vwv3, date);
-        WSET(buf, smb_vwv4, time);
-        
-        date_unix2dos(new_entry->mtime, &time, &date);
-        WSET(buf, smb_vwv5, date);
-        WSET(buf, smb_vwv6, time);
+	smb_lock_server(server);
+      retry:
+	result = smb_trans2_request(server, TRANSACT2_SETPATHINFO,
+				    26, data, p - param, param,
+				    &resp_data_len, &resp_data,
+				    &resp_param_len, &resp_param);
 
-        return smb_request_ok_unlock(server, SMBsetattrE, 0, 0);
+	if (server->rcls != 0)
+	{
+		smb_unlock_server(server);
+		return -smb_errno(server->rcls, server->err);
+	}
+	if (result < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+	}
+	smb_unlock_server(server);
+	return 0;
 }
 
-/* smb_proc_setattr: for protocol >= LANMAN1 we expect the file to be
-   opened for writing. */
 int
 smb_proc_setattr(struct smb_server *server, struct inode *inode,
-                 struct smb_dirent *new_finfo)
+		 struct smb_dirent *new_finfo)
 {
-        struct smb_dirent *finfo = SMB_FINFO(inode);
-        int result;
+	int result;
 
-        if (server->protocol >= PROTOCOL_LANMAN1) {
-                if ((result = smb_make_open(inode, O_RDWR)) < 0)
-                        return result;
-                return smb_proc_setattrE(server, finfo->fileid, new_finfo);
-        } else {
-                return smb_proc_setattr_core(server, finfo->path, finfo->len,
-                                             new_finfo);
-        }
+	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);
+	}
+	return result;
 }
 
 int
@@ -1587,25 +1610,26 @@
 	char *p;
 	struct smb_server *server = &(SMB_SBP(super)->s_server);
 
-        smb_lock_server(server);
+	smb_lock_server(server);
 
- retry:
+      retry:
 	smb_setup_header(server, SMBdskattr, 0, 0);
-	
-	if ((error = smb_request_ok(server, SMBdskattr, 5, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-                smb_unlock_server(server);
+
+	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);
-        smb_unlock_server(server);
+	smb_unlock_server(server);
 	return 0;
 }
 
@@ -1615,7 +1639,8 @@
 /*                                                                           */
 /*****************************************************************************/
 
-struct smb_prots {
+struct smb_prots
+{
 	enum smb_protocol prot;
 	const char *name;
 };
@@ -1629,50 +1654,50 @@
 smb_proc_reconnect(struct smb_server *server)
 {
 	struct smb_prots prots[] =
-        { { PROTOCOL_CORE, "PC NETWORK PROGRAM 1.0"},
-          { PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
+	{
+		{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"},
+		{PROTOCOL_LANMAN1, "MICROSOFT NETWORKS 3.0"},
+		{PROTOCOL_LANMAN1, "LANMAN1.0"},
 #endif
-#ifdef CONFIG_SMB_LONG
 #ifdef LANMAN2
-          { PROTOCOL_LANMAN2,"LM1.2X002"},
+		{PROTOCOL_LANMAN2, "LM1.2X002"},
 #endif
 #ifdef NT1
-	  { PROTOCOL_NT1,"NT LM 0.12"},
-	  { PROTOCOL_NT1,"NT LANMAN 1.0"},
-#endif
+		{PROTOCOL_NT1, "NT LM 0.12"},
+		{PROTOCOL_NT1, "NT LANMAN 1.0"},
 #endif
-          {-1, NULL} };
+		{-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 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_kfree_s(server->packet, server->max_xmit);
-        }
-        
-	server->packet = smb_kmalloc(max_xmit, GFP_KERNEL);
+	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) {
-		printk("smb_proc_connect: No memory! Bailing out.\n");
-                result = -ENOMEM;
-                goto fail;
+	if (server->packet != NULL)
+	{
+		smb_vfree(server->packet);
+		server->packet_size = 0;
 	}
+	server->packet = smb_vmalloc(max_xmit);
 
-        server->max_xmit = 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.
@@ -1681,98 +1706,110 @@
 
 	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) {
-		printk("smb_proc_connect: Failed to send SESSION REQUEST.\n");
-                smb_dont_catch_keepalive(server);
-                goto fail;
+			      (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 (server->packet[0] != 0x82) {
+	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", 
+		       "(err = %x)\n",
 		       server->packet[0]);
-                smb_dont_catch_keepalive(server);
-#if DEBUG_SMB > 0
-                smb_dump_packet(server->packet);
-#endif
-                result = -EIO;
-                goto fail;
+		smb_dont_catch_keepalive(server);
+		result = -EIO;
+		goto fail;
 	}
+	DPRINTK("smb_proc_connect: Passed SESSION REQUEST.\n");
 
-        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++) {
+	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 = smb_encode_dialect(p,prots[i].name, strlen(prots[i].name));
-        }
-	
-	if ((result = smb_request_ok(server, SMBnegprot, 1, -1)) < 0) {
-         	printk("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;
+
+	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);
+		prots[i].name);
+
+	if (server->protocol >= PROTOCOL_LANMAN1)
+	{
+
+		word passlen = strlen(server->m.password);
+		word userlen = strlen(server->m.username);
 
-        if (server->protocol >= PROTOCOL_LANMAN1) {
+		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));
 
-                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->maxxmt = 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->maxxmt = WVAL(server->packet, smb_vwv2);
+		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);
+			server->blkmode = WVAL(server->packet, smb_vwv5);
+			server->sesskey = DVAL(server->packet, smb_vwv6);
 		}
 
-
-		if (server->protocol >= PROTOCOL_NT1) {
-			char *workgroup = "WORKGROUP";
+		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";
 
@@ -1780,7 +1817,7 @@
 					 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);
@@ -1801,7 +1838,8 @@
 			strcpy(p, OS_id);
 			p += strlen(p) + 1;
 			strcpy(p, client_id);
-		} else {
+		} else
+		{
 			smb_setup_header(server, SMBsesssetupX, 10,
 					 2 + userlen + passlen);
 
@@ -1821,47 +1859,59 @@
 			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->maxxmt = 0;
-                server->maxmux = 0;
-                server->maxvcs = 0;
-                server->blkmode = 0;
-                server->sesskey = 0;
-        }
+		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));
+			 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, 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) {
+	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;
+		smb_dont_catch_keepalive(server);
+		goto fail;
 	}
+	DDPRINTK("OK! Managed to set up SMBtcon!\n");
 
-        DDPRINTK("OK! Managed to set up SMBtcon!\n");
-   
 	p = SMB_VWV(server->packet);
-	p = smb_decode_word(p, &server->max_xmit);
 
-        if (server->max_xmit > given_max_xmit)
-                server->max_xmit = given_max_xmit;
-        
+	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 */
@@ -1871,22 +1921,24 @@
 	DPRINTK("max_xmit = %d, tid = %d\n", server->max_xmit, server->tid);
 
 	/* Now make a new packet with the correct size. */
-	smb_kfree_s(server->packet, max_xmit); 
+	smb_vfree(server->packet);
 
-	server->packet = smb_kmalloc(server->max_xmit, GFP_KERNEL);
-	if (server->packet == NULL) {
+	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;
+		       "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;
+	DPRINTK("smb_proc_connect: Normal exit\n");
+	return 0;
 
- fail:
-        server->state = CONN_INVALID;
-        return result;
+      fail:
+	server->state = CONN_INVALID;
+	return result;
 }
 
 /* smb_proc_reconnect: server->packet is allocated with
@@ -1894,172 +1946,23 @@
 int
 smb_proc_connect(struct smb_server *server)
 {
-        int result;
-        smb_lock_server(server);
-
-        result = smb_proc_reconnect(server);
+	int result;
+	smb_lock_server(server);
 
-        if ((result < 0) && (server->packet != NULL)) {
-                smb_kfree_s(server->packet, server->max_xmit);
-                server->packet = NULL;
-        }
+	result = smb_proc_reconnect(server);
 
-        smb_unlock_server(server);
-        return result;
+	if ((result < 0) && (server->packet != NULL))
+	{
+		smb_vfree(server->packet);
+		server->packet = NULL;
+	}
+	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);
 }
-
-/* error code stuff - put together by Merik Karman
-   merik@blackadder.dsh.oz.au */
-
-#if DEBUG_SMB > 0
-
-typedef struct {
-	char *name;
-	int code;
-	char *message;
-} err_code_struct;
-
-/* Dos Error Messages */
-err_code_struct dos_msgs[] = {
-  { "ERRbadfunc",1,"Invalid function."},
-  { "ERRbadfile",2,"File not found."},
-  { "ERRbadpath",3,"Directory invalid."},
-  { "ERRnofids",4,"No file descriptors available"},
-  { "ERRnoaccess",5,"Access denied."},
-  { "ERRbadfid",6,"Invalid file handle."},
-  { "ERRbadmcb",7,"Memory control blocks destroyed."},
-  { "ERRnomem",8,"Insufficient server memory to perform the requested function."},
-  { "ERRbadmem",9,"Invalid memory block address."},
-  { "ERRbadenv",10,"Invalid environment."},
-  { "ERRbadformat",11,"Invalid format."},
-  { "ERRbadaccess",12,"Invalid open mode."},
-  { "ERRbaddata",13,"Invalid data."},
-  { "ERR",14,"reserved."},
-  { "ERRbaddrive",15,"Invalid drive specified."},
-  { "ERRremcd",16,"A Delete Directory request attempted  to  remove  the  server's  current directory."},
-  { "ERRdiffdevice",17,"Not same device."},
-  { "ERRnofiles",18,"A File Search command can find no more files matching the specified criteria."},
-  { "ERRbadshare",32,"The sharing mode specified for an Open conflicts with existing  FIDs  on the file."},
-  { "ERRlock",33,"A Lock request conflicted with an existing lock or specified an  invalid mode,  or an Unlock requested attempted to remove a lock held by another process."},
-  { "ERRfilexists",80,"The file named in a Create Directory, Make  New  File  or  Link  request already exists."},
-  { "ERRbadpipe",230,"Pipe invalid."},
-  { "ERRpipebusy",231,"All instances of the requested pipe are busy."},
-  { "ERRpipeclosing",232,"Pipe close in progress."},
-  { "ERRnotconnected",233,"No process on other end of pipe."},
-  { "ERRmoredata",234,"There is more data to be returned."},
-  { NULL,-1,NULL}};
-
-/* Server Error Messages */
-err_code_struct server_msgs[] = { 
-  { "ERRerror",1,"Non-specific error code."},
-  { "ERRbadpw",2,"Bad password - name/password pair in a Tree Connect or Session Setup are invalid."},
-  { "ERRbadtype",3,"reserved."},
-  { "ERRaccess",4,"The requester does not have  the  necessary  access  rights  within  the specified  context for the requested function. The context is defined by the TID or the UID."},
-  { "ERRinvnid",5,"The tree ID (TID) specified in a command was invalid."},
-  { "ERRinvnetname",6,"Invalid network name in tree connect."},
-  { "ERRinvdevice",7,"Invalid device - printer request made to non-printer connection or  non-printer request made to printer connection."},
-  { "ERRqfull",49,"Print queue full (files) -- returned by open print file."},
-  { "ERRqtoobig",50,"Print queue full -- no space."},
-  { "ERRqeof",51,"EOF on print queue dump."},
-  { "ERRinvpfid",52,"Invalid print file FID."},
-  { "ERRsmbcmd",64,"The server did not recognize the command received."},
-  { "ERRsrverror",65,"The server encountered an internal error, e.g., system file unavailable."},
-  { "ERRfilespecs",67,"The file handle (FID) and pathname parameters contained an invalid  combination of values."},
-  { "ERRreserved",68,"reserved."},
-  { "ERRbadpermits",69,"The access permissions specified for a file or directory are not a valid combination.  The server cannot set the requested attribute."},
-  { "ERRreserved",70,"reserved."},
-  { "ERRsetattrmode",71,"The attribute mode in the Set File Attribute request is invalid."},
-  { "ERRpaused",81,"Server is paused."},
-  { "ERRmsgoff",82,"Not receiving messages."},
-  { "ERRnoroom",83,"No room to buffer message."},
-  { "ERRrmuns",87,"Too many remote user names."},
-  { "ERRtimeout",88,"Operation timed out."},
-  { "ERRnoresource",89,"No resources currently available for request."},
-  { "ERRtoomanyuids",90,"Too many UIDs active on this session."},
-  { "ERRbaduid",91,"The UID is not known as a valid ID on this session."},
-  { "ERRusempx",250,"Temp unable to support Raw, use MPX mode."},
-  { "ERRusestd",251,"Temp unable to support Raw, use standard read/write."},
-  { "ERRcontmpx",252,"Continue in MPX mode."},
-  { "ERRreserved",253,"reserved."},
-  { "ERRreserved",254,"reserved."},
-  { "ERRnosupport",0xFFFF,"Function not supported."},
-  { NULL,-1,NULL}};
-
-/* Hard Error Messages */
-err_code_struct hard_msgs[] = { 
-  { "ERRnowrite",19,"Attempt to write on write-protected diskette."},
-  { "ERRbadunit",20,"Unknown unit."},
-  { "ERRnotready",21,"Drive not ready."},
-  { "ERRbadcmd",22,"Unknown command."},
-  { "ERRdata",23,"Data error (CRC)."},
-  { "ERRbadreq",24,"Bad request structure length."},
-  { "ERRseek",25 ,"Seek error."},
-  { "ERRbadmedia",26,"Unknown media type."},
-  { "ERRbadsector",27,"Sector not found."},
-  { "ERRnopaper",28,"Printer out of paper."},
-  { "ERRwrite",29,"Write fault."},
-  { "ERRread",30,"Read fault."},
-  { "ERRgeneral",31,"General failure."},
-  { "ERRbadshare",32,"A open conflicts with an existing open."},
-  { "ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."},
-  { "ERRwrongdisk",34,"The wrong disk was found in a drive."},
-  { "ERRFCBUnavail",35,"No FCBs are available to process request."},
-  { "ERRsharebufexc",36,"A sharing buffer has been exceeded."},
-  { NULL,-1,NULL}
-};
-
-
-struct { 
-	int code;
-	char *class;
-	err_code_struct *err_msgs;
-} err_classes[] = {  
-  { 0,"SUCCESS",NULL},
-  { 0x01,"ERRDOS",dos_msgs},
-  { 0x02,"ERRSRV",server_msgs},
-  { 0x03,"ERRHRD",hard_msgs},
-  { 0x04,"ERRXOS",NULL},
-  { 0xE1,"ERRRMX1",NULL},
-  { 0xE2,"ERRRMX2",NULL},
-  { 0xE3,"ERRRMX3",NULL},
-  { 0xFF,"ERRCMD",NULL},
-  { -1,NULL,NULL}
-};
-
-void
-smb_printerr(int class, int num)
-{
-	int i,j;
-	err_code_struct *err;
-
-	for (i=0; err_classes[i].class; i++) {
-		if (err_classes[i].code != class)
-			continue;
-		if (!err_classes[i].err_msgs) {
-			printk("%s - %d", err_classes[i].class, num);
-			return;
-		}
-
-		err = err_classes[i].err_msgs;
-		for (j=0; err[j].name; j++) {
-			if (num != err[j].code)
-				continue;
-			printk("%s - %s (%s)",
-			       err_classes[i].class, err[j].name,
-                               err[j].message);
-			return;
-		}
-	}
-	
-	printk("Unknown error - (%d,%d)", class, num);
-	return;
-}
-
-#endif /* DEBUG_SMB > 0 */
diff -u --recursive --new-file v2.0.26/linux/fs/smbfs/sock.c linux/fs/smbfs/sock.c
--- v2.0.26/linux/fs/smbfs/sock.c	Wed Sep 11 17:57:16 1996
+++ linux/fs/smbfs/sock.c	Sun Dec  1 15:58:06 1996
@@ -1,7 +1,7 @@
 /*
  *  sock.c
  *
- *  Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
  *
  */
 
@@ -28,747 +28,687 @@
 _recvfrom(struct socket *sock, unsigned char *ubuf, int size,
 	  int noblock, unsigned flags, struct sockaddr_in *sa, int *addr_len)
 {
-        struct iovec iov;
-        struct msghdr msg;
+	struct iovec iov;
+	struct msghdr msg;
 
-        iov.iov_base = ubuf;
-        iov.iov_len  = size;
+	iov.iov_base = ubuf;
+	iov.iov_len = size;
 
-        msg.msg_name      = (void *)sa;
-        msg.msg_namelen   = 0;
-        if (addr_len)
-                msg.msg_namelen = *addr_len;
-        msg.msg_control = NULL;
-        msg.msg_iov       = &iov;
-        msg.msg_iovlen    = 1;
+	msg.msg_name = (void *) sa;
+	msg.msg_namelen = 0;
+	if (addr_len)
+		msg.msg_namelen = *addr_len;
+	msg.msg_control = NULL;
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
 
-        return sock->ops->recvmsg(sock, &msg, size, noblock, flags, addr_len);
+	return sock->ops->recvmsg(sock, &msg, size, noblock, flags, addr_len);
 }
 
 static int
 _send(struct socket *sock, const void *buff, int len,
       int nonblock, unsigned flags)
 {
-        struct iovec iov;
-        struct msghdr msg;
+	struct iovec iov;
+	struct msghdr msg;
 
-        iov.iov_base = (void *)buff;
-        iov.iov_len  = len;
+	iov.iov_base = (void *) buff;
+	iov.iov_len = len;
 
-        msg.msg_name      = NULL;
-        msg.msg_namelen   = 0;
-        msg.msg_control = NULL;
-        msg.msg_iov       = &iov;
-        msg.msg_iovlen    = 1;
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+	msg.msg_control = NULL;
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
 
-        return sock->ops->sendmsg(sock, &msg, len, nonblock, flags);
+	return sock->ops->sendmsg(sock, &msg, len, nonblock, flags);
 }
 
 static void
-smb_data_callback(struct sock *sk,int len)
+smb_data_callback(struct sock *sk, int len)
 {
-        struct socket *sock = sk->socket;
+	struct socket *sock = sk->socket;
 
-	if(!sk->dead)
+	if (!sk->dead)
 	{
-                unsigned char peek_buf[4];
-                int result;
-                unsigned short fs;
-
-                fs = get_fs();
-                set_fs(get_ds());
-
-		result = _recvfrom(sock, (void *)peek_buf, 1, 1,
-                                             MSG_PEEK, NULL, NULL);
-
-                while ((result != -EAGAIN) && (peek_buf[0] == 0x85)) {
-
-                        /* got SESSION KEEP ALIVE */
-                        result = _recvfrom(sock, (void *)peek_buf,
-                                                     4, 1, 0, NULL, NULL);
-
-                        DDPRINTK("smb_data_callback:"
-                                 " got SESSION KEEP ALIVE\n");
-
-                        if (result == -EAGAIN)
-                                break;
+		unsigned char peek_buf[4];
+		int result;
+		unsigned short fs;
+
+		fs = get_fs();
+		set_fs(get_ds());
+
+		result = _recvfrom(sock, (void *) peek_buf, 1, 1,
+				   MSG_PEEK, NULL, NULL);
+
+		while ((result != -EAGAIN) && (peek_buf[0] == 0x85))
+		{
+			/* got SESSION KEEP ALIVE */
+			result = _recvfrom(sock, (void *) peek_buf,
+					   4, 1, 0, NULL, NULL);
+
+			DDPRINTK("smb_data_callback:"
+				 " got SESSION KEEP ALIVE\n");
+
+			if (result == -EAGAIN)
+			{
+				break;
+			}
+			result = _recvfrom(sock, (void *) peek_buf,
+					   1, 1, MSG_PEEK,
+					   NULL, NULL);
+		}
+		set_fs(fs);
+
+		if (result != -EAGAIN)
+		{
+			wake_up_interruptible(sk->sleep);
+		}
+	}
+}
 
-                        result = _recvfrom(sock, (void *)peek_buf,
-                                                     1, 1, MSG_PEEK,
-                                                     NULL, NULL);
+int
+smb_catch_keepalive(struct smb_server *server)
+{
+	struct file *file;
+	struct inode *inode;
+	struct socket *sock;
+	struct sock *sk;
+
+	if ((server == NULL)
+	    || ((file = server->sock_file) == NULL)
+	    || ((inode = file->f_inode) == NULL)
+	    || (!S_ISSOCK(inode->i_mode)))
+	{
+		printk("smb_catch_keepalive: did not get valid server!\n");
+		server->data_ready = NULL;
+		return -EINVAL;
+	}
+	sock = &(inode->u.socket_i);
 
-                }
+	if (sock->type != SOCK_STREAM)
+	{
+		printk("smb_catch_keepalive: did not get SOCK_STREAM\n");
+		server->data_ready = NULL;
+		return -EINVAL;
+	}
+	sk = (struct sock *) (sock->data);
 
-                set_fs(fs);
+	if (sk == NULL)
+	{
+		printk("smb_catch_keepalive: sk == NULL");
+		server->data_ready = NULL;
+		return -EINVAL;
+	}
+	DDPRINTK("smb_catch_keepalive.: sk->d_r = %x, server->d_r = %x\n",
+		 (unsigned int) (sk->data_ready),
+		 (unsigned int) (server->data_ready));
 
-                if (result != -EAGAIN) {
-                        wake_up_interruptible(sk->sleep);
-                }
+	if (sk->data_ready == smb_data_callback)
+	{
+		printk("smb_catch_keepalive: already done\n");
+		return -EINVAL;
 	}
+	server->data_ready = sk->data_ready;
+	sk->data_ready = smb_data_callback;
+	return 0;
 }
 
 int
-smb_catch_keepalive(struct smb_server *server)
+smb_dont_catch_keepalive(struct smb_server *server)
 {
-        struct file   *file;
-        struct inode  *inode;
-        struct socket *sock;
-        struct sock   *sk;
-
-        if (   (server == NULL)
-            || ((file  = server->sock_file) == NULL)
-            || ((inode = file->f_inode) == NULL)
-            || (!S_ISSOCK(inode->i_mode))) {
-
-                printk("smb_catch_keepalive: did not get valid server!\n");
-                server->data_ready = NULL;
-                return -EINVAL;
-        }
-
-        sock = &(inode->u.socket_i);
-
-        if (sock->type != SOCK_STREAM) {
-                printk("smb_catch_keepalive: did not get SOCK_STREAM\n");
-                server->data_ready = NULL;
-                return -EINVAL;
-        }
-
-        sk   = (struct sock *)(sock->data);
-
-        if (sk == NULL) {
-                printk("smb_catch_keepalive: sk == NULL");
-                server->data_ready = NULL;
-                return -EINVAL;
-        }
-
-        DDPRINTK("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");
-                return -EINVAL;
-        }
-
-        server->data_ready = sk->data_ready;
-        sk->data_ready = smb_data_callback;
-        return 0;
+	struct file *file;
+	struct inode *inode;
+	struct socket *sock;
+	struct sock *sk;
+
+	if ((server == NULL)
+	    || ((file = server->sock_file) == NULL)
+	    || ((inode = file->f_inode) == NULL)
+	    || (!S_ISSOCK(inode->i_mode)))
+	{
+		printk("smb_dont_catch_keepalive: "
+		       "did not get valid server!\n");
+		return -EINVAL;
+	}
+	sock = &(inode->u.socket_i);
+
+	if (sock->type != SOCK_STREAM)
+	{
+		printk("smb_dont_catch_keepalive: did not get SOCK_STREAM\n");
+		return -EINVAL;
+	}
+	sk = (struct sock *) (sock->data);
+
+	if (sk == NULL)
+	{
+		printk("smb_dont_catch_keepalive: sk == NULL");
+		return -EINVAL;
+	}
+	if (server->data_ready == NULL)
+	{
+		printk("smb_dont_catch_keepalive: "
+		       "server->data_ready == NULL\n");
+		return -EINVAL;
+	}
+	if (sk->data_ready != smb_data_callback)
+	{
+		printk("smb_dont_catch_keepalive: "
+		       "sk->data_callback != smb_data_callback\n");
+		return -EINVAL;
+	}
+	DDPRINTK("smb_dont_catch_keepalive: sk->d_r = %x, server->d_r = %x\n",
+		 (unsigned int) (sk->data_ready),
+		 (unsigned int) (server->data_ready));
+
+	sk->data_ready = server->data_ready;
+	server->data_ready = NULL;
+	return 0;
 }
-                
-int
-smb_dont_catch_keepalive(struct smb_server *server)
+
+static int
+smb_send_raw(struct socket *sock, unsigned char *source, int length)
 {
-        struct file   *file;
-        struct inode  *inode;
-        struct socket *sock;
-        struct sock   *sk;
-
-        if (   (server == NULL)
-            || ((file  = server->sock_file) == NULL)
-            || ((inode = file->f_inode) == NULL)
-            || (!S_ISSOCK(inode->i_mode))) {
-
-                printk("smb_dont_catch_keepalive: "
-                       "did not get valid server!\n");
-                return -EINVAL;
-        }
-
-        sock = &(inode->u.socket_i);
-
-        if (sock->type != SOCK_STREAM) {
-                printk("smb_dont_catch_keepalive: did not get SOCK_STREAM\n");
-                return -EINVAL;
-        }
-
-        sk   = (struct sock *)(sock->data);
-
-        if (sk == NULL) {
-                printk("smb_dont_catch_keepalive: sk == NULL");
-                return -EINVAL;
-        }
-
-        if (server->data_ready == NULL) {
-                printk("smb_dont_catch_keepalive: "
-                       "server->data_ready == NULL\n");
-                return -EINVAL;
-        }
-
-        if (sk->data_ready != smb_data_callback) {
-                printk("smb_dont_catch_keepalive: "
-                       "sk->data_callback != smb_data_callback\n");
-                return -EINVAL;
-        }
-
-        DDPRINTK("smb_dont_catch_keepalive: sk->d_r = %x, server->d_r = %x\n",
-                 (unsigned int)(sk->data_ready),
-                 (unsigned int)(server->data_ready));
-
-        sk->data_ready = server->data_ready;
-        server->data_ready = NULL;
-        return 0;
+	int result;
+	int already_sent = 0;
+
+	while (already_sent < length)
+	{
+		result = _send(sock,
+			       (void *) (source + already_sent),
+			       length - already_sent, 0, 0);
+
+		if (result < 0)
+		{
+			DPRINTK("smb_send_raw: sendto error = %d\n",
+				-result);
+			return result;
+		}
+		already_sent += result;
+	}
+	return already_sent;
 }
 
-/*
- * smb_receive_raw
- * fs points to the correct segment, sock != NULL, target != NULL
- * The smb header is only stored if want_header != 0.
- */
 static int
-smb_receive_raw(struct socket *sock, unsigned char *target,
-                int max_raw_length, int want_header)
+smb_receive_raw(struct socket *sock, unsigned char *target, int length)
 {
-        int len, result;
-        int already_read;
-        unsigned char peek_buf[4];
-        unsigned short fs;      /* We fool the kernel to believe
-                                   we call from user space. */
+	int result;
+	int already_read = 0;
 
+	while (already_read < length)
+	{
+		result = _recvfrom(sock,
+				   (void *) (target + already_read),
+				   length - already_read, 0, 0,
+				   NULL, NULL);
+
+		if (result < 0)
+		{
+			DPRINTK("smb_receive_raw: recvfrom error = %d\n",
+				-result);
+			return result;
+		}
+		already_read += result;
+	}
+	return already_read;
+}
 
- re_recv:
+static int
+smb_get_length(struct socket *sock, unsigned char *header)
+{
+	int result;
+	unsigned char peek_buf[4];
+	unsigned short fs;
 
+      re_recv:
 	fs = get_fs();
 	set_fs(get_ds());
-        result = _recvfrom(sock, (void *)peek_buf, 4, 0,
-                                     0, NULL, NULL);
-        set_fs(fs);
-
-        if (result < 0) {
-                DPRINTK("smb_receive_raw: recv error = %d\n", -result);
-                return result;
-        }
-
-        if (result < 4) {
-                DPRINTK("smb_receive_raw: got less than 4 bytes\n");
-                return -EIO;
-        }
-
-        switch (peek_buf[0]) {
-
-        case 0x00:
-        case 0x82:
-                break;
-
-        case 0x85:
-                DPRINTK("smb_receive_raw: Got SESSION KEEP ALIVE\n");
-                goto re_recv;
-                
-        default:
-                printk("smb_receive_raw: Invalid packet\n");
-                return -EIO;
-        }
-
-        /* The length in the RFC NB header is the raw data length */
-	len = smb_len(peek_buf); 
-        if (len > max_raw_length) { 
-                printk("smb_receive_raw: Received length (%d) > max_xmit (%d)!\n", 
-		       len, max_raw_length);
-                return -EIO;
-	}
-
-        if (want_header != 0) {
-                memcpy_tofs(target, peek_buf, 4);
-                target += 4;
-        }
-
-        already_read = 0;
-
-        while (already_read < len) {
-                
-                result = _recvfrom(sock,
-                                 (void *)(target+already_read),
-                                 len - already_read, 0, 0,
-                                 NULL, NULL);
-   
-                if (result < 0) {
-                        printk("smb_receive_raw: recvfrom error = %d\n",
-                               -result);
-                        return result;
-                }
-
-                already_read += result;
-        }
-        return already_read;
+	result = smb_receive_raw(sock, peek_buf, 4);
+	set_fs(fs);
+
+	if (result < 0)
+	{
+		DPRINTK("smb_get_length: recv error = %d\n", -result);
+		return result;
+	}
+	switch (peek_buf[0])
+	{
+	case 0x00:
+	case 0x82:
+		break;
+
+	case 0x85:
+		DPRINTK("smb_get_length: Got SESSION KEEP ALIVE\n");
+		goto re_recv;
+
+	default:
+		printk("smb_get_length: Invalid NBT packet\n");
+		return -EIO;
+	}
+
+	if (header != NULL)
+	{
+		memcpy(header, peek_buf, 4);
+	}
+	/* The length in the RFC NB header is the raw data length */
+	return smb_len(peek_buf);
+}
+
+static struct socket *
+server_sock(struct smb_server *server)
+{
+	struct file *file;
+	struct inode *inode;
+
+	if (server == NULL)
+		return NULL;
+	if ((file = server->sock_file) == NULL)
+		return NULL;
+	if ((inode = file->f_inode) == NULL)
+		return NULL;
+	return &(inode->u.socket_i);
 }
 
 /*
  * smb_receive
- * fs points to the correct segment, server != NULL, sock!=NULL
+ * fs points to the correct segment
  */
 static int
-smb_receive(struct smb_server *server, struct socket *sock)
+smb_receive(struct smb_server *server)
 {
-        int result;
-
-        result = smb_receive_raw(sock, server->packet,
-                                 server->max_xmit - 4, /* max_xmit in server
-                                                          includes NB header */
-                                 1); /* We want the header */
+	struct socket *sock = server_sock(server);
+	int len;
+	int result;
+	unsigned char peek_buf[4];
 
-        if (result < 0) {
-                printk("smb_receive: receive error: %d\n", result);
-                return result;
-        }
+	len = smb_get_length(sock, peek_buf);
 
-        server->rcls = *((unsigned char *)(server->packet+9));
-        server->err  = *((unsigned short *)(server->packet+11));
+	if (len < 0)
+	{
+		return len;
+	}
+	if (len + 4 > server->packet_size)
+	{
+		/* Some servers do not care about our max_xmit. They
+		   send larger packets */
+		DPRINTK("smb_receive: Increase packet size from %d to %d\n",
+			server->packet_size, len + 4);
+		smb_vfree(server->packet);
+		server->packet_size = 0;
+		server->packet = smb_vmalloc(len + 4);
+		if (server->packet == NULL)
+		{
+			return -ENOMEM;
+		}
+		server->packet_size = len + 4;
+	}
+	memcpy(server->packet, peek_buf, 4);
+	result = smb_receive_raw(sock, server->packet + 4, len);
 
-        if (server->rcls != 0) {
-                DPRINTK("smb_receive: rcls=%d, err=%d\n",
-                        server->rcls, server->err);
-        }
+	if (result < 0)
+	{
+		printk("smb_receive: receive error: %d\n", result);
+		return result;
+	}
+	server->rcls = BVAL(server->packet, 9);
+	server->err = WVAL(server->packet, 11);
 
-        return result;
+	if (server->rcls != 0)
+	{
+		DPRINTK("smb_receive: rcls=%d, err=%d\n",
+			server->rcls, server->err);
+	}
+	return result;
 }
 
-
-/*
- * smb_receive's preconditions also apply here.
- */
 static int
-smb_receive_trans2(struct smb_server *server, struct socket *sock,
-                   int *data_len, int *param_len,
-                   char **data, char **param)
-{
-        int total_data=0;
-        int total_param=0;
-        int result;
-        unsigned char *inbuf = server->packet;
-
-        *data_len = *param_len = 0;
-
-        DDPRINTK("smb_receive_trans2: enter\n");
-        
-        if ((result = smb_receive(server, sock)) < 0) {
-                return result;
-        }
-
-        if (server->rcls != 0) {
-                return result;
-        }
-
-        /* parse out the lengths */
-        total_data = WVAL(inbuf,smb_tdrcnt);
-        total_param = WVAL(inbuf,smb_tprcnt);
-
-        if (   (total_data  > TRANS2_MAX_TRANSFER)
-            || (total_param > TRANS2_MAX_TRANSFER)) {
-                printk("smb_receive_trans2: data/param too long\n");
-                return -EIO;
-        }
-
-        /* allocate it */
-        if ((*data  = smb_kmalloc(total_data, GFP_KERNEL)) == NULL) {
-                printk("smb_receive_trans2: could not alloc data area\n");
-                return -ENOMEM;
-        }
-
-        if ((*param = smb_kmalloc(total_param, GFP_KERNEL)) == NULL) {
-                printk("smb_receive_trans2: could not alloc param area\n");
-                smb_kfree_s(*data, total_data);
-                return -ENOMEM;
-        }
-
-        DDPRINTK("smb_rec_trans2: total_data/param: %d/%d\n",
-                 total_data, total_param);
-
-        while (1)
-        {
-                if (WVAL(inbuf,smb_prdisp)+WVAL(inbuf, smb_prcnt)
-                    > total_param) {
-                        printk("smb_receive_trans2: invalid parameters\n");
-                        result = -EIO;
-                        goto fail;
-                }
-                memcpy(*param + WVAL(inbuf,smb_prdisp),
-                       smb_base(inbuf) + WVAL(inbuf,smb_proff),
-                       WVAL(inbuf,smb_prcnt));
-                *param_len += WVAL(inbuf,smb_prcnt);
-
-
-                if (WVAL(inbuf,smb_drdisp)+WVAL(inbuf, smb_drcnt)>total_data) {
-                        printk("smb_receive_trans2: invalid data block\n");
-                        result = -EIO;
-                        goto fail;
-                }
-                memcpy(*data + WVAL(inbuf,smb_drdisp),
-                       smb_base(inbuf) + WVAL(inbuf,smb_droff),
-                       WVAL(inbuf,smb_drcnt));
-                *data_len += WVAL(inbuf,smb_drcnt);
-
-                DDPRINTK("smb_rec_trans2: drcnt/prcnt: %d/%d\n",
-                         WVAL(inbuf, smb_drcnt), WVAL(inbuf, smb_prcnt));
-
-                /* parse out the total lengths again - they can shrink! */
-
-                if (   (WVAL(inbuf,smb_tdrcnt) > total_data)
-                    || (WVAL(inbuf,smb_tprcnt) > total_param)) {
-                        printk("smb_receive_trans2: data/params grew!\n");
-                        result = -EIO;
-                        goto fail;
-                }
-
-                total_data = WVAL(inbuf,smb_tdrcnt);
-                total_param = WVAL(inbuf,smb_tprcnt);
-
-                if (total_data <= *data_len && total_param <= *param_len)
-                        break;
-
-                if ((result = smb_receive(server, sock)) < 0) {
-                        goto fail;
-                }
-                if (server->rcls != 0) {
-                        result = -EIO;
-                        goto fail;
-                }
-        }
-
-        DDPRINTK("smb_receive_trans2: normal exit\n");
-
-        return 0;
-
- fail:
-        DPRINTK("smb_receive_trans2: failed exit\n");
-
-        smb_kfree_s(*param, 0); *param = NULL;
-        smb_kfree_s(*data, 0);  *data = NULL;
-        return result;
-}
+smb_receive_trans2(struct smb_server *server,
+		   int *ldata, unsigned char **data,
+		   int *lparam, unsigned char **param)
+{
+	int total_data = 0;
+	int total_param = 0;
+	int result;
+	unsigned char *inbuf = server->packet;
+	unsigned char *rcv_buf;
+	int buf_len;
+	int data_len = 0;
+	int param_len = 0;
 
-static inline struct socket *
-server_sock(struct smb_server *server)
-{
-        struct file *file;
-        struct inode *inode;
+	if ((result = smb_receive(server)) < 0)
+	{
+		return result;
+	}
+	if (server->rcls != 0)
+	{
+		*param = *data = server->packet;
+		*ldata = *lparam = 0;
+		return 0;
+	}
+	total_data = WVAL(inbuf, smb_tdrcnt);
+	total_param = WVAL(inbuf, smb_tprcnt);
+
+	DDPRINTK("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");
+		return -EIO;
+	}
+	buf_len = total_data + total_param;
+	if (server->packet_size > buf_len)
+	{
+		buf_len = server->packet_size;
+	}
+	if ((rcv_buf = smb_vmalloc(buf_len)) == NULL)
+	{
+		DPRINTK("smb_receive_trans2: could not alloc data area\n");
+		return -ENOMEM;
+	}
+	*param = rcv_buf;
+	*data = rcv_buf + total_param;
+
+	while (1)
+	{
+		if (WVAL(inbuf, smb_prdisp) + WVAL(inbuf, smb_prcnt)
+		    > total_param)
+		{
+			DPRINTK("smb_receive_trans2: invalid parameters\n");
+			result = -EIO;
+			goto fail;
+		}
+		memcpy(*param + WVAL(inbuf, smb_prdisp),
+		       smb_base(inbuf) + WVAL(inbuf, smb_proff),
+		       WVAL(inbuf, smb_prcnt));
+		param_len += WVAL(inbuf, smb_prcnt);
+
+		if (WVAL(inbuf, smb_drdisp) + WVAL(inbuf, smb_drcnt)
+		    > total_data)
+		{
+			DPRINTK("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",
+			 WVAL(inbuf, smb_drdisp), WVAL(inbuf, smb_droff),
+			 WVAL(inbuf, smb_drcnt));
+
+		memcpy(*data + WVAL(inbuf, smb_drdisp),
+		       smb_base(inbuf) + WVAL(inbuf, smb_droff),
+		       WVAL(inbuf, smb_drcnt));
+		data_len += WVAL(inbuf, smb_drcnt);
+
+		if ((WVAL(inbuf, smb_tdrcnt) > total_data)
+		    || (WVAL(inbuf, smb_tprcnt) > total_param))
+		{
+			printk("smb_receive_trans2: data/params grew!\n");
+			result = -EIO;
+			goto fail;
+		}
+		/* the total lengths might shrink! */
+		total_data = WVAL(inbuf, smb_tdrcnt);
+		total_param = WVAL(inbuf, smb_tprcnt);
+
+		if ((data_len >= total_data) && (param_len >= total_param))
+		{
+			break;
+		}
+		if ((result = smb_receive(server)) < 0)
+		{
+			goto fail;
+		}
+		if (server->rcls != 0)
+		{
+			result = -EIO;
+			goto fail;
+		}
+	}
+	*ldata = data_len;
+	*lparam = param_len;
+
+	smb_vfree(server->packet);
+	server->packet = rcv_buf;
+	server->packet_size = buf_len;
+	return 0;
 
-        if (server == NULL)
-                return NULL;
-        if ((file = server->sock_file) == NULL)
-                return NULL;
-        if ((inode = file->f_inode) == NULL)
-                return NULL;
-        return &(inode->u.socket_i);
+      fail:
+	smb_vfree(rcv_buf);
+	return result;
 }
 
 int
 smb_release(struct smb_server *server)
 {
-        struct socket *sock = server_sock(server);
-        int result;
+	struct socket *sock = server_sock(server);
+	int result;
 
-        if (sock == NULL)
-                return -EINVAL;
+	if (sock == NULL)
+	{
+		return -EINVAL;
+	}
+	result = sock->ops->release(sock, NULL);
+	DPRINTK("smb_release: sock->ops->release = %d\n", result);
 
-        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;
 
-        /* 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 = sock->ops->create(sock, 0);
-        DPRINTK("smb_release: sock->ops->create = %d\n", result);
-        return result;
+	result = sock->ops->create(sock, 0);
+	DPRINTK("smb_release: sock->ops->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);
-}
-        
-/*****************************************************************************/
-/*                                                                           */
-/*  This routine was once taken from nfs, which is for udp. Here TCP does     */
-/*  most of the ugly stuff for us (thanks, Alan!)                            */
-/*                                                                           */
-/*****************************************************************************/
-int
-smb_request(struct smb_server *server)
-{
-	unsigned long old_mask;
-	unsigned short fs;      /* We fool the kernel to believe
-                                   we call from user space. */
-	int len, result, result2;
-
 	struct socket *sock = server_sock(server);
-	unsigned char *buffer = (server == NULL) ? NULL : server->packet;
-
-	if ((sock == NULL) || (buffer == NULL)) {
-		printk("smb_request: Bad server!\n");
-		return -EBADF;
+	if (sock == NULL)
+	{
+		return -EINVAL;
 	}
-
-        if (server->state != CONN_VALID)
-                return -EIO;
-        	
-        if ((result = smb_dont_catch_keepalive(server)) != 0) {
-                server->state = CONN_INVALID;
-                smb_invalidate_all_inodes(server);
-                return result;
-        }
-
-        len = smb_len(buffer) + 4;
-
-        DDPRINTK("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]);
-
-	old_mask = current->blocked;
-	current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
-	fs = get_fs();
-	set_fs(get_ds());
-
-        result = _send(sock, (void *)buffer, len, 0, 0);
-        if (result < 0) {
-                printk("smb_request: send error = %d\n", result);
-        }
-        else {
-                result = smb_receive(server, sock);
-        }
-
-        /* read/write errors are handled by errno */
-        current->signal &= ~_S(SIGPIPE);
-
-	current->blocked = old_mask;
-	set_fs(fs);
-
-        if ((result2 = smb_catch_keepalive(server)) < 0) {
-                result = result2;
-        }
-
-        if (result < 0) {
-                server->state = CONN_INVALID;
-                smb_invalidate_all_inodes(server);
-        }
-        
-        DDPRINTK("smb_request: result = %d\n", result);
-
-	return result;
+	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);
 }
 
-/*
- * This is not really a trans2 request, we assume that you only have
- * one packet to send.
- */ 
 int
-smb_trans2_request(struct smb_server *server,
-                   int *data_len, int *param_len,
-                   char **data, char **param)
+smb_request(struct smb_server *server)
 {
 	unsigned long old_mask;
-	unsigned short fs;      /* We fool the kernel to believe
-                                   we call from user space. */
-	int len, result, result2;
+	unsigned short fs;
+	int len, result;
 
-	struct socket *sock = server_sock(server);
 	unsigned char *buffer = (server == NULL) ? NULL : server->packet;
 
-	if ((sock == NULL) || (buffer == NULL)) {
-		printk("smb_trans2_request: Bad server!\n");
+	if (buffer == NULL)
+	{
+		printk("smb_request: Bad server!\n");
 		return -EBADF;
 	}
+	if (server->state != CONN_VALID)
+	{
+		return -EIO;
+	}
+	if ((result = smb_dont_catch_keepalive(server)) != 0)
+	{
+		server->state = CONN_INVALID;
+		smb_invalidate_all_inodes(server);
+		return result;
+	}
+	len = smb_len(buffer) + 4;
 
-        if (server->state != CONN_VALID)
-                return -EIO;
-        	
-        if ((result = smb_dont_catch_keepalive(server)) != 0) {
-                server->state = CONN_INVALID;
-                smb_invalidate_all_inodes(server);
-                return result;
-        }
-
-        len = smb_len(buffer) + 4;
+	DDPRINTK("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]);
 
 	old_mask = current->blocked;
 	current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
 	fs = get_fs();
 	set_fs(get_ds());
 
-        DDPRINTK("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]);
-
-        result = _send(sock, (void *)buffer, len, 0, 0);
-        if (result < 0) {
-                printk("smb_trans2_request: send error = %d\n", result);
-        }
-        else {
-                result = smb_receive_trans2(server, sock,
-                                            data_len, param_len,
-                                            data, param);
-        }
-
-        /* read/write errors are handled by errno */
-        current->signal &= ~_S(SIGPIPE);
-
+	result = smb_send_raw(server_sock(server), (void *) buffer, len);
+	if (result > 0)
+	{
+		result = smb_receive(server);
+	}
+	/* read/write errors are handled by errno */
+	current->signal &= ~_S(SIGPIPE);
 	current->blocked = old_mask;
 	set_fs(fs);
 
-        if ((result2 = smb_catch_keepalive(server)) < 0) {
-                result = result2;
-        }
-
-        if (result < 0) {
-                server->state = CONN_INVALID;
-                smb_invalidate_all_inodes(server);
-        }
-        
-        DDPRINTK("smb_trans2_request: result = %d\n", result);
+	if (result >= 0)
+	{
+		int result2 = smb_catch_keepalive(server);
+		if (result2 < 0)
+		{
+			result = result2;
+		}
+	}
+	if (result < 0)
+	{
+		server->state = CONN_INVALID;
+		smb_invalidate_all_inodes(server);
+	}
+	DDPRINTK("smb_request: result = %d\n", result);
 
 	return result;
 }
 
-/* target must be in user space */
-int
-smb_request_read_raw(struct smb_server *server,
-                     unsigned char *target, int max_len)
+#define ROUND_UP(x) (((x)+3) & ~3)
+static int
+smb_send_trans2(struct smb_server *server, __u16 trans2_command,
+		int ldata, unsigned char *data,
+		int lparam, unsigned char *param)
 {
-	unsigned long old_mask;
-	int len, result, result2;
-	unsigned short fs;      /* We fool the kernel to believe
-                                   we call from user space. */
-
 	struct socket *sock = server_sock(server);
-	unsigned char *buffer = (server == NULL) ? NULL : server->packet;
 
-	if ((sock == NULL) || (buffer == NULL)) {
-		printk("smb_request_read_raw: Bad server!\n");
-		return -EBADF;
-	}
+	/* I know the following is very ugly, but I want to build the
+	   smb packet as efficiently as possible. */
 
-        if (server->state != CONN_VALID)
-                return -EIO;
-        	
-        if ((result = smb_dont_catch_keepalive(server)) != 0) {
-                server->state = CONN_INVALID;
-                smb_invalidate_all_inodes(server);
-                return result;
-        }
+	const int smb_parameters = 15;
+	const int oparam =
+	ROUND_UP(SMB_HEADER_LEN + 2 * smb_parameters + 2 + 3);
+	const int odata =
+	ROUND_UP(oparam + lparam);
+	const int bcc =
+	odata + ldata - (SMB_HEADER_LEN + 2 * smb_parameters + 2);
+	const int packet_length =
+	SMB_HEADER_LEN + 2 * smb_parameters + bcc + 2;
+
+	unsigned char padding[4] =
+	{0,};
+	char *p;
 
-        len = smb_len(buffer) + 4;
+	struct iovec iov[4];
+	struct msghdr msg;
 
-	old_mask = current->blocked;
-	current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
-	fs = get_fs();
-	set_fs(get_ds());
-
-        DPRINTK("smb_request_read_raw: len = %d cmd = 0x%X\n",
-                len, buffer[8]);
-        DPRINTK("smb_request_read_raw: target=%X, max_len=%d\n",
-                (unsigned int)target, max_len);
-        DPRINTK("smb_request_read_raw: buffer=%X, sock=%X\n",
-                (unsigned int)buffer, (unsigned int)sock);
-
-        result = _send(sock, (void *)buffer, len, 0, 0);
-
-        DPRINTK("smb_request_read_raw: send returned %d\n", result);
-
-	set_fs(fs);             /* We recv into user space */
-
-        if (result < 0) {
-                printk("smb_request_read_raw: send error = %d\n", result);
-        }
-        else {
-                result = smb_receive_raw(sock, target, max_len, 0);
-        }
-
-        /* read/write errors are handled by errno */
-        current->signal &= ~_S(SIGPIPE);
-	current->blocked = old_mask;
+	if ((bcc + oparam) > server->max_xmit)
+	{
+		return -ENOMEM;
+	}
+	p = smb_setup_header(server, SMBtrans2, smb_parameters, bcc);
 
-        if ((result2 = smb_catch_keepalive(server)) < 0) {
-                result = result2;
-        }
-
-        if (result < 0) {
-                server->state = CONN_INVALID;
-                smb_invalidate_all_inodes(server);
-        }
-        
-        DPRINTK("smb_request_read_raw: result = %d\n", result);
+	WSET(server->packet, smb_tpscnt, lparam);
+	WSET(server->packet, smb_tdscnt, ldata);
+	WSET(server->packet, smb_mprcnt, TRANS2_MAX_TRANSFER);
+	WSET(server->packet, smb_mdrcnt, TRANS2_MAX_TRANSFER);
+	WSET(server->packet, smb_msrcnt, 0);
+	WSET(server->packet, smb_flags, 0);
+	DSET(server->packet, smb_timeout, 0);
+	WSET(server->packet, smb_pscnt, lparam);
+	WSET(server->packet, smb_psoff, oparam - 4);
+	WSET(server->packet, smb_dscnt, ldata);
+	WSET(server->packet, smb_dsoff, odata - 4);
+	WSET(server->packet, smb_suwcnt, 1);
+	WSET(server->packet, smb_setup0, trans2_command);
+	*p++ = 0;		/* null smb_name for trans2 */
+	*p++ = 'D';		/* this was added because OS/2 does it */
+	*p++ = ' ';
+
+	iov[0].iov_base = (void *) server->packet;
+	iov[0].iov_len = oparam;
+	iov[1].iov_base = (param == NULL) ? padding : param;
+	iov[1].iov_len = lparam;
+	iov[2].iov_base = padding;
+	iov[2].iov_len = odata - oparam - lparam;
+	iov[3].iov_base = (data == NULL) ? padding : data;
+	iov[3].iov_len = ldata;
+
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+	msg.msg_control = NULL;
+	msg.msg_iov = iov;
+	msg.msg_iovlen = 4;
 
-	return result;
+	return sock->ops->sendmsg(sock, &msg, packet_length, 0, 0);
 }
 
-/* Source must be in user space. smb_request_write_raw assumes that
- * the request SMBwriteBraw has been completed successfully, so that
- * we can send the raw data now.  */
+/*
+ * This is not really a trans2 request, we assume that you only have
+ * one packet to send.
+ */
 int
-smb_request_write_raw(struct smb_server *server,
-                      unsigned const char *source, int length)
+smb_trans2_request(struct smb_server *server, __u16 trans2_command,
+		   int ldata, unsigned char *data,
+		   int lparam, unsigned char *param,
+		   int *lrdata, unsigned char **rdata,
+		   int *lrparam, unsigned char **rparam)
 {
 	unsigned long old_mask;
-	int result, result2;
-	unsigned short fs;      /* We fool the kernel to believe
-                                   we call from user space. */
-        byte nb_header[4];
+	unsigned short fs;
+	int result;
 
-	struct socket *sock = server_sock(server);
-	unsigned char *buffer = (server == NULL) ? NULL : server->packet;
+	DDPRINTK("smb_trans2_request: com=%d, ld=%d, lp=%d\n",
+		 trans2_command, ldata, lparam);
 
-	if ((sock == NULL) || (buffer == NULL)) {
-                printk("smb_request_write_raw: Bad server!\n");
-		return -EBADF;
+	if (server->state != CONN_VALID)
+	{
+		return -EIO;
+	}
+	if ((result = smb_dont_catch_keepalive(server)) != 0)
+	{
+		server->state = CONN_INVALID;
+		smb_invalidate_all_inodes(server);
+		return result;
 	}
-
-        if (server->state != CONN_VALID)
-                return -EIO;
-        	
-        if ((result = smb_dont_catch_keepalive(server)) != 0) {
-                server->state = CONN_INVALID;
-                smb_invalidate_all_inodes(server);
-                return result;
-        }
-
 	old_mask = current->blocked;
 	current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
 	fs = get_fs();
 	set_fs(get_ds());
 
-        smb_encode_smb_length(nb_header, length);
-
-        result = _send(sock, (void *)nb_header, 4, 0, 0);
-
-        if (result == 4) {
-                set_fs(fs);     /* source is in user-land */
-                result = _send(sock, (void *)source, length, 0, 0);
-                set_fs(get_ds());
-        } else {
-                result = -EIO;
-        }
-
-        DPRINTK("smb_request_write_raw: send returned %d\n", result);
-
-        if (result == length) {
-                result = smb_receive(server, sock);
-        } else {
-                result = -EIO;
-        }
-
-        /* read/write errors are handled by errno */
-        current->signal &= ~_S(SIGPIPE);
+	result = smb_send_trans2(server, trans2_command,
+				 ldata, data, lparam, param);
+	if (result >= 0)
+	{
+		result = smb_receive_trans2(server,
+					    lrdata, rdata, lrparam, rparam);
+	}
+	/* read/write errors are handled by errno */
+	current->signal &= ~_S(SIGPIPE);
 	current->blocked = old_mask;
 	set_fs(fs);
 
-        if ((result2 = smb_catch_keepalive(server)) < 0) {
-                result = result2;
-        }
-
-        if (result < 0) {
-                server->state = CONN_INVALID;
-                smb_invalidate_all_inodes(server);
-        }
-
-        if (result > 0) {
-                result = length;
-        }
-        
-        DPRINTK("smb_request_write_raw: result = %d\n", result);
+	if (result >= 0)
+	{
+		int result2 = smb_catch_keepalive(server);
+		if (result2 < 0)
+		{
+			result = result2;
+		}
+	}
+	if (result < 0)
+	{
+		server->state = CONN_INVALID;
+		smb_invalidate_all_inodes(server);
+	}
+	DDPRINTK("smb_trans2_request: result = %d\n", result);
 
 	return result;
 }
diff -u --recursive --new-file v2.0.26/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.0.26/linux/include/linux/mm.h	Wed Sep 11 17:57:18 1996
+++ linux/include/linux/mm.h	Sun Dec  1 19:59:18 1996
@@ -319,10 +319,12 @@
 	unsigned long grow;
 
 	address &= PAGE_MASK;
+	grow = vma->vm_start - address;
 	if (vma->vm_end - address
-	    > (unsigned long) current->rlim[RLIMIT_STACK].rlim_cur)
+	    > (unsigned long) current->rlim[RLIMIT_STACK].rlim_cur ||
+	    (vma->vm_mm->total_vm << PAGE_SHIFT) + grow
+	    > (unsigned long) current->rlim[RLIMIT_AS].rlim_cur)
 		return -ENOMEM;
-	grow = vma->vm_start - address;
 	vma->vm_start = address;
 	vma->vm_offset -= grow;
 	vma->vm_mm->total_vm += grow >> PAGE_SHIFT;
diff -u --recursive --new-file v2.0.26/linux/include/linux/smb.h linux/include/linux/smb.h
--- v2.0.26/linux/include/linux/smb.h	Wed Jun  5 13:22:48 1996
+++ linux/include/linux/smb.h	Sun Dec  1 15:58:06 1996
@@ -28,26 +28,53 @@
 typedef unsigned long dword;
 #endif
 
-/*
- * Set/Get values in SMB-byte order
- */
-#define ARCH i386
-#if (ARCH == i386)
-#define BVAL(p,off)      (*((byte  *)(((void *)p)+off)))
-#define WVAL(p,off)      (*((word  *)(((void *)p)+off)))
-#define DVAL(p,off)      (*((dword *)(((void *)p)+off)))
-#define BSET(p,off,new)  (*((byte  *)(((void *)p)+off))=(new))
-#define WSET(p,off,new)  (*((word  *)(((void *)p)+off))=(new))
-#define DSET(p,off,new)  (*((dword *)(((void *)p)+off))=(new))
+/* The following macros have been taken directly from Samba. Thanks,
+   Andrew! */
 
-/* where to find the base of the SMB packet proper */
-#define smb_base(buf) ((byte *)(((byte *)(buf))+4))
+#undef CAREFUL_ALIGNMENT
+
+/* 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
 
+#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
-#error "Currently only on 386, sorry"
+/* 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
 
 
+/* where to find the base of the SMB packet proper */
+#define smb_base(buf) ((byte *)(((byte *)(buf))+4))
+
 #define LANMAN1
 #define LANMAN2
 #define NT1
@@ -87,19 +114,28 @@
  * Contains all relevant data on a SMB networked file.
  */
 struct smb_dirent {
+
+	unsigned long	f_ino;
+	umode_t		f_mode;
+	nlink_t		f_nlink;
+	uid_t		f_uid;
+	gid_t		f_gid;
+	kdev_t		f_rdev;
+	off_t		f_size;
+	time_t		f_atime;
+	time_t		f_mtime;
+	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 */
 
-        time_t atime, mtime,    /* Times, as seen by the server, normalized */
-               ctime;           /* to UTC. The ugly conversion happens in */
-                                /* proc.c */
-
-	unsigned long   size;	/* File size. */
 	unsigned short  access;	/* Access bits. */
         unsigned long   f_pos;	/* File position. (For readdir.) */
-	char*           path;   /* Complete path, MS-DOS notation, with '\' */
-	int             len;	/* Namelength. */
+	unsigned char   name[SMB_MAXNAMELEN+1];
+	int             len;	/* namelength */
 };
 
 #endif  /* __KERNEL__ */
diff -u --recursive --new-file v2.0.26/linux/include/linux/smb_fs.h linux/include/linux/smb_fs.h
--- v2.0.26/linux/include/linux/smb_fs.h	Wed Sep 11 17:57:18 1996
+++ linux/include/linux/smb_fs.h	Sun Dec  1 20:04:43 1996
@@ -55,27 +55,45 @@
 #include <linux/malloc.h>
 
 extern int smb_malloced;
-extern int smb_current_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_malloced += 1;
+        smb_current_kmalloced += 1;
         return kmalloc(size, priority);
 }
 
 static inline void
 smb_kfree_s(void *obj, int size)
 {
-        smb_current_malloced -= 1;
+        smb_current_kmalloced -= 1;
         kfree_s(obj, size);
 }
 
+static inline void *
+smb_vmalloc(unsigned int size)
+{
+        smb_malloced += 1;
+        smb_current_vmalloced += 1;
+        return vmalloc(size);
+}
+
+static inline void
+smb_vfree(void *obj)
+{
+        smb_current_vmalloced -= 1;
+        vfree(obj);
+}
+
 #else /* DEBUG_SMB_MALLOC */
 
 #define smb_kmalloc(s,p) kmalloc(s,p)
 #define smb_kfree_s(o,s) kfree_s(o,s)
+#define smb_vmalloc(s)   vmalloc(s)
+#define smb_vfree(o)     vfree(o)
 
 #endif /* DEBUG_SMB_MALLOC */
 
@@ -92,12 +110,27 @@
 #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
+}
+
 /* 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);
 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);
@@ -122,8 +155,12 @@
 /* linux/fs/smbfs/proc.c */
 dword smb_len(unsigned char *packet);
 byte *smb_encode_smb_length(byte *p, dword len);
-int smb_proc_open(struct smb_server *server, const char *pathname,
-                  int len, struct smb_dirent *entry);
+__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, 
@@ -134,19 +171,18 @@
 		   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 smb_server *server, const char *path,
-                    int len, struct smb_dirent *entry);
-int smb_proc_mv(struct smb_server *server, const char *opath, const int olen, 
-		const char *npath, const int nlen);
-int smb_proc_mkdir(struct smb_server *server, const char *path, const int len);
-int smb_proc_rmdir(struct smb_server *server, const char *path, const int len);
-int smb_proc_unlink(struct smb_server *server, const char *path,
-                    const int len);
+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,
                      int fpos, int cache_size, 
 		     struct smb_dirent *entry);
-int smb_proc_getattr(struct smb_server *server, const char *path,
-                     int len, 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,
                      struct inode *ino,
                      struct smb_dirent *new_finfo);
@@ -168,9 +204,11 @@
                           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,
-                       int *data_len, int *param_len,
-                       char **data, char **param);
+int smb_trans2_request(struct smb_server *server, __u16 trans2_command,
+		       int ldata, unsigned char *data,
+		       int lparam, unsigned char *param,
+		       int *lrdata, unsigned char **rdata,
+		       int *lrparam, unsigned char **rparam);
 
 /* linux/fs/smbfs/mmap.c */
 int smb_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma);
diff -u --recursive --new-file v2.0.26/linux/include/linux/smb_fs_sb.h linux/include/linux/smb_fs_sb.h
--- v2.0.26/linux/include/linux/smb_fs_sb.h	Thu Jul 18 14:59:02 1996
+++ linux/include/linux/smb_fs_sb.h	Sun Dec  1 20:04:43 1996
@@ -25,7 +25,7 @@
                                               protocols. */
 	struct wait_queue *wait;
 
-	word               max_xmit;
+	__u32              max_xmit;
 	char               hostname[256];
 	word               pid;
 	word               server_uid;
@@ -38,6 +38,8 @@
 
         unsigned short     rcls; /* The error codes we received */
         unsigned short     err;
+
+	__u32              packet_size;
 	unsigned char *    packet;
 
         enum smb_conn_state state;
@@ -46,7 +48,6 @@
         /* The following are LANMAN 1.0 options transferred to us in
            SMBnegprot */
         word   secmode;
-        word   maxxmt;
         word   maxmux;
         word   maxvcs;
         word   blkmode;
diff -u --recursive --new-file v2.0.26/linux/include/linux/smb_mount.h linux/include/linux/smb_mount.h
--- v2.0.26/linux/include/linux/smb_mount.h	Thu Jul 18 14:59:02 1996
+++ linux/include/linux/smb_mount.h	Sun Dec  1 20:04:42 1996
@@ -1,7 +1,7 @@
 /*
  *  smb_mount.h
  *
- *  Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
  *
  */
 
@@ -11,7 +11,7 @@
 #include <linux/types.h>
 #include <linux/in.h>
 
-#define SMB_MOUNT_VERSION 4
+#define SMB_MOUNT_VERSION 5
 
 struct smb_mount_data {
 	int version;
@@ -26,6 +26,7 @@
 
         char username[64];
 	char password[64];
+	char domain[64];
 
 	unsigned short max_xmit;
 
diff -u --recursive --new-file v2.0.26/linux/init/main.c linux/init/main.c
--- v2.0.26/linux/init/main.c	Thu Oct 31 12:08:55 1996
+++ linux/init/main.c	Sat Nov 23 15:28:23 1996
@@ -91,6 +91,8 @@
 extern void aic7xxx_setup(char *str, int *ints);
 extern void AM53C974_setup(char *str, int *ints);
 extern void BusLogic_Setup(char *str, int *ints);
+extern void eata2x_setup(char *str, int *ints);
+extern void u14_34f_setup(char *str, int *ints);
 extern void fdomain_setup(char *str, int *ints);
 extern void in2000_setup(char *str, int *ints);
 extern void NCR53c406a_setup(char *str, int *ints);
@@ -320,6 +322,12 @@
 #endif
 #ifdef CONFIG_SCSI_BUSLOGIC
 	{ "BusLogic=", BusLogic_Setup},
+#endif
+#ifdef CONFIG_SCSI_EATA
+	{ "eata=", eata2x_setup},
+#endif
+#ifdef CONFIG_SCSI_U14_34F
+	{ "u14-34f=", u14_34f_setup},
 #endif
 #ifdef CONFIG_SCSI_AM53C974
         { "AM53C974=", AM53C974_setup},
diff -u --recursive --new-file v2.0.26/linux/ipc/shm.c linux/ipc/shm.c
--- v2.0.26/linux/ipc/shm.c	Wed Sep 11 17:57:18 1996
+++ linux/ipc/shm.c	Fri Nov 22 16:25:18 1996
@@ -424,7 +424,11 @@
 	do_munmap(shmd->vm_start, shmd->vm_end - shmd->vm_start);
 
 	/* add new mapping */
-	current->mm->total_vm += (shmd->vm_end - shmd->vm_start) >> PAGE_SHIFT;
+	tmp = shmd->vm_end - shmd->vm_start;
+	if((current->mm->total_vm << PAGE_SHIFT) + tmp
+	   > (unsigned long) current->rlim[RLIMIT_AS].rlim_cur)
+		return -ENOMEM;
+	current->mm->total_vm += tmp >> PAGE_SHIFT;
 	insert_vm_struct(current->mm, shmd);
 	merge_segments(current->mm, shmd->vm_start, shmd->vm_end);
 
diff -u --recursive --new-file v2.0.26/linux/mm/mmap.c linux/mm/mmap.c
--- v2.0.26/linux/mm/mmap.c	Wed Sep 11 17:57:19 1996
+++ linux/mm/mmap.c	Fri Nov 22 16:25:17 1996
@@ -107,11 +107,11 @@
 	/*
 	 * Ok, looks good - let it rip.
 	 */
-	mm->brk = brk;
-	do_mmap(NULL, oldbrk, newbrk-oldbrk,
+	if(do_mmap(NULL, oldbrk, newbrk-oldbrk,
 		PROT_READ|PROT_WRITE|PROT_EXEC,
-		MAP_FIXED|MAP_PRIVATE, 0);
-	return brk;
+		   MAP_FIXED|MAP_PRIVATE, 0) != oldbrk)
+		return mm->brk;
+	return mm->brk = brk;
 }
 
 /*
@@ -252,6 +252,13 @@
 	vma->vm_pte = 0;
 
 	do_munmap(addr, len);	/* Clear old maps */
+
+	/* Check against address space limit. */
+	if ((mm->total_vm << PAGE_SHIFT) + len
+	    > current->rlim[RLIMIT_AS].rlim_cur) {
+		kfree(vma);
+		return -ENOMEM;
+	}
 
 	/* Private writable mapping? Check memory availability.. */
 	if ((vma->vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE) {
diff -u --recursive --new-file v2.0.26/linux/mm/mremap.c linux/mm/mremap.c
--- v2.0.26/linux/mm/mremap.c	Wed Sep 11 17:57:19 1996
+++ linux/mm/mremap.c	Fri Nov 22 16:25:17 1996
@@ -146,6 +146,7 @@
 			insert_vm_struct(current->mm, new_vma);
 			merge_segments(current->mm, new_vma->vm_start, new_vma->vm_end);
 			do_munmap(addr, old_len);
+			current->mm->total_vm += new_len >> PAGE_SHIFT;
 			return new_addr;
 		}
 		kfree(new_vma);
@@ -192,6 +193,9 @@
 		if (locked > current->rlim[RLIMIT_MEMLOCK].rlim_cur)
 			return -EAGAIN;
 	}
+	if ((current->mm->total_vm << PAGE_SHIFT) + (new_len - old_len)
+	    > current->rlim[RLIMIT_AS].rlim_cur)
+		return -ENOMEM;
 
 	/* old_len exactly to the end of the area.. */
 	if (old_len == vma->vm_end - addr &&
diff -u --recursive --new-file v2.0.26/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.0.26/linux/net/ipv4/tcp.c	Fri Nov 22 16:26:08 1996
+++ linux/net/ipv4/tcp.c	Wed Nov 27 09:44:11 1996
@@ -515,7 +515,7 @@
 #endif
 	th =(struct tcphdr *)header;
 	
-	if(len<sizeof(struct tcphdr))
+	if (len < 8)	/* NOT sizeof(struct tcphdr) */
 		return;
 		
 	sk = get_sock(&tcp_prot, th->source, daddr, th->dest, saddr, 0, 0);
diff -u --recursive --new-file v2.0.26/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.0.26/linux/net/ipv4/tcp_input.c	Fri Nov 22 16:26:09 1996
+++ linux/net/ipv4/tcp_input.c	Sat Nov 30 12:51:03 1996
@@ -501,6 +501,7 @@
 	newsk->retransmit_timer.function = tcp_retransmit_timer;
 	newsk->dummy_th.source = skb->h.th->dest;
 	newsk->dummy_th.dest = skb->h.th->source;
+	newsk->users=0;
 	
 #ifdef CONFIG_IP_TRANSPARENT_PROXY
 	/* 
diff -u --recursive --new-file v2.0.26/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- v2.0.26/linux/net/ipx/af_ipx.c	Fri Jul 19 08:24:05 1996
+++ linux/net/ipx/af_ipx.c	Wed Nov 27 09:44:21 1996
@@ -784,8 +784,7 @@
 		}
 #endif		
 		/* We only route point-to-point packets. */
-		if ((skb->pkt_type != PACKET_BROADCAST) &&
-			(skb->pkt_type != PACKET_MULTICAST))
+		if (skb->pkt_type == PACKET_HOST)
 			return ipxrtr_route_skb(skb);
 		
 		kfree_skb(skb,FREE_READ);
