diff -u --recursive --new-file v2.1.102/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.102/linux/Documentation/Configure.help	Thu May 14 19:47:37 1998
+++ linux/Documentation/Configure.help	Thu May 14 19:11:48 1998
@@ -626,6 +626,17 @@
   The module will be called epia.o.  You must also have a high-level 
   driver for the type of device that you want to support.
 
+FIT TD-2000 protocol
+CONFIG_PARIDE_FIT2
+  This option enables support for the TD-2000 parallel port IDE protocol
+  from Fidelity International Technology.  This is a simple (low speed) 
+  adapter that is used in some portable hard drives.  If you chose to 
+  build PARIDE support into your kernel, you may answer Y here to 
+  build in the protocol driver, otherwise you should answer M to 
+  build it as a loadable module.  The module will be called ktti.o.  
+  You must also have a high-level driver for the type of device 
+  that you want to support.
+
 FreeCom power protocol
 CONFIG_PARIDE_FRPW 
   This option enables support for the Freecom power parallel port IDE 
@@ -645,6 +656,17 @@
   answer M to build it as a loadable module.  The module will be called 
   kbic.o.  You must also have a high-level driver for the type of device 
   that you want to support.
+
+KT PHd protocol
+CONFIG_PARIDE_KTTI
+  This option enables support for the "PHd" parallel port IDE protocol
+  from KT Technology.  This is a simple (low speed) adapter that is
+  used in some 2.5" portable hard drives.  If you chose to build PARIDE 
+  support into your kernel, you may answer Y here to build in the 
+  protocol driver, otherwise you should answer M to build it as a 
+  loadable module.  The module will be called ktti.o.  You must also 
+  have a high-level driver for the type of device that you want to
+  support.
 
 OnSpec 90c20 protocol
 CONFIG_PARIDE_ON20 
diff -u --recursive --new-file v2.1.102/linux/Documentation/paride.txt linux/Documentation/paride.txt
--- v2.1.102/linux/Documentation/paride.txt	Sat May  2 14:19:51 1998
+++ linux/Documentation/paride.txt	Thu May 14 19:11:48 1998
@@ -1,7 +1,7 @@
 
 		Linux and parallel port IDE devices
 
-PARIDE v1.0   (c) 1997  Grant Guenther <grant@torque.net>
+PARIDE v1.02   (c) 1997-8  Grant Guenther <grant@torque.net>
 
 1. Introduction
 
@@ -38,6 +38,7 @@
 	MicroSolutions backpack CD-ROM
 	MicroSolutions backpack PD/CD
 	MicroSolutions backpack hard-drives
+	MicroSolutions backpack 8000t tape drive
 	SyQuest EZ-135, EZ-230 & SparQ drives
 	Avatar Shark
 	Imation Superdisk LS-120
@@ -57,8 +58,7 @@
 	pf	ATAPI disk
 	pt	ATAPI tape
 
-(Support for ATAPI CD-R and CD-RW drives is not yet in development,
-but this may change.)
+(Support for ATAPI CD-R and CD-RW drives is in the design phase.)
 
 The high-level drivers function according to the relevant standards.
 The third component of PARIDE is a set of low-level protocol drivers
@@ -72,14 +72,13 @@
         dstr    DataStor EP-2000                       (TW)
         epat    Shuttle EPAT                           (UK)
         epia    Shuttle EPIA                           (UK)
+	fit2    FIT TD-2000
         frpw    Freecom Power                          (DE)
         kbic    KingByte KBIC-951A and KBIC-971A       (TW)
+	ktti    KT Technology PHd adapter              (SG)
         on20    OnSpec 90c20                           (US)
         on26    OnSpec 90c26                           (US)
 
-(A driver for some modes of the Noveca RAP// protocol is also under 
-development).	
-
 
 2. Using the PARIDE subsystem
 
@@ -106,6 +105,7 @@
 	MicroSolutions		CD-ROM		pcd	bpck
 	MicroSolutions		PD drive	pf	bpck
 	MicroSolutions		hard-drive	pd	bpck
+	MicroSolutions          8000t tape      pt      bpck
 	SyQuest			EZ, SparQ	pd	epat
 	Imation			Superdisk	pf	epat
 	Avatar			Shark		pd	epat
diff -u --recursive --new-file v2.1.102/linux/Documentation/sysrq.txt linux/Documentation/sysrq.txt
--- v2.1.102/linux/Documentation/sysrq.txt	Mon Apr  6 17:40:59 1998
+++ linux/Documentation/sysrq.txt	Tue May 19 15:05:13 1998
@@ -1,23 +1,30 @@
-                      MAGIC SYSRQ KEY DOCUMENTATION v1.0
+                      MAGIC SYSRQ KEY DOCUMENTATION v1.2
                      ------------------------------------
-                        [Fri Apr  3 08:27:12 EST 1998]
+                        [Sat May 16 01:09:21 EDT 1998]
 
-1. What is the magic SysRQ key?
+*  What is the magic SysRQ key?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-It is a 'magical' key combo you can hit, and the kernel will respond to
-regardless of anything else, unless it is hard-locked.
+It is a 'magical' key combo you can hit which kernel will respond to
+regardless of whatever else it is doing, unless it is completely locked up.
 
-2. How do I enable the magic SysRQ key?
+*  How do I enable the magic SysRQ key?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 You need to say yes to 'Magic SysRq key (CONFIG_MAGIC_SYSRQ)' when
 configuring the kernel. This option is only available it 2.1.x or later
 kernels.
 
-3. How do I use the magic SysRQ key?
+*  How do I use the magic SysRQ key?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-You press the key combo 'ALT-SysRQ-<command key>'.
+On x86   - You press the key combo 'ALT-SysRQ-<command key>'. Note - Some
+           (older?) may not have a key labeled 'SysRQ'. The 'SysRQ' key is
+           also known as the 'Print Screen' key.
 
-4. What are the 'command' keys?
+On SPARC - You press 'ALT-STOP-<command key>', I believe.
+
+On other - If you know of the key combos for other architectures, please
+           let me know so I can add them to this section. 
+
+*  What are the 'command' keys?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 'r'     - Turns off keyboard raw mode and sets it to XLATE.
 
@@ -51,7 +58,7 @@
 'l'     - Send a SIGKILL to all processes, INCLUDING init. (Your system
           will be non-functional after this.)
 
-5. Okay, so what can I use them for?
+*  Okay, so what can I use them for?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Well, un'R'aw is very handy when your X server or a svgalib program crashes.
 
@@ -76,14 +83,25 @@
 are unable to kill any other way, especially if it's spawning other
 processes.
 
-6. Sometimes SysRQ seems to get 'stuck' after using it, what can I do?
+*  Sometimes SysRQ seems to get 'stuck' after using it, what can I do?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 That happens to me, also. I've found that tapping shift, alt, and control
 on both sides of the keyboard, and hitting an invalid sysrq sequence again
 will fix the problem. (ie, something like alt-sysrq-z).
 
-7. I have more questions, who can I ask?
+*  I hit SysRQ, but nothing seems to happen, what's wrong?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+There are some keyboards which do not support 'SysRQ', you can try running
+'showkey -s' and pressing SysRQ or alt-SysRQ to see if it generates any
+0x54 codes. If it doesn't, you may define the magic sysrq sequence to a
+different key. Find the keycode with showkey, and change the define of
+'#define SYSRQ_KEY 0x54' in [/usr/src/linux/]include/asm/keyboard.h to
+the keycode of the key you wish to use, then recompile. Oh, and by the way,
+you exit 'showkey' by not typing anything for ten seconds.
+
+*  I have more questions, who can I ask?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 You may feel free to send email to myrdraal@deathsdoor.com, and I will
-respond as soon as possible.
+respond as soon as possible. If that email address does not work, use
+myrdraal@jackalz.dyn.ml.org.
  -Myrdraal
diff -u --recursive --new-file v2.1.102/linux/MAINTAINERS linux/MAINTAINERS
--- v2.1.102/linux/MAINTAINERS	Thu May 14 19:47:37 1998
+++ linux/MAINTAINERS	Tue May 19 15:06:49 1998
@@ -581,6 +581,12 @@
 L:	linux-scsi@vger.rutgers.edu
 S:	Maintained
 
+UMSDOS FILESYSTEM
+P:	Matija Nalis
+M:	mnalis@jagor.srce.hr
+L:	linux-kernel@vger.rutgers.edu
+S:	Maintained
+
 UNIFORM CDROM DRIVER 
 P:	Erik Andersen
 M:	andersee@debian.org
diff -u --recursive --new-file v2.1.102/linux/Makefile linux/Makefile
--- v2.1.102/linux/Makefile	Thu May 14 19:47:37 1998
+++ linux/Makefile	Thu May 14 16:33:58 1998
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 102
+SUBLEVEL = 103
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
 
diff -u --recursive --new-file v2.1.102/linux/arch/arm/kernel/entry-armo.S linux/arch/arm/kernel/entry-armo.S
--- v2.1.102/linux/arch/arm/kernel/entry-armo.S	Fri May  8 23:14:42 1998
+++ linux/arch/arm/kernel/entry-armo.S	Thu May 14 19:01:21 1998
@@ -21,7 +21,6 @@
  * Ok, so this file may be a mess, but its as efficient as possible while
  * adhering to the above criteria.
  */
-#include <linux/autoconf.h>
 #include <linux/linkage.h>
 
 #include <asm/assembler.h>
diff -u --recursive --new-file v2.1.102/linux/arch/arm/kernel/entry-armv.S linux/arch/arm/kernel/entry-armv.S
--- v2.1.102/linux/arch/arm/kernel/entry-armv.S	Fri May  8 23:14:42 1998
+++ linux/arch/arm/kernel/entry-armv.S	Thu May 14 19:01:21 1998
@@ -10,7 +10,6 @@
  * it to save wrong values...  Be aware!
  */
 #include <linux/config.h> /* for CONFIG_ARCH_EBSA110 */
-#include <linux/autoconf.h>
 #include <linux/linkage.h>
 
 #include <asm/assembler.h>
diff -u --recursive --new-file v2.1.102/linux/arch/arm/lib/io-acorn.S linux/arch/arm/lib/io-acorn.S
--- v2.1.102/linux/arch/arm/lib/io-acorn.S	Fri May  8 23:14:42 1998
+++ linux/arch/arm/lib/io-acorn.S	Thu May 14 19:01:21 1998
@@ -4,7 +4,6 @@
  * Copyright (C) 1995, 1996 Russell King
  */
 #include <linux/config.h> /* for CONFIG_CPU_nn */
-#include <linux/autoconf.h>
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/hardware.h>
diff -u --recursive --new-file v2.1.102/linux/arch/arm/lib/uaccess.S linux/arch/arm/lib/uaccess.S
--- v2.1.102/linux/arch/arm/lib/uaccess.S	Tue Apr 14 14:29:20 1998
+++ linux/arch/arm/lib/uaccess.S	Thu May 14 19:01:21 1998
@@ -7,7 +7,6 @@
  *  These are highly optimised both for the 4k page size
  *  and for various alignments.
  */
-#include <linux/autoconf.h>
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/errno.h>
diff -u --recursive --new-file v2.1.102/linux/arch/i386/boot/tools/build.c linux/arch/i386/boot/tools/build.c
--- v2.1.102/linux/arch/i386/boot/tools/build.c	Mon Feb 23 18:12:02 1998
+++ linux/arch/i386/boot/tools/build.c	Thu May 14 18:55:33 1998
@@ -62,7 +62,7 @@
 
 #define MINIX_HEADER_LEN 32
 
-int minix_open(const char *name)
+void minix_open(const char *name)
 {
 	static byte hdr[] = { 0x01, 0x03, 0x10, 0x04, 0x20, 0x00, 0x00, 0x00 };
 	static u32 *lb = (u32 *) buf;
diff -u --recursive --new-file v2.1.102/linux/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c
--- v2.1.102/linux/arch/i386/kernel/bios32.c	Thu May  7 22:51:46 1998
+++ linux/arch/i386/kernel/bios32.c	Thu May 14 18:58:55 1998
@@ -1,12 +1,7 @@
 /*
  * bios32.c - Low-Level PCI Access
  *
- * $Id: bios32.c,v 1.32 1998/05/02 12:03:05 davem Exp $
- *
- * Sponsored by
- *	iX Multiuser Multitasking Magazine
- *	Hannover, Germany
- *	hm@ix.de
+ * $Id: bios32.c,v 1.33 1998/05/12 07:30:11 mj Exp $
  *
  * Copyright 1993, 1994 Drew Eckhardt
  *      Visionary Computing
@@ -14,21 +9,20 @@
  *      Drew@Colorado.EDU
  *      +1 (303) 786-7975
  *
- * For more information, please consult
+ * Drew's work was sponsored by:
+ *	iX Multiuser Multitasking Magazine
+ *	Hannover, Germany
+ *	hm@ix.de
  *
- * PCI BIOS Specification Revision
- * PCI Local Bus Specification
- * PCI System Design Guide
+ * Copyright 1997, 1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
  *
- * PCI Special Interest Group
- * M/S HF3-15A
- * 5200 N.E. Elam Young Parkway
- * Hillsboro, Oregon 97124-6497
- * +1 (503) 696-2000
- * +1 (800) 433-5177
+ * For more information, please consult the following manuals (look at
+ * http://www.pcisig.com/ for how to get them):
  *
- * Manuals are $25 each or $50 for all three, plus $7 shipping
- * within the United States, $35 abroad.
+ * PCI BIOS Specification
+ * PCI Local Bus Specification
+ * PCI to PCI Bridge Specification
+ * PCI System Design Guide
  *
  *
  * CHANGELOG :
@@ -458,6 +452,12 @@
 /* PCI service signature: "$PCI" */
 #define PCI_SERVICE		(('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24))
 
+/* PCI BIOS hardware mechanism flags */
+#define PCIBIOS_HW_TYPE1		0x01
+#define PCIBIOS_HW_TYPE2		0x02
+#define PCIBIOS_HW_TYPE1_SPEC		0x10
+#define PCIBIOS_HW_TYPE2_SPEC		0x20
+
 /*
  * This is the standard structure used to identify the entry point
  * to the BIOS32 Service Directory, as documented in
@@ -487,7 +487,6 @@
  * the array there.
  */
 
-static unsigned long bios32_entry = 0;
 static struct {
 	unsigned long address;
 	unsigned short segment;
@@ -529,7 +528,6 @@
 	}
 }
 
-static long pcibios_entry = 0;
 static struct {
 	unsigned long address;
 	unsigned short segment;
@@ -537,49 +535,48 @@
 
 __initfunc(static int check_pcibios(void))
 {
-	unsigned long signature;
-	unsigned char present_status;
-	unsigned char major_revision;
-	unsigned char minor_revision;
-	unsigned long flags;
-	int pack;
+	u32 signature, eax, ebx, ecx;
+	u8 status, major_ver, minor_ver, hw_mech, last_bus;
+	unsigned long flags, pcibios_entry;
 
 	if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
-		pci_indirect.address = pcibios_entry | PAGE_OFFSET;
+		pci_indirect.address = pcibios_entry + PAGE_OFFSET;
 
 		save_flags(flags); cli();
 		__asm__("lcall (%%edi)\n\t"
 			"jc 1f\n\t"
 			"xor %%ah, %%ah\n"
-			"1:\tshl $8, %%eax\n\t"
-			"movw %%bx, %%ax"
+			"1:"
 			: "=d" (signature),
-			  "=a" (pack)
+			  "=a" (eax),
+			  "=b" (ebx),
+			  "=c" (ecx)
 			: "1" (PCIBIOS_PCI_BIOS_PRESENT),
 			  "D" (&pci_indirect)
-			: "bx", "cx");
+			: "memory");
 		restore_flags(flags);
 
-		present_status = (pack >> 16) & 0xff;
-		major_revision = (pack >> 8) & 0xff;
-		minor_revision = pack & 0xff;
-		if (present_status || (signature != PCI_SIGNATURE)) {
-			printk ("PCI: %s: BIOS32 Service Directory says PCI BIOS is present,\n"
-				"	but PCI_BIOS_PRESENT subfunction fails with present status of 0x%x\n"
-				"	and signature of 0x%08lx (%c%c%c%c).  Report to <mj@ucw.cz>.\n",
-				(signature == PCI_SIGNATURE) ?  "WARNING" : "ERROR",
-				present_status, signature,
-				(char) (signature >>  0), (char) (signature >>  8),
-				(char) (signature >> 16), (char) (signature >> 24));
-
-			if (signature != PCI_SIGNATURE)
-				pcibios_entry = 0;
-		}
-		if (pcibios_entry) {
-			printk ("PCI: PCI BIOS revision %x.%02x entry at 0x%lx\n",
-				major_revision, minor_revision, pcibios_entry);
-			return 1;
+		status = (eax >> 8) & 0xff;
+		hw_mech = eax & 0xff;
+		major_ver = (ebx >> 8) & 0xff;
+		minor_ver = ebx & 0xff;
+		last_bus = ecx & 0xff;
+		DBG("PCI: BIOS probe returned s=%02x hw=%02x ver=%02x.%02x l=%02x\n",
+			status, hw_mech, major_ver, minor_ver, last_bus);
+		if (status || signature != PCI_SIGNATURE) {
+			printk (KERN_ERR "PCI: BIOS BUG #%x[%08x] found, report to <mj@ucw.cz>\n",
+				status, signature);
+			return 0;
 		}
+		printk("PCI: PCI BIOS revision %x.%02x entry at 0x%lx\n",
+			major_ver, minor_ver, pcibios_entry);
+#ifdef CONFIG_PCI_DIRECT
+		if (!(hw_mech & PCIBIOS_HW_TYPE1))
+			pci_probe &= ~PCI_PROBE_CONF1;
+		if (!(hw_mech & PCIBIOS_HW_TYPE2))
+			pci_probe &= ~PCI_PROBE_CONF2;
+#endif
+		return 1;
 	}
 	return 0;
 }
@@ -822,7 +819,7 @@
 			printk("PCI: BIOS32 entry (0x%p) in high memory, cannot use.\n", check);
 			return NULL;
 		} else {
-			bios32_entry = check->fields.entry;
+			unsigned long bios32_entry = check->fields.entry;
 			DBG("PCI: BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
 			bios32_indirect.address = bios32_entry + PAGE_OFFSET;
 			if (check_pcibios())
@@ -898,6 +895,16 @@
 
 	if (!pci_last_io_addr) {
 		printk("PCI: Unassigned I/O space for %02x:%02x\n", bus, devfn);
+		return;
+	}
+	if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && idx < 4) {
+		/*
+		 * In case the BIOS didn't assign an address 0--3 to an IDE
+		 * controller, we don't try to fix it as it means "use default
+		 * addresses" at least with several broken chips and the IDE
+		 * driver needs the original settings to recognize which devices
+		 * correspond to the primary controller.
+		 */
 		return;
 	}
 	pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
diff -u --recursive --new-file v2.1.102/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
--- v2.1.102/linux/arch/i386/kernel/head.S	Wed Apr  8 19:36:24 1998
+++ linux/arch/i386/kernel/head.S	Wed May 20 16:24:43 1998
@@ -152,6 +152,23 @@
  * apply at our cpl of 0 and the stack ought to be aligned already, and
  * we don't need to preserve eflags.
  */
+
+/*
+ * Don't do this here. Do it in the CPU init code in C, right now we
+ * must _not_ play unsafe games with the IO ports.
+ *
+ * A PPro and a P-II will also preserve the flags after a division,
+ * so this "cyrix" test is just completely unsafe. IO port 0x22 is
+ * some magic ACPI port on non-cyrix chips, so if this trashes that
+ * we're screwed.
+ *
+ * This code belongs in "asm-i386/bugs.h" anyway (at which point we
+ * _have_ done a CPUID for CPU's that support it directly, so we'll
+ * be able to tell a intel P-II trivially at that point).
+ */
+#undef CYRIX_CODE_BREAKAGE
+#ifdef CYRIX_CODE_BREAKAGE
+
 	/*
 	 * A Cyrix preserves flags in cases where other CPUs change
 	 * them in undefined ways. We need to know this since we may
@@ -206,7 +223,11 @@
 
 	setCx86($0xc3,%cl)	# Restore old CCR3
 
-ncyrix:	movl $3,X86		# at least 386
+ncyrix:
+
+#endif
+
+	movl $3,X86		# at least 386
 	pushfl			# push EFLAGS
 	popl %eax		# get EFLAGS
 	movl %eax,%ecx		# save original EFLAGS
@@ -256,6 +277,8 @@
 	movl %edx,X86_CAPABILITY
 
 nocpuid:
+
+#ifdef CYRIX_CODE_BREAKAGE
 	/*
 	 * Even if we had CPUID Cyrix tries to look compatible with
 	 * Intel so we have to go elsewhere for the nitty gritty.
@@ -289,8 +312,10 @@
 	andb $0xfd,%al		# works well on 6x86(L) CPU's.
 	movb %al,%bl
 	setCx86($0xe9,%bl)
+#endif
 
-is486:	movl %cr0,%eax		# 486 or better
+is486:
+	movl %cr0,%eax		# 486 or better
 	andl $0x80000011,%eax	# Save PG,PE,ET
 	orl $0x50022,%eax	# set AM, WP, NE and MP
 	jmp 2f
diff -u --recursive --new-file v2.1.102/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c
--- v2.1.102/linux/arch/i386/kernel/io_apic.c	Thu May 14 19:47:38 1998
+++ linux/arch/i386/kernel/io_apic.c	Tue May 19 00:15:00 1998
@@ -156,6 +156,30 @@
 	}
 }
 
+void mask_IO_APIC_irq(unsigned int irq)
+{
+	int pin = irq_2_pin[irq];
+	struct IO_APIC_route_entry entry;
+
+	if (pin != -1) {
+		*(((int *)&entry)+0) = io_apic_read(0x10+pin*2);
+		entry.mask = 1;
+		io_apic_write(0x10+2*pin, *(((int *)&entry)+0));
+	}
+}
+
+void unmask_IO_APIC_irq(unsigned int irq)
+{
+	int pin = irq_2_pin[irq];
+	struct IO_APIC_route_entry entry;
+
+	if (pin != -1) {
+		*(((int *)&entry)+0) = io_apic_read(0x10+pin*2);
+		entry.mask = 0;
+		io_apic_write(0x10+2*pin, *(((int *)&entry)+0));
+	}
+}
+
 void clear_IO_APIC_pin (unsigned int pin)
 {
 	struct IO_APIC_route_entry entry;
diff -u --recursive --new-file v2.1.102/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- v2.1.102/linux/arch/i386/kernel/irq.c	Thu May 14 19:47:38 1998
+++ linux/arch/i386/kernel/irq.c	Wed May 20 12:11:55 1998
@@ -761,99 +761,111 @@
 	}
 }
 
+/*
+ * Edge triggered needs to resend any interrupt
+ * that was delayed.
+ */
 static void enable_edge_ioapic_irq(unsigned int irq)
 {
 	self_IPI(irq);
+	enable_IO_APIC_irq(irq);
 }
 
 static void disable_edge_ioapic_irq(unsigned int irq)
 {
+	disable_IO_APIC_irq(irq);
 }
 
+/*
+ * Level triggered interrupts can just be masked
+ */
 static void enable_level_ioapic_irq(unsigned int irq)
 {
-	enable_IO_APIC_irq(irq);
-	self_IPI(irq);
+	unmask_IO_APIC_irq(irq);
 }
 
 static void disable_level_ioapic_irq(unsigned int irq)
 {
-	disable_IO_APIC_irq(irq);
+	mask_IO_APIC_irq(irq);
 }
 
 /*
- * Has to be called with the irq controller locked, and has to exit
- * with with the lock held as well.
+ * Enter and exit the irq handler context..
  */
-static void handle_ioapic_event (unsigned int irq, int cpu,
-						struct pt_regs * regs)
+static inline void enter_ioapic_irq(int cpu)
 {
-	irq_desc_t *desc = irq_desc + irq;
-
-	desc->status = IRQ_INPROGRESS;
-	desc->events = 0;
 	hardirq_enter(cpu);
-	spin_unlock(&irq_controller_lock);
-
 	while (test_bit(0,&global_irq_lock)) barrier();
-
-	for (;;) {
-		int pending, handler;
-
-		/*
-		 * If there is no IRQ handler, exit early, leaving the irq
-		 * "in progress"
-		 */
-		handler = handle_IRQ_event(irq, regs);
-
-		spin_lock(&irq_controller_lock);
-		if (!handler)
-			goto no_handler;
-
-		pending = desc->events;
-		desc->events = 0;
-		if (!pending)
-			break;
-		spin_unlock(&irq_controller_lock);
-	}
-	desc->status &= IRQ_DISABLED;
-
-no_handler:
 }
 
+static inline void exit_ioapic_irq(int cpu)
+{
+	hardirq_exit(cpu);
+	release_irqlock(cpu);
+}	
+
 static void do_edge_ioapic_IRQ(unsigned int irq, int cpu, struct pt_regs * regs)
 {
 	irq_desc_t *desc = irq_desc + irq;
+	struct irqaction * action;
+
+	spin_lock(&irq_controller_lock);
 
 	/*
 	 * Edge triggered IRQs can be acked immediately
+	 * and do not need to be masked.
 	 */
 	ack_APIC_irq();
-
-	spin_lock(&irq_controller_lock);
 	desc->ipi = 0;
+	desc->events = 1;
 
 	/*
-	 * If the irq is disabled for whatever reason, just
-	 * set a flag and return
+	 * If the irq is disabled for whatever reason, we cannot
+	 * use the action we have..
 	 */
-	if (desc->status & (IRQ_DISABLED | IRQ_INPROGRESS)) {
-		desc->events = 1;
-		spin_unlock(&irq_controller_lock);
-		return;
+	action = NULL;
+	if (!(desc->status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
+		action = desc->action;
+		desc->status = IRQ_INPROGRESS;
+		desc->events = 0;
 	}
+	spin_unlock(&irq_controller_lock);
+
+	/*
+	 * If there is no IRQ handler or it was disabled, exit early.
+	 */
+	if (!action)
+		return;
+
+	enter_ioapic_irq(cpu);
+
+	/*
+	 * Edge triggered interrupts need to remember
+	 * pending events..
+	 */
+	for (;;) {
+		int pending;
+
+		handle_IRQ_event(irq, regs);
 
-	handle_ioapic_event(irq,cpu,regs);
+		spin_lock(&irq_controller_lock);
+		pending = desc->events;
+		desc->events = 0;
+		if (!pending)
+			break;
+		spin_unlock(&irq_controller_lock);
+	}
+	desc->status &= IRQ_DISABLED;
 	spin_unlock(&irq_controller_lock);
 
-	hardirq_exit(cpu);
-	release_irqlock(cpu);
+	exit_ioapic_irq(cpu);
 }
 
 static void do_level_ioapic_IRQ (unsigned int irq, int cpu,
 						 struct pt_regs * regs)
 {
 	irq_desc_t *desc = irq_desc + irq;
+	struct irqaction * action;
 
 	spin_lock(&irq_controller_lock);
 	/*
@@ -864,28 +876,38 @@
 	 * disable has to happen before the ACK, to avoid IRQ storms.
 	 * So this all has to be within the spinlock.
 	 */
-	disable_IO_APIC_irq(irq);
-	ack_APIC_irq();
+	mask_IO_APIC_irq(irq);
+
 	desc->ipi = 0;
 
 	/*
-	 * If the irq is disabled for whatever reason, just
-	 * set a flag and return
+	 * If the irq is disabled for whatever reason, we must
+	 * not enter the irq action.
 	 */
-	if (desc->status & (IRQ_DISABLED | IRQ_INPROGRESS)) {
-		desc->events = 1;
-		spin_unlock(&irq_controller_lock);
-		return;
+	action = NULL;
+	if (!(desc->status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
+		action = desc->action;
+		desc->status = IRQ_INPROGRESS;
 	}
 
-	handle_ioapic_event(irq,cpu,regs);
-	/* we still have the spinlock held here */
+	ack_APIC_irq();
+	spin_unlock(&irq_controller_lock);
+
+	/* Exit early if we had no action or it was disabled */
+	if (!action)
+		return;
 
-	enable_IO_APIC_irq(irq);
+	enter_ioapic_irq(cpu);
+
+	handle_IRQ_event(irq, regs);
+
+	spin_lock(&irq_controller_lock);
+	desc->status &= ~IRQ_INPROGRESS;
+	if (!desc->status)
+		unmask_IO_APIC_irq(irq);
 	spin_unlock(&irq_controller_lock);
 
-	hardirq_exit(cpu);
-	release_irqlock(cpu);
+	exit_ioapic_irq(cpu);
 }
 
 #endif
@@ -1100,7 +1122,8 @@
 		/* Found it - now free it */
 		*p = action->next;
 		kfree(action);
-		irq_desc[irq].handler->disable(irq);
+		if (!irq_desc[irq].action)
+			irq_desc[irq].handler->disable(irq);
 		goto out;
 	}
 	printk("Trying to free free IRQ%d\n",irq);
@@ -1127,6 +1150,7 @@
 	spin_lock_irq(&irq_controller_lock);
 	for (i = NR_IRQS-1; i > 0; i--) {
 		if (!irq_desc[i].action) {
+			irq_desc[i].status = 0;
 			irq_desc[i].handler->enable(i);
 			irqs |= (1 << i);
 		}
@@ -1194,8 +1218,8 @@
 		    (IO_APIC_IRQ(i))) {
 			if (IO_APIC_irq_trigger(i))
 				irq_desc[i].handler = &ioapic_level_irq_type;
-			else /* edge */
-				irq_desc[i].handler = &ioapic_level_irq_type;
+			else
+				irq_desc[i].handler = &ioapic_edge_irq_type;
 			/*
 			 * disable it in the 8259A:
 			 */
diff -u --recursive --new-file v2.1.102/linux/arch/i386/kernel/irq.h linux/arch/i386/kernel/irq.h
--- v2.1.102/linux/arch/i386/kernel/irq.h	Thu May 14 19:47:38 1998
+++ linux/arch/i386/kernel/irq.h	Tue May 19 00:15:00 1998
@@ -12,6 +12,8 @@
 void unmask_irq(unsigned int irq);
 void enable_IO_APIC_irq (unsigned int irq);
 void disable_IO_APIC_irq (unsigned int irq);
+void unmask_IO_APIC_irq (unsigned int irq);
+void mask_IO_APIC_irq (unsigned int irq);
 void set_8259A_irq_mask (unsigned int irq);
 int i8259A_irq_pending (unsigned int irq);
 void ack_APIC_irq (void);
@@ -69,10 +71,6 @@
 
 #define irq_enter(cpu, irq)	(++local_irq_count[cpu])
 #define irq_exit(cpu, irq)	(--local_irq_count[cpu])
-
-/* Make these no-ops when not using SMP */
-#define enable_IO_APIC_irq(x)	do { } while (0)
-#define disable_IO_APIC_irq(x)	do { } while (0)
 
 #define IO_APIC_IRQ(x)	(0)
 
diff -u --recursive --new-file v2.1.102/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.1.102/linux/arch/i386/kernel/process.c	Thu May 14 19:47:38 1998
+++ linux/arch/i386/kernel/process.c	Tue May 19 09:46:39 1998
@@ -46,6 +46,8 @@
 #endif
 #include "irq.h"
 
+struct task_struct *last_task_used_math = NULL;
+
 #ifdef __SMP__
 asmlinkage void ret_from_smpfork(void) __asm__("ret_from_smpfork");
 #else
@@ -528,18 +530,12 @@
 	 */
 	p->tss.bitmap = sizeof(struct thread_struct);
 
-/*
- * This tried to copy the FPU state, but I wonder whether we really
- * want this at all. It is probably nicer to just have a newly started
- * process start with a clean slate wrt the fpu.  - Linus
- */
-#if 1
-	current->used_math = 0;
-	current->flags &= ~PF_USEDFPU;
+#ifdef __SMP__
+	if (current->flags & PF_USEDFPU)
 #else
 	if (last_task_used_math == current)
-		__asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387));
 #endif
+		__asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387));
 
 	return 0;
 }
diff -u --recursive --new-file v2.1.102/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.1.102/linux/arch/i386/kernel/smp.c	Thu May 14 19:47:38 1998
+++ linux/arch/i386/kernel/smp.c	Tue May 19 00:15:00 1998
@@ -365,7 +365,7 @@
 					printk("I/O APIC #%d Version %d at 0x%lX.\n",
 						m->mpc_apicid,m->mpc_apicver,
 						m->mpc_apicaddr);
-					io_apic_addr = (unsigned long)phys_to_virt(m->mpc_apicaddr);
+					io_apic_addr = m->mpc_apicaddr;
 				}
 				mpt+=sizeof(*m);
 				count+=sizeof(*m);
@@ -1526,7 +1526,7 @@
  */
 asmlinkage void smp_spurious_interrupt(void)
 {
-	ack_APIC_irq ();
+	/* ack_APIC_irq ();   see sw-dev-man vol 3, chapter 7.4.13.5 */
 	printk("spurious APIC interrupt, ayiee, should never happen.\n");
 }
 
diff -u --recursive --new-file v2.1.102/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c
--- v2.1.102/linux/arch/i386/kernel/time.c	Thu May 14 19:47:38 1998
+++ linux/arch/i386/kernel/time.c	Mon May 18 12:41:36 1998
@@ -399,11 +399,12 @@
 	 */
 	if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
 	    xtime.tv_usec > 500000 - (tick >> 1) &&
-	    xtime.tv_usec < 500000 + (tick >> 1))
-	  if (set_rtc_mmss(xtime.tv_sec) == 0)
-	    last_rtc_update = xtime.tv_sec;
-	  else
-	    last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+	    xtime.tv_usec < 500000 + (tick >> 1)) {
+		if (set_rtc_mmss(xtime.tv_sec) == 0)
+			last_rtc_update = xtime.tv_sec;
+		else
+			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+	}
 #if 0
 	/* As we return to user mode fire off the other CPU schedulers.. this is 
 	   basically because we don't yet share IRQ's around. This message is
@@ -524,6 +525,14 @@
 	xtime.tv_sec = get_cmos_time();
 	xtime.tv_usec = 0;
 
+/*
+ * If we have APM enabled we can't currently depend
+ * on the cycle counter, because a suspend to disk
+ * will reset it. Somebody should come up with a
+ * better solution than to just disable the fast time
+ * code..
+ */
+#ifndef CONFIG_APM
 	/* If we have the CPU hardware time counters, use them */
 	if (boot_cpu_data.x86_capability & 16) {
 		do_gettimeoffset = do_fast_gettimeoffset;
@@ -547,5 +556,6 @@
 			 "=d" (init_timer_cc.high));
 		irq0.handler = pentium_timer_interrupt;
 	}
+#endif
 	setup_x86_irq(0, &irq0);
 }
diff -u --recursive --new-file v2.1.102/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- v2.1.102/linux/arch/i386/mm/init.c	Sat May  2 14:19:52 1998
+++ linux/arch/i386/mm/init.c	Mon May 18 13:45:24 1998
@@ -273,7 +273,7 @@
 		 * and use it here)
 		 */
 		pg_table = pte_offset((pmd_t *)pg_dir, apic_area);
-		pte = mk_pte(__va(mp_lapic_addr), PAGE_KERNEL);
+		pte = mk_pte_phys(mp_lapic_addr, PAGE_KERNEL);
 		set_pte(pg_table, pte);
 
 		/*
@@ -281,7 +281,7 @@
 		 */
 		apic_area = 0xFEC00000; /*(unsigned long)IO_APIC_BASE;*/
 		pg_table = pte_offset((pmd_t *)pg_dir, apic_area);
-		pte = mk_pte(__va(apic_area), PAGE_KERNEL);
+		pte = mk_pte_phys(apic_area, PAGE_KERNEL);
 		set_pte(pg_table, pte);
 	} else {
 		/*
diff -u --recursive --new-file v2.1.102/linux/arch/mips/mm/r4xx0.c linux/arch/mips/mm/r4xx0.c
--- v2.1.102/linux/arch/mips/mm/r4xx0.c	Thu May 14 19:47:38 1998
+++ linux/arch/mips/mm/r4xx0.c	Thu May 14 19:01:21 1998
@@ -11,7 +11,6 @@
  *  - many of the bug workarounds are not efficient at all, but at
  *    least they are functional ...
  */
-#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -2720,7 +2719,7 @@
 
 	printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID));
 
-	set_cp0_config(CONFIG_CM_CMASK, CONFIG_CM_CACHABLE_NONCOHERENT);
+	set_cp0_config(CONF_REG_CM_CMASK, CONF_REG_CM_CACHABLE_NONCOHERENT);
 
 	probe_icache(config);
 	probe_dcache(config);
diff -u --recursive --new-file v2.1.102/linux/arch/mips/sgi/kernel/indy_sc.c linux/arch/mips/sgi/kernel/indy_sc.c
--- v2.1.102/linux/arch/mips/sgi/kernel/indy_sc.c	Thu May 14 19:47:38 1998
+++ linux/arch/mips/sgi/kernel/indy_sc.c	Thu May 14 19:01:21 1998
@@ -10,7 +10,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
-#include <linux/autoconf.h>
 
 #include <asm/bcache.h>
 #include <asm/sgi.h>
diff -u --recursive --new-file v2.1.102/linux/drivers/block/ide-disk.c linux/drivers/block/ide-disk.c
--- v2.1.102/linux/drivers/block/ide-disk.c	Thu May  7 22:51:48 1998
+++ linux/drivers/block/ide-disk.c	Mon May 18 12:50:26 1998
@@ -588,7 +588,7 @@
 {
 	unsigned long flags;
 
-	if (ide_spin_wait_hwgroup("set_nowerr", drive, &flags))
+	if (ide_spin_wait_hwgroup(drive, &flags))
 		return -EBUSY;
 	drive->nowerr = arg;
 	drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
diff -u --recursive --new-file v2.1.102/linux/drivers/block/ide-pci.c linux/drivers/block/ide-pci.c
--- v2.1.102/linux/drivers/block/ide-pci.c	Thu May  7 22:51:48 1998
+++ linux/drivers/block/ide-pci.c	Mon May 18 12:50:26 1998
@@ -282,11 +282,16 @@
 		ide_pci_enablebit_t *e = &(d->enablebits[port]);
 		if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) || (tmp & e->mask) != e->val))
 			continue;	/* port not enabled */
-		ctl = dev->base_address[(2*port)+1] & PCI_BASE_ADDRESS_IO_MASK;
+		if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE || (dev->class & (port ? 4 : 1)) != 0) {
+			ctl  = dev->base_address[(2*port)+1] & PCI_BASE_ADDRESS_IO_MASK;
+			base = dev->base_address[2*port] & ~7;
+		}
+		if ((ctl && !base) || (base && !ctl)) {
+			printk("%s: inconsistent baseregs (BIOS) for port %d, skipping\n", d->name, port);
+			continue;
+		}
 		if (!ctl)
 			ctl = port ? 0x374 : 0x3f4;	/* use default value */
-		base = dev->base_address[2*port] & ~7;
-
 		if (!base)
 			base = port ? 0x170 : 0x1f0;	/* use default value */
 		if ((hwif = ide_match_hwif(base, d->name)) == NULL)
diff -u --recursive --new-file v2.1.102/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.1.102/linux/drivers/block/ide.c	Thu May 14 19:47:39 1998
+++ linux/drivers/block/ide.c	Mon May 18 12:50:26 1998
@@ -149,28 +149,6 @@
  */
 ide_hwif_t	ide_hwifs[MAX_HWIFS];	/* master data repository */
 
-/*
- * This is our end_request replacement function.
- */
-void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup)
-{
-	struct request *req;
-	unsigned long flags;
-
-	spin_lock_irqsave(&io_request_lock,flags);
-	req = hwgroup->rq;
-
-	if (end_that_request_first(req, uptodate, DEVICE_NAME))
-		goto out;
-	add_blkdev_randomness(MAJOR(req->rq_dev));
-	hwgroup->drive->queue = req->next;
-        blk_dev[MAJOR(req->rq_dev)].current_request = NULL;
-        hwgroup->rq = NULL;
-	end_that_request_last(req);
-out:
-	spin_unlock_irqrestore(&io_request_lock,flags);
-}
-
 #if (DISK_RECOVERY_TIME > 0)
 /*
  * For really screwy hardware (hey, at least it *can* be used with Linux)
@@ -428,70 +406,27 @@
 	return 1;		/* drive ready: *might* be interrupting */
 }
 
-#if !defined(__SMP__) && defined(DEBUG_SPINLOCKS) && (DEBUG_SPINLOCKS > 1)
-
-static const char *ide_lock_name(spinlock_t *spinlock)
+/*
+ * This is our end_request replacement function.
+ */
+void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup)
 {
-	int index;
-
-	if (spinlock == &io_request_lock)
-		return "io_request_lock";
-	for (index = 0; index < MAX_HWIFS; index++) {
-		ide_hwif_t	*hwif    = &ide_hwifs[index];
-		ide_hwgroup_t	*hwgroup = hwif->hwgroup;
-		if (spinlock == &hwgroup->spinlock)
-			return hwif->name;
-	}
-	return "?";
-}
-
-#define IDE_SPIN_LOCK_IRQ(msg,spinlock)				\
-{								\
-	static int __babble = 20;				\
-	__cli();							\
-	if ((spinlock)->lock && __babble) {			\
-		__babble--;					\
-		printk("ide_lock: %s: already locked (%s)\n", msg, ide_lock_name(spinlock)); \
-	}							\
-	/* spin_lock_irq(spinlock); */				\
-	(spinlock)->lock = 1;					\
-}
-
-#define IDE_SPIN_LOCK_IRQSAVE(msg,spinlock,flags)		\
-{								\
-	__save_flags(flags);					\
-	IDE_SPIN_LOCK_IRQ(msg,spinlock);			\
-}
+	struct request *rq;
+	unsigned long flags;
 
-#define IDE_SPIN_UNLOCK_IRQRESTORE(msg,spinlock,flags)		\
-{								\
-	static int __babble = 20;				\
-	__cli();							\
-	if (!((spinlock)->lock) && __babble) {			\
-		__babble--;					\
-		printk("ide_unlock: %s: not locked (%s)\n", msg, ide_lock_name(spinlock)); \
-	}							\
-	/* spin_unlock_irqrestore(msg,spinlock,flags); */	\
-	(spinlock)->lock = 0;					\
-	restore_flags(flags);					\
-}
+	spin_lock_irqsave(&io_request_lock, flags);
+	rq = hwgroup->rq;
 
-#define IDE_SPIN_UNLOCK(msg,spinlock)				\
-{								\
-	unsigned long __flags;					\
-	__save_flags(__flags);					\
-	IDE_SPIN_UNLOCK_IRQRESTORE(msg,spinlock,__flags);	\
+	if (!end_that_request_first(rq, uptodate, hwgroup->drive->name)) {
+		add_blkdev_randomness(MAJOR(rq->rq_dev));
+		hwgroup->drive->queue = rq->next;
+        	blk_dev[MAJOR(rq->rq_dev)].current_request = NULL;
+        	hwgroup->rq = NULL;
+		end_that_request_last(rq);
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
-#else	/* DEBUG_SPINLOCKS */
-
-#define IDE_SPIN_LOCK_IRQ(msg,spinlock)			spin_lock_irq(spinlock)
-#define IDE_SPIN_LOCK_IRQSAVE(msg,spinlock,flags)	spin_lock_irqsave(spinlock,flags)
-#define IDE_SPIN_UNLOCK(msg,spinlock)			spin_unlock(spinlock)
-#define IDE_SPIN_UNLOCK_IRQRESTORE(msg,spinlock,flags)	spin_unlock_irqrestore(spinlock,flags)
-
-#endif	/* DEBUG_SPINLOCKS */
-
 /*
  * This should get invoked any time we exit the driver to
  * wait for an interrupt response from a drive.  handler() points
@@ -504,7 +439,7 @@
 	unsigned long flags;
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 
-	IDE_SPIN_LOCK_IRQSAVE("ide_set_handler", &hwgroup->spinlock, flags);
+	spin_lock_irqsave(&hwgroup->spinlock, flags);
 #ifdef DEBUG
 	if (hwgroup->handler != NULL) {
 		printk("%s: ide_set_handler: handler not null; old=%p, new=%p\n",
@@ -514,7 +449,7 @@
 	hwgroup->handler       = handler;
 	hwgroup->timer.expires = jiffies + timeout;
 	add_timer(&(hwgroup->timer));
-	IDE_SPIN_UNLOCK_IRQRESTORE("ide_set_handler", &hwgroup->spinlock, flags);
+	spin_unlock_irqrestore(&hwgroup->spinlock, flags);
 }
 
 /*
@@ -730,12 +665,12 @@
 			args[2] = IN_BYTE(IDE_NSECTOR_REG);
 		}
 	}
-	IDE_SPIN_LOCK_IRQSAVE("ide_end_drive_cmd", &io_request_lock, flags);
+	spin_lock_irqsave(&io_request_lock, flags);
 	drive->queue = rq->next;
 	blk_dev[MAJOR(rq->rq_dev)].current_request = NULL;
 	HWGROUP(drive)->rq = NULL;
 	rq->rq_status = RQ_INACTIVE;
-	IDE_SPIN_UNLOCK_IRQRESTORE("ide_end_drive_cmd", &io_request_lock, flags);
+	spin_unlock_irqrestore(&io_request_lock, flags);
 	save_flags(flags);	/* all CPUs; overkill? */
 	cli();			/* all CPUs; overkill? */
 	if (rq->sem != NULL)
@@ -1138,22 +1073,7 @@
 }
 
 /*
- * The driver enables interrupts as much as possible.  In order to do this,
- * (a) the device-interrupt is always masked before entry, and
- * (b) the timeout-interrupt is always disabled before entry.
- *
- * If we enter here from, say irq14, and then start a new request for irq15,
- * (possible with "serialize" option) then we cannot ensure that we exit
- * before the irq15 hits us. So, we must be careful not to let this bother us.
- *
- * Interrupts are still masked (by default) whenever we are exchanging
- * data/cmds with a drive, because some drives seem to have very poor
- * tolerance for latency during I/O.  For devices which don't suffer from
- * this problem (most don't), the unmask flag can be set using the "hdparm"
- * utility, to permit other interrupts during data/cmd transfers.
- *
  * Caller must have already acquired spinlock using *spinflags 
- *
  */
 static void ide_do_request (ide_hwgroup_t *hwgroup, unsigned long *hwgroup_flags, int masked_irq)
 {
@@ -1164,7 +1084,7 @@
 
 	hwgroup->busy = 1;
 	while (hwgroup->handler == NULL) {
-		IDE_SPIN_LOCK_IRQSAVE("ide_do_request1", &io_request_lock, io_flags);
+		spin_lock_irqsave(&io_request_lock, io_flags);
 		drive = choose_drive(hwgroup);
 		if (drive == NULL) {
 			unsigned long sleep = 0;
@@ -1178,7 +1098,7 @@
 				if (drive->sleep && (!sleep || 0 < (signed long)(sleep - drive->sleep)))
 					sleep = drive->sleep;
 			} while ((drive = drive->next) != hwgroup->drive);
-			IDE_SPIN_UNLOCK_IRQRESTORE("ide_do_request2", &io_request_lock, io_flags);
+			spin_unlock_irqrestore(&io_request_lock, io_flags);
 			if (sleep) {
 				if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep)) 
 					sleep = jiffies + WAIT_MIN_SLEEP;
@@ -1203,13 +1123,13 @@
 		if (bdev->current_request == &bdev->plug)	/* FIXME: paranoia */
 			printk("%s: Huh? nuking plugged queue\n", drive->name);
 		bdev->current_request = hwgroup->rq = drive->queue;
-		IDE_SPIN_UNLOCK_IRQRESTORE("ide_do_request3", &io_request_lock, io_flags);
+		spin_unlock_irqrestore(&io_request_lock, io_flags);
 
 		if (hwif->irq != masked_irq)
 			disable_irq(hwif->irq);
-		IDE_SPIN_UNLOCK_IRQRESTORE("ide_do_request4", &hwgroup->spinlock, *hwgroup_flags);
+		spin_unlock_irqrestore(&hwgroup->spinlock, *hwgroup_flags);
 		start_request(drive);
-		IDE_SPIN_LOCK_IRQSAVE("ide_do_request5", &hwgroup->spinlock, *hwgroup_flags);
+		spin_lock_irqsave(&hwgroup->spinlock, *hwgroup_flags);
 		if (hwif->irq != masked_irq)
 			enable_irq(hwif->irq);
 	}
@@ -1228,36 +1148,35 @@
 /*
  * do_hwgroup_request() invokes ide_do_request() after claiming hwgroup->busy.
  */
-static void do_hwgroup_request (const char *msg, ide_hwgroup_t *hwgroup)
+static void do_hwgroup_request (ide_hwgroup_t *hwgroup)
 {
 	unsigned long flags;
 
-	IDE_SPIN_LOCK_IRQSAVE(msg, &hwgroup->spinlock, flags);
+	spin_lock_irqsave(&hwgroup->spinlock, flags);
 	if (hwgroup->busy) {
-		IDE_SPIN_UNLOCK_IRQRESTORE(msg, &hwgroup->spinlock, flags);
+		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
 		return;
 	}
 	del_timer(&hwgroup->timer);
 	ide_get_lock(&ide_lock, ide_intr, hwgroup);	/* for atari only */
 	ide_do_request(hwgroup, &flags, 0);
-	IDE_SPIN_UNLOCK_IRQRESTORE(msg, &hwgroup->spinlock, flags);
+	spin_unlock_irqrestore(&hwgroup->spinlock, flags);
 }
 
 /*
- * As of linux-2.1.95, ll_rw_blk.c invokes our do_idex_request()
- * functions with the io_request_spinlock already grabbed.
+ * ll_rw_blk.c invokes our do_idex_request() function
+ * with the io_request_spinlock already grabbed.
  * Since we need to do our own spinlock's internally,
  * on paths that don't necessarily originate through the
- * do_idex_request() path.
- *
- * We have to undo the spinlock on entry, and restore it again on exit.
+ * do_idex_request() path, we have to undo the spinlock on entry,
+ * and restore it again on exit.
  * Fortunately, this is mostly a nop for non-SMP kernels.
  */
 static inline void unlock_do_hwgroup_request (ide_hwgroup_t *hwgroup)
 {
-	IDE_SPIN_UNLOCK("unlock_do_hwgroup_request", &io_request_lock);
-	do_hwgroup_request ("from unlock_do_hwgroup_request", hwgroup);
-	IDE_SPIN_LOCK_IRQ("unlock_do_hwgroup_request", &io_request_lock);
+	spin_unlock(&io_request_lock);
+	do_hwgroup_request (hwgroup);
+	spin_lock_irq(&io_request_lock);
 }
 
 void do_ide0_request (void)
@@ -1305,16 +1224,16 @@
 	unsigned long	flags;
 	ide_drive_t	*drive;
 
-	IDE_SPIN_LOCK_IRQSAVE("start_next_request", &hwgroup->spinlock, flags);
+	spin_lock_irqsave(&hwgroup->spinlock, flags);
 	if (hwgroup->handler != NULL) {
-		IDE_SPIN_UNLOCK_IRQRESTORE("start_next_request", &hwgroup->spinlock, flags);
+		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
 		return;
 	}
 	drive = hwgroup->drive;
 	set_recovery_timer(HWIF(drive));
 	drive->service_time = jiffies - drive->service_start;
 	ide_do_request(hwgroup, &flags, masked_irq);
-	IDE_SPIN_UNLOCK_IRQRESTORE("start_next_request", &hwgroup->spinlock, flags);
+	spin_unlock_irqrestore(&hwgroup->spinlock, flags);
 }
 
 void ide_timer_expiry (unsigned long data)
@@ -1324,29 +1243,29 @@
 	ide_handler_t *handler;
 	unsigned long flags;
 
-	IDE_SPIN_LOCK_IRQSAVE("ide_timer_expiry1", &hwgroup->spinlock, flags);
+	spin_lock_irqsave(&hwgroup->spinlock, flags);
 	drive = hwgroup->drive;
 	if ((handler = hwgroup->handler) == NULL) {
-		IDE_SPIN_UNLOCK_IRQRESTORE("ide_timer_expiry2", &hwgroup->spinlock, flags);
-		do_hwgroup_request("timer do_hwgroup_request", hwgroup);
+		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
+		do_hwgroup_request(hwgroup);
 		return;
 	}
 	hwgroup->busy = 1;	/* should already be "1" */
 	hwgroup->handler = NULL;
 	del_timer(&hwgroup->timer);
 	if (hwgroup->poll_timeout != 0) {	/* polling in progress? */
-		IDE_SPIN_UNLOCK_IRQRESTORE("ide_timer_expiry3", &hwgroup->spinlock, flags);
+		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
 		handler(drive);
 	} else if (drive_is_ready(drive)) {
 		printk("%s: lost interrupt\n", drive->name);
-		IDE_SPIN_UNLOCK_IRQRESTORE("ide_timer_expiry4", &hwgroup->spinlock, flags);
+		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
 		handler(drive);
 	} else {
 		if (drive->waiting_for_dma) {
 			(void) hwgroup->hwif->dmaproc(ide_dma_end, drive);
 			printk("%s: timeout waiting for DMA\n", drive->name);
 		}
-		IDE_SPIN_UNLOCK_IRQRESTORE("ide_timer_expiry5", &hwgroup->spinlock, flags);
+		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
 		ide_error(drive, "irq timeout", GET_STAT());
 	}
 	start_next_request(hwgroup, 0);
@@ -1411,7 +1330,7 @@
 	ide_handler_t *handler;
 
 	__cli();	/* local CPU only */
-	IDE_SPIN_LOCK_IRQSAVE("ide_intr1", &hwgroup->spinlock, flags);
+	spin_lock_irqsave(&hwgroup->spinlock, flags);
 	hwif = hwgroup->hwif;
 	if ((handler = hwgroup->handler) == NULL || hwgroup->poll_timeout != 0) {
 		/*
@@ -1437,18 +1356,18 @@
 			(void)ide_ack_intr(hwif->io_ports[IDE_STATUS_OFFSET], hwif->io_ports[IDE_IRQ_OFFSET]);
 			unexpected_intr(irq, hwgroup);
 		}
-		IDE_SPIN_UNLOCK_IRQRESTORE("ide_intr2", &hwgroup->spinlock, flags);
+		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
 		return;
 	}
 	drive = hwgroup->drive;
 	if (!drive || !drive_is_ready(drive)) {
-		IDE_SPIN_UNLOCK_IRQRESTORE("ide_intr3", &hwgroup->spinlock, flags);
+		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
 		return;
 	}
 	hwgroup->handler = NULL;
 	(void)ide_ack_intr(hwif->io_ports[IDE_STATUS_OFFSET], hwif->io_ports[IDE_IRQ_OFFSET]);
 	del_timer(&(hwgroup->timer));
-	IDE_SPIN_UNLOCK_IRQRESTORE("ide_intr4", &hwgroup->spinlock, flags);
+	spin_unlock_irqrestore(&hwgroup->spinlock, flags);
 	if (drive->unmask)
 		ide__sti();	/* local CPU only */
 	handler(drive);		/* service this interrupt, may set handler for next interrupt */
@@ -1543,7 +1462,7 @@
 	if (action == ide_wait)
 		rq->sem = &sem;
 
-	IDE_SPIN_LOCK_IRQSAVE("ide_do_drive_cmd", &io_request_lock, flags);
+	spin_lock_irqsave(&io_request_lock, flags);
 	cur_rq = drive->queue;
 	if (cur_rq == NULL || action == ide_preempt) {
 		rq->next = cur_rq;
@@ -1558,8 +1477,8 @@
 		rq->next = cur_rq->next;
 		cur_rq->next = rq;
 	}
-	IDE_SPIN_UNLOCK_IRQRESTORE("ide_do_drive_cmd", &io_request_lock, flags);
-	do_hwgroup_request("drive_cmd do_hwgroup_request", hwgroup);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	do_hwgroup_request(hwgroup);
 	save_flags(flags);	/* all CPUs; overkill? */
 	cli();			/* all CPUs; overkill? */
 	if (action == ide_wait && rq->rq_status != RQ_INACTIVE)
@@ -1588,14 +1507,14 @@
 	major = MAJOR(i_rdev);
 	minor = drive->select.b.unit << PARTN_BITS;
 	hwgroup = HWGROUP(drive);
-	IDE_SPIN_LOCK_IRQSAVE("ide_revalidate_disk", &hwgroup->spinlock, flags);
+	spin_lock_irqsave(&hwgroup->spinlock, flags);
 	if (drive->busy || (drive->usage > 1)) {
-		IDE_SPIN_UNLOCK_IRQRESTORE("ide_revalidate_disk", &hwgroup->spinlock, flags);
+		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
 		return -EBUSY;
 	};
 	drive->busy = 1;
 	MOD_INC_USE_COUNT;
-	IDE_SPIN_UNLOCK_IRQRESTORE("ide_revalidate_disk", &hwgroup->spinlock, flags);
+	spin_unlock_irqrestore(&hwgroup->spinlock, flags);
 
 	for (p = 0; p < (1<<PARTN_BITS); ++p) {
 		if (drive->part[p].nr_sects > 0) {
@@ -1954,7 +1873,7 @@
 	unsigned long	flags;
 
 	if ((setting->rw & SETTING_READ)) {
-		IDE_SPIN_LOCK_IRQSAVE("ide_read_setting", &HWGROUP(drive)->spinlock, flags);
+		spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags);
 		switch(setting->data_type) {
 			case TYPE_BYTE:
 				val = *((u8 *) setting->data);
@@ -1967,25 +1886,25 @@
 				val = *((u32 *) setting->data);
 				break;
 		}
-		IDE_SPIN_UNLOCK_IRQRESTORE("ide_read_setting", &HWGROUP(drive)->spinlock, flags);
+		spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
 	}
 	return val;
 }
 
-int ide_spin_wait_hwgroup (const char *msg, ide_drive_t *drive, unsigned long *flags)
+int ide_spin_wait_hwgroup (ide_drive_t *drive, unsigned long *flags)
 {
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	unsigned long timeout = jiffies + (3 * HZ);
 
-	IDE_SPIN_LOCK_IRQSAVE(msg, &hwgroup->spinlock, *flags);
+	spin_lock_irqsave(&hwgroup->spinlock, *flags);
 	while (hwgroup->busy) {
-		IDE_SPIN_UNLOCK_IRQRESTORE(msg, &hwgroup->spinlock, *flags);
+		spin_unlock_irqrestore(&hwgroup->spinlock, *flags);
 		__sti();	/* local CPU only; needed for jiffies */
 		if (0 < (signed long)(jiffies - timeout)) {
-			printk("%s: %s: channel busy\n", drive->name, msg);
+			printk("%s: channel busy\n", drive->name);
 			return -EBUSY;
 		}
-		IDE_SPIN_LOCK_IRQSAVE(msg, &hwgroup->spinlock, *flags);
+		spin_lock_irqsave(&hwgroup->spinlock, *flags);
 	}
 	return 0;
 }
@@ -2004,7 +1923,7 @@
 		return -EINVAL;
 	if (setting->set)
 		return setting->set(drive, val);
-	if (ide_spin_wait_hwgroup("ide_write_settings", drive, &flags))
+	if (ide_spin_wait_hwgroup(drive, &flags))
 		return -EBUSY;
 	switch (setting->data_type) {
 		case TYPE_BYTE:
@@ -2022,7 +1941,7 @@
 				*p = val;
 			break;
 	}
-	IDE_SPIN_UNLOCK_IRQRESTORE("ide_write_setting4", &HWGROUP(drive)->spinlock, flags);
+	spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
 	return 0;
 }
 
@@ -2958,6 +2877,7 @@
 EXPORT_SYMBOL(ide_hwifs);
 EXPORT_SYMBOL(ide_register_module);
 EXPORT_SYMBOL(ide_unregister_module);
+EXPORT_SYMBOL(ide_spin_wait_hwgroup);
 
 /*
  * Probe module
diff -u --recursive --new-file v2.1.102/linux/drivers/block/ide.h linux/drivers/block/ide.h
--- v2.1.102/linux/drivers/block/ide.h	Fri May  8 23:14:47 1998
+++ linux/drivers/block/ide.h	Wed May 20 16:21:59 1998
@@ -670,7 +670,7 @@
  */
 struct request **ide_get_queue (kdev_t dev);
 
-int  ide_spin_wait_hwgroup(const char *msg, ide_drive_t *drive, unsigned long *flags);
+int  ide_spin_wait_hwgroup(ide_drive_t *drive, unsigned long *flags);
 void ide_timer_expiry (unsigned long data);
 void ide_intr (int irq, void *dev_id, struct pt_regs *regs);
 void ide_geninit (struct gendisk *gd);
diff -u --recursive --new-file v2.1.102/linux/drivers/block/paride/Config.in linux/drivers/block/paride/Config.in
--- v2.1.102/linux/drivers/block/paride/Config.in	Fri Jan 30 11:28:06 1998
+++ linux/drivers/block/paride/Config.in	Thu May 14 19:11:48 1998
@@ -11,10 +11,12 @@
 dep_tristate '    MicroSolutions backpack protocol' CONFIG_PARIDE_BPCK $CONFIG_PARIDE
 dep_tristate '    DataStor Commuter protocol' CONFIG_PARIDE_COMM $CONFIG_PARIDE
 dep_tristate '    DataStor EP-2000 protocol' CONFIG_PARIDE_DSTR $CONFIG_PARIDE
+dep_tristate '    FIT TD-2000 protocol' CONFIG_PARIDE_FIT2 $CONFIG_PARIDE
 dep_tristate '    Shuttle EPAT/EPEZ protocol' CONFIG_PARIDE_EPAT $CONFIG_PARIDE
 dep_tristate '    Shuttle EPIA protocol' CONFIG_PARIDE_EPIA $CONFIG_PARIDE
 dep_tristate '    FreeCom power protocol' CONFIG_PARIDE_FRPW $CONFIG_PARIDE
 dep_tristate '    KingByte KBIC-951A/971A protocols' CONFIG_PARIDE_KBIC $CONFIG_PARIDE
+dep_tristate '    KT PHd protocol' CONFIG_PARIDE_KTTI $CONFIG_PARIDE
 dep_tristate '    OnSpec 90c20 protocol' CONFIG_PARIDE_ON20 $CONFIG_PARIDE
 dep_tristate '    OnSpec 90c26 protocol' CONFIG_PARIDE_ON26 $CONFIG_PARIDE
 #
diff -u --recursive --new-file v2.1.102/linux/drivers/block/paride/Makefile linux/drivers/block/paride/Makefile
--- v2.1.102/linux/drivers/block/paride/Makefile	Fri Jan 30 11:28:06 1998
+++ linux/drivers/block/paride/Makefile	Thu May 14 19:11:48 1998
@@ -114,6 +114,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_PARIDE_FIT2),y)
+  LX_OBJS += fit2.o
+else
+  ifeq ($(CONFIG_PARIDE_FIT2),m)
+    MX_OBJS += fit2.o
+  endif
+endif
+
 ifeq ($(CONFIG_PARIDE_FRPW),y)
   LX_OBJS += frpw.o
 else
@@ -138,4 +146,13 @@
   endif
 endif
 
+ifeq ($(CONFIG_PARIDE_KTTI),y)
+  LX_OBJS += ktti.o
+else
+  ifeq ($(CONFIG_PARIDE_KTTI),m)
+    MX_OBJS += ktti.o
+  endif
+endif
+
 include $(TOPDIR)/Rules.make
+
diff -u --recursive --new-file v2.1.102/linux/drivers/block/paride/aten.c linux/drivers/block/paride/aten.c
--- v2.1.102/linux/drivers/block/paride/aten.c	Sun Dec 28 12:05:45 1997
+++ linux/drivers/block/paride/aten.c	Thu May 14 19:11:48 1998
@@ -1,6 +1,6 @@
 /* 
-        aten.c        (c) 1997  Grant R. Guenther <grant@torque.net>
-                          Under the terms of the GNU public license.
+        aten.c  (c) 1997-8  Grant R. Guenther <grant@torque.net>
+                            Under the terms of the GNU public license.
 
 	aten.c is a low-level protocol driver for the ATEN EH-100
 	parallel port adapter.  The EH-100 supports 4-bit and 8-bit
@@ -9,7 +9,13 @@
 
 */
 
-#define ATEN_VERSION      "1.0"
+/* Changes:
+
+	1.01	GRG 1998.05.05	init_proto, release_proto
+
+*/
+
+#define ATEN_VERSION      "1.01"
 
 #include <linux/module.h>
 #include <linux/delay.h>
@@ -123,12 +129,12 @@
 
 }
 
-static void aten_inc_use ( void )
+static void aten_init_proto( PIA *pi )
 
 {       MOD_INC_USE_COUNT;
 }
 
-static void aten_dec_use ( void )
+static void aten_release_proto( PIA *pi )
 
 {       MOD_DEC_USE_COUNT;
 }
@@ -144,8 +150,8 @@
                            0,
                            0,
                            aten_log_adapter,
-                           aten_inc_use, 
-                           aten_dec_use 
+                           aten_init_proto,
+                           aten_release_proto
                           };
 
 
diff -u --recursive --new-file v2.1.102/linux/drivers/block/paride/bpck.c linux/drivers/block/paride/bpck.c
--- v2.1.102/linux/drivers/block/paride/bpck.c	Sun Dec 28 12:05:45 1997
+++ linux/drivers/block/paride/bpck.c	Thu May 14 19:11:48 1998
@@ -1,13 +1,19 @@
 /* 
-	bpck.c	(c) 1996,1997  Grant R. Guenther <grant@torque.net>
-		               Under the terms of the GNU public license.
+	bpck.c	(c) 1996-8  Grant R. Guenther <grant@torque.net>
+		            Under the terms of the GNU public license.
 
 	bpck.c is a low-level protocol driver for the MicroSolutions 
 	"backpack" parallel port IDE adapter.  
 
 */
 
-#define	BPCK_VERSION	"1.0" 
+/* Changes:
+
+	1.01	GRG 1998.05.05 init_proto, release_proto, pi->delay 
+
+*/
+
+#define	BPCK_VERSION	"1.01" 
 
 #include <linux/module.h>
 #include <linux/delay.h>
@@ -338,12 +344,12 @@
 
 static void bpck_read_eeprom ( PIA *pi, char * buf )
 
-{       int i,j,k,n,p,v,f, om;
+{       int i,j,k,n,p,v,f, om, od;
 
 	bpck_force_spp(pi);
 
-	om = pi->mode;
-	pi->mode = 0;
+	om = pi->mode;  od = pi->delay;
+	pi->mode = 0; pi->delay = 6;
 
 	bpck_connect(pi);
 	
@@ -385,7 +391,7 @@
                 bpck_disconnect(pi);
         }
 
-	pi->mode = om;
+	pi->mode = om; pi->delay = od;
 }
 
 static int bpck_test_port ( PIA *pi ) 	/* check for 8-bit port */
@@ -434,17 +440,17 @@
 		pi->mode,mode_string[pi->mode],pi->delay);
 }
 
-static void bpck_inc_use( void )
+static void bpck_init_proto( PIA *pi)
 
 {	MOD_INC_USE_COUNT;
 }
 
-static void bpck_dec_use( void )
+static void bpck_release_proto( PIA *pi)
 
 {       MOD_DEC_USE_COUNT;
 }
 
-struct pi_protocol bpck = { "bpck",0,5,2,4,256,
+struct pi_protocol bpck = { "bpck",0,5,2,1,256,
 			  bpck_write_regr,
 			  bpck_read_regr,
 			  bpck_write_block,
@@ -455,8 +461,8 @@
 			  bpck_probe_unit,
 		          bpck_test_proto,
 			  bpck_log_adapter,
-			  bpck_inc_use,
-			  bpck_dec_use
+			  bpck_init_proto,
+			  bpck_release_proto
 			};
 
 #ifdef MODULE
diff -u --recursive --new-file v2.1.102/linux/drivers/block/paride/comm.c linux/drivers/block/paride/comm.c
--- v2.1.102/linux/drivers/block/paride/comm.c	Sun Dec 28 12:05:45 1997
+++ linux/drivers/block/paride/comm.c	Thu May 14 19:11:48 1998
@@ -1,6 +1,6 @@
 /* 
-        comm.c    (c) 1997  Grant R. Guenther <grant@torque.net>
-                            Under the terms of the GNU public license.
+        comm.c    (c) 1997-8  Grant R. Guenther <grant@torque.net>
+                              Under the terms of the GNU public license.
 
 	comm.c is a low-level protocol driver for some older models
 	of the DataStor "Commuter" parallel to IDE adapter.  Some of
@@ -8,7 +8,13 @@
 	use this adapter.
 */
 
-#define COMM_VERSION      "1.0"
+/* Changes:
+
+	1.01	GRG 1998.05.05  init_proto, release_proto
+
+*/
+
+#define COMM_VERSION      "1.01"
 
 #include <linux/module.h>
 #include <linux/delay.h>
@@ -179,12 +185,12 @@
 
 }
 
-static void comm_inc_use ( void )
+static void comm_init_proto(PIA *pi)
 
 {       MOD_INC_USE_COUNT;
 }
 
-static void comm_dec_use ( void )
+static void comm_release_proto(PIA *pi)
 
 {       MOD_DEC_USE_COUNT;
 }
@@ -200,8 +206,8 @@
                            0,
                            0,
                            comm_log_adapter,
-                           comm_inc_use, 
-                           comm_dec_use 
+                           comm_init_proto,
+                           comm_release_proto
                           };
 
 
diff -u --recursive --new-file v2.1.102/linux/drivers/block/paride/dstr.c linux/drivers/block/paride/dstr.c
--- v2.1.102/linux/drivers/block/paride/dstr.c	Sun Dec 28 12:05:45 1997
+++ linux/drivers/block/paride/dstr.c	Thu May 14 19:11:48 1998
@@ -1,13 +1,19 @@
 /* 
-        dstr.c    (c) 1997  Grant R. Guenther <grant@torque.net>
-                            Under the terms of the GNU public license.
+        dstr.c    (c) 1997-8  Grant R. Guenther <grant@torque.net>
+                              Under the terms of the GNU public license.
 
         dstr.c is a low-level protocol driver for the 
         DataStor EP2000 parallel to IDE adapter chip.
 
 */
 
-#define DSTR_VERSION      "1.0"
+/* Changes:
+
+        1.01    GRG 1998.05.06 init_proto, release_proto
+
+*/
+
+#define DSTR_VERSION      "1.01"
 
 #include <linux/module.h>
 #include <linux/delay.h>
@@ -194,12 +200,12 @@
 
 }
 
-static void dstr_inc_use ( void )
+static void dstr_init_proto( PIA *pi)
 
 {       MOD_INC_USE_COUNT;
 }
 
-static void dstr_dec_use ( void )
+static void dstr_release_proto( PIA *pi)
 
 {       MOD_DEC_USE_COUNT;
 }
@@ -215,8 +221,8 @@
                            0,
                            0,
                            dstr_log_adapter,
-                           dstr_inc_use, 
-                           dstr_dec_use 
+                           dstr_init_proto,
+                           dstr_release_proto
                           };
 
 
diff -u --recursive --new-file v2.1.102/linux/drivers/block/paride/epat.c linux/drivers/block/paride/epat.c
--- v2.1.102/linux/drivers/block/paride/epat.c	Sun Dec 28 12:05:45 1997
+++ linux/drivers/block/paride/epat.c	Thu May 14 19:11:48 1998
@@ -1,6 +1,6 @@
 /* 
-        epat.c  (c) 1997  Grant R. Guenther <grant@torque.net>
-                          Under the terms of the GNU public license.
+        epat.c  (c) 1997-8  Grant R. Guenther <grant@torque.net>
+                            Under the terms of the GNU public license.
 
 	This is the low level protocol driver for the EPAT parallel
         to IDE adapter from Shuttle Technologies.  This adapter is
@@ -9,7 +9,13 @@
 	
 */
 
-#define EPAT_VERSION      "1.0"
+/* Changes:
+
+        1.01    GRG 1998.05.06 init_proto, release_proto
+
+*/
+
+#define EPAT_VERSION      "1.01"
 
 #include <linux/module.h>
 #include <linux/delay.h>
@@ -272,12 +278,12 @@
 
 }
 
-static void epat_inc_use ( void )
+static void epat_init_proto( PIA *pi)
 
 {  	MOD_INC_USE_COUNT;
 }
 
-static void epat_dec_use ( void )
+static void epat_release_proto( PIA *pi)
 
 {	MOD_DEC_USE_COUNT;
 }
@@ -293,8 +299,8 @@
 			   0,
 			   epat_test_proto,
 			   epat_log_adapter,
-			   epat_inc_use, 
-			   epat_dec_use 
+			   epat_init_proto,
+			   epat_release_proto
 			  };
 
 
diff -u --recursive --new-file v2.1.102/linux/drivers/block/paride/epia.c linux/drivers/block/paride/epia.c
--- v2.1.102/linux/drivers/block/paride/epia.c	Sun Dec 28 12:05:45 1997
+++ linux/drivers/block/paride/epia.c	Thu May 14 19:11:48 1998
@@ -1,6 +1,6 @@
 /* 
-        epia.c    (c) 1997  Grant R. Guenther <grant@torque.net>
-                            Under the terms of the GNU public license.
+        epia.c    (c) 1997-8  Grant R. Guenther <grant@torque.net>
+                              Under the terms of the GNU public license.
 
         epia.c is a low-level protocol driver for Shuttle Technologies 
 	EPIA parallel to IDE adapter chip.  This device is now obsolete
@@ -10,7 +10,13 @@
 
 */
 
-#define EPIA_VERSION      "1.0"
+/* Changes:
+
+        1.01    GRG 1998.05.06 init_proto, release_proto
+
+*/
+
+#define EPIA_VERSION      "1.01"
 
 #include <linux/module.h>
 #include <linux/delay.h>
@@ -274,12 +280,12 @@
 
 }
 
-static void epia_inc_use ( void )
+static void epia_init_proto( PIA *pi)
 
 {       MOD_INC_USE_COUNT;
 }
 
-static void epia_dec_use ( void )
+static void epia_release_proto( PIA *pi)
 
 {       MOD_DEC_USE_COUNT;
 }
@@ -295,8 +301,8 @@
                            0,
                            epia_test_proto,
                            epia_log_adapter,
-                           epia_inc_use, 
-                           epia_dec_use 
+                           epia_init_proto,
+                           epia_release_proto
                           };
 
 
diff -u --recursive --new-file v2.1.102/linux/drivers/block/paride/fit2.c linux/drivers/block/paride/fit2.c
--- v2.1.102/linux/drivers/block/paride/fit2.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/paride/fit2.c	Thu May 14 19:11:48 1998
@@ -0,0 +1,161 @@
+/* 
+        fit2.c        (c) 1998  Grant R. Guenther <grant@torque.net>
+                          Under the terms of the GNU public license.
+
+	fit2.c is a low-level protocol driver for the older version
+        of the Fidelity International Technology parallel port adapter.  
+	This adapter is used in their TransDisk 2000 and older TransDisk
+	3000 portable hard-drives.  As far as I can tell, this device
+	supports 4-bit mode _only_.  
+
+	Newer models of the FIT products use an enhanced protocol.
+	The "fit3" protocol module should support current drives.
+
+*/
+
+#define FIT2_VERSION      "1.0"
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+
+#include "paride.h"
+
+#define j44(a,b)                (((a>>4)&0x0f)|(b&0xf0))
+
+/* cont = 0 - access the IDE register file 
+   cont = 1 - access the IDE command set 
+
+NB:  The FIT adapter does not appear to use the control registers.
+So, we map ALT_STATUS to STATUS and NO-OP writes to the device
+control register - this means that IDE reset will not work on these
+devices.
+
+*/
+
+static void  fit2_write_regr( PIA *pi, int cont, int regr, int val)
+
+{	if (cont == 1) return;
+	w2(0xc); w0(regr); w2(4); w0(val); w2(5); w0(0); w2(4);
+}
+
+static int fit2_read_regr( PIA *pi, int cont, int regr )
+
+{	int  a, b, r;
+
+	if (cont) {
+	  if (regr != 6) return 0xff;
+	  r = 7;
+	} else r = regr + 0x10;
+
+	w2(0xc); w0(r); w2(4); w2(5); 
+	         w0(0); a = r1();
+	         w0(1); b = r1();
+	w2(4);
+
+	return j44(a,b);
+
+}
+
+static void fit2_read_block( PIA *pi, char * buf, int count )
+
+{	int  k, a, b, c, d;
+
+	w2(0xc); w0(0x10);
+
+	for (k=0;k<count/4;k++) {
+
+		w2(4); w2(5);
+		w0(0); a = r1(); w0(1); b = r1();
+		w0(3); c = r1(); w0(2); d = r1(); 
+		buf[4*k+0] = j44(a,b);
+		buf[4*k+1] = j44(d,c);
+
+                w2(4); w2(5);
+                       a = r1(); w0(3); b = r1();
+                w0(1); c = r1(); w0(0); d = r1(); 
+                buf[4*k+2] = j44(d,c);
+                buf[4*k+3] = j44(a,b);
+
+	}
+
+	w2(4);
+
+}
+
+static void fit2_write_block( PIA *pi, char * buf, int count )
+
+{	int k;
+
+
+	w2(0xc); w0(0); 
+	for (k=0;k<count/2;k++) {
+		w2(4); w0(buf[2*k]); 
+		w2(5); w0(buf[2*k+1]);
+	}
+	w2(4);
+}
+
+static void fit2_connect ( PIA *pi  )
+
+{       pi->saved_r0 = r0();
+        pi->saved_r2 = r2();
+	w2(0xcc); 
+}
+
+static void fit2_disconnect ( PIA *pi )
+
+{       w0(pi->saved_r0);
+        w2(pi->saved_r2);
+} 
+
+static void fit2_log_adapter( PIA *pi, char * scratch, int verbose )
+
+{       printk("%s: fit2 %s, FIT 2000 adapter at 0x%x, delay %d\n",
+                pi->device,FIT2_VERSION,pi->port,pi->delay);
+
+}
+
+static void fit2_init_proto( PIA *pi)
+
+{       MOD_INC_USE_COUNT;
+}
+
+static void fit2_release_proto( PIA *pi)
+
+{       MOD_DEC_USE_COUNT;
+}
+
+struct pi_protocol fit2 = {"fit2",0,1,2,1,1,
+                           fit2_write_regr,
+                           fit2_read_regr,
+                           fit2_write_block,
+                           fit2_read_block,
+                           fit2_connect,
+                           fit2_disconnect,
+                           0,
+                           0,
+                           0,
+                           fit2_log_adapter,
+                           fit2_init_proto,
+                           fit2_release_proto
+                          };
+
+
+#ifdef MODULE
+
+int     init_module(void)
+
+{       return pi_register( &fit2 ) - 1;
+}
+
+void    cleanup_module(void)
+
+{       pi_unregister( &fit2 );
+}
+
+#endif
+
+/* end of fit2.c */
diff -u --recursive --new-file v2.1.102/linux/drivers/block/paride/frpw.c linux/drivers/block/paride/frpw.c
--- v2.1.102/linux/drivers/block/paride/frpw.c	Sun Dec 28 12:05:45 1997
+++ linux/drivers/block/paride/frpw.c	Thu May 14 19:11:48 1998
@@ -1,13 +1,21 @@
 /* 
-	frpw.c	(c) 1997  Grant R. Guenther <grant@torque.net>
-		          Under the terms of the GNU public license
+	frpw.c	(c) 1996-8  Grant R. Guenther <grant@torque.net>
+		            Under the terms of the GNU public license
 
 	frpw.c is a low-level protocol driver for the Freecom "Power"
 	parallel port IDE adapter.
 	
 */
 
-#define	FRPW_VERSION	"1.0" 
+/* Changes:
+
+        1.01    GRG 1998.05.06 init_proto, release_proto
+			       fix chip detect
+			       added EPP-16 and EPP-32
+
+*/
+
+#define	FRPW_VERSION	"1.01" 
 
 #include <linux/module.h>
 #include <linux/delay.h>
@@ -93,6 +101,24 @@
 		w2(4);
 		break;
 
+	case 4: w2(4); w0(regr + 0x80); cec4;
+                for (k=0;k<(count/2)-1;k++) ((u16 *)buf)[k] = r4w();
+                w2(0xac); w2(0xa4);
+                buf[count-2] = r4();
+                buf[count-1] = r4();
+                w2(4);
+                break;
+
+	case 5: w2(4); w0(regr + 0x80); cec4;
+                for (k=0;k<(count/4)-1;k++) ((u32 *)buf)[k] = r4l();
+                buf[count-4] = r4();
+                buf[count-3] = r4();
+                w2(0xac); w2(0xa4);
+                buf[count-2] = r4();
+                buf[count-1] = r4();
+                w2(4);
+                break;
+
         }
 }
 
@@ -121,6 +147,16 @@
 		for (k=0;k<count;k++) w4(buf[k]);
 		w2(4);
 		break;
+
+        case 4: w2(4); w0(0xc8); cec4; w2(5);
+                for (k=0;k<count/2;k++) w4w(((u16 *)buf)[k]);
+                w2(4);
+                break;
+
+        case 5: w2(4); w0(0xc8); cec4; w2(5);
+                for (k=0;k<count/4;k++) w4l(((u32 *)buf)[k]);
+                w2(4);
+                break;
 	}
 }
 
@@ -144,6 +180,8 @@
 
 static int frpw_test_pnp ( PIA *pi )
 
+/*  returns chip_type:   0 = Xilinx, 1 = ASIC   */
+
 {	int olddelay, a, b;
 
 	olddelay = pi->delay;
@@ -163,24 +201,27 @@
 	return ((~a&0x40) && (b&0x40));
 } 
 
-/*  We use pi->private to record the chip type:  
-	0 = untested, 2 = Xilinx, 3 = ASIC
-*/  
+/* We use the pi->private to remember the result of the PNP test.
+   To make this work, private = port*2 + chip.  Yes, I know it's
+   a hack :-(
+*/
 
 static int frpw_test_proto( PIA *pi, char * scratch, int verbose )
 
-{       int     k, r;
+{       int     j, k, r;
+	int	e[2] = {0,0};
 
-	if (!pi->private) pi->private = frpw_test_pnp(pi) + 2;
+	if ((pi->private>>1) != pi->port)
+	   pi->private = frpw_test_pnp(pi) + 2*pi->port;
 
-	if ((pi->private == 2) && (pi->mode > 2)) {
+	if (((pi->private%2) == 0) && (pi->mode > 2)) {
 	   if (verbose) 
 		printk("%s: frpw: Xilinx does not support mode %d\n",
 			pi->device, pi->mode);
 	   return 1;
 	}
 
-	if ((pi->private == 3) && (pi->mode == 2)) {
+	if (((pi->private%2) == 1) && (pi->mode == 2)) {
 	   if (verbose)
 		printk("%s: frpw: ASIC does not support mode 2\n",
 			pi->device);
@@ -188,42 +229,55 @@
 	}
 
 	frpw_connect(pi);
+	for (j=0;j<2;j++) {
+                frpw_write_regr(pi,0,6,0xa0+j*0x10);
+                for (k=0;k<256;k++) {
+                        frpw_write_regr(pi,0,2,k^0xaa);
+                        frpw_write_regr(pi,0,3,k^0x55);
+                        if (frpw_read_regr(pi,0,2) != (k^0xaa)) e[j]++;
+                        }
+                }
+	frpw_disconnect(pi);
+
+	frpw_connect(pi);
         frpw_read_block_int(pi,scratch,512,0x10);
         r = 0;
         for (k=0;k<128;k++) if (scratch[k] != k) r++;
 	frpw_disconnect(pi);
 
         if (verbose)  {
-            printk("%s: frpw: port 0x%x, mode %d, test=%d\n",
-                   pi->device,pi->port,pi->mode,r);
+            printk("%s: frpw: port 0x%x, chip %d, mode %d, test=(%d,%d,%d)\n",
+                   pi->device,pi->port,(pi->private%2),pi->mode,e[0],e[1],r);
         }
 
-        return r;
+        return (r || (e[0] && e[1]));
 }
 
 
 static void frpw_log_adapter( PIA *pi, char * scratch, int verbose )
 
-{       char    *mode_string[4] = {"4-bit","8-bit","EPP-X","EPP-A"};
+{       char    *mode_string[6] = {"4-bit","8-bit","EPP",
+				   "EPP-8","EPP-16","EPP-32"};
 
         printk("%s: frpw %s, Freecom (%s) adapter at 0x%x, ", pi->device,
-		FRPW_VERSION,(pi->private == 2)?"Xilinx":"ASIC",pi->port);
+		FRPW_VERSION,((pi->private%2) == 0)?"Xilinx":"ASIC",pi->port);
         printk("mode %d (%s), delay %d\n",pi->mode,
 		mode_string[pi->mode],pi->delay);
 
 }
 
-static void frpw_inc_use ( void )
+static void frpw_init_proto( PIA *pi)
 
 {       MOD_INC_USE_COUNT;
+	pi->private = 0;
 }
 
-static void frpw_dec_use ( void )
+static void frpw_release_proto( PIA *pi)
 
 {       MOD_DEC_USE_COUNT;
 }
 
-struct pi_protocol frpw = {"frpw",0,4,2,2,1,
+struct pi_protocol frpw = {"frpw",0,6,2,2,1,
                            frpw_write_regr,
                            frpw_read_regr,
                            frpw_write_block,
@@ -234,8 +288,8 @@
                            0,
                            frpw_test_proto,
                            frpw_log_adapter,
-                           frpw_inc_use, 
-                           frpw_dec_use 
+                           frpw_init_proto,
+                           frpw_release_proto
                           };
 
 
diff -u --recursive --new-file v2.1.102/linux/drivers/block/paride/kbic.c linux/drivers/block/paride/kbic.c
--- v2.1.102/linux/drivers/block/paride/kbic.c	Sun Dec 28 12:05:45 1997
+++ linux/drivers/block/paride/kbic.c	Thu May 14 19:11:48 1998
@@ -1,6 +1,6 @@
 /*
-        kbic.c    (c) 1997  Grant R. Guenther <grant@torque.net>
-                            Under the terms of the GNU public license.
+        kbic.c    (c) 1997-8  Grant R. Guenther <grant@torque.net>
+                              Under the terms of the GNU public license.
 
         This is a low-level driver for the KBIC-951A and KBIC-971A
         parallel to IDE adapter chips from KingByte Information Systems.
@@ -12,7 +12,13 @@
 
 */
 
-#define KBIC_VERSION      "1.0"
+/* Changes:
+
+        1.01    GRG 1998.05.06 init_proto, release_proto
+
+*/
+
+#define KBIC_VERSION      "1.01"
 
 #include <linux/module.h>
 #include <linux/delay.h>
@@ -241,12 +247,12 @@
 {       kbic_log_adapter(pi,scratch,verbose,"KBIC-971A");
 }
 
-static void kbic_inc_use ( void )
+static void kbic_init_proto( PIA *pi)
 
 {       MOD_INC_USE_COUNT;
 }
 
-static void kbic_dec_use ( void )
+static void kbic_release_proto( PIA *pi)
 
 {       MOD_DEC_USE_COUNT;
 }
@@ -262,8 +268,8 @@
                            0,
                            0,
                            k951_log_adapter,
-                           kbic_inc_use, 
-                           kbic_dec_use 
+                           kbic_init_proto,
+                           kbic_release_proto
   			  };
 
 
@@ -278,8 +284,8 @@
                            0,
                            0,
                            k971_log_adapter,
-                           kbic_inc_use, 
-                           kbic_dec_use 
+                           kbic_init_proto,
+                           kbic_release_proto
                           };
 
 #ifdef MODULE
diff -u --recursive --new-file v2.1.102/linux/drivers/block/paride/ktti.c linux/drivers/block/paride/ktti.c
--- v2.1.102/linux/drivers/block/paride/ktti.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/paride/ktti.c	Thu May 14 19:11:48 1998
@@ -0,0 +1,138 @@
+/* 
+        ktti.c        (c) 1998  Grant R. Guenther <grant@torque.net>
+                          Under the terms of the GNU public license.
+
+	ktti.c is a low-level protocol driver for the KT Technology
+	parallel port adapter.  This adapter is used in the "PHd" 
+        portable hard-drives.  As far as I can tell, this device
+	supports 4-bit mode _only_.  
+
+*/
+
+#define KTTI_VERSION      "1.0"
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+
+#include "paride.h"
+
+#define j44(a,b)                (((a>>4)&0x0f)|(b&0xf0))
+
+/* cont = 0 - access the IDE register file 
+   cont = 1 - access the IDE command set 
+*/
+
+static int  cont_map[2] = { 0x10, 0x08 };
+
+static void  ktti_write_regr( PIA *pi, int cont, int regr, int val)
+
+{	int r;
+
+	r = regr + cont_map[cont];
+
+	w0(r); w2(0xb); w2(0xa); w2(3); w2(6); 
+	w0(val); w2(3); w0(0); w2(6); w2(0xb);
+}
+
+static int ktti_read_regr( PIA *pi, int cont, int regr )
+
+{	int  a, b, r;
+
+        r = regr + cont_map[cont];
+
+        w0(r); w2(0xb); w2(0xa); w2(9); w2(0xc); w2(9); 
+	a = r1(); w2(0xc);  b = r1(); w2(9); w2(0xc); w2(9);
+	return j44(a,b);
+
+}
+
+static void ktti_read_block( PIA *pi, char * buf, int count )
+
+{	int  k, a, b;
+
+	for (k=0;k<count/2;k++) {
+		w0(0x10); w2(0xb); w2(0xa); w2(9); w2(0xc); w2(9);
+		a = r1(); w2(0xc); b = r1(); w2(9);
+		buf[2*k] = j44(a,b);
+		a = r1(); w2(0xc); b = r1(); w2(9);
+		buf[2*k+1] = j44(a,b);
+	}
+}
+
+static void ktti_write_block( PIA *pi, char * buf, int count )
+
+{	int k;
+
+	for (k=0;k<count/2;k++) {
+		w0(0x10); w2(0xb); w2(0xa); w2(3); w2(6);
+		w0(buf[2*k]); w2(3);
+		w0(buf[2*k+1]); w2(6);
+		w2(0xb);
+	}
+}
+
+static void ktti_connect ( PIA *pi  )
+
+{       pi->saved_r0 = r0();
+        pi->saved_r2 = r2();
+	w2(0xb); w2(0xa); w0(0); w2(3); w2(6);	
+}
+
+static void ktti_disconnect ( PIA *pi )
+
+{       w2(0xb); w2(0xa); w0(0xa0); w2(3); w2(4);
+	w0(pi->saved_r0);
+        w2(pi->saved_r2);
+} 
+
+static void ktti_log_adapter( PIA *pi, char * scratch, int verbose )
+
+{       printk("%s: ktti %s, KT adapter at 0x%x, delay %d\n",
+                pi->device,KTTI_VERSION,pi->port,pi->delay);
+
+}
+
+static void ktti_init_proto( PIA *pi)
+
+{       MOD_INC_USE_COUNT;
+}
+
+static void ktti_release_proto( PIA *pi)
+
+{       MOD_DEC_USE_COUNT;
+}
+
+struct pi_protocol ktti = {"ktti",0,1,2,1,1,
+                           ktti_write_regr,
+                           ktti_read_regr,
+                           ktti_write_block,
+                           ktti_read_block,
+                           ktti_connect,
+                           ktti_disconnect,
+                           0,
+                           0,
+                           0,
+                           ktti_log_adapter,
+                           ktti_init_proto,
+                           ktti_release_proto
+                          };
+
+
+#ifdef MODULE
+
+int     init_module(void)
+
+{       return pi_register( &ktti ) - 1;
+}
+
+void    cleanup_module(void)
+
+{       pi_unregister( &ktti );
+}
+
+#endif
+
+/* end of ktti.c */
diff -u --recursive --new-file v2.1.102/linux/drivers/block/paride/mkd linux/drivers/block/paride/mkd
--- v2.1.102/linux/drivers/block/paride/mkd	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/paride/mkd	Thu May 14 19:11:48 1998
@@ -0,0 +1,25 @@
+#!/bin/bash
+#
+# mkd -- a script to create the device special files for the PARIDE subsystem
+#
+function mkdev {
+  mknod $1 $2 $3 $4 ; chmod 0660 $1 ; chown root:disk $1
+}
+#
+function pd {
+  D=$( printf \\$( printf "x%03x" $[ $1 + 97 ] ) )
+  mkdev pd$D b 45 $[ $1 * 16 ]
+  for P in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+  do mkdev pd$D$P b 45 $[ $1 * 16 + $P ]
+  done
+}
+#
+cd /dev
+#
+for u in 0 1 2 3 ; do pd $u ; done
+for u in 0 1 2 3 ; do mkdev pcd$u b 46 $u ; done 
+for u in 0 1 2 3 ; do mkdev pf$u  b 47 $u ; done 
+for u in 0 1 2 3 ; do mkdev pt$u  c 96 $u ; done 
+for u in 0 1 2 3 ; do mkdev npt$u c 96 $[ $u + 128 ] ; done 
+#
+# end of mkd
diff -u --recursive --new-file v2.1.102/linux/drivers/block/paride/on20.c linux/drivers/block/paride/on20.c
--- v2.1.102/linux/drivers/block/paride/on20.c	Sun Dec 28 12:05:45 1997
+++ linux/drivers/block/paride/on20.c	Thu May 14 19:11:48 1998
@@ -1,12 +1,18 @@
 /* 
-	on20.c	(c) 1996  Grant R. Guenther <grant@torque.net>
-		          Under the terms of the GNU public license.
+	on20.c	(c) 1996-8  Grant R. Guenther <grant@torque.net>
+		            Under the terms of the GNU public license.
 
         on20.c is a low-level protocol driver for the
         Onspec 90c20 parallel to IDE adapter. 
 */
 
-#define	ON20_VERSION	"1.0"
+/* Changes:
+
+        1.01    GRG 1998.05.06 init_proto, release_proto
+
+*/
+
+#define	ON20_VERSION	"1.01"
 
 #include <linux/module.h>
 #include <linux/delay.h>
@@ -114,12 +120,12 @@
 
 }
 
-static void on20_inc_use ( void )
+static void on20_init_proto( PIA *pi)
 
 {       MOD_INC_USE_COUNT;
 }
 
-static void on20_dec_use ( void )
+static void on20_release_proto( PIA *pi)
 
 {       MOD_DEC_USE_COUNT;
 }
@@ -135,8 +141,8 @@
                            0,
                            0,
                            on20_log_adapter,
-                           on20_inc_use, 
-                           on20_dec_use 
+                           on20_init_proto,
+                           on20_release_proto
                           };
 
 
diff -u --recursive --new-file v2.1.102/linux/drivers/block/paride/on26.c linux/drivers/block/paride/on26.c
--- v2.1.102/linux/drivers/block/paride/on26.c	Sun Dec 28 12:05:45 1997
+++ linux/drivers/block/paride/on26.c	Thu May 14 19:11:48 1998
@@ -1,13 +1,19 @@
 /* 
-        on26.c    (c) 1997  Grant R. Guenther <grant@torque.net>
-                            Under the terms of the GNU public license.
+        on26.c    (c) 1997-8  Grant R. Guenther <grant@torque.net>
+                              Under the terms of the GNU public license.
 
         on26.c is a low-level protocol driver for the 
         OnSpec 90c26 parallel to IDE adapter chip.
 
 */
 
-#define ON26_VERSION      "1.0"
+/* Changes:
+
+        1.01    GRG 1998.05.06 init_proto, release_proto
+
+*/
+
+#define ON26_VERSION      "1.01"
 
 #include <linux/module.h>
 #include <linux/delay.h>
@@ -217,12 +223,12 @@
 
 }
 
-static void on26_inc_use ( void )
+static void on26_init_proto( PIA *pi)
 
 {       MOD_INC_USE_COUNT;
 }
 
-static void on26_dec_use ( void )
+static void on26_release_proto( PIA *pi)
 
 {       MOD_DEC_USE_COUNT;
 }
@@ -238,8 +244,8 @@
                            0,
                            0,
                            on26_log_adapter,
-                           on26_inc_use, 
-                           on26_dec_use 
+                           on26_init_proto,
+                           on26_release_proto
                           };
 
 
diff -u --recursive --new-file v2.1.102/linux/drivers/block/paride/paride.c linux/drivers/block/paride/paride.c
--- v2.1.102/linux/drivers/block/paride/paride.c	Fri Jan 30 11:28:06 1998
+++ linux/drivers/block/paride/paride.c	Thu May 14 19:11:48 1998
@@ -1,13 +1,20 @@
 /* 
-        paride.c  (c) 1997  Grant R. Guenther <grant@torque.net>
-                            Under the terms of the GNU public license.
+        paride.c  (c) 1997-8  Grant R. Guenther <grant@torque.net>
+                              Under the terms of the GNU public license.
 
 	This is the base module for the family of device drivers
         that support parallel port IDE devices.  
 
 */
 
-#define PI_VERSION      "1.0"
+/* Changes:
+
+	1.01	GRG 1998.05.03	Use spinlocks
+	1.02	GRG 1998.05.05  init_proto, release_proto, ktti
+
+*/
+
+#define PI_VERSION      "1.02"
 
 #include <linux/module.h>
 #include <linux/config.h>
@@ -15,6 +22,7 @@
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 #include <linux/string.h>
+#include <asm/spinlock.h>
 
 #ifdef CONFIG_PARPORT_MODULE
 #define CONFIG_PARPORT
@@ -30,6 +38,7 @@
 
 static struct pi_protocol	*protocols[MAX_PROTOS];
 
+spinlock_t	pi_spinlock = SPIN_LOCK_UNLOCKED;
 
 void pi_write_regr( PIA *pi, int cont, int regr, int val)
 
@@ -59,8 +68,7 @@
 	long flags;
 	void (*cont)(void) = NULL;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&pi_spinlock,flags);
 
 	if (pi->claim_cont && !parport_claim(pi->pardev)) {
 		cont = pi->claim_cont;
@@ -68,8 +76,10 @@
 		pi->claimed = 1;
 	}
 
-	restore_flags(flags);	
+	spin_unlock_irqrestore(&pi_spinlock,flags);	
+
 	wake_up(&(pi->parq));
+
 	if (cont) cont();
 }
 
@@ -81,16 +91,15 @@
 
 {	long flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&pi_spinlock,flags); 
 
 	if (!pi->pardev || !parport_claim(pi->pardev)) {
 		pi->claimed = 1;
-		restore_flags(flags);
+		spin_unlock_irqrestore(&pi_spinlock,flags);
 		cont();
 	} else {
 		pi->claim_cont = cont;
-		restore_flags(flags);
+		spin_unlock_irqrestore(&pi_spinlock,flags);	
 	}
 }
 
@@ -148,7 +157,7 @@
 {	pi_unregister_parport(pi);
 	if ((!pi->pardev)&&(pi->reserved)) 
 		release_region(pi->port,pi->reserved);
-	pi->proto->dec_use();
+	pi->proto->release_proto(pi);
 }
 
 #define WR(r,v)         pi_write_regr(pi,0,r,v)
@@ -337,12 +346,12 @@
 	for (p=s;p<e;p++) {
 	  if (protocols[p]) {
 		pi->proto = protocols[p];
-		pi->proto->inc_use();
+		pi->private = 0;
+		pi->proto->init_proto(pi);
 		if (delay == -1) pi->delay = pi->proto->default_delay;
 		  else pi->delay = delay;
 		pi->devtype = devtype;
 		pi->device = device;
-		pi->private = 0;
 
 		pi->parname = NULL;
 		pi->pardev = NULL;
@@ -361,7 +370,7 @@
 			   if (pi_probe_unit(pi,unit,scratch,verbose)) break;
       			if (pi->port) break;
 		}
-		pi->proto->dec_use();
+		pi->proto->release_proto(pi);
 	  }
 	}
 
@@ -440,11 +449,21 @@
           pi_register(&frpw);
         };
 #endif
+#ifdef CONFIG_PARIDE_FIT2
+        { extern struct pi_protocol fit2;
+          pi_register(&fit2);
+        };
+#endif
 #ifdef CONFIG_PARIDE_KBIC
         { extern struct pi_protocol k951;
           extern struct pi_protocol k971;
           pi_register(&k951);
           pi_register(&k971);
+        };
+#endif
+#ifdef CONFIG_PARIDE_KTTI
+        { extern struct pi_protocol ktti;
+          pi_register(&ktti);
         };
 #endif
 #ifdef CONFIG_PARIDE_ON20
diff -u --recursive --new-file v2.1.102/linux/drivers/block/paride/paride.h linux/drivers/block/paride/paride.h
--- v2.1.102/linux/drivers/block/paride/paride.h	Sun Dec 28 12:05:45 1997
+++ linux/drivers/block/paride/paride.h	Thu May 14 19:11:48 1998
@@ -1,12 +1,18 @@
-/* paride.h	(c) 1997  Grant R. Guenther <grant@torque.net>
-   		          Under the terms of the GPL.
+/* 
+	paride.h	(c) 1997-8  Grant R. Guenther <grant@torque.net>
+   		                    Under the terms of the GPL.
 
    This file defines the interface between the high-level parallel
    IDE device drivers (pd, pf, pcd, pt) and the adapter chips.
 
 */
 
-#define PARIDE_H_VERSION 	"1.0"
+/* Changes:
+
+	1.01	GRG 1998.05.05	init_proto, release_proto
+*/
+
+#define PARIDE_H_VERSION 	"1.01"
 
 /* Some adapters need to know what kind of device they are in
 
@@ -145,8 +151,8 @@
 	int  (*test_proto)(PIA *,char *,int);
 	void (*log_adapter)(PIA *,char *,int);
 	
-	void (*inc_use)(void);
-	void (*dec_use)(void);
+	void (*init_proto)(PIA *);
+	void (*release_proto)(PIA *);
 };
 
 typedef struct pi_protocol PIP;
diff -u --recursive --new-file v2.1.102/linux/drivers/block/paride/pcd.c linux/drivers/block/paride/pcd.c
--- v2.1.102/linux/drivers/block/paride/pcd.c	Fri Jan 30 11:28:06 1998
+++ linux/drivers/block/paride/pcd.c	Thu May 14 19:11:48 1998
@@ -1,6 +1,6 @@
 /* 
-	pcd.c	(c) 1997  Grant R. Guenther <grant@torque.net>
-		          Under the terms of the GNU public license.
+	pcd.c	(c) 1997-8  Grant R. Guenther <grant@torque.net>
+		            Under the terms of the GNU public license.
 
 	This is high-level driver for parallel port ATAPI CDrom
         drives based on chips supported by the paride module.
@@ -86,16 +86,20 @@
 /* Changes:
 
 	1.01	GRG 1997.01.24	Added test unit ready support
+	1.02    GRG 1998.05.06  Changes to pcd_completion, ready_wait,
+				and loosen interpretation of ATAPI
+			        standard for clearing error status.
+				Use spinlocks. Eliminate sti().
 
 */
 
-#define	PCD_VERSION	"1.01"
+#define	PCD_VERSION	"1.02"
 #define PCD_MAJOR	46
 #define PCD_NAME	"pcd"
 #define PCD_UNITS	4
 
 /* Here are things one can override from the insmod command.
-   Most are autoprobed by paride unless set here.  Verbose is on
+   Most are autoprobed by paride unless set here.  Verbose is off
    by default.
 
 */
@@ -133,6 +137,7 @@
 #include <linux/cdrom.h>
 
 #include <asm/uaccess.h>
+#include <asm/spinlock.h>
 
 #ifndef MODULE
 
@@ -193,7 +198,7 @@
 
 static int 	pcd_open(struct inode *inode, struct file *file);
 static void 	do_pcd_request(void);
-static void 	do_pcd_read(int unit);
+static void 	do_pcd_read(void);
 static int 	pcd_ioctl(struct inode *inode,struct file *file,
                          unsigned int cmd, unsigned long arg);
 
@@ -343,8 +348,9 @@
 	        pcd_sector = CURRENT->sector;
 	        pcd_count = CURRENT->nr_sectors;
 	        pcd_buf = CURRENT->buffer;
-	        do_pcd_read(unit);
-		if (pcd_busy) return;
+		pcd_busy = 1;
+	        ps_set_intr(do_pcd_read,0,0,nice); 
+		return;
 	    } 
 	    else end_request(0);
 	}
@@ -474,7 +480,7 @@
         WR(0,5,dlen / 256);
         WR(0,7,0xa0);          /* ATAPI packet command */
 
-        if (pcd_wait(unit,IDE_BUSY,IDE_DRQ|IDE_ERR,fun,"command DRQ")) {
+        if (pcd_wait(unit,IDE_BUSY,IDE_DRQ,fun,"command DRQ")) {
 		pi_disconnect(PI);
 		return -1;
 	}
@@ -497,7 +503,7 @@
 	r = pcd_wait(unit,IDE_BUSY,IDE_DRQ|IDE_READY|IDE_ERR,fun,"completion");
 
 	if ((RR(0,2)&2) && (RR(0,7)&IDE_DRQ)) { 
-	        n = (RR(0,4)+256*RR(0,5));
+	        n = (((RR(0,4)+256*RR(0,5))+3)&0xfffc);
 	        pi_read_block(PI,buf,n);
 	}
 
@@ -589,23 +595,17 @@
 
 {	int	i, k, flg;
 	int	expect[5] = {1,1,1,0x14,0xeb};
-	long	flags;
 
 	pi_connect(PI);
 	WR(0,6,0xa0 + 0x10*PCD.drive);
 	WR(0,7,8);
 
-	save_flags(flags);
-	sti();
-
 	pcd_sleep(2);  		/* delay a bit*/
 
 	k = 0;
 	while ((k++ < PCD_RESET_TMO) && (RR(1,6)&IDE_BUSY))
 		pcd_sleep(10);
 
-	restore_flags(flags);
-
 	flg = 1;
 	for(i=0;i<5;i++) flg &= (RR(0,i+1) == expect[i]);
 
@@ -631,7 +631,7 @@
           pcd_atapi(unit,tr_cmd,0,NULL,DBMSG("test unit ready"));
           p = PCD.last_sense;
           if (!p) return 0;
-          if (!((p == 0x010402)||((p & 0xff) == 6))) return p;
+	  if (!(((p & 0xffff) == 0x0402)||((p & 0xff) == 6))) return p;
           k++;
           pcd_sleep(100);
         }
@@ -749,6 +749,7 @@
 {	int	unit = pcd_unit;
 	int	b, i;
 	char	rd_cmd[12] = {0xa8,0,0,0,0,0,0,0,0,1,0,0};
+	long    saved_flags;
 
 	pcd_bufblk = pcd_sector / 4;
         b = pcd_bufblk;
@@ -757,13 +758,13 @@
 	   b = b >> 8;
 	}
 
-
 	if (pcd_command(unit,rd_cmd,2048,"read block")) {
 		pcd_bufblk = -1; 
+		spin_lock_irqsave(&io_request_lock,saved_flags);
 		pcd_busy = 0;
-		cli();
 		end_request(0);
 		do_pcd_request();
+		spin_unlock_irqrestore(&io_request_lock,saved_flags);
 		return;
 	}
 
@@ -773,17 +774,23 @@
 
 }
 
-static void do_pcd_read( int unit )
+static void do_pcd_read( void )
 
-{	pcd_busy = 1;
+
+{	int	unit = pcd_unit;
+	long    saved_flags;
+
+	pcd_busy = 1;
 	pcd_retries = 0;
 	pcd_transfer();
 	if (!pcd_count) {
+		spin_lock_irqsave(&io_request_lock,saved_flags);
 		end_request(1);
 		pcd_busy = 0;
+		do_pcd_request();
+		spin_unlock_irqrestore(&io_request_lock,saved_flags);
 		return;
 	}
-	sti();
 
 	pi_do_claimed(PI,pcd_start);
 }
@@ -791,8 +798,7 @@
 static void do_pcd_read_drq( void )
 
 {	int	unit = pcd_unit;
-
-	sti();
+	long    saved_flags;
 
 	if (pcd_completion(unit,pcd_buffer,"read block")) {
                 if (pcd_retries < PCD_RETRIES) {
@@ -801,16 +807,20 @@
 			pi_do_claimed(PI,pcd_start);
                         return;
                         }
-		cli();
+		spin_lock_irqsave(&io_request_lock,saved_flags);
 		pcd_busy = 0;
 		pcd_bufblk = -1;
 		end_request(0);
 		do_pcd_request();
+		spin_unlock_irqrestore(&io_request_lock,saved_flags);
 		return;
 	}
 
-	do_pcd_read(unit);
+	do_pcd_read();
+	spin_lock_irqsave(&io_request_lock,saved_flags);
 	do_pcd_request();
+	spin_unlock_irqrestore(&io_request_lock,saved_flags); 
 }
 	
 /* end of pcd.c */
+
diff -u --recursive --new-file v2.1.102/linux/drivers/block/paride/pd.c linux/drivers/block/paride/pd.c
--- v2.1.102/linux/drivers/block/paride/pd.c	Thu May  7 22:51:48 1998
+++ linux/drivers/block/paride/pd.c	Thu May 14 19:11:48 1998
@@ -1,6 +1,6 @@
 /* 
-        pd.c    (c) 1997  Grant R. Guenther <grant@torque.net>
-                          Under the terms of the GNU public license.
+        pd.c    (c) 1997-8  Grant R. Guenther <grant@torque.net>
+                            Under the terms of the GNU public license.
 
         This is the high-level driver for parallel port IDE hard
         drives based on chips supported by the paride module.
@@ -14,9 +14,9 @@
         parameters are adjustable:
  
 	    drive0  	These four arguments can be arrays of	    
-	    drive1	1-7 integers as follows:
+	    drive1	1-8 integers as follows:
 	    drive2
-	    drive3	<prt>,<pro>,<uni>,<mod>,<geo>,<sby>,<dly>
+	    drive3	<prt>,<pro>,<uni>,<mod>,<geo>,<sby>,<dly>,<slv>
 
 			Where,
 
@@ -54,6 +54,11 @@
 			set this to a small integer, the larger it is
 			the slower the port i/o.  In some cases, setting
 			this to zero will speed up the device. (default -1)
+
+		<slv>   IDE disks can be jumpered to master or slave.
+                        Set this to 0 to choose the master drive, 1 to
+                        choose the slave, -1 (the default) to choose the
+                        first drive found.
 			
 
             major       You may use this parameter to overide the
@@ -100,16 +105,18 @@
 
 	1.01	GRG 1997.01.24	Restored pd_reset()
 				Added eject ioctl
+	1.02    GRG 1998.05.06  SMP spinlock changes, 
+				Added slave support
 
 */
 
-#define PD_VERSION      "1.01"
+#define PD_VERSION      "1.02"
 #define PD_MAJOR	45
 #define PD_NAME		"pd"
 #define PD_UNITS	4
 
 /* Here are things one can override from the insmod command.
-   Most are autoprobed by paride unless set here.  Verbose is on
+   Most are autoprobed by paride unless set here.  Verbose is off
    by default.
 
 */
@@ -121,12 +128,12 @@
 static int      nice = 0;
 static int      disable = 0;
 
-static int drive0[7] = {0,0,0,-1,0,1,-1};
-static int drive1[7] = {0,0,0,-1,0,1,-1};
-static int drive2[7] = {0,0,0,-1,0,1,-1};
-static int drive3[7] = {0,0,0,-1,0,1,-1};
+static int drive0[8] = {0,0,0,-1,0,1,-1,-1};
+static int drive1[8] = {0,0,0,-1,0,1,-1,-1};
+static int drive2[8] = {0,0,0,-1,0,1,-1,-1};
+static int drive3[8] = {0,0,0,-1,0,1,-1,-1};
 
-static int (*drives[4])[7] = {&drive0,&drive1,&drive2,&drive3};
+static int (*drives[4])[8] = {&drive0,&drive1,&drive2,&drive3};
 static int pd_drive_count;
 
 #define D_PRT	0
@@ -136,6 +143,7 @@
 #define D_GEO	4
 #define D_SBY	5
 #define D_DLY	6
+#define D_SLV   7
 
 #define	DU		(*drives[unit])
 
@@ -150,16 +158,17 @@
 #include <linux/hdreg.h>
 #include <linux/cdrom.h>	/* for the eject ioctl */
 
+#include <asm/spinlock.h>
 #include <asm/uaccess.h>
 
 #ifndef MODULE
 
 #include "setup.h"
 
-static STT pd_stt[7] = {{"drive0",7,drive0},
-		        {"drive1",7,drive1},
-		        {"drive2",7,drive2},
-		        {"drive3",7,drive3},
+static STT pd_stt[7] = {{"drive0",8,drive0},
+		        {"drive1",8,drive1},
+		        {"drive2",8,drive2},
+		        {"drive3",8,drive3},
 			{"disable",1,&disable},
 		        {"cluster",1,&cluster},
 		        {"nice",1,&nice}};
@@ -176,10 +185,10 @@
 MODULE_PARM(name,"s");
 MODULE_PARM(cluster,"i");
 MODULE_PARM(nice,"i");
-MODULE_PARM(drive0,"1-7i");
-MODULE_PARM(drive1,"1-7i");
-MODULE_PARM(drive2,"1-7i");
-MODULE_PARM(drive3,"1-7i");
+MODULE_PARM(drive0,"1-8i");
+MODULE_PARM(drive1,"1-8i");
+MODULE_PARM(drive2,"1-8i");
+MODULE_PARM(drive3,"1-8i");
 
 #include "paride.h"
 
@@ -258,7 +267,9 @@
 static int pd_revalidate(kdev_t dev);
 static int pd_detect(void);
 static void do_pd_read(void);
+static void do_pd_read_start(void);
 static void do_pd_write(void);
+static void do_pd_write_start(void);
 static void do_pd_read_drq( void );
 static void do_pd_write_done( void );
 
@@ -282,6 +293,7 @@
 	int heads;                	/* physical geometry */
 	int sectors;
 	int cylinders;
+	int drive;			/* master=0 slave=1 */
 	int changed;			/* Have we seen a disk change ? */
 	int removable;			/* removable media device  ?  */
 	int standby;
@@ -363,6 +375,7 @@
 		PD.access = 0;
 		PD.changed = 1;
 		PD.capacity = 0;
+		PD.drive = DU[D_SLV];
 		PD.present = 0;
 		j = 0;
 		while ((j < PD_NAMELEN-2) && (PD.name[j]=name[j])) j++;
@@ -646,6 +659,8 @@
 #define	WR(c,r,v)	pi_write_regr(PI,c,r,v)
 #define	RR(c,r)		(pi_read_regr(PI,c,r))
 
+#define DRIVE		(0xa0+0x10*PD.drive)
+
 /*  ide command interface */
 
 static void pd_print_error( int unit, char * msg, int status )
@@ -657,7 +672,7 @@
 	printk("\n");
 }
 
-static void pd_reset( int unit )
+static void pd_reset( int unit )    /* called only for MASTER drive */
 
 {       pi_connect(PI);
 	WR(1,6,4);
@@ -691,7 +706,7 @@
 			     int c0, int c1, int func )
 
 {
-        WR(0,6,0xa0+h);
+        WR(0,6,DRIVE+h);
         WR(0,1,0);                /* the IDE task file */
         WR(0,2,n);
         WR(0,3,s);
@@ -793,10 +808,16 @@
 {       int	j;
 	char id[PD_ID_LEN+1];
 
-	pd_reset(unit);
+/* WARNING:  here there may be dragons.  reset() applies to both drives,
+   but we call it only on probing the MASTER. This should allow most
+   common configurations to work, but be warned that a reset can clear
+   settings on the SLAVE drive.
+*/ 
+
+	if (PD.drive == 0) pd_reset(unit);
 
         pi_connect(PI);
-	WR(0,6,0xa0);
+	WR(0,6,DRIVE);
         pd_wait_for(unit,0,DBMSG("before IDENT"));  
         pd_send_command(unit,1,0,0,0,0,IDE_IDENTIFY);
 
@@ -818,8 +839,10 @@
 
         PD.removable = (word_val(0) & 0x80);
  
-        printk("%s: %s, %d blocks [%dM], (%d/%d/%d), %s media\n",
-                    PD.name,id,PD.capacity,PD.capacity/2048,
+        printk("%s: %s, %s, %d blocks [%dM], (%d/%d/%d), %s media\n",
+                    PD.name,id,
+		    PD.drive?"slave":"master",
+		    PD.capacity,PD.capacity/2048,
                     PD.cylinders,PD.heads,PD.sectors,
                     PD.removable?"removable":"fixed");
 
@@ -832,36 +855,39 @@
         return 1;
 }
 
+static int pd_probe_drive( int unit )
+
+{	if (PD.drive == -1) {
+	  for (PD.drive=0;PD.drive<=1;PD.drive++)
+	     if (pd_identify(unit)) return 1;
+	  return 0;
+	  }
+	else return pd_identify(unit);
+}
+
 static int pd_detect( void )
 
-{       long 	flags;
-	int	k, unit;
+{       int	k, unit;
 
 	k = 0;
 	if (pd_drive_count == 0) {  /* nothing spec'd - so autoprobe for 1 */
 	    unit = 0;
 	    if (pi_init(PI,1,-1,-1,-1,-1,-1,pd_scratch,
 	             PI_PD,verbose,PD.name)) {
-		save_flags(flags);
-		sti();
-		if (pd_identify(unit)) {
+		if (pd_probe_drive(unit)) {
 			PD.present = 1;
 			k = 1;
 		} else pi_release(PI);
-		restore_flags(flags);
 	    }
 
    	} else for (unit=0;unit<PD_UNITS;unit++) if (DU[D_PRT])
 	    if (pi_init(PI,0,DU[D_PRT],DU[D_MOD],DU[D_UNI],
 			DU[D_PRO],DU[D_DLY],pd_scratch,
 			PI_PD,verbose,PD.name)) {
-                save_flags(flags);
-                sti();
-                if (pd_identify(unit)) {
+                if (pd_probe_drive(unit)) {
                         PD.present = 1;
                         k = unit+1;
                 } else pi_release(PI);
-                restore_flags(flags);
             }
 
 /* We lie about the number of drives found, as the generic partition
@@ -926,18 +952,24 @@
         pd_buf = CURRENT->buffer;
         pd_retries = 0;
 
+	pd_busy = 1;
         if (pd_cmd == READ) pi_do_claimed(PI,do_pd_read);
         else if (pd_cmd == WRITE) pi_do_claimed(PI,do_pd_write);
-        else {  end_request(0);
+        else {  pd_busy = 0;
+		end_request(0);
                 goto repeat;
         }
 }
 
 static void pd_next_buf( int unit )
 
-{	cli();
+{	long	saved_flags;
+
+	spin_lock_irqsave(&io_request_lock,saved_flags);
 	end_request(1);
-	if (!pd_run) { sti(); return; }
+	if (!pd_run) {  spin_unlock_irqrestore(&io_request_lock,saved_flags);
+			return; 
+	}
 	
 /* paranoia */
 
@@ -951,29 +983,34 @@
 
 	pd_count = CURRENT->nr_sectors;
 	pd_buf = CURRENT->buffer;
-	sti();
+	spin_unlock_irqrestore(&io_request_lock,saved_flags);
 }
 
 static void do_pd_read( void )
 
+{	ps_set_intr(do_pd_read_start,0,0,nice);
+}
+
+static void do_pd_read_start( void )
+ 
 {       int	unit = pd_unit;
+	long    saved_flags;
 
 	pd_busy = 1;
 
-        sti();
-
         pi_connect(PI);
         if (pd_wait_for(unit,STAT_READY,"do_pd_read") & STAT_ERR) {
                 pi_disconnect(PI);
                 if (pd_retries < PD_MAX_RETRIES) {
                         pd_retries++;
-                        pi_do_claimed(PI,do_pd_read);
+                        pi_do_claimed(PI,do_pd_read_start);
 			return;
                 }
+		spin_lock_irqsave(&io_request_lock,saved_flags);
                 end_request(0);
                 pd_busy = 0;
-                cli();
                 do_pd_request();
+		spin_unlock_irqrestore(&io_request_lock,saved_flags);
                 return;
         }
         pd_ide_command(unit,IDE_READ,pd_block,pd_run);
@@ -983,21 +1020,21 @@
 static void do_pd_read_drq( void )
 
 {       int	unit = pd_unit;
-
-	sti();
+	long    saved_flags;
 
 	while (1) {
             if (pd_wait_for(unit,STAT_DRQ,"do_pd_read_drq") & STAT_ERR) {
                 pi_disconnect(PI);
                 if (pd_retries < PD_MAX_RETRIES) {
                         pd_retries++;
-                        pi_do_claimed(PI,do_pd_read);
+                        pi_do_claimed(PI,do_pd_read_start);
                         return;
                 }
+		spin_lock_irqsave(&io_request_lock,saved_flags);
                 end_request(0);
                 pd_busy = 0;
-                cli();
                 do_pd_request();
+		spin_unlock_irqrestore(&io_request_lock,saved_flags);
                 return;
             }
             pi_read_block(PI,pd_buf,512);
@@ -1008,32 +1045,38 @@
 	    if (!pd_count) pd_next_buf(unit);
         }
         pi_disconnect(PI);
+	spin_lock_irqsave(&io_request_lock,saved_flags);
         end_request(1);
         pd_busy = 0;
-        cli();
         do_pd_request();
+	spin_unlock_irqrestore(&io_request_lock,saved_flags);
 }
 
 static void do_pd_write( void )
 
+{	 ps_set_intr(do_pd_write_start,0,0,nice);
+}
+
+static void do_pd_write_start( void )
+
 {       int 	unit = pd_unit;
+	long    saved_flags;
 
 	pd_busy = 1;
 
-        sti();
-
         pi_connect(PI);
         if (pd_wait_for(unit,STAT_READY,"do_pd_write") & STAT_ERR) {
                 pi_disconnect(PI);
                 if (pd_retries < PD_MAX_RETRIES) {
                         pd_retries++;
-			pi_do_claimed(PI,do_pd_write);
+			pi_do_claimed(PI,do_pd_write_start);
                         return;
                 }
+		spin_lock_irqsave(&io_request_lock,saved_flags);
                 end_request(0);
                 pd_busy = 0;
-                cli();
                 do_pd_request();
+		spin_unlock_irqrestore(&io_request_lock,saved_flags);
                 return;
         }
         pd_ide_command(unit,IDE_WRITE,pd_block,pd_run);
@@ -1042,14 +1085,15 @@
                 pi_disconnect(PI);
                 if (pd_retries < PD_MAX_RETRIES) {
                         pd_retries++;
-                        pi_do_claimed(PI,do_pd_write);
+                        pi_do_claimed(PI,do_pd_write_start);
                         return;
                 }
+		spin_lock_irqsave(&io_request_lock,saved_flags);
                 end_request(0);
                 pd_busy = 0;
-                cli();
                 do_pd_request();
-                return;
+                spin_unlock_irqrestore(&io_request_lock,saved_flags);
+		return;
             }
             pi_write_block(PI,pd_buf,512);
 	    pd_count--; pd_run--;
@@ -1064,26 +1108,28 @@
 static void do_pd_write_done( void )
 
 {       int	unit = pd_unit;
+	long    saved_flags;
 
-	sti();
         if (pd_wait_for(unit,STAT_READY,"do_pd_write_done") & STAT_ERR) {
                 pi_disconnect(PI);
                 if (pd_retries < PD_MAX_RETRIES) {
                         pd_retries++;
-                        pi_do_claimed(PI,do_pd_write);
+                        pi_do_claimed(PI,do_pd_write_start);
                         return;
                 }
+		spin_lock_irqsave(&io_request_lock,saved_flags);
                 end_request(0);
                 pd_busy = 0;
-                cli();
                 do_pd_request();
+		spin_unlock_irqrestore(&io_request_lock,saved_flags);
                 return;
         }
         pi_disconnect(PI);
+	spin_lock_irqsave(&io_request_lock,saved_flags);
         end_request(1);
         pd_busy = 0;
-        cli();
         do_pd_request();
+	spin_unlock_irqrestore(&io_request_lock,saved_flags);
 }
 
 /* end of pd.c */
diff -u --recursive --new-file v2.1.102/linux/drivers/block/paride/pf.c linux/drivers/block/paride/pf.c
--- v2.1.102/linux/drivers/block/paride/pf.c	Thu May  7 22:51:48 1998
+++ linux/drivers/block/paride/pf.c	Thu May 14 19:11:48 1998
@@ -1,6 +1,6 @@
 /* 
-        pf.c    (c) 1997  Grant R. Guenther <grant@torque.net>
-                          Under the terms of the GNU public license.
+        pf.c    (c) 1997-8  Grant R. Guenther <grant@torque.net>
+                            Under the terms of the GNU public license.
 
         This is the high-level driver for parallel port ATAPI disk
         drives based on chips supported by the paride module.
@@ -83,8 +83,8 @@
 	    nice        This parameter controls the driver's use of
 			idle CPU time, at the expense of some speed.
 
-        If this driver is built into the kernel, you can use kernel
-        the following command line parameters, with the same values
+        If this driver is built into the kernel, you can use the
+        following command line parameters, with the same values
         as the corresponding module parameters listed above:
 
             pf.drive0
@@ -99,13 +99,23 @@
 
 */
 
-#define PF_VERSION      "1.0"
+/* Changes:
+
+	1.01	GRG 1998.05.03  Changes for SMP.  Eliminate sti().
+				Fix for drives that don't clear STAT_ERR
+			        until after next CDB delivered.
+				Small change in pf_completion to round
+				up transfer size.
+
+*/
+
+#define PF_VERSION      "1.01"
 #define PF_MAJOR	47
 #define PF_NAME		"pf"
 #define PF_UNITS	4
 
 /* Here are things one can override from the insmod command.
-   Most are autoprobed by paride unless set here.  Verbose is on
+   Most are autoprobed by paride unless set here.  Verbose is off
    by default.
 
 */
@@ -146,6 +156,7 @@
 #include <linux/genhd.h>
 #include <linux/hdreg.h>
 #include <linux/cdrom.h>
+#include <asm/spinlock.h>
 
 #include <asm/uaccess.h>
 
@@ -238,7 +249,9 @@
 
 static int pf_detect(void);
 static void do_pf_read(void);
+static void do_pf_read_start(void);
 static void do_pf_write(void);
+static void do_pf_write_start(void);
 static void do_pf_read_drq( void );
 static void do_pf_write_done( void );
 
@@ -562,7 +575,7 @@
         WR(0,5,dlen / 256);
         WR(0,7,0xa0);          /* ATAPI packet command */
 
-        if (pf_wait(unit,STAT_BUSY,STAT_DRQ|STAT_ERR,fun,"command DRQ")) {
+        if (pf_wait(unit,STAT_BUSY,STAT_DRQ,fun,"command DRQ")) {
                 pi_disconnect(PI);
                 return -1;
         }
@@ -586,7 +599,7 @@
 			fun,"completion");
 
         if ((RR(0,2)&2) && (RR(0,7)&STAT_DRQ)) { 
-                n = (RR(0,4)+256*RR(0,5));
+                n = (((RR(0,4)+256*RR(0,5))+3)&0xfffc);
                 pi_read_block(PI,buf,n);
         }
 
@@ -661,23 +674,17 @@
 
 {	int	i, k, flg;
 	int	expect[5] = {1,1,1,0x14,0xeb};
-	long	flags;
 
 	pi_connect(PI);
 	WR(0,6,DRIVE);
 	WR(0,7,8);
 
-	save_flags(flags);
-	sti();
-
 	pf_sleep(2);
 
         k = 0;
         while ((k++ < PF_RESET_TMO) && (RR(1,6)&STAT_BUSY))
                 pf_sleep(10);
 
-	restore_flags(flags);
-
 	flg = 1;
 	for(i=0;i<5;i++) flg &= (RR(0,i+1) == expect[i]);
 
@@ -906,19 +913,24 @@
         pf_buf = CURRENT->buffer;
         pf_retries = 0;
 
-
+	pf_busy = 1;
         if (pf_cmd == READ) pi_do_claimed(PI,do_pf_read);
         else if (pf_cmd == WRITE) pi_do_claimed(PI,do_pf_write);
-        else {  end_request(0);
+        else {  pf_busy = 0;
+		end_request(0);
                 goto repeat;
         }
 }
 
 static void pf_next_buf( int unit )
 
-{	cli();
+{	long	saved_flags;
+
+	spin_lock_irqsave(&io_request_lock,saved_flags);
 	end_request(1);
-	if (!pf_run) { sti(); return; }
+	if (!pf_run) { spin_unlock_irqrestore(&io_request_lock,saved_flags);
+		       return; 
+	}
 	
 /* paranoia */
 
@@ -932,39 +944,46 @@
 
 	pf_count = CURRENT->nr_sectors;
 	pf_buf = CURRENT->buffer;
-	sti();
+	spin_unlock_irqrestore(&io_request_lock,saved_flags);
 }
 
 static void do_pf_read( void )
 
+/* detach from the calling context - in case the spinlock is held */
+
+{	ps_set_intr(do_pf_read_start,0,0,nice);
+}
+
+static void do_pf_read_start( void )
+
 {       int	unit = pf_unit;
+	long	saved_flags;
 
 	pf_busy = 1;
 
-        sti();
-
 	if (pf_start(unit,ATAPI_READ_10,pf_block,pf_run)) {
                 pi_disconnect(PI);
                 if (pf_retries < PF_MAX_RETRIES) {
                         pf_retries++;
-                        pi_do_claimed(PI,do_pf_read);
+                        pi_do_claimed(PI,do_pf_read_start);
 			return;
                 }
+		spin_lock_irqsave(&io_request_lock,saved_flags);
                 end_request(0);
                 pf_busy = 0;
-                cli();
                 do_pf_request();
+		spin_unlock_irqrestore(&io_request_lock,saved_flags);
                 return;
         }
-	pf_mask=STAT_DRQ;
+	pf_mask = STAT_DRQ;
         ps_set_intr(do_pf_read_drq,pf_ready,PF_TMO,nice);
 }
 
 static void do_pf_read_drq( void )
 
 {       int	unit = pf_unit;
-
-	sti();
+	long	saved_flags;
+	
 	while (1) {
             if (pf_wait(unit,STAT_BUSY,STAT_DRQ|STAT_ERR,
 			"read block","completion") & STAT_ERR) {
@@ -972,13 +991,14 @@
                 if (pf_retries < PF_MAX_RETRIES) {
 			pf_req_sense(unit,0);
                         pf_retries++;
-                        pi_do_claimed(PI,do_pf_read);
+                        pi_do_claimed(PI,do_pf_read_start);
                         return;
                 }
+		spin_lock_irqsave(&io_request_lock,saved_flags);
                 end_request(0);
                 pf_busy = 0;
-                cli();
                 do_pf_request();
+		spin_unlock_irqrestore(&io_request_lock,saved_flags);
                 return;
             }
             pi_read_block(PI,pf_buf,512);
@@ -989,31 +1009,37 @@
 	    if (!pf_count) pf_next_buf(unit);
         }
         pi_disconnect(PI);
+	spin_lock_irqsave(&io_request_lock,saved_flags); 
         end_request(1);
         pf_busy = 0;
-        cli();
         do_pf_request();
+	spin_unlock_irqrestore(&io_request_lock,saved_flags);
 }
 
 static void do_pf_write( void )
 
+{	ps_set_intr(do_pf_write_start,0,0,nice);
+}
+
+static void do_pf_write_start( void )
+
 {       int	unit = pf_unit;
+	long	saved_flags;
 
 	pf_busy = 1;
 
-        sti();
-
 	if (pf_start(unit,ATAPI_WRITE_10,pf_block,pf_run)) {
                 pi_disconnect(PI);
                 if (pf_retries < PF_MAX_RETRIES) {
                         pf_retries++;
-                        pi_do_claimed(PI,do_pf_write);
+                        pi_do_claimed(PI,do_pf_write_start);
 			return;
                 }
+		spin_lock_irqsave(&io_request_lock,saved_flags);
                 end_request(0);
                 pf_busy = 0;
-                cli();
                 do_pf_request();
+		spin_unlock_irqrestore(&io_request_lock,saved_flags);
                 return;
         }
 
@@ -1023,13 +1049,14 @@
                 pi_disconnect(PI);
                 if (pf_retries < PF_MAX_RETRIES) {
                         pf_retries++;
-                        pi_do_claimed(PI,do_pf_write);
+                        pi_do_claimed(PI,do_pf_write_start);
                         return;
                 }
+		spin_lock_irqsave(&io_request_lock,saved_flags);
                 end_request(0);
                 pf_busy = 0;
-                cli();
                 do_pf_request();
+		spin_unlock_irqrestore(&io_request_lock,saved_flags);
                 return;
             }
             pi_write_block(PI,pf_buf,512);
@@ -1046,26 +1073,28 @@
 static void do_pf_write_done( void )
 
 {       int	unit = pf_unit;
+	long	saved_flags;
 
-	sti();
         if (pf_wait(unit,STAT_BUSY,0,"write block","done") & STAT_ERR) {
                 pi_disconnect(PI);
                 if (pf_retries < PF_MAX_RETRIES) {
                         pf_retries++;
-			pi_do_claimed(PI,do_pf_write);
+			pi_do_claimed(PI,do_pf_write_start);
                         return;
                 }
+		spin_lock_irqsave(&io_request_lock,saved_flags);
                 end_request(0);
                 pf_busy = 0;
-                cli();
                 do_pf_request();
+		spin_unlock_irqrestore(&io_request_lock,saved_flags);
                 return;
         }
         pi_disconnect(PI);
+	spin_lock_irqsave(&io_request_lock,saved_flags);
         end_request(1);
         pf_busy = 0;
-        cli();
         do_pf_request();
+	spin_unlock_irqrestore(&io_request_lock,saved_flags);
 }
 
 /* end of pf.c */
diff -u --recursive --new-file v2.1.102/linux/drivers/block/paride/pseudo.h linux/drivers/block/paride/pseudo.h
--- v2.1.102/linux/drivers/block/paride/pseudo.h	Sun Dec 28 12:05:45 1997
+++ linux/drivers/block/paride/pseudo.h	Thu May 14 19:11:48 1998
@@ -1,6 +1,6 @@
 /* 
-        pseudo.h    (c) 1997  Grant R. Guenther <grant@torque.net>
-                              Under the terms of the GNU public license.
+        pseudo.h    (c) 1997-8  Grant R. Guenther <grant@torque.net>
+                                Under the terms of the GNU public license.
 
 	This is the "pseudo-interrupt" logic for parallel port drivers.
 
@@ -22,6 +22,14 @@
 
 */
 
+/* Changes:
+
+	1.01	1998.05.03	Switched from cli()/sti() to spinlocks
+
+*/
+	
+#define PS_VERSION	"1.01"
+
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/tqueue.h>
@@ -37,6 +45,8 @@
 static int ps_timer_active = 0;
 static int ps_tq_active = 0;
 
+spinlock_t ps_spinlock = SPIN_LOCK_UNLOCKED;
+
 static struct timer_list ps_timer = {0,0,0,0,ps_timer_int};
 static struct tq_struct ps_tq = {0,0,ps_tq_int,NULL};
 
@@ -46,8 +56,7 @@
 
 {       long	flags;
 
-	save_flags(flags); 
-	cli();
+	spin_lock_irqsave(&ps_spinlock,flags);
 
 	ps_continuation = continuation;
 	ps_ready = ready;
@@ -69,7 +78,7 @@
                 add_timer(&ps_timer);
         }
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&ps_spinlock,flags);
 }
 
 static void ps_tq_int( void *data )
@@ -77,8 +86,7 @@
 {       void (*con)(void);
 	long flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&ps_spinlock,flags);
 
         con = ps_continuation;
 
@@ -89,12 +97,12 @@
         ps_tq_active = 0;
 
         if (!con) {
-		restore_flags(flags);
+		spin_unlock_irqrestore(&ps_spinlock,flags);
 		return;
 	}
-        if (ps_ready() || (jiffies >= ps_timeout)) {
+        if (!ps_ready || ps_ready() || (jiffies >= ps_timeout)) {
                 ps_continuation = NULL;
-		restore_flags(flags);
+        	spin_unlock_irqrestore(&ps_spinlock,flags);
                 con();
                 return;
                 }
@@ -105,7 +113,7 @@
 
         ps_tq_active = 1;
 	queue_task(&ps_tq,&tq_scheduler);
-	restore_flags(flags);
+        spin_unlock_irqrestore(&ps_spinlock,flags);
 }
 
 static void ps_timer_int( unsigned long data)
@@ -113,25 +121,24 @@
 {       void (*con)(void);
 	long	flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&ps_spinlock,flags);
 
 	con = ps_continuation;
 	ps_timer_active = 0;
 	if (!con) {
-		restore_flags(flags);
+	        spin_unlock_irqrestore(&ps_spinlock,flags);
 		return;
 	}
-        if (ps_ready() || (jiffies >= ps_timeout)) {
+        if (!ps_ready || ps_ready() || (jiffies >= ps_timeout)) {
                 ps_continuation = NULL;
-		restore_flags(flags);
+	        spin_unlock_irqrestore(&ps_spinlock,flags);
                 con();
 		return;
 		}
 	ps_timer_active = 1;
         ps_timer.expires = jiffies;
         add_timer(&ps_timer);
-	restore_flags(flags);
+        spin_unlock_irqrestore(&ps_spinlock,flags);
 }
 
 /* end of pseudo.h */
diff -u --recursive --new-file v2.1.102/linux/drivers/block/paride/pt.c linux/drivers/block/paride/pt.c
--- v2.1.102/linux/drivers/block/paride/pt.c	Thu Feb 12 20:56:05 1998
+++ linux/drivers/block/paride/pt.c	Thu May 14 19:11:48 1998
@@ -90,7 +90,16 @@
 
 */
 
-#define PT_VERSION      "1.0"
+/*   Changes:
+
+	1.01	GRG 1998.05.06	Round up transfer size, fix ready_wait,
+			        loosed interpretation of ATAPI standard
+				for clearing error status.
+				Eliminate sti();
+
+*/
+
+#define PT_VERSION      "1.01"
 #define PT_MAJOR	96
 #define PT_NAME		"pt"
 #define PT_UNITS	4
@@ -383,7 +392,7 @@
         WR(0,5,dlen / 256);
         WR(0,7,0xa0);          /* ATAPI packet command */
 
-        if (pt_wait(unit,STAT_BUSY,STAT_DRQ|STAT_ERR,fun,"command DRQ")) {
+        if (pt_wait(unit,STAT_BUSY,STAT_DRQ,fun,"command DRQ")) {
                 pi_disconnect(PI);
                 return -1;
         }
@@ -407,7 +416,7 @@
 			fun,"completion");
 
         if (RR(0,7)&STAT_DRQ) { 
-           n = (RR(0,4)+256*RR(0,5));
+           n = (((RR(0,4)+256*RR(0,5))+3)&0xfffc);
 	   p = RR(0,2)&3;
 	   if (p == 0) pi_write_block(PI,buf,n);
 	   if (p == 2) pi_read_block(PI,buf,n);
@@ -512,23 +521,17 @@
 
 {	int	i, k, flg;
 	int	expect[5] = {1,1,1,0x14,0xeb};
-	long	flags;
 
 	pi_connect(PI);
 	WR(0,6,DRIVE);
 	WR(0,7,8);
 
-	save_flags(flags);
-	sti();
-
 	pt_sleep(2);
 
         k = 0;
         while ((k++ < PT_RESET_TMO) && (RR(1,6)&STAT_BUSY))
                 pt_sleep(10);
 
-	restore_flags(flags);
-
 	flg = 1;
 	for(i=0;i<5;i++) flg &= (RR(0,i+1) == expect[i]);
 
@@ -554,7 +557,7 @@
 	  pt_atapi(unit,tr_cmd,0,NULL,DBMSG("test unit ready"));
 	  p = PT.last_sense;
 	  if (!p) return 0;
-	  if (!((p == 0x010402)||((p & 0xff) == 6))) return p;
+	  if (!(((p & 0xffff) == 0x0402)||((p & 0xff) == 6))) return p;
 	  k++;
           pt_sleep(100);
 	}
diff -u --recursive --new-file v2.1.102/linux/drivers/block/paride/setup.h linux/drivers/block/paride/setup.h
--- v2.1.102/linux/drivers/block/paride/setup.h	Sun Dec 28 12:05:45 1997
+++ linux/drivers/block/paride/setup.h	Thu May 14 19:11:48 1998
@@ -1,12 +1,18 @@
 /*
-	setup.h	   (c) 1997 Grant R. Guenther <grant@torque.net>
-		            Under the terms of the GNU public license.
+	setup.h	   (c) 1997-8   Grant R. Guenther <grant@torque.net>
+		                Under the terms of the GNU public license.
 
         This is a table driven setup function for kernel modules
         using the module.variable=val,... command line notation.
 
 */
 
+/* Changes:
+
+	1.01	GRG 1998.05.05	Allow negative and defaulted values
+
+*/
+
 #include <linux/ctype.h>
 #include <linux/string.h>
 
@@ -29,7 +35,7 @@
 
 static void generic_setup( STT t[], int n, char *ss )
 
-{	int	j,k;
+{	int	j,k, sgn;
 
 	k = 0;
 	for (j=0;j<n;j++) {
@@ -47,10 +53,17 @@
 	ss += (k+1);
 
 	k = 0;
-	while (ss && isdigit(*ss) && (k < t[j].size)) {
-		t[j].iv[k++] = simple_strtoul(ss,NULL,0);
+	while (ss && (k < t[j].size)) {
+		if (!*ss) break;
+		sgn = 1;
+		if (*ss == '-') { ss++; sgn = -1; }
+		if (!*ss) break;
+		if (isdigit(*ss))
+		  t[j].iv[k] = sgn * simple_strtoul(ss,NULL,0);
+		k++; 
 		if ((ss = strchr(ss,',')) != NULL) ss++;
 	}
 }
 
 /* end of setup.h */
+
diff -u --recursive --new-file v2.1.102/linux/drivers/block/xd.c linux/drivers/block/xd.c
--- v2.1.102/linux/drivers/block/xd.c	Fri May  8 23:14:47 1998
+++ linux/drivers/block/xd.c	Thu May 14 18:54:46 1998
@@ -872,13 +872,14 @@
 			xd_info[drive].ecc = 0x0B;
 #endif /* 0 */
 		}
-		if (!wd_1002)
+		if (!wd_1002) {
 			if (use_jumper_geo)
 				xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,
 					geometry_table[n][2],geometry_table[n][3],0x0B);
 			else
 				xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,
 					((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]);
+		}
 	/* 1002 based RLL controler requests converted adressing, but reports physical 
 	   (physical 26 sec., logical 17 sec.) 
 	   1004 based ???? */
diff -u --recursive --new-file v2.1.102/linux/drivers/cdrom/sbpcd.c linux/drivers/cdrom/sbpcd.c
--- v2.1.102/linux/drivers/cdrom/sbpcd.c	Thu May  7 22:51:49 1998
+++ linux/drivers/cdrom/sbpcd.c	Thu May 14 18:39:01 1998
@@ -5667,8 +5667,10 @@
 		i=ResponseStatus();  /* returns orig. status or p_busy_new */
 		if (famT_drive) i=ResponseStatus();  /* returns orig. status or p_busy_new */
 		if (i<0)
+		{
 			if (i!=-402)
 				msg(DBG_INF,"init: ResponseStatus returns %d.\n",i);
+		}
 		else
 		{
 			if (st_check)
diff -u --recursive --new-file v2.1.102/linux/drivers/char/bttv.c linux/drivers/char/bttv.c
--- v2.1.102/linux/drivers/char/bttv.c	Thu May  7 22:51:49 1998
+++ linux/drivers/char/bttv.c	Mon May 18 13:48:53 1998
@@ -1592,8 +1592,7 @@
 			        if ((unsigned int)v.base>=0xe0000000UL)
 			                btv->win.vidadr=(uint)v.base;
 				else 
-				  btv->win.vidadr=PAGE_OFFSET|
-				    uvirt_to_bus((uint)v.base);
+				  btv->win.vidadr= __va(uvirt_to_bus((uint)v.base));
 			btv->win.sheight=v.height;
 			btv->win.swidth=v.width;
 			btv->win.bpp=v.depth/8;
diff -u --recursive --new-file v2.1.102/linux/drivers/char/console.c linux/drivers/char/console.c
--- v2.1.102/linux/drivers/char/console.c	Thu May  7 22:51:49 1998
+++ linux/drivers/char/console.c	Thu May 14 18:41:17 1998
@@ -1766,11 +1766,12 @@
 						set_mode(currcons,0);
 						continue;
 					case 'n':
-						if (!ques)
+						if (!ques) {
 							if (par[0] == 5)
 								status_report(tty);
 							else if (par[0] == 6)
 								cursor_report(currcons,tty);
+						}
 						continue;
 				}
 				if (ques) {
diff -u --recursive --new-file v2.1.102/linux/drivers/char/esp.c linux/drivers/char/esp.c
--- v2.1.102/linux/drivers/char/esp.c	Thu May  7 22:51:49 1998
+++ linux/drivers/char/esp.c	Thu May 14 18:41:40 1998
@@ -2381,13 +2381,15 @@
 	
 	init_bh(ESP_BH, do_serial_bh);
 
-	for (i = 0; i < NR_PRIMARY; i++)
-		if (irq[i] != 0)
+	for (i = 0; i < NR_PRIMARY; i++) {
+		if (irq[i] != 0) {
 			if ((irq[i] < 2) || (irq[i] > 15) || (irq[i] == 6) ||
 			    (irq[i] == 8) || (irq[i] == 13))
 				irq[i] = 0;
 			else if (irq[i] == 2)
 				irq[i] = 9;
+		}
+	}
 
 	if ((dma != 1) && (dma != 3))
 		dma = 0;
diff -u --recursive --new-file v2.1.102/linux/drivers/isdn/hisax/hfc_2bds0.c linux/drivers/isdn/hisax/hfc_2bds0.c
--- v2.1.102/linux/drivers/isdn/hisax/hfc_2bds0.c	Wed Apr  1 20:11:50 1998
+++ linux/drivers/isdn/hisax/hfc_2bds0.c	Thu May 14 18:42:23 1998
@@ -1042,7 +1042,7 @@
 				del_timer(&cs->dbusytimer);
 			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
 				sched_event_D(cs, D_CLEARBUSY);
-			if (cs->tx_skb)
+			if (cs->tx_skb) {
 				if (cs->tx_skb->len) {
 					if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
 						hfc_fill_dfifo(cs);
@@ -1056,6 +1056,7 @@
 					cs->tx_cnt = 0;
 					cs->tx_skb = NULL;
 				}
+			}
 			if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
 				cs->tx_cnt = 0;
 				if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
diff -u --recursive --new-file v2.1.102/linux/drivers/isdn/hisax/hscx_irq.c linux/drivers/isdn/hisax/hscx_irq.c
--- v2.1.102/linux/drivers/isdn/hisax/hscx_irq.c	Wed Apr  1 20:11:50 1998
+++ linux/drivers/isdn/hisax/hscx_irq.c	Thu May 14 18:42:40 1998
@@ -219,7 +219,7 @@
 		}
 	}
 	if (val & 0x10) {	/* XPR */
-		if (bcs->hw.hscx.tx_skb)
+		if (bcs->hw.hscx.tx_skb) {
 			if (bcs->hw.hscx.tx_skb->len) {
 				hscx_fill_fifo(bcs);
 				return;
@@ -231,6 +231,7 @@
 				bcs->hw.hscx.count = 0; 
 				bcs->hw.hscx.tx_skb = NULL;
 			}
+		}
 		if ((bcs->hw.hscx.tx_skb = skb_dequeue(&bcs->squeue))) {
 			bcs->hw.hscx.count = 0;
 			test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
diff -u --recursive --new-file v2.1.102/linux/drivers/isdn/hisax/isac.c linux/drivers/isdn/hisax/isac.c
--- v2.1.102/linux/drivers/isdn/hisax/isac.c	Wed Apr  1 20:11:50 1998
+++ linux/drivers/isdn/hisax/isac.c	Thu May 14 18:43:27 1998
@@ -305,7 +305,7 @@
 			del_timer(&cs->dbusytimer);
 		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
 			isac_sched_event(cs, D_CLEARBUSY);
-		if (cs->tx_skb)
+		if (cs->tx_skb) {
 			if (cs->tx_skb->len) {
 				isac_fill_fifo(cs);
 				goto afterXPR;
@@ -314,6 +314,7 @@
 				cs->tx_cnt = 0;
 				cs->tx_skb = NULL;
 			}
+		}
 		if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
 			cs->tx_cnt = 0;
 			isac_fill_fifo(cs);
@@ -348,7 +349,7 @@
 			}
 #if ARCOFI_USE
 			if (v1 & 0x08) {
-				if (!cs->mon_rx)
+				if (!cs->mon_rx) {
 					if (!(cs->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
 						if (cs->debug & L1_DEB_WARN)
 							debugl1(cs, "ISAC MON RX out of memory!");
@@ -358,6 +359,7 @@
 						goto afterMONR0;
 					} else
 						cs->mon_rxp = 0;
+				}
 				if (cs->mon_rxp >= MAX_MON_FRAME) {
 					cs->mocr &= 0xf0;
 					cs->mocr |= 0x0a;
@@ -379,7 +381,7 @@
 			}
 		      afterMONR0:
 			if (v1 & 0x80) {
-				if (!cs->mon_rx)
+				if (!cs->mon_rx) {
 					if (!(cs->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
 						if (cs->debug & L1_DEB_WARN)
 							debugl1(cs, "ISAC MON RX out of memory!");
@@ -389,6 +391,7 @@
 						goto afterMONR1;
 					} else
 						cs->mon_rxp = 0;
+				}
 				if (cs->mon_rxp >= MAX_MON_FRAME) {
 					cs->mocr &= 0x0f;
 					cs->mocr |= 0xa0;
diff -u --recursive --new-file v2.1.102/linux/drivers/isdn/hisax/isdnl2.c linux/drivers/isdn/hisax/isdnl2.c
--- v2.1.102/linux/drivers/isdn/hisax/isdnl2.c	Wed Apr  1 20:11:50 1998
+++ linux/drivers/isdn/hisax/isdnl2.c	Thu May 14 18:43:55 1998
@@ -650,11 +650,12 @@
 			FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 4);
 			test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
 		} else {
-			if (!test_and_clear_bit(FLG_L3_INIT, &st->l2.flag))
+			if (!test_and_clear_bit(FLG_L3_INIT, &st->l2.flag)) {
 				if (st->l2.vs != st->l2.va)
 					discard_i_queue(st);
 				else
 					est = 0;
+			}
 			st->l2.vs = 0;
 			st->l2.va = 0;
 			st->l2.vr = 0;
diff -u --recursive --new-file v2.1.102/linux/drivers/isdn/hisax/teles3.c linux/drivers/isdn/hisax/teles3.c
--- v2.1.102/linux/drivers/isdn/hisax/teles3.c	Wed Apr  1 20:11:51 1998
+++ linux/drivers/isdn/hisax/teles3.c	Thu May 14 18:44:53 1998
@@ -216,12 +216,13 @@
 	if (cs->typ == ISDN_CTYPE_TELESPCMCIA)
 		release_region(cs->hw.teles3.cfg_reg, 97);
 	else {
-		if (cs->hw.teles3.cfg_reg)
+		if (cs->hw.teles3.cfg_reg) {
 			if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
 				release_region(cs->hw.teles3.cfg_reg, 1);
 			} else {
 				release_region(cs->hw.teles3.cfg_reg, 8);
 			}
+		}
 		release_ioregs(cs, 0x7);
 	}
 }
@@ -399,12 +400,13 @@
 			       CardType[cs->typ],
 			       cs->hw.teles3.isac + 32,
 			       cs->hw.teles3.isac + 64);
-			if (cs->hw.teles3.cfg_reg)
+			if (cs->hw.teles3.cfg_reg) {
 				if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
 					release_region(cs->hw.teles3.cfg_reg, 1);
 				} else {
 					release_region(cs->hw.teles3.cfg_reg, 8);
 				}
+			}
 			return (0);
 		} else
 			request_region(cs->hw.teles3.isac + 32, 32, "HiSax isac");
@@ -414,12 +416,13 @@
 			       CardType[cs->typ],
 			       cs->hw.teles3.hscx[0] + 32,
 			       cs->hw.teles3.hscx[0] + 64);
-			if (cs->hw.teles3.cfg_reg)
+			if (cs->hw.teles3.cfg_reg) {
 				if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
 					release_region(cs->hw.teles3.cfg_reg, 1);
 				} else {
 					release_region(cs->hw.teles3.cfg_reg, 8);
 				}
+			}
 			release_ioregs(cs, 1);
 			return (0);
 		} else
@@ -430,12 +433,13 @@
 			       CardType[cs->typ],
 			       cs->hw.teles3.hscx[1] + 32,
 			       cs->hw.teles3.hscx[1] + 64);
-			if (cs->hw.teles3.cfg_reg)
+			if (cs->hw.teles3.cfg_reg) {
 				if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
 					release_region(cs->hw.teles3.cfg_reg, 1);
 				} else {
 					release_region(cs->hw.teles3.cfg_reg, 8);
 				}
+			}
 			release_ioregs(cs, 3);
 			return (0);
 		} else
diff -u --recursive --new-file v2.1.102/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c
--- v2.1.102/linux/drivers/isdn/isdn_net.c	Thu May 14 19:47:39 1998
+++ linux/drivers/isdn/isdn_net.c	Thu May 14 18:45:35 1998
@@ -431,7 +431,7 @@
 		if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) {
 			anymore = 1;
 			l->huptimer++;
-			if ((l->onhtime) && (l->huptimer > l->onhtime))
+			if ((l->onhtime) && (l->huptimer > l->onhtime)) {
 				if (l->hupflags & ISDN_MANCHARGE &&
 				    l->hupflags & ISDN_CHARGEHUP) {
 					while (jiffies - l->chargetime > l->chargeint)
@@ -455,6 +455,7 @@
 						isdn_net_hangup(&p->dev);
 				} else if (l->hupflags & ISDN_INHUP)
 					isdn_net_hangup(&p->dev);
+			}
 		}
 		p = (isdn_net_dev *) p->next;
 	}
@@ -792,11 +793,12 @@
 				 * If timeout and max retries not
 				 * reached, switch back to state 3.
 				 */
-				if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
+				if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10) {
 					if (lp->dialretry < lp->dialmax) {
 						lp->dialstate = 3;
 					} else
 						isdn_net_hangup(&p->dev);
+				}
 				anymore = 1;
 				break;
 			case 5:
diff -u --recursive --new-file v2.1.102/linux/drivers/net/hamradio/dmascc.c linux/drivers/net/hamradio/dmascc.c
--- v2.1.102/linux/drivers/net/hamradio/dmascc.c	Thu Feb 12 20:56:08 1998
+++ linux/drivers/net/hamradio/dmascc.c	Thu May 14 18:45:56 1998
@@ -381,7 +381,7 @@
 
     /* Check valid I/O address regions */
     for (i = 0; i < hw[h].num_devs; i++)
-      if (base[i])
+      if (base[i]) {
 	if (check_region(base[i], hw[h].io_size))
 	  base[i] = 0;
 	else {
@@ -389,6 +389,7 @@
 	  t0[i]   = base[i] + hw[h].tmr_offset + TMR_CNT0;
 	  t1[i]   = base[i] + hw[h].tmr_offset + TMR_CNT1;
 	}
+      }
 
     /* Start timers */
     for (i = 0; i < hw[h].num_devs; i++)
diff -u --recursive --new-file v2.1.102/linux/drivers/net/ni52.c linux/drivers/net/ni52.c
--- v2.1.102/linux/drivers/net/ni52.c	Mon Feb 23 18:12:05 1998
+++ linux/drivers/net/ni52.c	Thu May 14 18:53:53 1998
@@ -366,11 +366,11 @@
 #endif
 	int base_addr = dev->base_addr;
 
-	if (base_addr > 0x1ff)		/* Check a single specified location. */
+	if (base_addr > 0x1ff) {		/* Check a single specified location. */
 		if( (inb(base_addr+NI52_MAGIC1) == NI52_MAGICVAL1) &&
 				(inb(base_addr+NI52_MAGIC2) == NI52_MAGICVAL2))
 			return ni52_probe1(dev, base_addr);
-	else if (base_addr > 0)		/* Don't probe at all. */
+	} else if (base_addr > 0)		/* Don't probe at all. */
 		return ENXIO;
 
 #ifdef MODULE
diff -u --recursive --new-file v2.1.102/linux/drivers/net/sdla.c linux/drivers/net/sdla.c
--- v2.1.102/linux/drivers/net/sdla.c	Mon Feb 23 18:12:06 1998
+++ linux/drivers/net/sdla.c	Thu May 14 18:46:35 1998
@@ -565,11 +565,12 @@
 	flp->dlci[i] = -*(short *)(master->dev_addr);
 	master->mtu = slave->mtu;
 
-	if (slave->start)
+	if (slave->start) {
 		if (flp->config.station == FRAD_STATION_CPE)
 			sdla_reconfig(slave);
 		else
 			sdla_cmd(slave, SDLA_ADD_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
+	}
 
 	return(0);
 }
@@ -593,11 +594,12 @@
 
 	MOD_DEC_USE_COUNT;
 
-	if (slave->start)
+	if (slave->start) {
 		if (flp->config.station == FRAD_STATION_CPE)
 			sdla_reconfig(slave);
 		else
 			sdla_cmd(slave, SDLA_DELETE_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
+	}
 
 	return(0);
 }
@@ -622,13 +624,14 @@
 
 	ret = SDLA_RET_OK;
 	len = sizeof(struct dlci_conf);
-	if (slave->start)
+	if (slave->start) {
 		if (get)
 			ret = sdla_cmd(slave, SDLA_READ_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,  
 			            NULL, 0, &dlp->config, &len);
 		else
 			ret = sdla_cmd(slave, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,  
 			            &dlp->config, sizeof(struct dlci_conf) - 4 * sizeof(short), NULL, NULL);
+	}
 
 	return(ret == SDLA_RET_OK ? 0 : -EIO);
 }
diff -u --recursive --new-file v2.1.102/linux/drivers/net/tulip.c linux/drivers/net/tulip.c
--- v2.1.102/linux/drivers/net/tulip.c	Mon Apr  6 17:41:00 1998
+++ linux/drivers/net/tulip.c	Thu May 14 18:47:30 1998
@@ -472,11 +472,12 @@
 			if (pcibios_find_class
 				(PCI_CLASS_NETWORK_ETHERNET << 8,
 				 reverse_probe ? 0xfe - pci_index : pci_index,
-				 &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL)
+				 &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL) {
 				if (reverse_probe)
 					continue;
 				else
 					break;
+			}
 			pcibios_read_config_word(pci_bus, pci_device_fn,
 									 PCI_VENDOR_ID, &vendor);
 			pcibios_read_config_word(pci_bus, pci_device_fn,
@@ -1658,13 +1659,15 @@
 		   dev->name, inl(ioaddr + CSR5), csr12,
 		   inl(ioaddr + CSR13), inl(ioaddr + CSR14));
 	tp->mediasense = 1;
-	if (dev->if_port == 1 || dev->if_port == 2)
+
+	if (dev->if_port == 1 || dev->if_port == 2) {
 		if (csr12 & 0x0004) {
 			dev->if_port = 2 - dev->if_port;
 		} else
 			dev->if_port = 0;
-	else
+	} else
 		dev->if_port = 1;
+
 	select_media(dev, 0);
 	tp->stats.tx_errors++;
 	dev->trans_start = jiffies;
diff -u --recursive --new-file v2.1.102/linux/drivers/pci/oldproc.c linux/drivers/pci/oldproc.c
--- v2.1.102/linux/drivers/pci/oldproc.c	Thu May  7 22:51:50 1998
+++ linux/drivers/pci/oldproc.c	Thu May 14 18:58:55 1998
@@ -1,5 +1,5 @@
 /*
- *	$Id: oldproc.c,v 1.12 1998/05/01 10:58:21 mj Exp $
+ *	$Id: oldproc.c,v 1.13 1998/05/07 20:49:50 davem Exp $
  *
  *	Backward-compatible procfs interface for PCI.
  *
diff -u --recursive --new-file v2.1.102/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.1.102/linux/drivers/pci/pci.c	Thu May  7 22:51:50 1998
+++ linux/drivers/pci/pci.c	Thu May 14 18:58:55 1998
@@ -1,10 +1,12 @@
 /*
- *	$Id: pci.c,v 1.84 1998/05/02 19:22:06 mj Exp $
+ *	$Id: pci.c,v 1.85 1998/05/12 07:36:01 mj Exp $
  *
- *	PCI Bus Services
+ *	PCI Bus Services, see include/linux/pci.h for further explanation.
  *
- *	Copyright 1993 -- 1998 Drew Eckhardt, Frederic Potter,
- *	David Mosberger-Tang, Martin Mares
+ *	Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter,
+ *	David Mosberger-Tang
+ *
+ *	Copyright 1997 -- 1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
  */
 
 #include <linux/config.h>
@@ -370,7 +372,7 @@
 		return;
 	}
 
-	printk("PCI: Probing PCI hardware.\n");
+	printk("PCI: Probing PCI hardware\n");
 
 	memset(&pci_root, 0, sizeof(pci_root));
 	pci_root.subordinate = pci_scan_bus(&pci_root);
diff -u --recursive --new-file v2.1.102/linux/drivers/pci/pcisyms.c linux/drivers/pci/pcisyms.c
--- v2.1.102/linux/drivers/pci/pcisyms.c	Thu May  7 22:51:50 1998
+++ linux/drivers/pci/pcisyms.c	Thu May 14 18:58:55 1998
@@ -1,5 +1,5 @@
 /*
- *	$Id: pcisyms.c,v 1.7 1998/05/02 19:20:06 mj Exp $
+ *	$Id: pcisyms.c,v 1.8 1998/05/12 07:36:04 mj Exp $
  *
  *	PCI Bus Services -- Exported Symbols
  *
@@ -28,6 +28,8 @@
 EXPORT_SYMBOL(pci_find_device);
 EXPORT_SYMBOL(pci_find_slot);
 EXPORT_SYMBOL(pci_set_master);
+EXPORT_SYMBOL(pci_proc_attach_device);
+EXPORT_SYMBOL(pci_proc_detach_device);
 
 /* Backward compatibility */
 
diff -u --recursive --new-file v2.1.102/linux/drivers/pci/proc.c linux/drivers/pci/proc.c
--- v2.1.102/linux/drivers/pci/proc.c	Thu May  7 22:51:50 1998
+++ linux/drivers/pci/proc.c	Thu May 14 18:58:55 1998
@@ -1,5 +1,5 @@
 /*
- *	$Id: proc.c,v 1.10 1998/04/16 20:48:30 mj Exp $
+ *	$Id: proc.c,v 1.13 1998/05/12 07:36:07 mj Exp $
  *
  *	Procfs interface for the PCI bus.
  *
@@ -280,41 +280,63 @@
 	get_pci_dev_info
 };
 
-__initfunc(void proc_bus_pci_add(struct pci_bus *bus, struct proc_dir_entry *proc_pci))
+static struct proc_dir_entry *proc_bus_pci_dir;
+
+int pci_proc_attach_device(struct pci_dev *dev)
+{
+	struct pci_bus *bus = dev->bus;
+	struct proc_dir_entry *de, *e;
+	char name[16];
+
+	if (!(de = bus->procdir)) {
+		sprintf(name, "%02x", bus->number);
+		de = bus->procdir = create_proc_entry(name, S_IFDIR, proc_bus_pci_dir);
+		if (!de)
+			return -ENOMEM;
+	}
+	sprintf(name, "%02x.%x", PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+	e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, de);
+	if (!e)
+		return -ENOMEM;
+	e->ops = &proc_bus_pci_inode_operations;
+	e->data = dev;
+	e->size = PCI_CFG_SPACE_SIZE;
+	return 0;
+}
+
+int pci_proc_detach_device(struct pci_dev *dev)
+{
+	struct proc_dir_entry *e;
+
+	if ((e = dev->procent)) {
+		if (e->count)
+			return -EBUSY;
+		remove_proc_entry(e->name, dev->bus->procdir);
+		dev->procent = NULL;
+	}
+	return 0;
+}
+
+__initfunc(void proc_bus_pci_add(struct pci_bus *bus))
 {
 	while (bus) {
-		char name[16];
-		struct proc_dir_entry *de;
 		struct pci_dev *dev;
 
-		sprintf(name, "%02x", bus->number);
-		de = create_proc_entry(name, S_IFDIR, proc_pci);
-		for(dev = bus->devices; dev; dev = dev->sibling) {
-			struct proc_dir_entry *e;
-
-			sprintf(name, "%02x.%x",
-				PCI_SLOT(dev->devfn),
-				PCI_FUNC(dev->devfn));
-			e = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, de);
-			e->ops = &proc_bus_pci_inode_operations;
-			e->data = dev;
-			e->size = PCI_CFG_SPACE_SIZE;
-		}
+		for(dev = bus->devices; dev; dev = dev->sibling)
+			pci_proc_attach_device(dev);
 		if (bus->children)
-			proc_bus_pci_add(bus->children, proc_pci);
+			proc_bus_pci_add(bus->children);
 		bus = bus->next;
 	}
 }
 
 __initfunc(void pci_proc_init(void))
 {
-	struct proc_dir_entry *proc_pci;
-
 	if (!pci_present())
 		return;
-	proc_pci = create_proc_entry("pci", S_IFDIR, proc_bus);
-	proc_register(proc_pci, &proc_pci_devices);
-	proc_bus_pci_add(&pci_root, proc_pci);
+	proc_bus_pci_dir = create_proc_entry("pci", S_IFDIR, proc_bus);
+	proc_register(proc_bus_pci_dir, &proc_pci_devices);
+	proc_bus_pci_add(&pci_root);
 
 #ifdef CONFIG_PCI_OLD_PROC
 	proc_old_pci_init();
diff -u --recursive --new-file v2.1.102/linux/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c
--- v2.1.102/linux/drivers/scsi/53c7,8xx.c	Thu May 14 19:47:40 1998
+++ linux/drivers/scsi/53c7,8xx.c	Thu May 14 18:48:16 1998
@@ -2202,10 +2202,10 @@
 	ncr_prev = (u32*) ((char*)bus_to_virt(ncr_search) + 
 	    hostdata->dsa_next), ncr_search = le32_to_cpu(*ncr_prev), --left);
 
-    if (left < 0) 
+    if (left < 0) {
 	printk("scsi%d: loop detected in ncr reconnect list\n",
 	    host->host_no);
-    else if (ncr_search) 
+    } else if (ncr_search) {
 	if (found)
 	    printk("scsi%d: scsi %ld in ncr issue array and reconnect lists\n",
 		host->host_no, c->pid);
@@ -2216,6 +2216,7 @@
 /* If we're at the tail end of the issue queue, update that pointer too. */
 	    found = 1;
 	}
+    }
 
     /*
      * Traverse the host running list until we find this command or discover
@@ -6325,11 +6326,12 @@
 	    	}
     	    }
 	}
-	if (!(istat & (ISTAT_SIP|ISTAT_DIP))) 
+	if (!(istat & (ISTAT_SIP|ISTAT_DIP))) {
 	    if (stage == 0)
 	    	++stage;
 	    else if (stage == 3)
 		break;
+	}
     }
     hostdata->state = STATE_HALTED;
     restore_flags(flags);
diff -u --recursive --new-file v2.1.102/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c
--- v2.1.102/linux/drivers/scsi/aha152x.c	Thu May 14 19:47:40 1998
+++ linux/drivers/scsi/aha152x.c	Thu May 14 18:49:34 1998
@@ -613,11 +613,12 @@
       prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble)
     ;
 
-  if(ptr)
+  if(ptr){
     if(prev)
       prev->host_scribble = ptr->host_scribble;
     else
       *SC= (Scsi_Cmnd *) ptr->host_scribble;
+  }
 
   return ptr;
 }
@@ -1727,7 +1728,7 @@
 
   /* we are waiting for the result of a selection attempt */
   if(CURRENT_SC->SCp.phase & in_selection) {
-    if(TESTLO(SSTAT1, SELTO))
+    if(TESTLO(SSTAT1, SELTO)) {
       /* no timeout */
       if(TESTHI(SSTAT0, SELDO)) {
         /* clear BUS FREE interrupt */
@@ -1803,7 +1804,7 @@
         return;
       } else
         aha152x_panic(shpnt, "neither timeout nor selection\007");
-    else {
+    } else {
 #if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
       if(HOSTDATA(shpnt)->debug & (debug_selection|debug_phases))
         printk("SELTO, ");
diff -u --recursive --new-file v2.1.102/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c
--- v2.1.102/linux/drivers/scsi/eata.c	Thu May 14 19:47:40 1998
+++ linux/drivers/scsi/eata.c	Wed May 20 10:38:43 1998
@@ -1,6 +1,18 @@
 /*
  *      eata.c - Low-level driver for EATA/DMA SCSI host adapters.
  *
+ *      16 May 1998 Rev. 4.31 for linux 2.0.33 and 2.1.102
+ *          Improved abort handling during the eh recovery process.
+ *
+ *      13 May 1998 Rev. 4.30 for linux 2.0.33 and 2.1.101
+ *          The driver is now fully SMP safe, including the
+ *          abort and reset routines.
+ *          Added command line options (eh:[y|n]) to choose between
+ *          new_eh_code and the old scsi code.
+ *          If linux verion >= 2.1.101 the default is eh:y, while the eh
+ *          option is ignored for previous releases and the old scsi code
+ *          is used.
+ *
  *      18 Apr 1998 Rev. 4.20 for linux 2.0.33 and 2.1.97
  *          Reworked interrupt handler.
  *
@@ -237,6 +249,8 @@
  *  After the optional list of detection probes, other possible command line
  *  options are:
  *
+ *  eh:y  use new scsi code (linux 2.2 only);
+ *  eh:n  use old scsi code;
  *  lc:y  enables linked commands;
  *  lc:n  disables linked commands;
  *  tc:y  enables tagged commands;
@@ -248,13 +262,14 @@
  *  mq:xx set the max queue depth to the value xx (2 <= xx <= 32).
  *
  *  The default value is: "eata=lc:n,tc:n,mq:16,tm:0". An example using
- *  the list of detection probes could be: "eata=0x7410,0x230,lc:y,tc:n,mq:4".
+ *  the list of detection probes could be:
+ *  "eata=0x7410,0x230,lc:y,tc:n,mq:4,eh:n".
  *
  *  When loading as a module, parameters can be specified as well.
  *  The above example would be (use 1 in place of y and 0 in place of n):
  *
  *  modprobe eata io_port=0x7410,0x230 linked_comm=1 tagged_comm=0 \
- *                max_queue_depth=4 tag_mode=0
+ *                max_queue_depth=4 tag_mode=0 use_new_eh_code=0
  *
  *  ----------------------------------------------------------------------------
  *  In this implementation, linked commands are designed to work with any DISK
@@ -310,6 +325,7 @@
 MODULE_PARM(link_statistics, "i");
 MODULE_PARM(max_queue_depth, "i");
 MODULE_PARM(tag_mode, "i");
+MODULE_PARM(use_new_eh_code, "i");
 MODULE_AUTHOR("Dario Ballabio");
 #endif
 
@@ -323,11 +339,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/byteorder.h>
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,95)
-#include <asm/spinlock.h>
-#endif
-
 #include <linux/proc_fs.h>
 #include <linux/blk.h>
 #include "scsi.h"
@@ -352,6 +363,34 @@
 #define __init
 #endif
 
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
+#include <asm/spinlock.h>
+#define IRQ_FLAGS
+#define IRQ_LOCK
+#define IRQ_LOCK_SAVE
+#define IRQ_UNLOCK
+#define IRQ_UNLOCK_RESTORE
+#define SPIN_FLAGS unsigned long spin_flags;
+#define SPIN_LOCK spin_lock_irq(&io_request_lock);
+#define SPIN_LOCK_SAVE spin_lock_irqsave(&io_request_lock, spin_flags);
+#define SPIN_UNLOCK spin_unlock_irq(&io_request_lock);
+#define SPIN_UNLOCK_RESTORE \
+                  spin_unlock_irqrestore(&io_request_lock, spin_flags);
+static int use_new_eh_code = TRUE;
+#else
+#define IRQ_FLAGS unsigned long irq_flags;
+#define IRQ_LOCK cli();
+#define IRQ_LOCK_SAVE do {save_flags(irq_flags); cli();} while (0);
+#define IRQ_UNLOCK sti();
+#define IRQ_UNLOCK_RESTORE do {restore_flags(irq_flags);} while (0);
+#define SPIN_FLAGS
+#define SPIN_LOCK
+#define SPIN_LOCK_SAVE
+#define SPIN_UNLOCK
+#define SPIN_UNLOCK_RESTORE
+static int use_new_eh_code = FALSE;
+#endif
+
 struct proc_dir_entry proc_scsi_eata2x = {
     PROC_SCSI_EATA2X, 6, "eata2x",
     S_IFDIR | S_IRUGO | S_IXUGO, 2
@@ -368,6 +407,8 @@
 #undef  DEBUG_PCI_DETECT
 #undef  DEBUG_INTERRUPT
 #undef  DEBUG_RESET
+#undef  DEBUG_GENERATE_ERRORS
+#undef  DEBUG_GENERATE_ABORTS
 
 #define MAX_ISA 4
 #define MAX_VESA 0
@@ -619,19 +660,19 @@
 static int link_statistics = 0;
 static int tag_mode = TAG_MIXED;
 
-#if defined (CONFIG_SCSI_EATA_TAGGED_QUEUE)
+#if defined(CONFIG_SCSI_EATA_TAGGED_QUEUE)
 static int tagged_comm = TRUE;
 #else
 static int tagged_comm = FALSE;
 #endif
 
-#if defined (CONFIG_SCSI_EATA_LINKED_COMMANDS)
+#if defined(CONFIG_SCSI_EATA_LINKED_COMMANDS)
 static int linked_comm = TRUE;
 #else
 static int linked_comm = FALSE;
 #endif
 
-#if defined CONFIG_SCSI_EATA_MAX_TAGS
+#if defined(CONFIG_SCSI_EATA_MAX_TAGS)
 static int max_queue_depth = CONFIG_SCSI_EATA_MAX_TAGS;
 #else
 static int max_queue_depth = MAX_CMD_PER_LUN;
@@ -640,11 +681,9 @@
 static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) {
    Scsi_Device *dev;
    int j, ntag = 0, nuntag = 0, tqd, utqd;
-   unsigned long flags;
-
-   save_flags(flags);
-   cli();
+   IRQ_FLAGS
 
+   IRQ_LOCK_SAVE
    j = ((struct hostdata *) host->hostdata)->board_number;
 
    for(dev = devlist; dev; dev = dev->next) {
@@ -697,7 +736,7 @@
              dev->queue_depth, link_suffix, tag_suffix);
       }
 
-   restore_flags(flags);
+   IRQ_UNLOCK_RESTORE
    return;
 }
 
@@ -899,7 +938,7 @@
       return FALSE;
       }
 
-#if defined (FORCE_CONFIG)
+#if defined(FORCE_CONFIG)
    {
    struct eata_config config;
 
@@ -1016,21 +1055,32 @@
       }
    else                                 tag_type = 'n';
 
-   printk("%s: 2.0%c, %s 0x%03lx, IRQ %u, %s, SG %d, MB %d, tc:%c, lc:%c, "\
-          "mq:%d.\n", BN(j), HD(j)->protocol_rev, bus_type,
-          (unsigned long)sh[j]->io_port, sh[j]->irq, dma_name,
-          sh[j]->sg_tablesize, sh[j]->can_queue, tag_type, YESNO(linked_comm),
-          max_queue_depth);
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
+   sh[j]->hostt->use_new_eh_code = use_new_eh_code;
+#else
+   use_new_eh_code = FALSE;
+#endif
+
+   if (j == 0) {
+      printk("EATA/DMA 2.0x: Copyright (C) 1994-1998 Dario Ballabio.\n");
+      printk("%s config options -> tc:%c, lc:%c, mq:%d, eh:%c.\n",
+             driver_name, tag_type, YESNO(linked_comm),
+             max_queue_depth, YESNO(use_new_eh_code));
+      }
+
+   printk("%s: 2.0%c, %s 0x%03lx, IRQ %u, %s, SG %d, MB %d.\n",
+          BN(j), HD(j)->protocol_rev, bus_type, (unsigned long)sh[j]->io_port,
+          sh[j]->irq, dma_name, sh[j]->sg_tablesize, sh[j]->can_queue);
 
    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 (i = 0; i <= sh[j]->max_channel; i++)
-      printk("%s: SCSI channel %u enabled, host target ID %u.\n",
+      printk("%s: SCSI channel %u enabled, host target ID %d.\n",
              BN(j), i, info.host_addr[3 - i]);
 
-#if defined (DEBUG_DETECT)
+#if defined(DEBUG_DETECT)
    printk("%s: Vers. 0x%x, ocs %u, tar %u, trnxfr %u, more %u, SYNC 0x%x, "\
           "sec. %u, infol %ld, cpl %ld spl %ld.\n", name, info.version,
           info.ocsena, info.tarsup, info.trnxfr, info.morsup, info.sync,
@@ -1077,6 +1127,7 @@
       else if (!strncmp(cur, "tm:", 3)) tag_mode = val;
       else if (!strncmp(cur, "mq:", 3))  max_queue_depth = val;
       else if (!strncmp(cur, "ls:", 3))  link_statistics = val;
+      else if (!strncmp(cur, "eh:", 3))  use_new_eh_code = val;
 
       if ((cur = strchr(cur, ','))) ++cur;
       }
@@ -1151,14 +1202,12 @@
 }
 
 __initfunc (int eata2x_detect(Scsi_Host_Template *tpnt)) {
-   unsigned long flags;
    unsigned int j = 0, k;
+   IRQ_FLAGS
 
+   IRQ_LOCK_SAVE
    tpnt->proc_dir = &proc_scsi_eata2x;
 
-   save_flags(flags);
-   cli();
-
 #if defined(MODULE)
    /* io_port could have been modified when loading as a module */
    if(io_port[0] != SKIP) {
@@ -1178,11 +1227,8 @@
       if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt)) j++;
       }
 
-   if (j > 0)
-      printk("EATA/DMA 2.0x: Copyright (C) 1994-1998 Dario Ballabio.\n");
-
    num_boards = j;
-   restore_flags(flags);
+   IRQ_UNLOCK_RESTORE
    return j;
 }
 
@@ -1201,8 +1247,7 @@
    cpp->data_len = H2DEV((SCpnt->use_sg * sizeof(struct sg_list)));
 }
 
-int eata2x_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
-   unsigned long flags;
+static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
    unsigned int i, j, k;
    struct mscp *cpp;
    struct mssp *spp;
@@ -1219,22 +1264,12 @@
       0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5
       };
 
-   save_flags(flags);
-   cli();
    /* j is the board number */
    j = ((struct hostdata *) SCpnt->host->hostdata)->board_number;
 
-   if (!done) panic("%s: qcomm, pid %ld, null done.\n", BN(j), SCpnt->pid);
-
-   if (SCpnt->cmnd[0] == REQUEST_SENSE && SCpnt->sense_buffer[0]) {
-      SCpnt->result = DID_OK << 16;
-      SCpnt->host_scribble = NULL;
-      printk("%s: qcomm, target %d.%d:%d, pid %ld, request sense ignored.\n",
-             BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid);
-      restore_flags(flags);
-      done(SCpnt);
-      return 0;
-      }
+   if (SCpnt->host_scribble)
+      panic("%s: qcomm, pid %ld, SCpnt %p already active.\n",
+            BN(j), SCpnt->pid, SCpnt);
 
    /* i is the mailbox number, look for the first free mailbox
       starting from last_cp_used */
@@ -1251,19 +1286,7 @@
       }
 
    if (k == sh[j]->can_queue) {
-      printk("%s: qcomm, no free mailbox, resetting.\n", BN(j));
-
-      if (HD(j)->in_reset)
-         printk("%s: qcomm, already in reset.\n", BN(j));
-      else if (eata2x_reset(SCpnt, SCSI_RESET_SUGGEST_BUS_RESET)
-               == SCSI_RESET_SUCCESS)
-         panic("%s: qcomm, SCSI_RESET_SUCCESS.\n", BN(j));
-
-      SCpnt->result = DID_BUS_BUSY << 16;
-      SCpnt->host_scribble = NULL;
-      printk("%s: qcomm, pid %ld, DID_BUS_BUSY, done.\n", BN(j), SCpnt->pid);
-      restore_flags(flags);
-      done(SCpnt);
+      printk("%s: qcomm, no free mailbox.\n", BN(j));
       return 1;
       }
 
@@ -1346,40 +1369,41 @@
                                      && TLDEV(SCpnt->device->type)) {
       HD(j)->cp_stat[i] = READY;
       flush_dev(SCpnt->device, SCpnt->request.sector, j, FALSE);
-      restore_flags(flags);
       return 0;
       }
 
    /* Send control packet to the board */
    if (do_dma(sh[j]->io_port, (unsigned int) cpp, SEND_CP_DMA)) {
-      SCpnt->result = DID_ERROR << 16;
       SCpnt->host_scribble = NULL;
-      printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy, DID_ERROR,"\
-             " done.\n", BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun,
-             SCpnt->pid);
-      restore_flags(flags);
-      done(SCpnt);
+      printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy.\n",
+             BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid);
       return 1;
       }
 
    HD(j)->cp_stat[i] = IN_USE;
-   restore_flags(flags);
    return 0;
 }
 
-int eata2x_abort(Scsi_Cmnd *SCarg) {
-   unsigned long flags;
+int eata2x_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
+   int rtn;
+   IRQ_FLAGS
+
+   IRQ_LOCK_SAVE
+   rtn = do_qcomm(SCpnt, done);
+   IRQ_UNLOCK_RESTORE
+   return rtn;
+}
+
+static inline int do_old_abort(Scsi_Cmnd *SCarg) {
    unsigned int i, j;
 
-   save_flags(flags);
-   cli();
    j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
 
-   if (SCarg->host_scribble == NULL
-       || SCarg->serial_number != SCarg->serial_number_at_timeout) {
+   if (SCarg->host_scribble == NULL ||
+       (SCarg->serial_number_at_timeout &&
+       (SCarg->serial_number != SCarg->serial_number_at_timeout))) {
       printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n",
              BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
-      restore_flags(flags);
       return SCSI_ABORT_NOT_RUNNING;
       }
 
@@ -1392,13 +1416,11 @@
 
    if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
       printk("%s: abort, timeout error.\n", BN(j));
-      restore_flags(flags);
       return SCSI_ABORT_ERROR;
       }
 
    if (HD(j)->cp_stat[i] == FREE) {
       printk("%s: abort, mbox %d is free.\n", BN(j), i);
-      restore_flags(flags);
       return SCSI_ABORT_NOT_RUNNING;
       }
 
@@ -1412,19 +1434,16 @@
       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;
       }
 
    if (HD(j)->cp_stat[i] == IN_RESET) {
       printk("%s: abort, mbox %d is in reset.\n", BN(j), i);
-      restore_flags(flags);
       return SCSI_ABORT_ERROR;
       }
 
    if (HD(j)->cp_stat[i] == LOCKED) {
       printk("%s: abort, mbox %d is locked.\n", BN(j), i);
-      restore_flags(flags);
       return SCSI_ABORT_NOT_RUNNING;
       }
 
@@ -1435,45 +1454,128 @@
       printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n",
              BN(j), i, SCarg->pid);
       SCarg->scsi_done(SCarg);
-      restore_flags(flags);
       return SCSI_ABORT_SUCCESS;
       }
 
-   restore_flags(flags);
    panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j), i);
 }
 
-int eata2x_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
-   unsigned long flags;
+int eata2x_old_abort(Scsi_Cmnd *SCarg) {
+   int rtn;
+   IRQ_FLAGS
+
+   IRQ_LOCK_SAVE
+   rtn = do_old_abort(SCarg);
+   IRQ_UNLOCK_RESTORE
+   return rtn;
+}
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
+
+static inline int do_abort(Scsi_Cmnd *SCarg) {
+   unsigned int i, j;
+
+   j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
+
+   if (SCarg->host_scribble == NULL) {
+      printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n",
+             BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
+      return SUCCESS;
+      }
+
+   i = *(unsigned int *)SCarg->host_scribble;
+   printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n",
+          BN(j), i, SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
+
+   if (i >= sh[j]->can_queue)
+      panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
+
+   if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+      printk("%s: abort, timeout error.\n", BN(j));
+      return FAILED;
+      }
+
+   if (HD(j)->cp_stat[i] == FREE) {
+      printk("%s: abort, mbox %d is free.\n", BN(j), i);
+      return SUCCESS;
+      }
+
+   if (HD(j)->cp_stat[i] == IN_USE) {
+      printk("%s: abort, mbox %d is in use.\n", BN(j), i);
+
+      if (SCarg != HD(j)->cp[i].SCpnt)
+         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);
+
+      if (SCarg->eh_state == SCSI_STATE_TIMEOUT) {
+         SCarg->host_scribble = NULL;
+         HD(j)->cp_stat[i] = FREE;
+         printk("%s, abort, mbox %d, eh_state timeout, pid %ld.\n",
+                BN(j), i, SCarg->pid);
+         return SUCCESS;
+         }
+
+      return FAILED;
+      }
+
+   if (HD(j)->cp_stat[i] == IN_RESET) {
+      printk("%s: abort, mbox %d is in reset.\n", BN(j), i);
+      return FAILED;
+      }
+
+   if (HD(j)->cp_stat[i] == LOCKED) {
+      printk("%s: abort, mbox %d is locked.\n", BN(j), i);
+      return SUCCESS;
+      }
+
+   if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
+      SCarg->result = DID_ABORT << 16;
+      SCarg->host_scribble = NULL;
+      HD(j)->cp_stat[i] = FREE;
+      printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n",
+             BN(j), i, SCarg->pid);
+      SCarg->scsi_done(SCarg);
+      return SUCCESS;
+      }
+
+   panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j), i);
+}
+
+int eata2x_abort(Scsi_Cmnd *SCarg) {
+
+   return do_abort(SCarg);
+}
+
+#endif /* new_eh_code */
+
+static inline int do_old_reset(Scsi_Cmnd *SCarg) {
    unsigned int i, j, time, k, c, limit = 0;
    int arg_done = FALSE;
    Scsi_Cmnd *SCpnt;
 
-   save_flags(flags);
-   cli();
    j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
-   printk("%s: reset, enter, target %d.%d:%d, pid %ld, reset_flags %u.\n",
-          BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid,
-          reset_flags);
+   printk("%s: reset, enter, target %d.%d:%d, pid %ld.\n",
+          BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
 
    if (SCarg->host_scribble == NULL)
       printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
 
-   if (SCarg->serial_number != SCarg->serial_number_at_timeout) {
+   if (SCarg->serial_number_at_timeout &&
+       (SCarg->serial_number != SCarg->serial_number_at_timeout)) {
       printk("%s: reset, pid %ld, reset not running.\n", BN(j), SCarg->pid);
-      restore_flags(flags);
       return SCSI_RESET_NOT_RUNNING;
       }
 
    if (HD(j)->in_reset) {
       printk("%s: reset, exit, already in reset.\n", BN(j));
-      restore_flags(flags);
       return SCSI_RESET_ERROR;
       }
 
    if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
       printk("%s: reset, exit, timeout error.\n", BN(j));
-      restore_flags(flags);
       return SCSI_RESET_ERROR;
       }
 
@@ -1524,21 +1626,22 @@
 
    if (do_dma(sh[j]->io_port, 0, RESET_PIO)) {
       printk("%s: reset, cannot reset, timeout error.\n", BN(j));
-      restore_flags(flags);
       return SCSI_RESET_ERROR;
       }
 
    printk("%s: reset, board reset done, enabling interrupts.\n", BN(j));
 
-#if defined (DEBUG_RESET)
+#if defined(DEBUG_RESET)
    do_trace = TRUE;
 #endif
 
    HD(j)->in_reset = TRUE;
-
-   /* Wait 2 seconds ???!!! */
-   { unsigned long msec = 2 * 1000; while (--msec) udelay(1000); }
-
+   SPIN_UNLOCK
+   IRQ_UNLOCK
+   time = jiffies;
+   while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L);
+   IRQ_LOCK
+   SPIN_LOCK
    printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
 
    for (i = 0; i < sh[j]->can_queue; i++) {
@@ -1572,14 +1675,12 @@
          /* Any other mailbox has already been set free by interrupt */
          continue;
 
-      restore_flags(flags);
       SCpnt->scsi_done(SCpnt);
-      cli();
+      IRQ_LOCK
       }
 
    HD(j)->in_reset = FALSE;
    do_trace = FALSE;
-   restore_flags(flags);
 
    if (arg_done) {
       printk("%s: reset, exit, success.\n", BN(j));
@@ -1591,6 +1692,156 @@
       }
 }
 
+int eata2x_old_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
+   int rtn;
+   IRQ_FLAGS
+
+   IRQ_LOCK_SAVE
+   rtn = do_old_reset(SCarg);
+   IRQ_UNLOCK_RESTORE
+   return rtn;
+}
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
+
+static inline int do_reset(Scsi_Cmnd *SCarg) {
+   unsigned int i, j, time, k, c, limit = 0;
+   int arg_done = FALSE;
+   Scsi_Cmnd *SCpnt;
+
+   j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
+   printk("%s: reset, enter, target %d.%d:%d, pid %ld.\n",
+          BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
+
+   if (SCarg->host_scribble == NULL)
+      printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
+
+   if (HD(j)->in_reset) {
+      printk("%s: reset, exit, already in reset.\n", BN(j));
+      return FAILED;
+      }
+
+   if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+      printk("%s: reset, exit, timeout error.\n", BN(j));
+      return FAILED;
+      }
+
+   HD(j)->retries = 0;
+
+   for (c = 0; c <= sh[j]->max_channel; c++)
+      for (k = 0; k < sh[j]->max_id; k++) {
+         HD(j)->target_redo[k][c] = TRUE;
+         HD(j)->target_to[k][c] = 0;
+         }
+
+   for (i = 0; i < sh[j]->can_queue; i++) {
+
+      if (HD(j)->cp_stat[i] == FREE) continue;
+
+      if (HD(j)->cp_stat[i] == LOCKED) {
+         HD(j)->cp_stat[i] = FREE;
+         printk("%s: reset, locked mbox %d forced free.\n", BN(j), i);
+         continue;
+         }
+
+      if (!(SCpnt = HD(j)->cp[i].SCpnt))
+         panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
+
+      if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
+         HD(j)->cp_stat[i] = ABORTING;
+         printk("%s: reset, mbox %d aborting, pid %ld.\n",
+                BN(j), i, SCpnt->pid);
+         }
+
+      else {
+         HD(j)->cp_stat[i] = IN_RESET;
+         printk("%s: reset, mbox %d in reset, pid %ld.\n",
+                BN(j), i, SCpnt->pid);
+         }
+
+      if (SCpnt->host_scribble == NULL)
+         panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
+
+      if (*(unsigned int *)SCpnt->host_scribble != i)
+         panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
+
+      if (SCpnt->scsi_done == NULL)
+         panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
+
+      if (SCpnt == SCarg) arg_done = TRUE;
+      }
+
+   if (do_dma(sh[j]->io_port, 0, RESET_PIO)) {
+      printk("%s: reset, cannot reset, timeout error.\n", BN(j));
+      return FAILED;
+      }
+
+   printk("%s: reset, board reset done, enabling interrupts.\n", BN(j));
+
+#if defined(DEBUG_RESET)
+   do_trace = TRUE;
+#endif
+
+   HD(j)->in_reset = TRUE;
+   SPIN_UNLOCK
+   IRQ_UNLOCK
+   time = jiffies;
+   while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L);
+   IRQ_LOCK
+   SPIN_LOCK
+   printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
+
+   for (i = 0; i < sh[j]->can_queue; i++) {
+
+      if (HD(j)->cp_stat[i] == IN_RESET) {
+         SCpnt = HD(j)->cp[i].SCpnt;
+         SCpnt->result = DID_RESET << 16;
+         SCpnt->host_scribble = NULL;
+
+         /* This mailbox is still waiting for its interrupt */
+         HD(j)->cp_stat[i] = LOCKED;
+
+         printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
+                BN(j), i, SCpnt->pid);
+         }
+
+      else if (HD(j)->cp_stat[i] == ABORTING) {
+         SCpnt = HD(j)->cp[i].SCpnt;
+         SCpnt->result = DID_RESET << 16;
+         SCpnt->host_scribble = NULL;
+
+         /* This mailbox was never queued to the adapter */
+         HD(j)->cp_stat[i] = FREE;
+
+         printk("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n",
+                BN(j), i, SCpnt->pid);
+         }
+
+      else
+
+         /* Any other mailbox has already been set free by interrupt */
+         continue;
+
+      SCpnt->scsi_done(SCpnt);
+      IRQ_LOCK
+      }
+
+   HD(j)->in_reset = FALSE;
+   do_trace = FALSE;
+
+   if (arg_done) printk("%s: reset, exit, pid %ld done.\n", BN(j), SCarg->pid);
+   else          printk("%s: reset, exit.\n", BN(j));
+
+   return SUCCESS;
+}
+
+int eata2x_reset(Scsi_Cmnd *SCarg) {
+
+   return do_reset(SCarg);
+}
+
+#endif /* new_eh_code */
+
 static void sort(unsigned long sk[], unsigned int da[], unsigned int n,
                  unsigned int rev) {
    unsigned int i, j, k, y;
@@ -1698,7 +1949,7 @@
       if (!rev && !s)    { sortcount++; readysorted += n_ready; }
       }
 
-#if defined (DEBUG_LINKED_COMMANDS)
+#if defined(DEBUG_LINKED_COMMANDS)
    if (link_statistics && (overlap || !(flushcount % link_statistics)))
       for (n = 0; n < n_ready; n++) {
          k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
@@ -1789,16 +2040,20 @@
    reg = inb(sh[j]->io_port + REG_STATUS);
 
    /* Reject any sp with supspect data */
-   if (spp->eoc == FALSE) 
+   if (spp->eoc == FALSE)
       printk("%s: ihdlr, spp->eoc == FALSE, irq %d, reg 0x%x, count %d.\n",
              BN(j), irq, reg, HD(j)->iocount);
-   if (spp->cpp == NULL) 
+   if (spp->cpp == NULL)
       printk("%s: ihdlr, spp->cpp == NULL,  irq %d, reg 0x%x, count %d.\n",
              BN(j), irq, reg, HD(j)->iocount);
    if (spp->eoc == FALSE || spp->cpp == NULL) return;
 
    cpp = spp->cpp;
 
+#if defined(DEBUG_GENERATE_ABORTS)
+   if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 500) < 3)) return;
+#endif
+
    /* Find the mailbox to be serviced on this board */
    i = cpp - HD(j)->cp;
 
@@ -1847,6 +2102,11 @@
 
    tstatus = status_byte(spp->target_status);
 
+#if defined(DEBUG_GENERATE_ERRORS)
+   if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 200) < 2))
+                                           spp->adapter_status = 0x01;
+#endif
+
    switch (spp->adapter_status) {
       case ASOK:     /* status OK */
 
@@ -1905,7 +2165,12 @@
 
          if (SCpnt->device->type != TYPE_TAPE
              && HD(j)->retries < MAX_INTERNAL_RETRIES) {
+
+#if defined(DID_SOFT_ERROR)
+            status = DID_SOFT_ERROR << 16;
+#else
             status = DID_BUS_BUSY << 16;
+#endif
             HD(j)->retries++;
             HD(j)->last_retried_pid = SCpnt->pid;
             }
@@ -1928,7 +2193,7 @@
 
    SCpnt->result = status | spp->target_status;
 
-#if defined (DEBUG_INTERRUPT)
+#if defined(DEBUG_INTERRUPT)
    if (SCpnt->result || do_trace)
 #else
    if ((spp->adapter_status != ASOK && HD(j)->iocount >  1000) ||
@@ -1954,31 +2219,25 @@
 }
 
 static void do_interrupt_handler(int irq, void *shap, struct pt_regs *regs) {
-
    unsigned int j;
+   IRQ_FLAGS
+   SPIN_FLAGS
 
    /* Check if the interrupt must be processed by this handler */
    if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return;
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,95)
-   {
-   unsigned long flags;
-   spin_lock_irqsave(&io_request_lock, flags);
+   SPIN_LOCK_SAVE
+   IRQ_LOCK_SAVE
    ihdlr(irq, j);
-   spin_unlock_irqrestore(&io_request_lock, flags);
-   }
-#else
-   ihdlr(irq, j);
-#endif
-
+   IRQ_UNLOCK_RESTORE
+   SPIN_UNLOCK_RESTORE
 }
 
 int eata2x_release(struct Scsi_Host *shpnt) {
-   unsigned long flags;
    unsigned int i, j;
+   IRQ_FLAGS
 
-   save_flags(flags);
-   cli();
+   IRQ_LOCK_SAVE
 
    for (j = 0; sh[j] != NULL && sh[j] != shpnt; j++);
 
@@ -1994,7 +2253,7 @@
 
    release_region(sh[j]->io_port, sh[j]->n_io_port);
    scsi_unregister(sh[j]);
-   restore_flags(flags);
+   IRQ_UNLOCK_RESTORE
    return FALSE;
 }
 
diff -u --recursive --new-file v2.1.102/linux/drivers/scsi/eata.h linux/drivers/scsi/eata.h
--- v2.1.102/linux/drivers/scsi/eata.h	Sat Apr 25 18:13:11 1998
+++ linux/drivers/scsi/eata.h	Wed May 20 16:22:59 1998
@@ -11,41 +11,47 @@
 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);
+int eata2x_old_abort(Scsi_Cmnd *);
+int eata2x_reset(Scsi_Cmnd *);
+int eata2x_old_reset(Scsi_Cmnd *, unsigned int);
 
-#define EATA_VERSION "4.20.00"
+#define EATA_VERSION "4.31.00"
 
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,88)
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
 
 #define EATA {                                                               \
                 name:              "EATA/DMA 2.0x rev. " EATA_VERSION " ",   \
-                detect:            eata2x_detect,                            \
-                release:           eata2x_release,                           \
-                queuecommand:      eata2x_queuecommand,                      \
-                abort:             eata2x_abort,                             \
-                reset:             eata2x_reset,                             \
-                bios_param:        scsicam_bios_param,                       \
-                this_id:           7,                                        \
-                unchecked_isa_dma: 1,                                        \
-                use_clustering:    ENABLE_CLUSTERING,                        \
-                use_new_eh_code: 1    /* Enable new error code */            \
+                detect:                  eata2x_detect,                      \
+                release:                 eata2x_release,                     \
+                queuecommand:            eata2x_queuecommand,                \
+                abort:                   eata2x_old_abort,                   \
+                reset:                   eata2x_old_reset,                   \
+                eh_abort_handler:        eata2x_abort,                       \
+                eh_device_reset_handler: NULL,                               \
+                eh_bus_reset_handler:    NULL,                               \
+                eh_host_reset_handler:   eata2x_reset,                       \
+                bios_param:              scsicam_bios_param,                 \
+                this_id:                 7,                                  \
+                unchecked_isa_dma:       1,                                  \
+                use_clustering:          ENABLE_CLUSTERING,                  \
+                use_new_eh_code:         1    /* Enable new error code */    \
              }
 
 #else /* Use old scsi code */
 
 #define EATA {                                                               \
                 name:              "EATA/DMA 2.0x rev. " EATA_VERSION " ",   \
-                detect:            eata2x_detect,                            \
-                release:           eata2x_release,                           \
-                queuecommand:      eata2x_queuecommand,                      \
-                abort:             eata2x_abort,                             \
-                reset:             eata2x_reset,                             \
-                bios_param:        scsicam_bios_param,                       \
-                this_id:           7,                                        \
-                unchecked_isa_dma: 1,                                        \
-                use_clustering:    ENABLE_CLUSTERING                         \
+                detect:                  eata2x_detect,                      \
+                release:                 eata2x_release,                     \
+                queuecommand:            eata2x_queuecommand,                \
+                abort:                   eata2x_old_abort,                   \
+                reset:                   eata2x_old_reset,                   \
+                bios_param:              scsicam_bios_param,                 \
+                this_id:                 7,                                  \
+                unchecked_isa_dma:       1,                                  \
+                use_clustering:          ENABLE_CLUSTERING                   \
              }
 
 #endif
diff -u --recursive --new-file v2.1.102/linux/drivers/scsi/eata_pio.c linux/drivers/scsi/eata_pio.c
--- v2.1.102/linux/drivers/scsi/eata_pio.c	Tue Apr 14 14:29:22 1998
+++ linux/drivers/scsi/eata_pio.c	Thu May 14 18:49:55 1998
@@ -155,7 +155,7 @@
 	do
 	{
 	    stat=inb(base+HA_RSTATUS);
-	    if (stat&HA_SDRQ)
+	    if (stat&HA_SDRQ) {
 		if (cp->DataIn)
 		{
 		    z=256; odd=FALSE;
@@ -215,6 +215,7 @@
 			odd=FALSE;
 		    }
 		}
+	    }
 	}
 	while ((stat&HA_SDRQ)||((stat&HA_SMORE)&&hd->moresupport));
 	
diff -u --recursive --new-file v2.1.102/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c
--- v2.1.102/linux/drivers/scsi/fdomain.c	Thu May 14 19:47:40 1998
+++ linux/drivers/scsi/fdomain.c	Tue May 19 22:05:57 1998
@@ -272,6 +272,7 @@
 #include <linux/proc_fs.h>
 #include <linux/pci.h>
 #include <linux/stat.h>
+#include <linux/delay.h>
 
 #include <linux/config.h>	/* for CONFIG_PCI */
 
@@ -553,9 +554,9 @@
 
 static void do_pause( unsigned amount )	/* Pause for amount*10 milliseconds */
 {
-   unsigned long the_time = jiffies + amount; /* 0.01 seconds per jiffy */
-
-   while (jiffies < the_time);
+   do {
+	udelay(10*1000);
+   } while (--amount);
 }
 
 inline static void fdomain_make_bus_idle( void )
@@ -1101,12 +1102,13 @@
    outb( adapter_mask, port_base + SCSI_Data_NoACK ); /* Set our id bit */
    outb( 0x04 | PARITY_MASK, TMC_Cntl_port ); /* Start arbitration */
 
-   timeout = jiffies + 50;		      /* 500 mS */
-   while (jiffies < timeout) {
+   timeout = 500;
+   do {
       status = inb( TMC_Status_port );        /* Read adapter status */
       if (status & 0x02)		      /* Arbitration complete */
-	    return 0;	
-   }
+	    return 0;
+      udelay(1000);			/* Wait one millisecond */
+   } while (--timeout);
 
    /* Make bus idle */
    fdomain_make_bus_idle();
@@ -1134,17 +1136,17 @@
    /* Stop arbitration and enable parity */
    outb( PARITY_MASK, TMC_Cntl_port ); 
 
-   timeout = jiffies + 35;		/* 350mS -- because of timeouts
-					   (was 250mS) */
+   timeout = 350;			/* 350 msec */
 
-   while (jiffies < timeout) {
+   do {
       status = inb( SCSI_Status_port ); /* Read adapter status */
       if (status & 1) {			/* Busy asserted */
 	 /* Enable SCSI Bus (on error, should make bus idle with 0) */
 	 outb( 0x80, SCSI_Cntl_port );
 	 return 0;
       }
-   }
+      udelay(1000);			/* wait one msec */
+   } while (--timeout);
    /* Make bus idle */
    fdomain_make_bus_idle();
 #if EVERY_ACCESS
diff -u --recursive --new-file v2.1.102/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v2.1.102/linux/drivers/scsi/hosts.c	Fri May  8 23:14:49 1998
+++ linux/drivers/scsi/hosts.c	Wed May 20 10:36:12 1998
@@ -575,6 +575,7 @@
 {
     static int called = 0;
     int i, pcount;
+    unsigned long flags;
     Scsi_Host_Template * tpnt;
     struct Scsi_Host * shpnt;
     const char * name;
@@ -590,9 +591,27 @@
 	 */
 	
 	pcount = next_scsi_host;
-	if ((tpnt->detect) &&
-	    (tpnt->present =
-	     tpnt->detect(tpnt)))
+	if (tpnt->detect) {
+
+           /* The detect routine must carefully spinunlock/spinlock if 
+              it enables interrupts, since all interrupt handlers do 
+              spinlock as well.
+              All lame drivers are going to fail due to the following 
+              spinlock. For the time beeing let's use it only for drivers 
+              using the new scsi code. NOTE: the detect routine could
+              redefine the value tpnt->use_new_eh_code. (DB, 13 May 1998) */
+
+           if (tpnt->use_new_eh_code) {
+              spin_lock_irqsave(&io_request_lock, flags);
+              tpnt->present = tpnt->detect(tpnt);
+              spin_unlock_irqrestore(&io_request_lock, flags);
+              }
+           else
+              tpnt->present = tpnt->detect(tpnt);
+
+           }
+
+	if (tpnt->detect && tpnt->present)
 	{
 	    /* The only time this should come up is when people use
 	     * some kind of patched driver of some kind or another. */
diff -u --recursive --new-file v2.1.102/linux/drivers/scsi/ppa.c linux/drivers/scsi/ppa.c
--- v2.1.102/linux/drivers/scsi/ppa.c	Thu May  7 22:51:51 1998
+++ linux/drivers/scsi/ppa.c	Thu May 14 18:50:09 1998
@@ -1035,7 +1035,7 @@
 	    if ((r_str(ppb) & 0x08) == 0x00)
 		retv--;
 
-	    if (retv)
+	    if (retv) {
 		if ((jiffies - tmp->jstart) > (1 * HZ)) {
 		    printk("ppa: Parallel port cable is unplugged!!\n");
 		    ppa_fail(host_no, DID_BUS_BUSY);
@@ -1044,6 +1044,7 @@
 		    ppa_disconnect(host_no);
 		    return 1;	/* Try again in a jiffy */
 		}
+	    }
 	    cmd->SCp.phase++;
 	}
 
diff -u --recursive --new-file v2.1.102/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.1.102/linux/drivers/scsi/scsi.c	Thu May 14 19:47:41 1998
+++ linux/drivers/scsi/scsi.c	Wed May 20 10:36:12 1998
@@ -127,7 +127,6 @@
 static unsigned long      serial_number = 0;
 static Scsi_Cmnd        * scsi_bh_queue_head = NULL;
 static Scsi_Cmnd	* scsi_bh_queue_tail = NULL;
-static spinlock_t	  scsi_bh_queue_spin = SPIN_LOCK_UNLOCKED;
 static FreeSectorBitmap * dma_malloc_freelist = NULL;
 static int                need_isa_bounce_buffers;
 static unsigned int       dma_sectors = 0;
@@ -1260,7 +1259,7 @@
    */
   if( SCpnt->host->in_recovery
       && !SCpnt->host->eh_active
-      && atomic_read(&SCpnt->host->host_active) == SCpnt->host->host_failed )
+      && SCpnt->host->host_busy == SCpnt->host->host_failed )
   {
       SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler thread (%d)\n",
                                  atomic_read(&SCpnt->host->eh_wait->count)));
@@ -1510,16 +1509,22 @@
 void
 scsi_done (Scsi_Cmnd * SCpnt)
 {
-  unsigned long      flags;
 
   /*
    * We don't have to worry about this one timing out any more.
    */
   scsi_delete_timer(SCpnt);
 
+  /* Set the serial numbers back to zero */
+  SCpnt->serial_number = 0;
+
   /*
    * First, see whether this command already timed out.  If so, we ignore
    * the response.  We treat it as if the command never finished.
+   *
+   * Since serial_number is now 0, the error handler cound detect this
+   * situation and avoid to call the the low level driver abort routine.
+   * (DB)
    */
   if( SCpnt->state == SCSI_STATE_TIMEOUT )
     {
@@ -1527,27 +1532,22 @@
       return;
     }
 
-  /* Set the serial numbers back to zero */
-  SCpnt->serial_number = 0;
   SCpnt->serial_number_at_timeout = 0;
-
   SCpnt->state = SCSI_STATE_BHQUEUE;
   SCpnt->owner = SCSI_OWNER_BH_HANDLER;
   SCpnt->bh_next = NULL;
 
   /*
-   * Next, put this command in the BH queue.  All processing of the command
-   * past this point will take place with interrupts turned on.
-   * We start by atomicly swapping the pointer into the queue head slot.
-   * If it was NULL before, then everything is fine, and we are done
-   * (this is the normal case).  If it was not NULL, then we block interrupts,
-   * and link them together.
+   * Next, put this command in the BH queue.
+   * 
    * We need a spinlock here, or compare and exchange if we can reorder incoming
    * Scsi_Cmnds, as it happens pretty often scsi_done is called multiple times
    * before bh is serviced. -jj
+   *
+   * We already have the io_request_lock here, since we are called from the
+   * interrupt handler or the error handler. (DB)
+   *
    */
-
-  spin_lock_irqsave(&scsi_bh_queue_spin, flags);
   if (!scsi_bh_queue_head) {
   	scsi_bh_queue_head = SCpnt;
   	scsi_bh_queue_tail = SCpnt;
@@ -1555,7 +1555,6 @@
   	scsi_bh_queue_tail->bh_next = SCpnt;
   	scsi_bh_queue_tail = SCpnt;
   }
-  spin_unlock_irqrestore(&scsi_bh_queue_spin, flags);
 
   /*
    * Mark the bottom half handler to be run.
@@ -1573,45 +1572,29 @@
  * Notes:       This is called with all interrupts enabled.  This should reduce
  *              interrupt latency, stack depth, and reentrancy of the low-level
  *              drivers.
+ *
+ * The io_request_lock is required in all the routine. There was a subtle
+ * race condition when scsi_done is called after a command has already
+ * timed out but before the time out is processed by the error handler.
+ * (DB)
  */
 void scsi_bottom_half_handler(void)
 {
   Scsi_Cmnd        * SCpnt;
   Scsi_Cmnd        * SCnext;
-  static atomic_t    recursion_depth;
   unsigned long      flags;
   
+  spin_lock_irqsave(&io_request_lock, flags);
+
   while(1==1)
   {
-      /*
-       * If the counter is > 0, that means that there is another interrupt handler
-       * out there somewhere processing commands.  We don't want to get these guys
-       * nested as this can lead to stack overflow problems, and there isn't any
-       * real sense in it anyways.
-       */
-      if( atomic_read(&recursion_depth) > 0 )
-      {
-          printk("SCSI bottom half recursion depth = %d \n", atomic_read(&recursion_depth));
-          SCSI_LOG_MLCOMPLETE(1,printk("SCSI bottom half recursion depth = %d \n", 
-                                       atomic_read(&recursion_depth)));
-          break;
-      }
-      
-      /*
-       * We need to hold the spinlock, so that nobody is tampering with the queue. -jj
-       * We will process everything we find in the list here.
-       */
-      
-      spin_lock_irqsave(&scsi_bh_queue_spin, flags);
       SCpnt = scsi_bh_queue_head;
       scsi_bh_queue_head = NULL;
-      spin_unlock_irqrestore(&scsi_bh_queue_spin, flags);
       
-      if( SCpnt == NULL )
+      if( SCpnt == NULL ) {
+          spin_unlock_irqrestore(&io_request_lock, flags);
           return;
-      
-      spin_lock_irqsave(&io_request_lock, flags);
-      atomic_inc(&recursion_depth);
+          }
       
       SCnext = SCpnt->bh_next;
       
@@ -1684,7 +1667,7 @@
                    * If the host is having troubles, then look to see if this was the last
                    * command that might have failed.  If so, wake up the error handler.
                    */
-                  if( atomic_read(&SCpnt->host->host_active) == SCpnt->host->host_failed )
+                  if( SCpnt->host->host_busy == SCpnt->host->host_failed )
                   {
                     SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler thread (%d)\n",
                                                       atomic_read(&SCpnt->host->eh_wait->count)));
@@ -1701,11 +1684,10 @@
           }
       } /* for(; SCpnt...) */
 
-      atomic_dec(&recursion_depth);
-      spin_unlock_irqrestore(&io_request_lock, flags);
-
   } /* while(1==1) */
 
+  spin_unlock_irqrestore(&io_request_lock, flags);
+
 }
 
 /*
@@ -1790,6 +1772,10 @@
     
     SCpnt->owner = SCSI_OWNER_HIGHLEVEL;
     SCpnt->state = SCSI_STATE_FINISHED;
+
+    /* We can get here with use_sg=0, causing a panic in the upper level (DB) */
+    SCpnt->use_sg = SCpnt->old_use_sg;
+
     SCpnt->done (SCpnt);
 }
 
@@ -2305,8 +2291,13 @@
 	    return(-ENOSYS);  /* We do not yet support unplugging */
 
 	scan_scsis (HBA_ptr, 1, channel, id, lun);
+
+        /* FIXME (DB) This assumes that the queue_depth routines can be used
+           in this context as well, while they were all designed to be
+           called only once after the detect routine. (DB) */
 	if (HBA_ptr->select_queue_depths != NULL)
 		(HBA_ptr->select_queue_depths)(HBA_ptr, HBA_ptr->host_queue);
+
 	return(length);
 
     }
@@ -2566,12 +2557,30 @@
     Scsi_Device * SDpnt;
     struct Scsi_Device_Template * sdtpnt;
     const char * name;
+    unsigned long flags;
 
     if (tpnt->next || !tpnt->detect) return 1;/* Must be already loaded, or
 					       * no detect routine available
 					       */
     pcount = next_scsi_host;
-    if ((tpnt->present = tpnt->detect(tpnt)))
+
+    /* The detect routine must carefully spinunlock/spinlock if 
+       it enables interrupts, since all interrupt handlers do 
+       spinlock as well.
+       All lame drivers are going to fail due to the following 
+       spinlock. For the time beeing let's use it only for drivers 
+       using the new scsi code. NOTE: the detect routine could
+       redefine the value tpnt->use_new_eh_code. (DB, 13 May 1998) */
+
+    if (tpnt->use_new_eh_code) {
+       spin_lock_irqsave(&io_request_lock, flags);
+       tpnt->present = tpnt->detect(tpnt);
+       spin_unlock_irqrestore(&io_request_lock, flags);
+       }
+    else
+       tpnt->present = tpnt->detect(tpnt);
+
+    if (tpnt->present)
     {
 	if(pcount == next_scsi_host) 
         {
@@ -2784,8 +2793,9 @@
                 SDpnt->online = FALSE;
 	        if(SCpnt->request.rq_status != RQ_INACTIVE) 
                 {
-                    printk("SCSI device not inactive - state=%d, id=%d\n",
-                           SCpnt->request.rq_status, SCpnt->target);
+                    printk("SCSI device not inactive - rq_status=%d, target=%d, pid=%ld, state=%d, owner=%d.\n",
+                           SCpnt->request.rq_status, SCpnt->target, SCpnt->pid,
+                           SCpnt->state, SCpnt->owner);
                     for(SDpnt1 = shpnt->host_queue; SDpnt1; 
                         SDpnt1 = SDpnt1->next)
                       {
diff -u --recursive --new-file v2.1.102/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v2.1.102/linux/drivers/scsi/scsi.h	Fri Apr 10 13:03:49 1998
+++ linux/drivers/scsi/scsi.h	Wed May 20 16:23:00 1998
@@ -253,6 +253,7 @@
 #define DID_RESET       0x08 /* Reset by somebody.                      */
 #define DID_BAD_INTR    0x09 /* Got an interrupt we weren't expecting.  */ 
 #define DID_PASSTHROUGH 0x0a /* Force command past mid-layer            */
+#define DID_SOFT_ERROR  0x0b /* The low level driver just wish a retry  */
 #define DRIVER_OK       0x00 /* Driver status                           */ 
 
 /*
diff -u --recursive --new-file v2.1.102/linux/drivers/scsi/scsi_error.c linux/drivers/scsi/scsi_error.c
--- v2.1.102/linux/drivers/scsi/scsi_error.c	Thu May 14 19:47:41 1998
+++ linux/drivers/scsi/scsi_error.c	Wed May 20 10:36:12 1998
@@ -113,9 +113,9 @@
     SCset->eh_timeout.data = (unsigned long) SCset;
     SCset->eh_timeout.expires = jiffies + timeout;
     SCset->eh_timeout.function = (void (*)(unsigned long))complete;
-    
+
     SCSI_LOG_ERROR_RECOVERY(5,printk("Adding timer for command %p at %d (%p)\n", SCset, timeout, complete));
-    
+
     add_timer(&SCset->eh_timeout);
 
 }
@@ -204,6 +204,7 @@
     /* Set the serial_number_at_timeout to the current serial_number */
     SCpnt->serial_number_at_timeout = SCpnt->serial_number;
 
+    SCpnt->eh_state = FAILED;
     SCpnt->state = SCSI_STATE_TIMEOUT;
     SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
     
@@ -219,7 +220,7 @@
      * If the host is having troubles, then look to see if this was the last
      * command that might have failed.  If so, wake up the error handler.
      */
-    if( atomic_read(&SCpnt->host->host_active) == SCpnt->host->host_failed )
+    if( SCpnt->host->host_busy == SCpnt->host->host_failed )
     {
         up(SCpnt->host->eh_wait);
     }
@@ -277,11 +278,22 @@
 void scsi_eh_times_out (Scsi_Cmnd * SCpnt)
 {
   unsigned long flags;
+  int rtn = FAILED;
 
   spin_lock_irqsave(&io_request_lock, flags);
+
+  SCpnt->eh_state = SCSI_STATE_TIMEOUT;
+  SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+
+  /*
+   * As far as the low level driver is concerned, this command is still
+   * active, so we must give the low level driver a chance to abort it. (DB)
+   */
+  if (SCpnt->host->hostt->eh_abort_handler)
+     rtn = SCpnt->host->hostt->eh_abort_handler(SCpnt);
+
   SCpnt->request.rq_status = RQ_SCSI_DONE;
   SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
-  SCpnt->eh_state = SCSI_STATE_TIMEOUT;
 
   SCSI_LOG_ERROR_RECOVERY(5,printk("In scsi_eh_times_out %p\n", SCpnt));
 
@@ -384,8 +396,6 @@
   SCpnt->use_sg = SCpnt->old_use_sg;
   SCpnt->cmd_len = SCpnt->old_cmd_len;
 
-  SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
-
   scsi_send_eh_cmnd (SCpnt, SCpnt->timeout_per_command);
 
   /*
@@ -412,20 +422,57 @@
 scsi_request_sense(Scsi_Cmnd * SCpnt)
 {
   static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
+  unsigned char scsi_result0[256], *scsi_result=NULL;
+
 
   memcpy ((void *) SCpnt->cmnd , (void *) generic_sense,
 	  sizeof(generic_sense));
 
   SCpnt->cmnd[1] = SCpnt->lun << 5;
-  SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
 
-  SCpnt->request_buffer = &SCpnt->sense_buffer;
-  SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
+  scsi_result = (!SCpnt->host->hostt->unchecked_isa_dma)
+             ? &scsi_result0[0] : scsi_init_malloc (512, GFP_ATOMIC|GFP_DMA);
+
+  if (scsi_result == NULL) {
+     printk("cannot allocate scsi_result in scsi_request_sense.\n");
+     return FAILED;
+     }
+
+  /*
+   * Zero the sense buffer.  Some host adapters automatically always request
+   * sense, so it is not a good idea that SCpnt->request_buffer and
+   * SCpnt->sense_buffer point to the same address (DB).
+   * 0 is not a valid sense code. 
+   */
+  memset ((void *) SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
+  memset ((void *) scsi_result, 0, 256);
+
+  SCpnt->request_buffer = scsi_result;
+  SCpnt->request_bufflen = 256;
   SCpnt->use_sg = 0;
   SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
 
   scsi_send_eh_cmnd (SCpnt, SENSE_TIMEOUT);
 
+  /* Last chance to have valid sense data */
+  if (!scsi_sense_valid(SCpnt)) memcpy((void *) SCpnt->sense_buffer,
+                                                SCpnt->request_buffer,
+                                                sizeof(SCpnt->sense_buffer));
+
+  if (scsi_result != &scsi_result0[0] && scsi_result != NULL)
+        scsi_init_free (scsi_result, 512);
+
+  /*
+   * When we eventually call scsi_finish, we really wish to complete
+   * the original request, so let's restore the original data. (DB)
+   */
+  memcpy ((void *) SCpnt->cmnd,  (void*) SCpnt->data_cmnd,
+          sizeof(SCpnt->data_cmnd));
+  SCpnt->request_buffer = SCpnt->buffer;
+  SCpnt->request_bufflen = SCpnt->bufflen;
+  SCpnt->use_sg = SCpnt->old_use_sg;
+  SCpnt->cmd_len = SCpnt->old_cmd_len;
+
   /*
    * Hey, we are done.  Let's look to see what happened.
    */
@@ -442,20 +489,55 @@
 scsi_test_unit_ready(Scsi_Cmnd * SCpnt)
 {
   static unsigned char tur_command[6] = {TEST_UNIT_READY, 0,0,0,0,0};
+  unsigned char scsi_result0[256], *scsi_result=NULL;
 
   memcpy ((void *) SCpnt->cmnd , (void *) tur_command,
 	  sizeof(tur_command));
 
   SCpnt->cmnd[1] = SCpnt->lun << 5;
-  SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
 
-  SCpnt->request_buffer = &SCpnt->sense_buffer;
-  SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
+  scsi_result = (!SCpnt->host->hostt->unchecked_isa_dma)
+             ? &scsi_result0[0] : scsi_init_malloc (512, GFP_ATOMIC|GFP_DMA);
+
+  if (scsi_result == NULL) {
+     printk("cannot allocate scsi_result in scsi_test_unit_ready.\n");
+     return FAILED;
+     }
+
+  /*
+   * Zero the sense buffer.  Some host adapters automatically always request
+   * sense, so it is not a good idea that SCpnt->request_buffer and
+   * SCpnt->sense_buffer point to the same address (DB).
+   * 0 is not a valid sense code. 
+   */
+  memset ((void *) SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
+  memset ((void *) scsi_result, 0, 256);
+
+  SCpnt->request_buffer = scsi_result;
+  SCpnt->request_bufflen = 256;
   SCpnt->use_sg = 0;
   SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
-
   scsi_send_eh_cmnd (SCpnt, SENSE_TIMEOUT);
 
+  /* Last chance to have valid sense data */
+  if (!scsi_sense_valid(SCpnt)) memcpy((void *) SCpnt->sense_buffer,
+                                                SCpnt->request_buffer,
+                                                sizeof(SCpnt->sense_buffer));
+
+  if (scsi_result != &scsi_result0[0] && scsi_result != NULL)
+        scsi_init_free (scsi_result, 512);
+
+  /*
+   * When we eventually call scsi_finish, we really wish to complete
+   * the original request, so let's restore the original data. (DB)
+   */
+  memcpy ((void *) SCpnt->cmnd,  (void*) SCpnt->data_cmnd,
+          sizeof(SCpnt->data_cmnd));
+  SCpnt->request_buffer = SCpnt->buffer;
+  SCpnt->request_bufflen = SCpnt->bufflen;
+  SCpnt->use_sg = SCpnt->old_use_sg;
+  SCpnt->cmd_len = SCpnt->old_cmd_len;
+
   /*
    * Hey, we are done.  Let's look to see what happened.
    */
@@ -490,7 +572,9 @@
     
     add_timer(&timer);
 
+    spin_unlock_irq(&io_request_lock);
     down(&sem);
+    spin_lock_irq(&io_request_lock);
     
     del_timer(&timer);
 }
@@ -532,7 +616,10 @@
 	SCpnt->request.rq_status = RQ_SCSI_BUSY;
 
 	host->hostt->queuecommand (SCpnt, scsi_eh_done);
-	down(&sem);
+        spin_unlock_irq(&io_request_lock);
+        down(&sem);
+        spin_lock_irq(&io_request_lock);
+
         SCpnt->host->eh_action = NULL;
 
 	del_timer(&SCpnt->eh_timeout);
@@ -678,7 +765,13 @@
     {
       return FAILED;
     }
-  
+
+  /* 
+   * scsi_done was called just after the command timed out and before
+   * we had a chance to process it. (DB)
+   */
+  if (SCpnt->serial_number == 0) return SUCCESS;
+
   SCpnt->owner = SCSI_OWNER_LOWLEVEL;
 
   return SCpnt->host->hostt->eh_abort_handler(SCpnt);
@@ -701,6 +794,8 @@
 STATIC int
 scsi_try_bus_device_reset(Scsi_Cmnd * SCpnt, int timeout)
 {
+  int		   rtn;
+
   SCpnt->eh_state = FAILED; /* Until we come up with something better */
 
   if( SCpnt->host->hostt->eh_device_reset_handler == NULL )
@@ -710,7 +805,11 @@
   
   SCpnt->owner = SCSI_OWNER_LOWLEVEL;
     
-  return SCpnt->host->hostt->eh_device_reset_handler(SCpnt);
+  rtn = SCpnt->host->hostt->eh_device_reset_handler(SCpnt);
+
+  if (rtn == SUCCESS) SCpnt->eh_state = SUCCESS;
+
+  return SCpnt->eh_state;
 }
 
 /*
@@ -730,6 +829,7 @@
 
   SCpnt->eh_state = FAILED; /* Until we come up with something better */
   SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+  SCpnt->serial_number_at_timeout = SCpnt->serial_number;
 
   if( SCpnt->host->hostt->eh_bus_reset_handler == NULL )
     {
@@ -738,6 +838,8 @@
 
   rtn = SCpnt->host->hostt->eh_bus_reset_handler(SCpnt);
 
+  if (rtn == SUCCESS) SCpnt->eh_state = SUCCESS;
+
   /*
    * If we had a successful bus reset, mark the command blocks to expect
    * a condition code of unit attention.
@@ -776,6 +878,7 @@
 
     SCpnt->eh_state = FAILED; /* Until we come up with something better */
     SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+    SCpnt->serial_number_at_timeout = SCpnt->serial_number;
     
     if( SCpnt->host->hostt->eh_host_reset_handler == NULL )
     {
@@ -784,6 +887,8 @@
     
     rtn = SCpnt->host->hostt->eh_host_reset_handler(SCpnt);
 
+    if (rtn == SUCCESS) SCpnt->eh_state = SUCCESS;
+
     /*
      * If we had a successful host reset, mark the command blocks to expect
      * a condition code of unit attention.
@@ -868,8 +973,16 @@
        * sucess.
        */
       return SUCCESS;
-    case DID_PARITY:
+      /*
+       * When the low level driver returns DID_SOFT_ERROR,
+       * it is responsible for keeping an internal retry counter 
+       * in order to avoid endless loops (DB)
+       */
+    case DID_SOFT_ERROR:
+      return NEEDS_RETRY;
+
     case DID_BUS_BUSY:
+    case DID_PARITY:
     case DID_ERROR:
       goto maybe_retry;
     case DID_TIME_OUT:
@@ -1217,6 +1330,7 @@
       {
           if( SCpnt->state == SCSI_STATE_FAILED 
               || SCpnt->state == SCSI_STATE_TIMEOUT 
+              || SCpnt->state == SCSI_STATE_INITIALIZING
               || SCpnt->state == SCSI_STATE_UNUSED)
           {
               continue;
@@ -1230,7 +1344,24 @@
            * the command will be queued and will be finished along the way.
            */
           SCSI_LOG_ERROR_RECOVERY(1,printk("Error handler prematurely woken - commands still active (%p %x %d)\n", SCpnt, SCpnt->state, SCpnt->target));
-          panic("SCSI Error handler woken too early\n");
+
+/*
+ *        panic("SCSI Error handler woken too early\n");
+ *
+ * This is no longer a problem, since now the code cares only about
+ * SCSI_STATE_TIMEOUT and SCSI_STATE_FAILED.
+ * Other states are useful only to release active commands when devices are
+ * set offline. If (host->host_active == host->host_busy) we can safely assume
+ * that there are no commands in state other then TIMEOUT od FAILED. (DB)
+ *
+ * FIXME:
+ * It is not easy to release correctly commands according to their state when 
+ * devices are set offline, when the state is neither TIMEOUT nor FAILED.
+ * When a device is set offline, we can have some command with
+ * rq_status=RQ_SCSY_BUSY, owner=SCSI_STATE_HIGHLEVEL, 
+ * state=SCSI_STATE_INITIALIZING and the driver module cannot be released.
+ * (DB, 17 May 1998)
+ */
       }
   }
 
@@ -1370,7 +1501,6 @@
           }
 
 	  rtn = scsi_try_to_abort_command(SCloop, ABORT_TIMEOUT);
-
 	  if( rtn == SUCCESS )
           {
 	      rtn = scsi_test_unit_ready(SCloop);
@@ -1518,6 +1648,13 @@
                        * *after* the error recovery procedure started, and if this
                        * is the case, we are worrying about nothing here.
                        */
+
+                      /*
+                       * Due to the spinlock, we will never get out of this
+                       * loop without a proper wait (DB)
+                       */
+                      scsi_sleep(1 * HZ);
+
                       goto next_device;
                   }
               }
@@ -1620,6 +1757,13 @@
                */
               SCSI_LOG_ERROR_RECOVERY(3,
                         printk("scsi_unjam_host: Unable to try hard host reset\n"));
+
+               /*
+                * Due to the spinlock, we will never get out of this
+                * loop without a proper wait. (DB)
+                */
+               scsi_sleep(1 * HZ);
+
               goto next_device2;
           }
 
@@ -1674,7 +1818,6 @@
       }
   }
 
-
   /*
    * If we solved all of the problems, then let's rev up the engines again.
    */
@@ -1783,6 +1926,7 @@
 	struct Scsi_Host     * host = (struct Scsi_Host *) data;
 	int	               rtn;
 	struct semaphore sem = MUTEX_LOCKED;
+        unsigned long flags;
 
 	lock_kernel();
 
@@ -1836,6 +1980,7 @@
 
             SCSI_LOG_ERROR_RECOVERY(1,printk("Error handler waking up\n"));
 
+	    spin_lock_irqsave(&io_request_lock, flags);
             host->eh_active = 1;
 
 	    /*
@@ -1862,6 +2007,9 @@
 	     * which are still online.
 	     */
 	    scsi_restart_operations(host);
+ 
+            /* The spinlock is really needed up to this point. (DB) */
+	    spin_unlock_irqrestore(&io_request_lock, flags);
 	  }
 
         SCSI_LOG_ERROR_RECOVERY(1,printk("Error handler exiting\n"));
diff -u --recursive --new-file v2.1.102/linux/drivers/scsi/sr_vendor.c linux/drivers/scsi/sr_vendor.c
--- v2.1.102/linux/drivers/scsi/sr_vendor.c	Thu Feb 12 20:56:10 1998
+++ linux/drivers/scsi/sr_vendor.c	Mon May 18 11:06:42 1998
@@ -238,6 +238,7 @@
 		sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
 		if (sector)
 			sector -= CD_MSF_OFFSET;
+		sr_set_blocklength(minor,2048);
 		break;
 	}
 
diff -u --recursive --new-file v2.1.102/linux/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c
--- v2.1.102/linux/drivers/scsi/u14-34f.c	Thu May 14 19:47:41 1998
+++ linux/drivers/scsi/u14-34f.c	Wed May 20 10:38:44 1998
@@ -1,6 +1,18 @@
 /*
  *      u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
  *
+ *      18 May 1998 Rev. 4.31 for linux 2.0.33 and 2.1.102
+ *          Improved abort handling during the eh recovery process.
+ *
+ *      13 May 1998 Rev. 4.30 for linux 2.0.33 and 2.1.101
+ *          The driver is now fully SMP safe, including the
+ *          abort and reset routines.
+ *          Added command line options (eh:[y|n]) to choose between
+ *          new_eh_code and the old scsi code.
+ *          If linux verion >= 2.1.101 the default is eh:y, while the eh
+ *          option is ignored for previous releases and the old scsi code
+ *          is used.
+ *
  *      18 Apr 1998 Rev. 4.20 for linux 2.0.33 and 2.1.97
  *          Reworked interrupt handler.
  *
@@ -227,6 +239,8 @@
  *  After the optional list of detection probes, other possible command line
  *  options are:
  *
+ *  eh:y  use new scsi code (linux 2.2 only);
+ *  eh:n  use old scsi code;
  *  lc:y  enables linked commands;
  *  lc:n  disables linked commands;
  *  of:y  enables old firmware support;
@@ -234,13 +248,13 @@
  *  mq:xx set the max queue depth to the value xx (2 <= xx <= 8).
  *
  *  The default value is: "u14-34f=lc:n,of:n,mq:8". An example using the list
- *  of detection probes could be: "u14-34f=0x230,0x340,lc:y,of:n,mq:4".
+ *  of detection probes could be: "u14-34f=0x230,0x340,lc:y,of:n,mq:4,eh:n".
  *
  *  When loading as a module, parameters can be specified as well.
  *  The above example would be (use 1 in place of y and 0 in place of n):
  *
  *  modprobe u14-34f io_port=0x230,0x340 linked_comm=1 have_old_firmware=0 \
- *                max_queue_depth=4
+ *                max_queue_depth=4 use_new_eh_code=0
  *
  *  ----------------------------------------------------------------------------
  *  In this implementation, linked commands are designed to work with any DISK
@@ -295,6 +309,7 @@
 MODULE_PARM(have_old_firmware, "i");
 MODULE_PARM(link_statistics, "i");
 MODULE_PARM(max_queue_depth, "i");
+MODULE_PARM(use_new_eh_code, "i");
 MODULE_AUTHOR("Dario Ballabio");
 #endif
 
@@ -308,11 +323,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/byteorder.h>
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,95)
-#include <asm/spinlock.h>
-#endif
-
 #include <linux/proc_fs.h>
 #include <linux/blk.h>
 #include "scsi.h"
@@ -332,6 +342,34 @@
 #define __init
 #endif
 
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
+#include <asm/spinlock.h>
+#define IRQ_FLAGS
+#define IRQ_LOCK
+#define IRQ_LOCK_SAVE
+#define IRQ_UNLOCK
+#define IRQ_UNLOCK_RESTORE
+#define SPIN_FLAGS unsigned long spin_flags;
+#define SPIN_LOCK spin_lock_irq(&io_request_lock);
+#define SPIN_LOCK_SAVE spin_lock_irqsave(&io_request_lock, spin_flags);
+#define SPIN_UNLOCK spin_unlock_irq(&io_request_lock);
+#define SPIN_UNLOCK_RESTORE \
+                  spin_unlock_irqrestore(&io_request_lock, spin_flags);
+static int use_new_eh_code = TRUE;
+#else
+#define IRQ_FLAGS unsigned long irq_flags;
+#define IRQ_LOCK cli();
+#define IRQ_LOCK_SAVE do {save_flags(irq_flags); cli();} while (0);
+#define IRQ_UNLOCK sti();
+#define IRQ_UNLOCK_RESTORE do {restore_flags(irq_flags);} while (0);
+#define SPIN_FLAGS
+#define SPIN_LOCK
+#define SPIN_LOCK_SAVE
+#define SPIN_UNLOCK
+#define SPIN_UNLOCK_RESTORE
+static int use_new_eh_code = FALSE;
+#endif
+
 struct proc_dir_entry proc_scsi_u14_34f = {
     PROC_SCSI_U14_34F, 6, "u14_34f",
     S_IFDIR | S_IRUGO | S_IXUGO, 2
@@ -361,6 +399,8 @@
 #undef  DEBUG_DETECT
 #undef  DEBUG_INTERRUPT
 #undef  DEBUG_RESET
+#undef  DEBUG_GENERATE_ERRORS
+#undef  DEBUG_GENERATE_ABORTS
 
 #define MAX_ISA 3
 #define MAX_VESA 1
@@ -513,19 +553,19 @@
 static int setup_done = FALSE;
 static int link_statistics = 0;
 
-#if defined (HAVE_OLD_UX4F_FIRMWARE)
+#if defined(HAVE_OLD_UX4F_FIRMWARE)
 static int have_old_firmware = TRUE;
 #else
 static int have_old_firmware = FALSE;
 #endif
 
-#if defined (CONFIG_SCSI_U14_34F_LINKED_COMMANDS)
+#if defined(CONFIG_SCSI_U14_34F_LINKED_COMMANDS)
 static int linked_comm = TRUE;
 #else
 static int linked_comm = FALSE;
 #endif
 
-#if defined CONFIG_SCSI_U14_34F_MAX_TAGS
+#if defined(CONFIG_SCSI_U14_34F_MAX_TAGS)
 static int max_queue_depth = CONFIG_SCSI_U14_34F_MAX_TAGS;
 #else
 static int max_queue_depth = MAX_CMD_PER_LUN;
@@ -534,11 +574,9 @@
 static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) {
    Scsi_Device *dev;
    int j, ntag = 0, nuntag = 0, tqd, utqd;
-   unsigned long flags;
-
-   save_flags(flags);
-   cli();
+   IRQ_FLAGS
 
+   IRQ_LOCK_SAVE
    j = ((struct hostdata *) host->hostdata)->board_number;
 
    for(dev = devlist; dev; dev = dev->next) {
@@ -586,7 +624,7 @@
              dev->queue_depth, link_suffix, tag_suffix);
       }
 
-   restore_flags(flags);
+   IRQ_UNLOCK_RESTORE
    return;
 }
 
@@ -629,8 +667,12 @@
    /* Issue OGM interrupt */
    outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
 
-   /* Wait a second.. */
-   { unsigned int msec = 1000; while (--msec) udelay(1000); }
+   SPIN_UNLOCK
+   IRQ_UNLOCK
+   time = jiffies;
+   while ((jiffies - time) < HZ && limit++ < 20000) udelay(100L);
+   IRQ_LOCK
+   SPIN_LOCK
 
    if (cpp->adapter_status || HD(j)->cp_stat[0] != FREE) {
       HD(j)->cp_stat[0] = FREE;
@@ -719,6 +761,14 @@
       return FALSE;
       }
 
+   if (have_old_firmware) tpnt->use_clustering = DISABLE_CLUSTERING;
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
+   tpnt->use_new_eh_code = use_new_eh_code;
+#else
+   use_new_eh_code = FALSE;
+#endif
+
    sh[j] = scsi_register(tpnt, sizeof(struct hostdata));
 
    if (sh[j] == NULL) {
@@ -752,6 +802,9 @@
    }
 #endif
 
+   /* Probably a bogus host scsi id, set it to the dummy value */
+   if (sh[j]->this_id == 0) sh[j]->this_id = -1;
+
    /* If BIOS is disabled, force enable interrupts */
    if (sh[j]->base == 0) outb(CMD_ENA_INTR, sh[j]->io_port + REG_SYS_MASK);
 
@@ -779,9 +832,6 @@
       clear_dma_ff(dma_channel);
       set_dma_mode(dma_channel, DMA_MODE_CASCADE);
       enable_dma(dma_channel);
-
-      if (have_old_firmware) sh[j]->hostt->use_clustering = DISABLE_CLUSTERING;
-
       sh[j]->dma_channel = dma_channel;
       sprintf(BN(j), "U14F%d", j);
       bus_type = "ISA";
@@ -820,18 +870,23 @@
 
    if (max_queue_depth < MAX_CMD_PER_LUN) max_queue_depth = MAX_CMD_PER_LUN;
 
-   printk("%s: %s 0x%03lx, BIOS 0x%05x, IRQ %u, %s, SG %d, MB %d, of:%c, "\
-          "lc:%c, mq:%d.\n", BN(j), bus_type, (unsigned long)sh[j]->io_port,
-          (int)sh[j]->base, sh[j]->irq, dma_name, sh[j]->sg_tablesize,
-          sh[j]->can_queue, YESNO(have_old_firmware), YESNO(linked_comm),
-          max_queue_depth);
+   if (j == 0) {
+      printk("UltraStor 14F/34F: Copyright (C) 1994-1998 Dario Ballabio.\n");
+      printk("%s config options -> of:%c, lc:%c, mq:%d, eh:%c.\n",
+             driver_name, YESNO(have_old_firmware), YESNO(linked_comm),
+             max_queue_depth, YESNO(use_new_eh_code));
+      }
+
+   printk("%s: %s 0x%03lx, BIOS 0x%05x, IRQ %u, %s, SG %d, MB %d.\n",
+          BN(j), bus_type, (unsigned long)sh[j]->io_port, (int)sh[j]->base,
+          sh[j]->irq, dma_name, sh[j]->sg_tablesize, sh[j]->can_queue);
 
    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 (i = 0; i <= sh[j]->max_channel; i++)
-      printk("%s: SCSI channel %u enabled, host target ID %u.\n",
+      printk("%s: SCSI channel %u enabled, host target ID %d.\n",
              BN(j), i, sh[j]->this_id);
 
    return TRUE;
@@ -862,6 +917,7 @@
       else if (!strncmp(cur, "of:", 3)) have_old_firmware = val;
       else if (!strncmp(cur, "mq:", 3))  max_queue_depth = val;
       else if (!strncmp(cur, "ls:", 3))  link_statistics = val;
+      else if (!strncmp(cur, "eh:", 3))  use_new_eh_code = val;
 
       if ((cur = strchr(cur, ','))) ++cur;
       }
@@ -870,14 +926,12 @@
 }
 
 __initfunc (int u14_34f_detect(Scsi_Host_Template *tpnt)) {
-   unsigned long flags;
    unsigned int j = 0, k;
+   IRQ_FLAGS
 
+   IRQ_LOCK_SAVE
    tpnt->proc_dir = &proc_scsi_u14_34f;
 
-   save_flags(flags);
-   cli();
-
 #if defined(MODULE)
    /* io_port could have been modified when loading as a module */
    if(io_port[0] != SKIP) {
@@ -895,11 +949,8 @@
       if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt)) j++;
       }
 
-   if (j > 0)
-      printk("UltraStor 14F/34F: Copyright (C) 1994-1998 Dario Ballabio.\n");
-
    num_boards = j;
-   restore_flags(flags);
+   IRQ_UNLOCK_RESTORE
    return j;
 }
 
@@ -920,8 +971,7 @@
    cpp->data_len = H2DEV(data_len);
 }
 
-int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
-   unsigned long flags;
+static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
    unsigned int i, j, k;
    struct mscp *cpp;
 
@@ -937,22 +987,12 @@
       0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5
       };
 
-   save_flags(flags);
-   cli();
    /* j is the board number */
    j = ((struct hostdata *) SCpnt->host->hostdata)->board_number;
 
-   if (!done) panic("%s: qcomm, pid %ld, null done.\n", BN(j), SCpnt->pid);
-
-   if (SCpnt->cmnd[0] == REQUEST_SENSE && SCpnt->sense_buffer[0]) {
-      SCpnt->result = DID_OK << 16;
-      SCpnt->host_scribble = NULL;
-      printk("%s: qcomm, target %d.%d:%d, pid %ld, request sense ignored.\n",
-             BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid);
-      restore_flags(flags);
-      done(SCpnt);
-      return 0;
-      }
+   if (SCpnt->host_scribble)
+      panic("%s: qcomm, pid %ld, SCpnt %p already active.\n",
+            BN(j), SCpnt->pid, SCpnt);
 
    /* i is the mailbox number, look for the first free mailbox
       starting from last_cp_used */
@@ -969,19 +1009,7 @@
       }
 
    if (k == sh[j]->can_queue) {
-      printk("%s: qcomm, no free mailbox, resetting.\n", BN(j));
-
-      if (HD(j)->in_reset)
-         printk("%s: qcomm, already in reset.\n", BN(j));
-      else if (u14_34f_reset(SCpnt, SCSI_RESET_SUGGEST_BUS_RESET)
-               == SCSI_RESET_SUCCESS)
-         panic("%s: qcomm, SCSI_RESET_SUCCESS.\n", BN(j));
-
-      SCpnt->result = DID_BUS_BUSY << 16;
-      SCpnt->host_scribble = NULL;
-      printk("%s: qcomm, pid %ld, DID_BUS_BUSY, done.\n", BN(j), SCpnt->pid);
-      restore_flags(flags);
-      done(SCpnt);
+      printk("%s: qcomm, no free mailbox.\n", BN(j));
       return 1;
       }
 
@@ -1036,18 +1064,13 @@
                                      && TLDEV(SCpnt->device->type)) {
       HD(j)->cp_stat[i] = READY;
       flush_dev(SCpnt->device, SCpnt->request.sector, j, FALSE);
-      restore_flags(flags);
       return 0;
       }
 
    if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
-      SCpnt->result = DID_ERROR << 16;
       SCpnt->host_scribble = NULL;
-      printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy, DID_ERROR,"\
-             " done.\n", BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun,
-             SCpnt->pid);
-      restore_flags(flags);
-      done(SCpnt);
+      printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy.\n",
+             BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid);
       return 1;
       }
 
@@ -1058,23 +1081,29 @@
    outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
 
    HD(j)->cp_stat[i] = IN_USE;
-   restore_flags(flags);
    return 0;
 }
 
-int u14_34f_abort(Scsi_Cmnd *SCarg) {
-   unsigned long flags;
+int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
+   int rtn;
+   IRQ_FLAGS
+
+   IRQ_LOCK_SAVE
+   rtn = do_qcomm(SCpnt, done);
+   IRQ_UNLOCK_RESTORE
+   return rtn;
+}
+
+static inline int do_old_abort(Scsi_Cmnd *SCarg) {
    unsigned int i, j;
 
-   save_flags(flags);
-   cli();
    j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
 
-   if (SCarg->host_scribble == NULL
-       || SCarg->serial_number != SCarg->serial_number_at_timeout) {
+   if (SCarg->host_scribble == NULL ||
+       (SCarg->serial_number_at_timeout &&
+       (SCarg->serial_number != SCarg->serial_number_at_timeout))) {
       printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n",
              BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
-      restore_flags(flags);
       return SCSI_ABORT_NOT_RUNNING;
       }
 
@@ -1087,13 +1116,11 @@
 
    if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
       printk("%s: abort, timeout error.\n", BN(j));
-      restore_flags(flags);
       return SCSI_ABORT_ERROR;
       }
 
    if (HD(j)->cp_stat[i] == FREE) {
       printk("%s: abort, mbox %d is free.\n", BN(j), i);
-      restore_flags(flags);
       return SCSI_ABORT_NOT_RUNNING;
       }
 
@@ -1107,19 +1134,16 @@
       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;
       }
 
    if (HD(j)->cp_stat[i] == IN_RESET) {
       printk("%s: abort, mbox %d is in reset.\n", BN(j), i);
-      restore_flags(flags);
       return SCSI_ABORT_ERROR;
       }
 
    if (HD(j)->cp_stat[i] == LOCKED) {
       printk("%s: abort, mbox %d is locked.\n", BN(j), i);
-      restore_flags(flags);
       return SCSI_ABORT_NOT_RUNNING;
       }
 
@@ -1130,45 +1154,128 @@
       printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n",
              BN(j), i, SCarg->pid);
       SCarg->scsi_done(SCarg);
-      restore_flags(flags);
       return SCSI_ABORT_SUCCESS;
       }
 
-   restore_flags(flags);
    panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j), i);
 }
 
-int u14_34f_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
-   unsigned long flags;
+int u14_34f_old_abort(Scsi_Cmnd *SCarg) {
+   int rtn;
+   IRQ_FLAGS
+
+   IRQ_LOCK_SAVE
+   rtn = do_old_abort(SCarg);
+   IRQ_UNLOCK_RESTORE
+   return rtn;
+}
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
+
+static inline int do_abort(Scsi_Cmnd *SCarg) {
+   unsigned int i, j;
+
+   j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
+
+   if (SCarg->host_scribble == NULL) {
+      printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n",
+             BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
+      return SUCCESS;
+      }
+
+   i = *(unsigned int *)SCarg->host_scribble;
+   printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n",
+          BN(j), i, SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
+
+   if (i >= sh[j]->can_queue)
+      panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
+
+   if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+      printk("%s: abort, timeout error.\n", BN(j));
+      return FAILED;
+      }
+
+   if (HD(j)->cp_stat[i] == FREE) {
+      printk("%s: abort, mbox %d is free.\n", BN(j), i);
+      return SUCCESS;
+      }
+
+   if (HD(j)->cp_stat[i] == IN_USE) {
+      printk("%s: abort, mbox %d is in use.\n", BN(j), i);
+
+      if (SCarg != HD(j)->cp[i].SCpnt)
+         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);
+
+      if (SCarg->eh_state == SCSI_STATE_TIMEOUT) {
+         SCarg->host_scribble = NULL;
+         HD(j)->cp_stat[i] = FREE;
+         printk("%s, abort, mbox %d, eh_state timeout, pid %ld.\n",
+                BN(j), i, SCarg->pid);
+         return SUCCESS;
+         }
+
+      return FAILED;
+      }
+
+   if (HD(j)->cp_stat[i] == IN_RESET) {
+      printk("%s: abort, mbox %d is in reset.\n", BN(j), i);
+      return FAILED;
+      }
+
+   if (HD(j)->cp_stat[i] == LOCKED) {
+      printk("%s: abort, mbox %d is locked.\n", BN(j), i);
+      return SUCCESS;
+      }
+
+   if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
+      SCarg->result = DID_ABORT << 16;
+      SCarg->host_scribble = NULL;
+      HD(j)->cp_stat[i] = FREE;
+      printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n",
+             BN(j), i, SCarg->pid);
+      SCarg->scsi_done(SCarg);
+      return SUCCESS;
+      }
+
+   panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j), i);
+}
+
+int u14_34f_abort(Scsi_Cmnd *SCarg) {
+
+   return do_abort(SCarg);
+}
+
+#endif /* new_eh_code */
+
+static inline int do_old_reset(Scsi_Cmnd *SCarg) {
    unsigned int i, j, time, k, c, limit = 0;
    int arg_done = FALSE;
    Scsi_Cmnd *SCpnt;
 
-   save_flags(flags);
-   cli();
    j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
-   printk("%s: reset, enter, target %d.%d:%d, pid %ld, reset_flags %u.\n",
-          BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid,
-          reset_flags);
+   printk("%s: reset, enter, target %d.%d:%d, pid %ld.\n",
+          BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
 
    if (SCarg->host_scribble == NULL)
       printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
 
-   if (SCarg->serial_number != SCarg->serial_number_at_timeout) {
+   if (SCarg->serial_number_at_timeout &&
+       (SCarg->serial_number != SCarg->serial_number_at_timeout)) {
       printk("%s: reset, pid %ld, reset not running.\n", BN(j), SCarg->pid);
-      restore_flags(flags);
       return SCSI_RESET_NOT_RUNNING;
       }
 
    if (HD(j)->in_reset) {
       printk("%s: reset, exit, already in reset.\n", BN(j));
-      restore_flags(flags);
       return SCSI_RESET_ERROR;
       }
 
    if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
       printk("%s: reset, exit, timeout error.\n", BN(j));
-      restore_flags(flags);
       return SCSI_RESET_ERROR;
       }
 
@@ -1219,22 +1326,23 @@
 
    if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
       printk("%s: reset, cannot reset, timeout error.\n", BN(j));
-      restore_flags(flags);
       return SCSI_RESET_ERROR;
       }
 
    outb(CMD_RESET, sh[j]->io_port + REG_LCL_INTR);
    printk("%s: reset, board reset done, enabling interrupts.\n", BN(j));
 
-#if defined (DEBUG_RESET)
+#if defined(DEBUG_RESET)
    do_trace = TRUE;
 #endif
 
    HD(j)->in_reset = TRUE;
-
-   /* Wait 2 seconds ???!!! */
-   { unsigned int msec = 2*1000; while (--msec) udelay(1000); }
-
+   SPIN_UNLOCK
+   IRQ_UNLOCK
+   time = jiffies;
+   while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L);
+   IRQ_LOCK
+   SPIN_LOCK
    printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
 
    for (i = 0; i < sh[j]->can_queue; i++) {
@@ -1268,14 +1376,12 @@
          /* Any other mailbox has already been set free by interrupt */
          continue;
 
-      restore_flags(flags);
       SCpnt->scsi_done(SCpnt);
-      cli();
+      IRQ_LOCK
       }
 
    HD(j)->in_reset = FALSE;
    do_trace = FALSE;
-   restore_flags(flags);
 
    if (arg_done) {
       printk("%s: reset, exit, success.\n", BN(j));
@@ -1287,6 +1393,157 @@
       }
 }
 
+int u14_34f_old_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
+   int rtn;
+   IRQ_FLAGS
+
+   IRQ_LOCK_SAVE
+   rtn = do_old_reset(SCarg);
+   IRQ_UNLOCK_RESTORE
+   return rtn;
+}
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
+
+static inline int do_reset(Scsi_Cmnd *SCarg) {
+   unsigned int i, j, time, k, c, limit = 0;
+   int arg_done = FALSE;
+   Scsi_Cmnd *SCpnt;
+
+   j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
+   printk("%s: reset, enter, target %d.%d:%d, pid %ld.\n",
+          BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
+
+   if (SCarg->host_scribble == NULL)
+      printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
+
+   if (HD(j)->in_reset) {
+      printk("%s: reset, exit, already in reset.\n", BN(j));
+      return FAILED;
+      }
+
+   if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+      printk("%s: reset, exit, timeout error.\n", BN(j));
+      return FAILED;
+      }
+
+   HD(j)->retries = 0;
+
+   for (c = 0; c <= sh[j]->max_channel; c++)
+      for (k = 0; k < sh[j]->max_id; k++) {
+         HD(j)->target_redo[k][c] = TRUE;
+         HD(j)->target_to[k][c] = 0;
+         }
+
+   for (i = 0; i < sh[j]->can_queue; i++) {
+
+      if (HD(j)->cp_stat[i] == FREE) continue;
+
+      if (HD(j)->cp_stat[i] == LOCKED) {
+         HD(j)->cp_stat[i] = FREE;
+         printk("%s: reset, locked mbox %d forced free.\n", BN(j), i);
+         continue;
+         }
+
+      if (!(SCpnt = HD(j)->cp[i].SCpnt))
+         panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
+
+      if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
+         HD(j)->cp_stat[i] = ABORTING;
+         printk("%s: reset, mbox %d aborting, pid %ld.\n",
+                BN(j), i, SCpnt->pid);
+         }
+
+      else {
+         HD(j)->cp_stat[i] = IN_RESET;
+         printk("%s: reset, mbox %d in reset, pid %ld.\n",
+                BN(j), i, SCpnt->pid);
+         }
+
+      if (SCpnt->host_scribble == NULL)
+         panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
+
+      if (*(unsigned int *)SCpnt->host_scribble != i)
+         panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
+
+      if (SCpnt->scsi_done == NULL)
+         panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
+
+      if (SCpnt == SCarg) arg_done = TRUE;
+      }
+
+   if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+      printk("%s: reset, cannot reset, timeout error.\n", BN(j));
+      return FAILED;
+      }
+
+   outb(CMD_RESET, sh[j]->io_port + REG_LCL_INTR);
+   printk("%s: reset, board reset done, enabling interrupts.\n", BN(j));
+
+#if defined(DEBUG_RESET)
+   do_trace = TRUE;
+#endif
+
+   HD(j)->in_reset = TRUE;
+   SPIN_UNLOCK
+   IRQ_UNLOCK
+   time = jiffies;
+   while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L);
+   IRQ_LOCK
+   SPIN_LOCK
+   printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
+
+   for (i = 0; i < sh[j]->can_queue; i++) {
+
+      if (HD(j)->cp_stat[i] == IN_RESET) {
+         SCpnt = HD(j)->cp[i].SCpnt;
+         SCpnt->result = DID_RESET << 16;
+         SCpnt->host_scribble = NULL;
+
+         /* This mailbox is still waiting for its interrupt */
+         HD(j)->cp_stat[i] = LOCKED;
+
+         printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
+                BN(j), i, SCpnt->pid);
+         }
+
+      else if (HD(j)->cp_stat[i] == ABORTING) {
+         SCpnt = HD(j)->cp[i].SCpnt;
+         SCpnt->result = DID_RESET << 16;
+         SCpnt->host_scribble = NULL;
+
+         /* This mailbox was never queued to the adapter */
+         HD(j)->cp_stat[i] = FREE;
+
+         printk("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n",
+                BN(j), i, SCpnt->pid);
+         }
+
+      else
+
+         /* Any other mailbox has already been set free by interrupt */
+         continue;
+
+      SCpnt->scsi_done(SCpnt);
+      IRQ_LOCK
+      }
+
+   HD(j)->in_reset = FALSE;
+   do_trace = FALSE;
+
+   if (arg_done) printk("%s: reset, exit, pid %ld done.\n", BN(j), SCarg->pid);
+   else          printk("%s: reset, exit.\n", BN(j));
+
+   return SUCCESS;
+}
+
+int u14_34f_reset(Scsi_Cmnd *SCarg) {
+
+   return do_reset(SCarg);
+}
+
+#endif /* new_eh_code */
+
 int u14_34f_biosparam(Disk *disk, kdev_t dev, int *dkinfo) {
    unsigned int j = 0;
    int size = disk->capacity;
@@ -1404,7 +1661,7 @@
       if (!rev && !s)    { sortcount++; readysorted += n_ready; }
       }
 
-#if defined (DEBUG_LINKED_COMMANDS)
+#if defined(DEBUG_LINKED_COMMANDS)
    if (link_statistics && (overlap || !(flushcount % link_statistics)))
       for (n = 0; n < n_ready; n++) {
          k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
@@ -1489,6 +1746,10 @@
    /* Clear interrupt pending flag */
    outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
 
+#if defined(DEBUG_GENERATE_ABORTS)
+   if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 500) < 3)) return;
+#endif
+
    /* Find the mailbox to be serviced on this board */
    i = cpp - HD(j)->cp;
 
@@ -1537,6 +1798,11 @@
 
    tstatus = status_byte(spp->target_status);
 
+#if defined(DEBUG_GENERATE_ERRORS)
+   if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 200) < 2))
+                                           spp->adapter_status = 0x01;
+#endif
+
    switch (spp->adapter_status) {
       case ASOK:     /* status OK */
 
@@ -1599,7 +1865,13 @@
 
          if (SCpnt->device->type != TYPE_TAPE
              && HD(j)->retries < MAX_INTERNAL_RETRIES) {
+
+#if defined(DID_SOFT_ERROR)
+            status = DID_SOFT_ERROR << 16;
+#else
             status = DID_BUS_BUSY << 16;
+#endif
+
             HD(j)->retries++;
             HD(j)->last_retried_pid = SCpnt->pid;
             }
@@ -1621,7 +1893,7 @@
 
    SCpnt->result = status | spp->target_status;
 
-#if defined (DEBUG_INTERRUPT)
+#if defined(DEBUG_INTERRUPT)
    if (SCpnt->result || do_trace)
 #else
    if ((spp->adapter_status != ASOK && HD(j)->iocount >  1000) ||
@@ -1647,31 +1919,25 @@
 }
 
 static void do_interrupt_handler(int irq, void *shap, struct pt_regs *regs) {
-
    unsigned int j;
+   IRQ_FLAGS
+   SPIN_FLAGS
 
    /* Check if the interrupt must be processed by this handler */
    if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return;
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,95)
-   {
-   unsigned long flags;
-   spin_lock_irqsave(&io_request_lock, flags);
+   SPIN_LOCK_SAVE
+   IRQ_LOCK_SAVE
    ihdlr(irq, j);
-   spin_unlock_irqrestore(&io_request_lock, flags);
-   }
-#else
-   ihdlr(irq, j);
-#endif
-
+   IRQ_UNLOCK_RESTORE
+   SPIN_UNLOCK_RESTORE
 }
 
 int u14_34f_release(struct Scsi_Host *shpnt) {
-   unsigned long flags;
    unsigned int i, j;
+   IRQ_FLAGS
 
-   save_flags(flags);
-   cli();
+   IRQ_LOCK_SAVE
 
    for (j = 0; sh[j] != NULL && sh[j] != shpnt; j++);
 
@@ -1687,7 +1953,7 @@
 
    release_region(sh[j]->io_port, sh[j]->n_io_port);
    scsi_unregister(sh[j]);
-   restore_flags(flags);
+   IRQ_UNLOCK_RESTORE
    return FALSE;
 }
 
diff -u --recursive --new-file v2.1.102/linux/drivers/scsi/u14-34f.h linux/drivers/scsi/u14-34f.h
--- v2.1.102/linux/drivers/scsi/u14-34f.h	Sat Apr 25 18:13:11 1998
+++ linux/drivers/scsi/u14-34f.h	Wed May 20 16:22:59 1998
@@ -10,42 +10,48 @@
 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_old_abort(Scsi_Cmnd *);
+int u14_34f_reset(Scsi_Cmnd *);
+int u14_34f_old_reset(Scsi_Cmnd *, unsigned int);
 int u14_34f_biosparam(Disk *, kdev_t, int *);
 
-#define U14_34F_VERSION "4.20.00"
+#define U14_34F_VERSION "4.31.00"
 
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,88)
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
 
 #define ULTRASTOR_14_34F {                                                   \
                 name:         "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \
-                detect:       u14_34f_detect,                                \
-                release:      u14_34f_release,                               \
-                queuecommand: u14_34f_queuecommand,                          \
-                abort:        u14_34f_abort,                                 \
-                reset:        u14_34f_reset,                                 \
-                bios_param:   u14_34f_biosparam,                             \
-                this_id:      7,                                             \
-                unchecked_isa_dma: 1,                                        \
-                use_clustering: ENABLE_CLUSTERING,                           \
-                use_new_eh_code: 1    /* Enable new error code */            \
+                detect:                  u14_34f_detect,                     \
+                release:                 u14_34f_release,                    \
+                queuecommand:            u14_34f_queuecommand,               \
+                abort:                   u14_34f_old_abort,                  \
+                reset:                   u14_34f_old_reset,                  \
+                eh_abort_handler:        u14_34f_abort,                      \
+                eh_device_reset_handler: NULL,                               \
+                eh_bus_reset_handler:    NULL,                               \
+                eh_host_reset_handler:   u14_34f_reset,                      \
+                bios_param:              u14_34f_biosparam,                  \
+                this_id:                 7,                                  \
+                unchecked_isa_dma:       1,                                  \
+                use_clustering:          ENABLE_CLUSTERING,                  \
+                use_new_eh_code:         1    /* Enable new error code */    \
                 }
 
 #else /* Use old scsi code */
 
 #define ULTRASTOR_14_34F {                                                   \
                 name:         "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \
-                detect:       u14_34f_detect,                                \
-                release:      u14_34f_release,                               \
-                queuecommand: u14_34f_queuecommand,                          \
-                abort:        u14_34f_abort,                                 \
-                reset:        u14_34f_reset,                                 \
-                bios_param:   u14_34f_biosparam,                             \
-                this_id:      7,                                             \
-                unchecked_isa_dma: 1,                                        \
-                use_clustering: ENABLE_CLUSTERING,                           \
+                detect:                  u14_34f_detect,                     \
+                release:                 u14_34f_release,                    \
+                queuecommand:            u14_34f_queuecommand,               \
+                abort:                   u14_34f_old_abort,                  \
+                reset:                   u14_34f_old_reset,                  \
+                bios_param:              u14_34f_biosparam,                  \
+                this_id:                 7,                                  \
+                unchecked_isa_dma:       1,                                  \
+                use_clustering:          ENABLE_CLUSTERING                   \
                 }
 
 #endif
diff -u --recursive --new-file v2.1.102/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c
--- v2.1.102/linux/drivers/scsi/wd7000.c	Thu May 14 19:47:41 1998
+++ linux/drivers/scsi/wd7000.c	Mon May 18 13:50:50 1998
@@ -683,7 +683,7 @@
 	else
 	    configs[wd7000_card_num].bus_off = BUS_OFF;
 
-	if (wd7000_card_num)
+	if (wd7000_card_num) {
 	    for (i = 0; i < (wd7000_card_num - 1); i++)
 		for (j = i + 1; j < wd7000_card_num; j++)
 		    if (configs[i].irq == configs[j].irq) {
@@ -698,6 +698,7 @@
 	                setup_error ("duplicated I/O base address!", ints);
 			return;
 		    }
+	}
 
 #ifdef WD7000_DEBUG
 	printk ("wd7000_setup: IRQ=%d, DMA=%d, I/O=0x%x, BUS_ON=%dns, BUS_OFF=%dns\n",
@@ -1119,7 +1120,7 @@
 		return;
 	    }
 	    /* Aaaargh! (Zaga) */
-	    scb = (struct scb *) (scsi2int ((unchar *) icmbs[icmb].scbptr) | PAGE_OFFSET);
+	    scb = bus_to_virt(scsi2int ((unchar *) icmbs[icmb].scbptr));
 	    icmbs[icmb].status = 0;
 	    if (!(scb->op & ICB_OP_MASK)) {	/* an SCB is done */
 		SCpnt = scb->SCpnt;
diff -u --recursive --new-file v2.1.102/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c
--- v2.1.102/linux/drivers/sound/gus_wave.c	Thu May 14 19:47:42 1998
+++ linux/drivers/sound/gus_wave.c	Thu May 14 18:50:39 1998
@@ -499,13 +499,14 @@
 {
 	int sample_no;
 
-	if ((sample_no = sample_map[voice]) != -1)
+	if ((sample_no = sample_map[voice]) != -1) {
 		if (position < samples[sample_no].len)
 			if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
 				voices[voice].offset_pending = position;
 			else
 				gus_write_addr(0x0a, sample_ptrs[sample_no] + position, 0,
 				 samples[sample_no].mode & WAVE_16_BITS);
+	}
 }
 
 static void gus_voice_init(int voice)
diff -u --recursive --new-file v2.1.102/linux/drivers/sound/pas2_mixer.c linux/drivers/sound/pas2_mixer.c
--- v2.1.102/linux/drivers/sound/pas2_mixer.c	Thu May 14 19:47:42 1998
+++ linux/drivers/sound/pas2_mixer.c	Thu May 14 18:50:50 1998
@@ -125,11 +125,12 @@
 	left = level & 0x7f;
 	right = (level & 0x7f00) >> 8;
 
-	if (whichDev < SOUND_MIXER_NRDEVICES)
+	if (whichDev < SOUND_MIXER_NRDEVICES) {
 		if ((1 << whichDev) & rec_devices)
 			mixer = 0x20;
 		else
 			mixer = 0x00;
+	}
 
 	switch (whichDev)
 	  {
diff -u --recursive --new-file v2.1.102/linux/fs/dquot.c linux/fs/dquot.c
--- v2.1.102/linux/fs/dquot.c	Fri May  8 23:14:51 1998
+++ linux/fs/dquot.c	Thu May 14 18:40:01 1998
@@ -724,10 +724,10 @@
 	if (dqblk == (struct dqblk *)NULL)
 		return(-EFAULT);
 
-	if (flags & QUOTA_SYSCALL)
+	if (flags & QUOTA_SYSCALL) {
 		if ((error = copy_from_user((caddr_t)&dq_dqblk, (caddr_t)dqblk, sizeof(struct dqblk))) != 0)
 			return(error);
-	else
+	} else
 		memcpy((caddr_t)&dq_dqblk, (caddr_t)dqblk, sizeof(struct dqblk));
 
 	if ((dquot = dqget(dev, id, type)) != NODQUOT) {
diff -u --recursive --new-file v2.1.102/linux/fs/ext2/dir.c linux/fs/ext2/dir.c
--- v2.1.102/linux/fs/ext2/dir.c	Mon Apr  6 17:41:00 1998
+++ linux/fs/ext2/dir.c	Wed May 20 13:08:35 1998
@@ -44,7 +44,7 @@
 	NULL,			/* mmap */
 	NULL,			/* no special open code */
 	NULL,			/* no special release code */
-	file_fsync,		/* fsync */
+	ext2_sync_file,		/* fsync */
 	NULL,			/* fasync */
 	NULL,			/* check_media_change */
 	NULL			/* revalidate */
diff -u --recursive --new-file v2.1.102/linux/fs/ext2/fsync.c linux/fs/ext2/fsync.c
--- v2.1.102/linux/fs/ext2/fsync.c	Wed Dec 10 13:13:30 1997
+++ linux/fs/ext2/fsync.c	Wed May 20 13:09:12 1998
@@ -260,9 +260,6 @@
 	int wait, err = 0;
 	struct inode *inode = dentry->d_inode;
 
-	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
-	     S_ISLNK(inode->i_mode)))
-		return -EINVAL;
 	if (S_ISLNK(inode->i_mode) && !(inode->i_blocks))
 		/*
 		 * Don't sync fast links!
diff -u --recursive --new-file v2.1.102/linux/fs/fat/fatfs_syms.c linux/fs/fat/fatfs_syms.c
--- v2.1.102/linux/fs/fat/fatfs_syms.c	Mon Feb 23 18:12:10 1998
+++ linux/fs/fat/fatfs_syms.c	Tue May 19 15:06:49 1998
@@ -52,6 +52,8 @@
 EXPORT_SYMBOL(fat_get_cluster);
 EXPORT_SYMBOL(lock_fat);
 EXPORT_SYMBOL(unlock_fat);
+EXPORT_SYMBOL(fat_dir_ioctl);
+EXPORT_SYMBOL(fat_readpage);
 
 int init_fat_fs(void)
 {
diff -u --recursive --new-file v2.1.102/linux/fs/hpfs/hpfs_fs.c linux/fs/hpfs/hpfs_fs.c
--- v2.1.102/linux/fs/hpfs/hpfs_fs.c	Mon Apr  6 17:41:01 1998
+++ linux/fs/hpfs/hpfs_fs.c	Thu May 14 18:51:23 1998
@@ -969,13 +969,13 @@
 
 	while (len--) {
 		c = *p++;
-		if (c < ' ')
+		if (c < ' ') {
 			if (c == '\r' && len && *p == '\n')
 				tvote += 10;
 			else if (c == '\t' || c == '\n');
 			else
 				bvote += 5;
-		else if (c < '\177')
+		} else if (c < '\177')
 			tvote++;
 		else
 			bvote += 5;
diff -u --recursive --new-file v2.1.102/linux/fs/ntfs/inode.c linux/fs/ntfs/inode.c
--- v2.1.102/linux/fs/ntfs/inode.c	Tue Mar 10 10:03:34 1998
+++ linux/fs/ntfs/inode.c	Thu May 14 18:51:39 1998
@@ -470,11 +470,12 @@
 		dest->size=l;
 		return 0;
 	}
-	if(attr->compressed)
+	if(attr->compressed) {
 		if(dest->do_read)
 			return ntfs_read_compressed(ino,attr,offset,dest);
 		else
 			return ntfs_write_compressed(ino,attr,offset,dest);
+	}
 	vcn=0;
 	s_vcn = offset/clustersize;
 	for(rnum=0;rnum<attr->d.r.len && 
diff -u --recursive --new-file v2.1.102/linux/fs/ntfs/super.c linux/fs/ntfs/super.c
--- v2.1.102/linux/fs/ntfs/super.c	Fri Dec 19 15:24:21 1997
+++ linux/fs/ntfs/super.c	Thu May 14 18:51:57 1998
@@ -483,13 +483,14 @@
 		error=ntfs_read_attr(bitmap,bitmap->vol->at_data,
 				     0,start,&io);
 		if(error)goto fail;
-		if(io.size==0)
+		if(io.size==0) {
 			if(found)
 				goto success;
 			else{
 				error=ENOSPC;
 				goto fail;
 			}
+		}
 		loc=start*8;
 		cnt=*count;
 		error=search_bits(bits,&loc,&cnt,io.size);
diff -u --recursive --new-file v2.1.102/linux/fs/proc/root.c linux/fs/proc/root.c
--- v2.1.102/linux/fs/proc/root.c	Thu Apr 23 20:21:37 1998
+++ linux/fs/proc/root.c	Sun May 17 11:34:57 1998
@@ -684,7 +684,7 @@
 
 	if (prof_shift) {
 		proc_register(&proc_root, &proc_root_profile);
-		proc_root_profile.size = (1+prof_len) * sizeof(unsigned long);
+		proc_root_profile.size = (1+prof_len) * sizeof(unsigned int);
 	}
 
 	proc_tty_init();
diff -u --recursive --new-file v2.1.102/linux/fs/sysv/namei.c linux/fs/sysv/namei.c
--- v2.1.102/linux/fs/sysv/namei.c	Thu May  7 22:51:54 1998
+++ linux/fs/sysv/namei.c	Thu May 14 18:52:31 1998
@@ -69,11 +69,12 @@
 	if (!dir)
 		return NULL;
 	sb = dir->i_sb;
-	if (namelen > SYSV_NAMELEN)
+	if (namelen > SYSV_NAMELEN) {
 		if (sb->sv_truncate)
 			namelen = SYSV_NAMELEN;
 		else
 			return NULL;
+	}
 	bh = NULL;
 	pos = block = offset = 0;
 	while (pos < dir->i_size) {
@@ -152,11 +153,12 @@
 	if (!dir)
 		return -ENOENT;
 	sb = dir->i_sb;
-	if (namelen > SYSV_NAMELEN)
+	if (namelen > SYSV_NAMELEN) {
 		if (sb->sv_truncate)
 			namelen = SYSV_NAMELEN;
 		else
 			return -ENAMETOOLONG;
+	}
 	if (!namelen)
 		return -ENOENT;
 	bh = NULL;
diff -u --recursive --new-file v2.1.102/linux/fs/umsdos/README-WIP.txt linux/fs/umsdos/README-WIP.txt
--- v2.1.102/linux/fs/umsdos/README-WIP.txt	Wed Apr  8 19:36:28 1998
+++ linux/fs/umsdos/README-WIP.txt	Tue May 19 15:06:49 1998
@@ -8,7 +8,7 @@
 YOU'VE BEEN WARNED.
 --------- WARNING --------- WARNING --------- WARNING -----------
 
-Current status (980220) - UMSDOS dentry-WIP-Beta 0.82-3:
+Current status (980428) - UMSDOS dentry-WIP-Beta 0.82-4:
 
 (1) pure MSDOS (no --linux-.--- EMD file):
 
@@ -32,14 +32,13 @@
 - long file names - works
 - read file - works
 - switching MSDOS/UMSDOS - works?
-- switching UMSDOS/MSDOS - UNTESTED
-- pseudo root things - COMMENTED OUT mostly currently. To be fixed when
-  dentries stuff is straightened out.
+- switching UMSDOS/MSDOS - works?
+- pseudo root things - COMPLETELY UNTESTED
 - resolve symlink - seems to work fully now!
 - dereference symlink - seems to work fully now!
 - hard links - seems to work now
 - special files (block/char device, fifos, sockets...) - seems to work ok.
-- other ioctls - MOSTLY UNTESTED
+- other ioctls - some UNTESTED
 - dangling symlink - UNTESTED !
 
 - create symlink		- seems to work both on short & long names now !
@@ -47,16 +46,16 @@
 - create file			- seems to work both on short & long names now !
 - create special file		- seems to work both on short & long names now !
 - write to file			- seems to work both on short & long names now !
-- rename file (same dir)	- WARNING: NOT FIXED YET!
-- rename file (dif. dir)	- WARNING: NOT FIXED YET!
-- rename dir (same dir)		- WARNING: NOT FIXED YET!
-- rename dir (dif. dir)		- WARNING: NOT FIXED YET!
+- rename file (same dir)	- seems to work, but with i_count PROBLEMS
+- rename file (dif. dir)	- seems to work, but with i_count PROBLEMS
+- rename dir (same dir)		- seems to work, but with i_count PROBLEMS
+- rename dir (dif. dir)		- seems to work, but with i_count PROBLEMS
 - delete file			- seems to work fully now!
 - notify_change (chown,perms)	- seems to work!
 - delete hardlink		- WARNING: NOT FIXED YET!
 - mkdir				- seems to work both on short & long names now !
-- rmdir 			- WARNING: NOT FIXED YET!
-- umssyncing			- seems to work, but NEEDS EXTENSIVE TESTING
+- rmdir 			- may work, but readdir blocks linux afterwards. to be FIXED!
+- umssyncing			- seems to work, but NEEDS MORE TESTING
 
 - CVF-FAT stuff (compressed DOS filesystem) - there is some support from
   Frank Gockel <gockel@sent13.uni-duisburg.de> to use it even under
@@ -130,6 +129,8 @@
 - what about .dotfiles ? working ? multiple dots ? etc....
 - fix stuff like dir->i_count++ to atomic_inc(&dir->i_count) and simular?
 
+- chase down all "FIXME", "DELME", "CNT", check_dentry, check_inode, kill_dentry
+  and fix it properly.
 
 - umsdos_create_any - calling msdos_create will create dentry for shor name. Hmmmm..?
 - kill_dentry - put it where is needed. Also dput() at needed places.
@@ -143,6 +144,14 @@
 
 - SECURITY WARNING: short dentries should be invalidated, or they could be
   accessed instead of proper long names.
+
+- I've put many check_dentry() calls to trace down problems. those should be
+  removed in final version.
+
+- iput()s with "FIXME?" comment are uncomented and probably ok. Those with
+  "FIXME??" should be tested but prolly work. Commented iput()s with
+  any "FIXME" comments should probably be uncommented and tested. At some
+  places we may need dput() instead of iput(), but that should be checked.
 
 - as for iput() : (my only pointer so far. anyone else ?)
 
diff -u --recursive --new-file v2.1.102/linux/fs/umsdos/check.c linux/fs/umsdos/check.c
--- v2.1.102/linux/fs/umsdos/check.c	Sun Feb 25 01:17:59 1996
+++ linux/fs/umsdos/check.c	Tue May 19 15:06:49 1998
@@ -17,11 +17,11 @@
 
 #include <asm/system.h>
 
-static int check_one_table(struct pde * page_dir)
+static int check_one_table (struct pde *page_dir)
 {
-	if (pgd_none(*page_dir))
+	if (pgd_none (*page_dir))
 		return 0;
-	if (pgd_bad(*page_dir))
+	if (pgd_bad (*page_dir))
 		return 1;
 	return 0;
 }
@@ -29,23 +29,28 @@
 /*
  * This function checks all page tables of "current"
  */
-void check_page_tables(void)
+void check_page_tables (void)
 {
-	struct pgd * pg_dir;
+	struct pgd *pg_dir;
 	static int err = 0;
 
-	int stack_level = (long)(&pg_dir)-current->kernel_stack_page;
-	if (stack_level < 1500) printk ("** %d ** ",stack_level);
-	pg_dir = PAGE_DIR_OFFSET(current, 0);
+	int stack_level = (long) (&pg_dir) - current->kernel_stack_page;
+
+	if (stack_level < 1500)
+		printk ("** %d ** ", stack_level);
+	pg_dir = PAGE_DIR_OFFSET (current, 0);
 	if (err == 0) {
 		int i;
-		for (i = 0 ; i < PTRS_PER_PAGE ; i++,page_dir++){
-			int notok = check_one_table(page_dir);
-			if (notok){
+
+		for (i = 0; i < PTRS_PER_PAGE; i++, page_dir++) {
+			int notok = check_one_table (page_dir);
+
+			if (notok) {
 				err++;
-				printk ("|%d:%08lx| ",i, page_dir->pgd);
+				printk ("|%d:%08lx| ", i, page_dir->pgd);
 			}
 		}
-		if (err) printk ("\nErreur MM %d\n",err);
+		if (err)
+			printk ("\nErreur MM %d\n", err);
 	}
 }
diff -u --recursive --new-file v2.1.102/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c
--- v2.1.102/linux/fs/umsdos/dir.c	Wed Apr  8 19:36:28 1998
+++ linux/fs/umsdos/dir.c	Tue May 19 15:06:49 1998
@@ -2,7 +2,7 @@
  *  linux/fs/umsdos/dir.c
  *
  *  Written 1993 by Jacques Gelinas
- *	Inspired from linux/fs/msdos/... : Werner Almesberger
+ *      Inspired from linux/fs/msdos/... : Werner Almesberger
  *
  *  Extended MS-DOS directory handling functions
  */
@@ -27,48 +27,76 @@
 
 
 /* P.T.Waltenberg
-   I've retained this to facilitate the lookup of some of the hard-wired files/directories UMSDOS
-   uses. It's easier to do once than hack all the other instances. Probably safer as well
-*/   
+ * I've retained this to facilitate the lookup of some of the hard-wired files/directories UMSDOS
+ * uses. It's easier to do once than hack all the other instances. Probably safer as well
+ */
+
+/* FIXME: it returns inode with i_count of 0. this should be redesigned to return dentry instead,
+   and correct dentry (with correct d_parent) */
 
-int compat_umsdos_real_lookup (struct inode *dir,const char *name,int len, struct inode **inode)
+int compat_umsdos_real_lookup (struct inode *dir, const char *name, int len, struct inode **inode)
 {
-  int rv;
-  struct dentry *dentry;
+	int rv;
+	struct dentry *dentry;
+	unsigned long ino;
+
+	Printk ((KERN_DEBUG "compat_umsdos_real_lookup !!CNTx!!: start\n"));
+	check_inode (dir);
+	dentry = creat_dentry (name, len, NULL, NULL);
+	rv = umsdos_real_lookup (dir, dentry);
+	iput (dir);	/* should be here, because umsdos_real_lookup does inc_count(dir) */
+
+	if (rv) {
+		Printk ((KERN_WARNING "compat_umsdos_real_lookup failed with %d\n", rv));
+		return rv;
+	}
 
-  dentry = creat_dentry (name, len, NULL, NULL);
-  rv = umsdos_real_lookup(dir,dentry);
-  if (inode) *inode = dentry->d_inode;
-  kill_dentry (dentry);
-  
-  return rv;
-}    
+	if (!inode) {
+		Printk ((KERN_ERR "inode should be set here. Arrgh! segfaulting...\n"));
+	}
+		
+	ino = dentry->d_inode->i_ino;
+	*inode = dentry->d_inode;
 
+	dput (dentry);	/* we are done with it: FIXME: does this work /mn/ ? */
+	
+	check_dentry (dentry);
+	check_inode (dir);
 
-int compat_msdos_create(struct inode *dir,const char *name,int len, int mode, struct inode **inode)
+	Printk ((KERN_DEBUG "compat_umsdos_real_lookup !!CNTx!!: end\n"));
+	
+	return rv;
+}
+
+
+int compat_msdos_create (struct inode *dir, const char *name, int len, int mode, struct inode **inode)
 {
-  int rv;
-  struct dentry *dentry;
+	int rv;
+	struct dentry *dentry;
 
-  dentry = creat_dentry (name, len, NULL, NULL);
-  rv = msdos_create(dir,dentry,mode);
-  if(inode != NULL) *inode = dentry->d_inode;
-  
-  return rv;
-}    
+	check_inode (dir);
+	dentry = creat_dentry (name, len, NULL, NULL);
+	check_dentry (dentry);
+	rv = msdos_create (dir, dentry, mode);
+	check_dentry (dentry);
+	if (inode != NULL)
+		*inode = dentry->d_inode;
+
+	check_inode (dir);
+	return rv;
+}
 
 
 /*
-	So  grep *  doesn't complain in the presence of directories.
-*/
-int UMSDOS_dir_read(struct file *filp,
-		    char *buff,
-		    size_t size,
-		    loff_t * count)
+ * So  grep *  doesn't complain in the presence of directories.
+ */
+ 
+int UMSDOS_dir_read (struct file *filp, char *buff, size_t size, loff_t *count)
 {
 	return -EISDIR;
 }
 
+
 struct UMSDOS_DIR_ONCE {
 	void *dirbuf;
 	filldir_t filldir;
@@ -77,873 +105,929 @@
 };
 
 /*
-	Record a single entry the first call.
-	Return -EINVAL the next one.
-	NOTE: filldir DOES NOT use a dentry
-*/
-static int umsdos_dir_once(
-	void * buf,
-	const char *name,
-	int len,
-	off_t offset,
-	ino_t ino)
-{
-  int ret = -EINVAL;
-  struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *)buf;
-  if (d->count == 0){
-    PRINTK ((KERN_DEBUG "dir_once :%.*s: offset %Ld\n", dentry->d_len, dentry->d_name, offset));
-    ret = d->filldir (d->dirbuf,name,len,offset,ino);
-    d->stop = ret < 0;
-    d->count = 1;
-  }
-  return ret;
-}
-
-/*
-  Read count directory entries from directory filp
-  Return a negative value from linux/errno.h.
-  Return > 0 if success (The amount of byte written by filldir).
-  
-  This function is used by the normal readdir VFS entry point and by
-  some function who try to find out info on a file from a pure MSDOS
-  inode. See umsdos_locate_ancestor() below.
-*/
-static int umsdos_readdir_x(
-			    struct inode *dir,		/* Point to a description of the super block */
-			    struct file *filp,		/* Point to a directory which is read */
-			    void *dirbuf,			/* Will hold count directory entry */
-			    /* but filled by the filldir function */
-			    int internal_read,		/* Called for internal purpose */
-			    struct umsdos_dirent *u_entry,	/* Optional umsdos entry */
-			    int follow_hlink,
-			    filldir_t filldir)
-{
-  int ret = 0;
-  struct inode *root_inode;
-  
-  root_inode = iget(dir->i_sb,UMSDOS_ROOT_INO);
-  umsdos_startlookup(dir);	
-  if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS
-      && pseudo_root
-      && dir == pseudo_root
-      && !internal_read){
-      
-      Printk (("umsdos_readdir_x: what UMSDOS_SPECIAL_DIRFPOS /mn/?\n"));
-    /*
-      We don't need to simulate this pseudo directory
-      when umsdos_readdir_x is called for internal operation
-      of umsdos. This is why dirent_in_fs is tested
-    */
-    /* #Specification: pseudo root / directory /DOS
-       When umsdos operates in pseudo root mode (C:\linux is the
-       linux root), it simulate a directory /DOS which points to
-       the real root of the file system.
-    */
-    if (filldir (dirbuf,"DOS",3,UMSDOS_SPECIAL_DIRFPOS
-		 ,UMSDOS_ROOT_INO) == 0){
-      filp->f_pos++;
-    }
-  }else if (filp->f_pos < 2
-	    || (dir != root_inode && filp->f_pos == 32)){
-    /* #Specification: readdir / . and ..
-       The msdos filesystem manage the . and .. entry properly
-       so the EMD file won't hold any info about it.
-       
-       In readdir, we assume that for the root directory
-       the read position will be 0 for ".", 1 for "..". For
-       a non root directory, the read position will be 0 for "."
-       and 32 for "..".
-    */
-    /*
-      This is a trick used by the msdos file system (fs/msdos/dir.c)
-      to manage . and .. for the root directory of a file system.
-      Since there is no such entry in the root, fs/msdos/dir.c
-      use the following:
-      
-      if f_pos == 0, return ".".
-      if f_pos == 1, return "..".
-      
-      So let msdos handle it
-      
-      Since umsdos entries are much larger, we share the same f_pos.
-      if f_pos is 0 or 1 or 32, we are clearly looking at . and
-      ..
-      
-      As soon as we get f_pos == 2 or f_pos == 64, then back to
-      0, but this time we are reading the EMD file.
-      
-      Well, not so true. The problem, is that UMSDOS_REC_SIZE is
-      also 64, so as soon as we read the first record in the
-      EMD, we are back at offset 64. So we set the offset
-      to UMSDOS_SPECIAL_DIRFPOS(3) as soon as we have read the
-      .. entry from msdos.
-      
-      Now (linux 1.3), umsdos_readdir can read more than one
-      entry even if we limit (umsdos_dir_once) to only one:
-      It skips over hidden file. So we switch to
-      UMSDOS_SPECIAL_DIRFPOS as soon as we have read successfully
-      the .. entry.
-    */
-    int last_f_pos = filp->f_pos;	
-    struct UMSDOS_DIR_ONCE bufk;
-
-    Printk (("umsdos_readdir_x: . or .. /mn/?\n"));
-
-    bufk.dirbuf = dirbuf;
-    bufk.filldir = filldir;
-    bufk.count = 0;
-
-    ret = fat_readdir(filp,&bufk,umsdos_dir_once);
-    if (last_f_pos > 0 && filp->f_pos > last_f_pos) filp->f_pos = UMSDOS_SPECIAL_DIRFPOS;
-    if (u_entry != NULL) u_entry->flags = 0;
-  }else{
-    struct inode *emd_dir;
-    Printk (("umsdos_readdir_x: normal file /mn/?\n"));
-    emd_dir = umsdos_emd_dir_lookup(dir,0);
-    if (emd_dir != NULL){
-      off_t start_fpos = filp->f_pos;
-      Printk (("umsdos_readdir_x: emd_dir->i_ino=%ld\n",emd_dir->i_ino));
-      if (filp->f_pos <= UMSDOS_SPECIAL_DIRFPOS+1) filp->f_pos = 0;
-      Printk (("f_pos %Ld i_size %ld\n",filp->f_pos,emd_dir->i_size));
-      ret = 0;
-      while (filp->f_pos < emd_dir->i_size){
-	struct umsdos_dirent entry;
-	off_t cur_f_pos = filp->f_pos;
-	if (umsdos_emd_dir_readentry (emd_dir,filp,&entry)!=0){
-	  ret = -EIO;
-	  break;
-	}else if (entry.name_len != 0){
-	  /* #Specification: umsdos / readdir
-	     umsdos_readdir() should fill a struct dirent with
-	     an inode number. The cheap way to get it is to
-	     do a lookup in the MSDOS directory for each
-	     entry processed by the readdir() function.
-	     This is not very efficient, but very simple. The
-	     other way around is to maintain a copy of the inode
-	     number in the EMD file. This is a problem because
-	     this has to be maintained in sync using tricks.
-	     Remember that MSDOS (the OS) does not update the
-	     modification time (mtime) of a directory. There is
-	     no easy way to tell that a directory was modified
-	     during a DOS session and synchronise the EMD file.
-	     
-	     Suggestion welcome.
-	     
-	     So the easy way is used!
-	  */
-	  struct umsdos_info info;
-	  struct inode *inode;
-	  
-	  int lret;
-	  umsdos_parse (entry.name,entry.name_len,&info);
-	  info.f_pos = cur_f_pos;
-	  umsdos_manglename (&info);
-	  /* FIXME, fake a dentry --> /mn/ fixed ? */
-	  lret = compat_umsdos_real_lookup (dir,info.fake.fname,
-					    info.fake.len,&inode);
-	  Printk (("Cherche inode de %s lret %d flags %d\n"
-		   ,info.fake.fname,lret,entry.flags));
-	  if (lret == 0
-	      && (entry.flags & UMSDOS_HLINK)
-	      && follow_hlink){
-	    struct inode *rinode;
-	    lret = umsdos_hlink2inode (inode,&rinode);
-	    inode = rinode;
-	  }
-	  if (lret == 0){
-	    /* #Specification: pseudo root / reading real root
-	       The pseudo root (/linux) is logically
-	       erased from the real root. This mean that
-	       ls /DOS, won't show "linux". This avoids
-	       infinite recursion /DOS/linux/DOS/linux while
-	       walking the file system.
-	    */
-	    if (inode != pseudo_root
-		&& (internal_read
-		    || !(entry.flags & UMSDOS_HIDDEN))){
-	      if (filldir (dirbuf, 
-			   entry.name,
-			   entry.name_len,
-			   cur_f_pos, 
-			   inode->i_ino) < 0){
-		filp->f_pos = cur_f_pos;
-	      }
-	      Printk (("Trouve ino %ld ",inode->i_ino));
-	      if (u_entry != NULL) *u_entry = entry;
-	      /* iput (inode); FIXME */
-	      break;
-	    }
-	    /* iput (inode); FIXME */
-	  }else{
-	    /* #Specification: umsdos / readdir / not in MSDOS
-	       During a readdir operation, if the file is not
-	       in the MSDOS directory anymore, the entry is
-	       removed from the EMD file silently.
-	    */
-	    Printk (("'Silently' removing EMD for file\n"));
-	    ret = umsdos_writeentry (dir,emd_dir,&info,1);
-	    if (ret != 0){
-	      break;
-	    }
-	  }
-	}
-      }
-      /*
-	If the fillbuf has failed, f_pos is back to 0.
-	To avoid getting back into the . and .. state
-	(see comments at the beginning), we put back
-	the special offset.
-      */
-      if (filp->f_pos == 0) filp->f_pos = start_fpos;
-      /* iput(emd_dir); FIXME */
-    }
-  }
-  umsdos_endlookup(dir);	
-  Printk (("read dir %p pos %Ld ret %d\n",dir,filp->f_pos,ret));
-  return ret;
-}
-
-
-/*
-  Read count directory entries from directory filp
-  Return a negative value from linux/errno.h.
-  Return 0 or positive if successful
-*/
-static int UMSDOS_readdir(
-			  struct file *filp,		/* Point to a directory which is read */
-			  void *dirbuf,			/* Will hold directory entries  */
-			  filldir_t filldir)
-{
-  struct inode *dir = filp->f_dentry->d_inode;
-  int ret = 0;
-  int count = 0;
-  struct UMSDOS_DIR_ONCE bufk;
-  bufk.dirbuf = dirbuf;
-  bufk.filldir = filldir;
-  bufk.stop = 0;
-
-  Printk (("UMSDOS_readdir in\n"));
-  while (ret == 0 && bufk.stop == 0){
-    struct umsdos_dirent entry;
-    bufk.count = 0;
-    Printk (("UMSDOS_readdir: calling _x (%p,%p,%p,%d,%p,%d,%p)\n",dir,filp,&bufk,0,&entry,1,umsdos_dir_once));
-    ret = umsdos_readdir_x (dir,filp,&bufk,0,&entry,1,umsdos_dir_once);
-    if (bufk.count == 0) break;
-    count += bufk.count;
-  }
-  Printk (("UMSDOS_readdir out %d count %d pos %Ld\n",ret,count
-	   ,filp->f_pos));
-  return count?:ret;
+ * Record a single entry the first call.
+ * Return -EINVAL the next one.
+ * NOTE: filldir DOES NOT use a dentry
+ */
+
+static int umsdos_dir_once (	void *buf,
+				const char *name,
+				int len,
+				off_t offset,
+				ino_t ino)
+{
+	int ret = -EINVAL;
+	struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *) buf;
+
+	if (d->count == 0) {
+		PRINTK ((KERN_DEBUG "dir_once :%.*s: offset %Ld\n", dentry->d_len, dentry->d_name, offset));
+		ret = d->filldir (d->dirbuf, name, len, offset, ino);
+		d->stop = ret < 0;
+		d->count = 1;
+	}
+	return ret;
 }
 
+
 /*
-  Complete the inode content with info from the EMD file
-*/
+ * Read count directory entries from directory filp
+ * Return a negative value from linux/errno.h.
+ * Return > 0 if success (The amount of byte written by filldir).
+ * 
+ * This function is used by the normal readdir VFS entry point and by
+ * some function who try to find out info on a file from a pure MSDOS
+ * inode. See umsdos_locate_ancestor() below.
+ */
+ 
+static int umsdos_readdir_x (
+				    struct inode *dir,	/* Point to a description of the super block */
+				    struct file *filp,	/* Point to a directory which is read */
+				    void *dirbuf,	/* Will hold count directory entry */
+							/* but filled by the filldir function */
+				    int internal_read,	/* Called for internal purpose */
+				    struct umsdos_dirent *u_entry,	/* Optional umsdos entry */
+				    int follow_hlink,
+				    filldir_t filldir)
+{
+	int ret = 0;
+
+	umsdos_startlookup (dir);
+	if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS
+	    && pseudo_root
+	    && dir == pseudo_root
+	    && !internal_read) {
+
+		Printk (("umsdos_readdir_x: what UMSDOS_SPECIAL_DIRFPOS /mn/?\n"));
+		/*
+		 * We don't need to simulate this pseudo directory
+		 * when umsdos_readdir_x is called for internal operation
+		 * of umsdos. This is why dirent_in_fs is tested
+		 */
+		/* #Specification: pseudo root / directory /DOS
+		 * When umsdos operates in pseudo root mode (C:\linux is the
+		 * linux root), it simulate a directory /DOS which points to
+		 * the real root of the file system.
+		 */
+		if (filldir (dirbuf, "DOS", 3, UMSDOS_SPECIAL_DIRFPOS, UMSDOS_ROOT_INO) == 0) {
+			filp->f_pos++;
+		}
+	} else if (filp->f_pos < 2 || (dir->i_ino != UMSDOS_ROOT_INO && filp->f_pos == 32)) {
+	
+	/* FIXME: that was in 2.0.x: else if (filp->f_pos < 2 || (dir != dir->i_sb->s_mounted && filp->f_pos == 32))
+	 * I'm probably screwing up pseudo-root and stuff with this. It needs proper fix.
+	 */
+	                
+	
+		/* #Specification: readdir / . and ..
+		 * The msdos filesystem manage the . and .. entry properly
+		 * so the EMD file won't hold any info about it.
+		 * 
+		 * In readdir, we assume that for the root directory
+		 * the read position will be 0 for ".", 1 for "..". For
+		 * a non root directory, the read position will be 0 for "."
+		 * and 32 for "..".
+		 */
+		/*
+		 * This is a trick used by the msdos file system (fs/msdos/dir.c)
+		 * to manage . and .. for the root directory of a file system.
+		 * Since there is no such entry in the root, fs/msdos/dir.c
+		 * use the following:
+		 * 
+		 * if f_pos == 0, return ".".
+		 * if f_pos == 1, return "..".
+		 * 
+		 * So let msdos handle it
+		 * 
+		 * Since umsdos entries are much larger, we share the same f_pos.
+		 * if f_pos is 0 or 1 or 32, we are clearly looking at . and
+		 * ..
+		 * 
+		 * As soon as we get f_pos == 2 or f_pos == 64, then back to
+		 * 0, but this time we are reading the EMD file.
+		 * 
+		 * Well, not so true. The problem, is that UMSDOS_REC_SIZE is
+		 * also 64, so as soon as we read the first record in the
+		 * EMD, we are back at offset 64. So we set the offset
+		 * to UMSDOS_SPECIAL_DIRFPOS(3) as soon as we have read the
+		 * .. entry from msdos.
+		 * 
+		 * Now (linux 1.3), umsdos_readdir can read more than one
+		 * entry even if we limit (umsdos_dir_once) to only one:
+		 * It skips over hidden file. So we switch to
+		 * UMSDOS_SPECIAL_DIRFPOS as soon as we have read successfully
+		 * the .. entry.
+		 */
+		int last_f_pos = filp->f_pos;
+		struct UMSDOS_DIR_ONCE bufk;
+
+		Printk (("umsdos_readdir_x: . or .. /mn/?\n"));
+
+		bufk.dirbuf = dirbuf;
+		bufk.filldir = filldir;
+		bufk.count = 0;
+
+		ret = fat_readdir (filp, &bufk, umsdos_dir_once);
+		if (last_f_pos > 0 && filp->f_pos > last_f_pos)
+			filp->f_pos = UMSDOS_SPECIAL_DIRFPOS;
+		if (u_entry != NULL)
+			u_entry->flags = 0;
+	} else {
+		struct inode *emd_dir;
+
+		Printk (("umsdos_readdir_x: normal file /mn/?\n"));
+		emd_dir = umsdos_emd_dir_lookup (dir, 0);
+		if (emd_dir != NULL) {
+			off_t start_fpos = filp->f_pos;
+
+			Printk (("umsdos_readdir_x: emd_dir->i_ino=%ld\n", emd_dir->i_ino));
+			if (filp->f_pos <= UMSDOS_SPECIAL_DIRFPOS + 1)
+				filp->f_pos = 0;
+			Printk (("f_pos %Ld i_size %ld\n", filp->f_pos, emd_dir->i_size));
+			ret = 0;
+			while (filp->f_pos < emd_dir->i_size) {
+				struct umsdos_dirent entry;
+				off_t cur_f_pos = filp->f_pos;
+
+				if (umsdos_emd_dir_readentry (emd_dir, filp, &entry) != 0) {
+					ret = -EIO;
+					break;
+				} else if (entry.name_len != 0) {
+					/* #Specification: umsdos / readdir
+					 * umsdos_readdir() should fill a struct dirent with
+					 * an inode number. The cheap way to get it is to
+					 * do a lookup in the MSDOS directory for each
+					 * entry processed by the readdir() function.
+					 * This is not very efficient, but very simple. The
+					 * other way around is to maintain a copy of the inode
+					 * number in the EMD file. This is a problem because
+					 * this has to be maintained in sync using tricks.
+					 * Remember that MSDOS (the OS) does not update the
+					 * modification time (mtime) of a directory. There is
+					 * no easy way to tell that a directory was modified
+					 * during a DOS session and synchronise the EMD file.
+					 * 
+					 * Suggestion welcome.
+					 * 
+					 * So the easy way is used!
+					 */
+					struct umsdos_info info;
+					struct inode *inode;
+
+					int lret;
+
+					umsdos_parse (entry.name, entry.name_len, &info);
+					info.f_pos = cur_f_pos;
+					umsdos_manglename (&info);
+					lret = compat_umsdos_real_lookup (dir, info.fake.fname, info.fake.len, &inode);
+					Printk (("Cherche inode de %s lret %d flags %d\n", info.fake.fname, lret, entry.flags));
+					if (lret == 0
+					  && (entry.flags & UMSDOS_HLINK)
+					    && follow_hlink) {
+						struct inode *rinode;
+
+						Printk ((KERN_DEBUG "umsdos_hlink2inode now\n"));
+						lret = umsdos_hlink2inode (inode, &rinode);
+						inode = rinode;
+					}
+					if (lret == 0) {
+						/* #Specification: pseudo root / reading real root
+						 * The pseudo root (/linux) is logically
+						 * erased from the real root. This mean that
+						 * ls /DOS, won't show "linux". This avoids
+						 * infinite recursion /DOS/linux/DOS/linux while
+						 * walking the file system.
+						 */
+						if (inode != pseudo_root
+						    && (internal_read
+							|| !(entry.flags & UMSDOS_HIDDEN))) {
+							Printk ((KERN_DEBUG "filldir now\n"));
+							if (filldir (dirbuf, entry.name, entry.name_len, cur_f_pos, inode->i_ino) < 0) {
+								filp->f_pos = cur_f_pos;
+							}
+							Printk (("Trouve ino %ld ", inode->i_ino));
+							if (u_entry != NULL)
+								*u_entry = entry;
+							iput (inode); /* FIXME? */
+							break;
+						}
+						Printk ((KERN_DEBUG " dir.c:Putting inode %lu with i_count=%d\n", inode->i_ino, inode->i_count));
+						iput (inode); /* FIXME? */
+					} else {
+						/* #Specification: umsdos / readdir / not in MSDOS
+						 * During a readdir operation, if the file is not
+						 * in the MSDOS directory anymore, the entry is
+						 * removed from the EMD file silently.
+						 */
+						Printk (("'Silently' removing EMD for file\n"));
+						ret = umsdos_writeentry (dir, emd_dir, &info, 1);
+						if (ret != 0) {
+							break;
+						}
+					}
+				}
+			}
+			/*
+			 * If the fillbuf has failed, f_pos is back to 0.
+			 * To avoid getting back into the . and .. state
+			 * (see comments at the beginning), we put back
+			 * the special offset.
+			 */
+			if (filp->f_pos == 0)
+				filp->f_pos = start_fpos;
+			Printk ((KERN_DEBUG " dir.c:Putting emd_dir %lu with i_count=%d\n", emd_dir->i_ino, emd_dir->i_count));
+			iput (emd_dir); /* FIXME? */
+		}
+	}
+	umsdos_endlookup (dir);
+	
+	Printk (("read dir %p pos %Ld ret %d\n", dir, filp->f_pos, ret));
+	return ret;
+}
+
+
+/*
+ * Read count directory entries from directory filp
+ * Return a negative value from linux/errno.h.
+ * Return 0 or positive if successful
+ */
+ 
+static int UMSDOS_readdir (
+				  struct file *filp,	/* Point to a directory which is read */
+				  void *dirbuf,		/* Will hold directory entries  */
+				  filldir_t filldir)
+{
+	struct inode *dir = filp->f_dentry->d_inode;
+	int ret = 0;
+	int count = 0;
+	struct UMSDOS_DIR_ONCE bufk;
+
+	bufk.dirbuf = dirbuf;
+	bufk.filldir = filldir;
+	bufk.stop = 0;
+
+	Printk (("UMSDOS_readdir in\n"));
+	while (ret == 0 && bufk.stop == 0) {
+		struct umsdos_dirent entry;
+
+		bufk.count = 0;
+		Printk (("UMSDOS_readdir: calling _x (%p,%p,%p,%d,%p,%d,%p)\n", dir, filp, &bufk, 0, &entry, 1, umsdos_dir_once));
+		ret = umsdos_readdir_x (dir, filp, &bufk, 0, &entry, 1, umsdos_dir_once);
+		if (bufk.count == 0)
+			break;
+		count += bufk.count;
+	}
+	Printk (("UMSDOS_readdir out %d count %d pos %Ld\n", ret, count, filp->f_pos));
+	return count ? : ret;
+}
+
+
+/*
+ * Complete the inode content with info from the EMD file
+ */
+
 void umsdos_lookup_patch (
-			  struct inode *dir,
-			  struct inode *inode,
-			  struct umsdos_dirent *entry,
-			  off_t  emd_pos)
-{
-  /*
-    This function modify the state of a dir inode. It decides
-    if the dir is a umsdos dir or a dos dir. This is done
-    deeper in umsdos_patch_inode() called at the end of this function.
-    
-    umsdos_patch_inode() may block because it is doing disk access.
-    At the same time, another process may get here to initialise
-    the same dir inode. There is 3 cases.
-    
-    1-The inode is already initialised. We do nothing.
-    2-The inode is not initialised. We lock access and do it.
-    3-Like 2 but another process has lock the inode, so we try
-    to lock it and right after check if initialisation is still
-    needed.
-    
-    
-    Thanks to the mem option of the kernel command line, it was
-    possible to consistently reproduce this problem by limiting
-    my mem to 4 meg and running X.
-  */
-  /*
-    Do this only if the inode is freshly read, because we will lose
-    the current (updated) content.
-  */
-  /*
-    A lookup of a mount point directory yield the inode into
-    the other fs, so we don't care about initialising it. iget()
-    does this automatically.
-  */
-  if (inode->i_sb == dir->i_sb && !umsdos_isinit(inode)){
-    if (S_ISDIR(inode->i_mode)) umsdos_lockcreate(inode);
-    if (!umsdos_isinit(inode)){
-      /* #Specification: umsdos / lookup / inode info
-	 After successfully reading an inode from the MSDOS
-	 filesystem, we use the EMD file to complete it.
-	 We update the following field.
-	 
-	 uid, gid, atime, ctime, mtime, mode.
-	 
-	 We rely on MSDOS for mtime. If the file
-	 was modified during an MSDOS session, at least
-	 mtime will be meaningful. We do this only for regular
-	 file.
-	 
-	 We don't rely on MSDOS for mtime for directory because
-	 the MSDOS directory date is creation time (strange
-	 MSDOS behavior) which fit nowhere in the three UNIX
-	 time stamp.
-      */
-      if (S_ISREG(entry->mode)) entry->mtime = inode->i_mtime;
-      inode->i_mode  = entry->mode;
-      inode->i_rdev  = to_kdev_t(entry->rdev);
-      inode->i_atime = entry->atime;
-      inode->i_ctime = entry->ctime;
-      inode->i_mtime = entry->mtime;
-      inode->i_uid   = entry->uid;
-      inode->i_gid   = entry->gid;
-      /* #Specification: umsdos / conversion mode
-	 The msdos fs can do some inline conversion
-	 of the data of a file. It can translate
-	 silently from MsDOS text file format to Unix
-	 one (crlf -> lf) while reading, and the reverse
-	 while writing. This is activated using the mount
-	 option conv=....
-	 
-	 This is not useful for Linux file in promoted
-	 directory. It can even be harmful. For this
-	 reason, the binary (no conversion) mode is
-	 always activated.
-      */
-      /* #Specification: umsdos / conversion mode / todo
-	 A flag could be added to file and directories
-	 forcing an automatic conversion mode (as
-	 done with the msdos fs).
-	 
-	 This flag could be setup on a directory basis
-	 (instead of file) and all file in it would
-	 logically inherited. If the conversion mode
-	 is active (conv=) then the i_binary flag would
-	 be left untouched in those directories.
-	 
-	 It was proposed that the sticky bit was used
-	 to set this. The problem is that new file would
-	 be written incorrectly. The other problem is that
-	 the sticky bit has a meaning for directories. So
-	 another bit should be used (there is some space
-	 in the EMD file for it) and a special utilities
-	 would be used to assign the flag to a directory).
-	 I don't think it is useful to assign this flag
-	 on a single file.
-      */
-      
-      MSDOS_I(inode)->i_binary = 1;
-      /* #Specification: umsdos / i_nlink
-	 The nlink field of an inode is maintain by the MSDOS file system
-	 for directory and by UMSDOS for other file. The logic is that
-	 MSDOS is already figuring out what to do for directories and
-	 does nothing for other files. For MSDOS, there are no hard link
-	 so all file carry nlink==1. UMSDOS use some info in the
-	 EMD file to plug the correct value.
-      */
-      if (!S_ISDIR(entry->mode)){
-	if (entry->nlink > 0){
-	  inode->i_nlink = entry->nlink;
-	}else{
-	  printk (KERN_ERR "UMSDOS: lookup_patch entry->nlink < 1 ???\n");
-	}
-      }
-      umsdos_patch_inode(inode,dir,emd_pos);
-    }
-    if (S_ISDIR(inode->i_mode)) umsdos_unlockcreate(inode);
-    if (inode->u.umsdos_i.i_emd_owner==0) printk (KERN_WARNING "emd_owner still 0 ???\n");
-  }
-}
-
-struct UMSDOS_DIRENT_K{
-  off_t f_pos; /* will hold the offset of the entry in EMD */
-  ino_t ino;
+				 struct inode *dir,
+				 struct inode *inode,
+				 struct umsdos_dirent *entry,
+				 off_t emd_pos)
+{
+	/*
+	 * This function modify the state of a dir inode. It decides
+	 * if the dir is a umsdos dir or a dos dir. This is done
+	 * deeper in umsdos_patch_inode() called at the end of this function.
+	 * 
+	 * umsdos_patch_inode() may block because it is doing disk access.
+	 * At the same time, another process may get here to initialise
+	 * the same dir inode. There is 3 cases.
+	 * 
+	 * 1-The inode is already initialised. We do nothing.
+	 * 2-The inode is not initialised. We lock access and do it.
+	 * 3-Like 2 but another process has lock the inode, so we try
+	 * to lock it and right after check if initialisation is still
+	 * needed.
+	 * 
+	 * 
+	 * Thanks to the mem option of the kernel command line, it was
+	 * possible to consistently reproduce this problem by limiting
+	 * my mem to 4 meg and running X.
+	 */
+	/*
+	 * Do this only if the inode is freshly read, because we will lose
+	 * the current (updated) content.
+	 */
+	/*
+	 * A lookup of a mount point directory yield the inode into
+	 * the other fs, so we don't care about initialising it. iget()
+	 * does this automatically.
+	 */
+
+	if (inode->i_sb == dir->i_sb && !umsdos_isinit (inode)) {
+		if (S_ISDIR (inode->i_mode))
+			umsdos_lockcreate (inode);
+		if (!umsdos_isinit (inode)) {
+			/* #Specification: umsdos / lookup / inode info
+			 * After successfully reading an inode from the MSDOS
+			 * filesystem, we use the EMD file to complete it.
+			 * We update the following field.
+			 * 
+			 * uid, gid, atime, ctime, mtime, mode.
+			 * 
+			 * We rely on MSDOS for mtime. If the file
+			 * was modified during an MSDOS session, at least
+			 * mtime will be meaningful. We do this only for regular
+			 * file.
+			 * 
+			 * We don't rely on MSDOS for mtime for directory because
+			 * the MSDOS directory date is creation time (strange
+			 * MSDOS behavior) which fit nowhere in the three UNIX
+			 * time stamp.
+			 */
+			if (S_ISREG (entry->mode))
+				entry->mtime = inode->i_mtime;
+			inode->i_mode = entry->mode;
+			inode->i_rdev = to_kdev_t (entry->rdev);
+			inode->i_atime = entry->atime;
+			inode->i_ctime = entry->ctime;
+			inode->i_mtime = entry->mtime;
+			inode->i_uid = entry->uid;
+			inode->i_gid = entry->gid;
+			/* #Specification: umsdos / conversion mode
+			 * The msdos fs can do some inline conversion
+			 * of the data of a file. It can translate
+			 * silently from MsDOS text file format to Unix
+			 * one (crlf -> lf) while reading, and the reverse
+			 * while writing. This is activated using the mount
+			 * option conv=....
+			 * 
+			 * This is not useful for Linux file in promoted
+			 * directory. It can even be harmful. For this
+			 * reason, the binary (no conversion) mode is
+			 * always activated.
+			 */
+			/* #Specification: umsdos / conversion mode / todo
+			 * A flag could be added to file and directories
+			 * forcing an automatic conversion mode (as
+			 * done with the msdos fs).
+			 * 
+			 * This flag could be setup on a directory basis
+			 * (instead of file) and all file in it would
+			 * logically inherited. If the conversion mode
+			 * is active (conv=) then the i_binary flag would
+			 * be left untouched in those directories.
+			 * 
+			 * It was proposed that the sticky bit was used
+			 * to set this. The problem is that new file would
+			 * be written incorrectly. The other problem is that
+			 * the sticky bit has a meaning for directories. So
+			 * another bit should be used (there is some space
+			 * in the EMD file for it) and a special utilities
+			 * would be used to assign the flag to a directory).
+			 * I don't think it is useful to assign this flag
+			 * on a single file.
+			 */
+
+			MSDOS_I (inode)->i_binary = 1;
+			/* #Specification: umsdos / i_nlink
+			 * The nlink field of an inode is maintain by the MSDOS file system
+			 * for directory and by UMSDOS for other file. The logic is that
+			 * MSDOS is already figuring out what to do for directories and
+			 * does nothing for other files. For MSDOS, there are no hard link
+			 * so all file carry nlink==1. UMSDOS use some info in the
+			 * EMD file to plug the correct value.
+			 */
+			if (!S_ISDIR (entry->mode)) {
+				if (entry->nlink > 0) {
+					inode->i_nlink = entry->nlink;
+				} else {
+					printk (KERN_ERR "UMSDOS: lookup_patch entry->nlink < 1 ???\n");
+				}
+			}
+			umsdos_patch_inode (inode, dir, emd_pos);
+		}
+		if (S_ISDIR (inode->i_mode))
+			umsdos_unlockcreate (inode);
+		if (inode->u.umsdos_i.i_emd_owner == 0)
+			printk (KERN_WARNING "emd_owner still 0 ???\n");
+	}
+}
+
+
+
+struct UMSDOS_DIRENT_K {
+	off_t f_pos;		/* will hold the offset of the entry in EMD */
+	ino_t ino;
 };
 
+
 /*
-  Just to record the offset of one entry.
-*/
-static int umsdos_filldir_k(
-			    void * buf,
-			    const char *name,
-			    int len,
-			    off_t offset,
-			    ino_t ino)
-{
-  struct UMSDOS_DIRENT_K *d = (struct UMSDOS_DIRENT_K *)buf;
-  d->f_pos = offset;
-  d->ino = ino;
-  return 0;
-}
-
-struct UMSDOS_DIR_SEARCH{
-  struct umsdos_dirent *entry;
-  int found;
-  ino_t search_ino;
+ * Just to record the offset of one entry.
+ */
+
+static int umsdos_filldir_k (
+				    void *buf,
+				    const char *name,
+				    int len,
+				    off_t offset,
+				    ino_t ino)
+{
+	struct UMSDOS_DIRENT_K *d = (struct UMSDOS_DIRENT_K *) buf;
+
+	d->f_pos = offset;
+	d->ino = ino;
+	return 0;
+}
+
+struct UMSDOS_DIR_SEARCH {
+	struct umsdos_dirent *entry;
+	int found;
+	ino_t search_ino;
 };
 
 static int umsdos_dir_search (
-			      void * buf,
-			      const char *name,
-			      int len,
-			      off_t offset,
-			      ino_t ino)
-{
-  int ret = 0;
-  struct UMSDOS_DIR_SEARCH *d = (struct UMSDOS_DIR_SEARCH *)buf;
-  if (d->search_ino == ino){
-    d->found = 1;
-    memcpy (d->entry->name,name,len);
-    d->entry->name[len] = '\0';
-    d->entry->name_len = len;
-    ret = 1;	/* So fat_readdir will terminate */
-  }
-  return ret;
+				     void *buf,
+				     const char *name,
+				     int len,
+				     off_t offset,
+				     ino_t ino)
+{
+	int ret = 0;
+	struct UMSDOS_DIR_SEARCH *d = (struct UMSDOS_DIR_SEARCH *) buf;
+
+	if (d->search_ino == ino) {
+		d->found = 1;
+		memcpy (d->entry->name, name, len);
+		d->entry->name[len] = '\0';
+		d->entry->name_len = len;
+		ret = 1;	/* So fat_readdir will terminate */
+	}
+	return ret;
 }
 
 
+
 /*
-  Locate entry of an inode in a directory.
-  Return 0 or a negative error code.
-  
-  Normally, this function must succeed. It means a strange corruption
-  in the file system if not.
-*/
+ * Locate entry of an inode in a directory.
+ * Return 0 or a negative error code.
+ * 
+ * Normally, this function must succeed. It means a strange corruption
+ * in the file system if not.
+ */
+
 int umsdos_inode2entry (
-			struct inode *dir,
-			struct inode *inode,
-			struct umsdos_dirent *entry)	/* Will hold the entry */
-{
-  int ret = -ENOENT;
-  if (pseudo_root && inode == pseudo_root){
-    /*
-      Quick way to find the name.
-      Also umsdos_readdir_x won't show /linux anyway
-    */
-    memcpy (entry->name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN+1);
-    entry->name_len = UMSDOS_PSDROOT_LEN;
-    ret = 0;
-  }else{
-    struct inode *emddir = umsdos_emd_dir_lookup(dir,0);
-    /* iput (emddir); FIXME */
-    if (emddir == NULL){
-      /* This is a DOS directory */
-      struct UMSDOS_DIR_SEARCH bufk;
-      struct file filp;
-      
-      fill_new_filp (&filp, NULL);
-            
-      Printk ((KERN_ERR "umsdos_inode2entry emddir==NULL: WARNING: Known filp problem. segfaulting :) /mn/\n"));
-      filp.f_reada = 1;
-      filp.f_pos = 0;
-      bufk.entry = entry;
-      bufk.search_ino = inode->i_ino;
-      fat_readdir (&filp,&bufk,umsdos_dir_search);
-      if (bufk.found){
-	ret = 0;
-	inode->u.umsdos_i.i_dir_owner = dir->i_ino;
-	inode->u.umsdos_i.i_emd_owner = 0;
-	umsdos_setup_dir_inode(inode);
-      }
-    }else{
-      /* skip . and .. see umsdos_readdir_x() */
-      struct file filp;
-      fill_new_filp (&filp, NULL);
-      
-      filp.f_reada = 1;
-      filp.f_pos = UMSDOS_SPECIAL_DIRFPOS;
-      Printk ((KERN_ERR "umsdos_inode2entry skip./..: WARNING: Known filp problem. segfaulting :) /mn/\n"));
-      while (1){
-	struct UMSDOS_DIRENT_K bufk;
-	if (umsdos_readdir_x(dir,&filp,&bufk
-			     ,1,entry,0,umsdos_filldir_k) < 0){
-	  printk ("UMSDOS: can't locate inode %ld in EMD file???\n"
-		  ,inode->i_ino);
-	  break;
-	}else if (bufk.ino == inode->i_ino){
-	  ret = 0;
-	  umsdos_lookup_patch (dir,inode,entry,bufk.f_pos);
-	  break;
-	}
-      }
-    }
-  }
-  return ret;
-}
-
-
-/*
-  Locate the parent of a directory and the info on that directory
-  Return 0 or a negative error code.
-*/
+			       struct inode *dir,
+			       struct inode *inode,
+			       struct umsdos_dirent *entry)
+{				/* Will hold the entry */
+	int ret = -ENOENT;
+
+	if (pseudo_root && inode == pseudo_root) {
+		/*
+		 * Quick way to find the name.
+		 * Also umsdos_readdir_x won't show /linux anyway
+		 */
+		memcpy (entry->name, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN + 1);
+		entry->name_len = UMSDOS_PSDROOT_LEN;
+		ret = 0;
+	} else {
+		struct inode *emddir = umsdos_emd_dir_lookup (dir, 0);
+
+		iput (emddir); /* FIXME? */
+		if (emddir == NULL) {
+			/* This is a DOS directory */
+			struct UMSDOS_DIR_SEARCH bufk;
+			struct file filp;
+			struct dentry *i2e;
+			
+			i2e = creat_dentry ("i2e.nul", 7, dir, NULL);
+
+			fill_new_filp (&filp, i2e);
+
+			Printk ((KERN_ERR "umsdos_inode2entry emddir==NULL: WARNING: Known filp problem. segfaulting :) fixed ?/mn/\n"));
+			filp.f_reada = 1;
+			filp.f_pos = 0;
+			bufk.entry = entry;
+			bufk.search_ino = inode->i_ino;
+			fat_readdir (&filp, &bufk, umsdos_dir_search);
+			if (bufk.found) {
+				ret = 0;
+				inode->u.umsdos_i.i_dir_owner = dir->i_ino;
+				inode->u.umsdos_i.i_emd_owner = 0;
+				umsdos_setup_dir_inode (inode);
+			}
+		} else {
+			/* skip . and .. see umsdos_readdir_x() */
+			struct file filp;
+			struct dentry *i2e;
+
+			i2e = creat_dentry ("i2e.nn", 6, dir, NULL);
+			fill_new_filp (&filp, i2e);
+
+			filp.f_reada = 1;
+			filp.f_pos = UMSDOS_SPECIAL_DIRFPOS;
+			Printk ((KERN_ERR "umsdos_inode2entry skip...: WARNING: Known filp problem. segfaulting :) fixed ?/mn/\n"));
+			while (1) {
+				struct UMSDOS_DIRENT_K bufk;
+
+				if (umsdos_readdir_x (dir, &filp, &bufk
+				   ,1, entry, 0, umsdos_filldir_k) < 0) {
+					printk ("UMSDOS: can't locate inode %ld in EMD file???\n"
+						,inode->i_ino);
+					break;
+				} else if (bufk.ino == inode->i_ino) {
+					ret = 0;
+					umsdos_lookup_patch (dir, inode, entry, bufk.f_pos);
+					break;
+				}
+			}
+		}
+	}
+	return ret;
+}
+
+
+/*
+ * Locate the parent of a directory and the info on that directory
+ * Return 0 or a negative error code.
+ */
+
 static int umsdos_locate_ancestor (
-				   struct inode *dir,
-				   struct inode **result,
-				   struct umsdos_dirent *entry)
-{
-  int ret;
-  
-  umsdos_patch_inode (dir,NULL,0);
-  /* FIXME */
-  ret = compat_umsdos_real_lookup (dir,"..",2,result);
-  Printk (("result %d %p ",ret,*result));
-  if (ret == 0){
-    struct inode *adir = *result;
-    ret = umsdos_inode2entry (adir,dir,entry);
-  }
-  Printk (("\n"));
-  return ret;
-}
-/*
-  Build the path name of an inode (relative to the file system.
-  This function is need to set (pseudo) hard link.
-  
-  It uses the same strategy as the standard getcwd().
-*/
+					  struct inode *dir,
+					  struct inode **result,
+					  struct umsdos_dirent *entry)
+{
+	int ret;
+
+	umsdos_patch_inode (dir, NULL, 0);
+	/* FIXME */
+	ret = compat_umsdos_real_lookup (dir, "..", 2, result);
+	Printk (("result %d %p ", ret, *result));
+	if (ret == 0) {
+		struct inode *adir = *result;
+
+		ret = umsdos_inode2entry (adir, dir, entry);
+	}
+	Printk (("\n"));
+	return ret;
+}
+
+
+/*
+ * Build the path name of an inode (relative to the file system.
+ * This function is need to set (pseudo) hard link.
+ * 
+ * It uses the same strategy as the standard getcwd().
+ */
+
 int umsdos_locate_path (
-			struct inode *inode,
-			char *path)
+			       struct inode *inode,
+			       char *path)
 {
-  int ret = 0;
-  struct inode *dir = inode;
-  struct inode *root_inode;
-  char *bpath = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
-  root_inode = iget(inode->i_sb,UMSDOS_ROOT_INO);
-  if (bpath == NULL){
-    ret = -ENOMEM;
-  }else{
-    struct umsdos_dirent entry;
-    char *ptbpath = bpath+PATH_MAX-1;
-    *ptbpath = '\0';
-    Printk (("locate_path mode %x ",inode->i_mode));
-    if (!S_ISDIR(inode->i_mode)){
-      ret = umsdos_get_dirowner (inode,&dir);
-      Printk (("locate_path ret %d ",ret));
-      if (ret == 0){
-	ret = umsdos_inode2entry (dir,inode,&entry);
-	if (ret == 0){
-	  ptbpath -= entry.name_len;
-	  memcpy (ptbpath,entry.name,entry.name_len);
-	  Printk (("ptbpath :%.*s: ",entry.name_len,ptbpath));
-	}
-      }
-    }else{
-      dir->i_count++;
-    }
-    if (ret == 0){
-      while (dir != root_inode){
-	struct inode *adir;
-	ret = umsdos_locate_ancestor (dir,&adir,&entry);
-	/* iput (dir); FIXME */
-	dir = NULL;
-	Printk (("ancestor %d ",ret));
-	if (ret == 0){
-	  *--ptbpath = '/';
-	  ptbpath -= entry.name_len;
-	  memcpy (ptbpath,entry.name,entry.name_len);
-	  dir = adir;
-	  Printk (("ptbpath :%.*s: ",entry.name_len,ptbpath));
-	}else{
-	  break;
-	}
-      }
-    }
-    strcpy (path,ptbpath);
-    kfree (bpath);
-  }
-  Printk (("\n"));
-  /* iput (dir); FIXME */
-  return ret;
+	int ret = 0;
+	struct inode *dir = inode;
+	struct inode *root_inode;
+	char *bpath = (char *) kmalloc (PATH_MAX, GFP_KERNEL);
+
+	root_inode = iget (inode->i_sb, UMSDOS_ROOT_INO);
+	if (bpath == NULL) {
+		ret = -ENOMEM;
+	} else {
+		struct umsdos_dirent entry;
+		char *ptbpath = bpath + PATH_MAX - 1;
+
+		*ptbpath = '\0';
+		Printk (("locate_path mode %x ", inode->i_mode));
+		if (!S_ISDIR (inode->i_mode)) {
+			ret = umsdos_get_dirowner (inode, &dir);
+			Printk (("locate_path ret %d ", ret));
+			if (ret == 0) {
+				ret = umsdos_inode2entry (dir, inode, &entry);
+				if (ret == 0) {
+					ptbpath -= entry.name_len;
+					memcpy (ptbpath, entry.name, entry.name_len);
+					Printk (("ptbpath :%.*s: ", entry.name_len, ptbpath));
+				}
+			}
+		} else {
+			inc_count (dir);
+		}
+		if (ret == 0) {
+			while (dir != root_inode) {
+				struct inode *adir;
+
+				ret = umsdos_locate_ancestor (dir, &adir, &entry);
+				/* iput (dir); FIXME */
+				dir = NULL;
+				Printk (("ancestor %d ", ret));
+				if (ret == 0) {
+					*--ptbpath = '/';
+					ptbpath -= entry.name_len;
+					memcpy (ptbpath, entry.name, entry.name_len);
+					dir = adir;
+					Printk (("ptbpath :%.*s: ", entry.name_len, ptbpath));
+				} else {
+					break;
+				}
+			}
+		}
+		strcpy (path, ptbpath);
+		kfree (bpath);
+	}
+	Printk (("\n"));
+	iput (dir); /* FIXME?? */
+	return ret;
 }
 
+
 /*
-	Return != 0 if an entry is the pseudo DOS entry in the pseudo root.
-*/
+ * Return != 0 if an entry is the pseudo DOS entry in the pseudo root.
+ */
+
 int umsdos_is_pseudodos (
-	struct inode *dir,
-	struct dentry *dentry)
+				struct inode *dir,
+				struct dentry *dentry)
 {
-  /* #Specification: pseudo root / DOS hard coded
-     The pseudo sub-directory DOS in the pseudo root is hard coded.
-     The name is DOS. This is done this way to help standardised
-     the umsdos layout. The idea is that from now on /DOS is
-     a reserved path and nobody will think of using such a path
-     for a package.
-  */
-  return pseudo_root
-    && dir == pseudo_root
-    && dentry->d_name.len == 3
-    && dentry->d_name.name[0] == 'D' 
-    && dentry->d_name.name[1] == 'O' 
-    && dentry->d_name.name[2] == 'S';
+	/* #Specification: pseudo root / DOS hard coded
+	 * The pseudo sub-directory DOS in the pseudo root is hard coded.
+	 * The name is DOS. This is done this way to help standardised
+	 * the umsdos layout. The idea is that from now on /DOS is
+	 * a reserved path and nobody will think of using such a path
+	 * for a package.
+	 */
+	return pseudo_root
+	    && dir == pseudo_root
+	    && dentry->d_name.len == 3
+	    && dentry->d_name.name[0] == 'D'
+	    && dentry->d_name.name[1] == 'O'
+	    && dentry->d_name.name[2] == 'S';
 }
 
+
 /*
-  Check if a file exist in the current directory.
-  Return 0 if ok, negative error code if not (ex: -ENOENT).
-*/
+ * Check if a file exist in the current directory.
+ * Return 0 if ok, negative error code if not (ex: -ENOENT).
+ */
+
 int umsdos_lookup_x (
 			    struct inode *dir,
 			    struct dentry *dentry,
-			    int nopseudo)/* Don't care about pseudo root mode */
-{
-  int ret = -ENOENT;
-  struct inode *root_inode;
-  struct inode *pseudo_root_inode=NULL;
-  int len = dentry->d_name.len;
-  const char *name = dentry->d_name.name;
-  
-  Printk ((KERN_DEBUG "umsdos_lookup_x: /mn/ name=%.*s, dir=%lu, d_parent=%p\n", (int) dentry->d_name.len, dentry->d_name.name, dir->i_ino, dentry->d_parent));	/* FIXME /mn/ debug only */
-  if (dentry->d_parent) Printk ((KERN_DEBUG "   d_parent is %.*s\n", (int) dentry->d_parent->d_name.len, dentry->d_parent->d_name.name)); /* FIXME : delme /mn/ */
-  
-  root_inode = iget(dir->i_sb,UMSDOS_ROOT_INO);
-  /*	pseudo_root_inode = iget( ... ) ? */
-  dentry->d_inode = NULL;
-  umsdos_startlookup(dir);
-  if (len == 1 && name[0] == '.'){
-    d_add (dentry, dir);
-    dir->i_count++;
-    ret = 0;
-  }else if (len == 2 && name[0] == '.' && name[1] == '.'){
-    if (pseudo_root && dir == pseudo_root_inode){
-      /* #Specification: pseudo root / .. in real root
-	 Whenever a lookup is those in the real root for
-	 the directory .., and pseudo root is active, the
-	 pseudo root is returned.
-      */
-      ret = 0;
-      d_add (dentry, pseudo_root);
-      pseudo_root->i_count++;
-    }else{
-      /* #Specification: locating .. / strategy
-	 We use the msdos filesystem to locate the parent directory.
-	 But it is more complicated than that.
-	 
-	 We have to step back even further to
-	 get the parent of the parent, so we can get the EMD
-	 of the parent of the parent. Using the EMD file, we can
-	 locate all the info on the parent, such a permissions
-	 and owner.
-      */
-      
-      ret = compat_umsdos_real_lookup (dir,"..",2,&dentry->d_inode);
-      Printk (("ancestor ret %d dir %p *result %p ",ret,dir,dentry->d_inode));
-      if (ret == 0
-	  && dentry->d_inode != root_inode
-	  && dentry->d_inode != pseudo_root){
-	struct inode *aadir;
-	struct umsdos_dirent entry;
-	ret = umsdos_locate_ancestor (dentry->d_inode,&aadir,&entry);
-	/* iput (aadir); FIXME */
-      }
-    }
-  }else if (umsdos_is_pseudodos(dir,dentry)){
-    /* #Specification: pseudo root / lookup(DOS)
-       A lookup of DOS in the pseudo root will always succeed
-       and return the inode of the real root.
-    */
-    d_add (dentry, root_inode);
-    (dentry->d_inode)->i_count++;
-    ret = 0;
-  }else{
-    struct umsdos_info info;
-    ret = umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info);
-    if (ret == 0) ret = umsdos_findentry (dir,&info,0);
-    Printk (("lookup %.*s pos %lu ret %d len %d ",info.fake.len,info.fake.fname,info.f_pos,ret
-	     ,info.fake.len));
-    if (ret == 0){
-      /* #Specification: umsdos / lookup
-	 A lookup for a file is done in two step. First, we locate
-	 the file in the EMD file. If not present, we return
-	 an error code (-ENOENT). If it is there, we repeat the
-	 operation on the msdos file system. If this fails, it means
-	 that the file system is not in sync with the emd file.
-	 We silently remove this entry from the emd file,
-	 and return ENOENT.
-      */
-      struct inode *inode;
-      
-      ret = compat_umsdos_real_lookup (dir,info.fake.fname,info.fake.len,&inode);
-
-      Printk ((KERN_DEBUG "umsdos_lookup_x: compat_umsdos_real_lookup for %.*s returned %d with inode=%p\n", info.fake.len, info.fake.fname, ret, inode));
-
-      if (inode == NULL){
-	printk (KERN_WARNING "UMSDOS: Erase entry %.*s, out of sync with MsDOS\n"
-		,info.fake.len, info.fake.fname);
-	umsdos_delentry (dir,&info,S_ISDIR(info.entry.mode));
-      }else{
-        Printk ((KERN_DEBUG "umsdos_lookup_x /mn/ debug: ino=%li\n", inode->i_ino));
-
-        /* we've found it. now get inode and put it in dentry. Is this ok /mn/ ? */
-        d_add (dentry, iget(dir->i_sb, inode->i_ino));
-        
-	umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
-	Printk (("lookup ino %ld flags %d\n",inode->i_ino
-		 ,info.entry.flags));
-	if (info.entry.flags & UMSDOS_HLINK){
-	  Printk ((KERN_DEBUG "umsdos_lookup_x: here goes HLINK\n"));
-	  ret = umsdos_hlink2inode (inode,&dentry->d_inode);
-	}
-	if (pseudo_root && dentry->d_inode == pseudo_root && !nopseudo){
-	  /* #Specification: pseudo root / dir lookup
-	     For the same reason as readdir, a lookup in /DOS for
-	     the pseudo root directory (linux) will fail.
-	  */
-	  /*
-	    This has to be allowed for resolving hard link
-	    which are recorded independently of the pseudo-root
-	    mode.
-	  */
-	  Printk ((KERN_ERR "umsdos_lookup_x: warning: untested /mn/ Pseudo_root thingy\n"));
-	  /* iput (pseudo_root); FIXME */
-	  dentry->d_inode = NULL;
-	  ret = -ENOENT;
-	}
-      }
-    }
-  }
-  umsdos_endlookup(dir);	
-  /* iput (dir); FIXME */
-  Printk ((KERN_DEBUG "umsdos_lookup_x: returning %d\n", ret));
-  return ret;
-}
-
-
-/*
-  Check if a file exist in the current directory.
-  Return 0 if ok, negative error code if not (ex: -ENOENT).
-  
-  
-*/
+			    int nopseudo)
+{				/* Don't care about pseudo root mode */
+	int ret = -ENOENT;
+	struct inode *root_inode;
+	int len = dentry->d_name.len;
+	const char *name = dentry->d_name.name;
+
+	PRINTK ((KERN_DEBUG "umsdos_lookup_x: /mn/ name=%.*s, dir=%lu (i_count=%d), d_parent=%p\n", (int) dentry->d_name.len, dentry->d_name.name, dir->i_ino, dir->i_count, dentry->d_parent));		/* FIXME /mn/ debug only */
+	if (dentry->d_parent)
+		PRINTK ((KERN_DEBUG "   d_parent is %.*s\n", (int) dentry->d_parent->d_name.len, dentry->d_parent->d_name.name));	/* FIXME : delme /mn/ */
+
+	root_inode = iget (dir->i_sb, UMSDOS_ROOT_INO);
+	Printk ((KERN_ERR "umsdos_lookup_x (CNT!): entering root_count=%d, dir %lu _count=%d\n", root_inode->i_count, dir->i_ino, dir->i_count));	/* FIXME: DEBUG, DELME */
+
+	d_instantiate (dentry, NULL);
+	umsdos_startlookup (dir);
+	if (len == 1 && name[0] == '.') {
+		d_add (dentry, dir);
+		inc_count (dir);
+		ret = 0;
+	} else if (len == 2 && name[0] == '.' && name[1] == '.') {
+		if (pseudo_root && dir == pseudo_root) {
+			/* #Specification: pseudo root / .. in real root
+			 * Whenever a lookup is those in the real root for
+			 * the directory .., and pseudo root is active, the
+			 * pseudo root is returned.
+			 */
+			ret = 0;
+			d_add (dentry, pseudo_root);
+			inc_count (pseudo_root);
+		} else {
+			/* #Specification: locating .. / strategy
+			 * We use the msdos filesystem to locate the parent directory.
+			 * But it is more complicated than that.
+			 * 
+			 * We have to step back even further to
+			 * get the parent of the parent, so we can get the EMD
+			 * of the parent of the parent. Using the EMD file, we can
+			 * locate all the info on the parent, such a permissions
+			 * and owner.
+			 */
+
+			ret = compat_umsdos_real_lookup (dir, "..", 2, &dentry->d_inode);
+			Printk (("ancestor ret %d dir %p *result %p ", ret, dir, dentry->d_inode));
+			if (ret == 0
+			    && dentry->d_inode != root_inode
+			    && dentry->d_inode != pseudo_root) {
+				struct inode *aadir;
+				struct umsdos_dirent entry;
+
+				ret = umsdos_locate_ancestor (dentry->d_inode, &aadir, &entry);
+				iput (aadir);	/* FIXME */
+			}
+		}
+	} else if (umsdos_is_pseudodos (dir, dentry)) {
+		/* #Specification: pseudo root / lookup(DOS)
+		 * A lookup of DOS in the pseudo root will always succeed
+		 * and return the inode of the real root.
+		 */
+		d_add (dentry, root_inode);
+		inc_count (dentry->d_inode);
+		ret = 0;
+	} else {
+		struct umsdos_info info;
+
+		ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
+		if (ret == 0)
+			ret = umsdos_findentry (dir, &info, 0);
+		Printk (("lookup %.*s pos %lu ret %d len %d ", info.fake.len, info.fake.fname, info.f_pos, ret
+			 ,info.fake.len));
+		if (ret == 0) {
+			/* #Specification: umsdos / lookup
+			 * A lookup for a file is done in two step. First, we locate
+			 * the file in the EMD file. If not present, we return
+			 * an error code (-ENOENT). If it is there, we repeat the
+			 * operation on the msdos file system. If this fails, it means
+			 * that the file system is not in sync with the emd file.
+			 * We silently remove this entry from the emd file,
+			 * and return ENOENT.
+			 */
+			struct inode *inode;
+
+			ret = compat_umsdos_real_lookup (dir, info.fake.fname, info.fake.len, &inode);
+
+			Printk ((KERN_DEBUG "umsdos_lookup_x: compat_umsdos_real_lookup for %.*s returned %d with inode=%p\n", info.fake.len, info.fake.fname, ret, inode));
+
+			if (inode == NULL) {
+				printk (KERN_WARNING "UMSDOS: Erase entry %.*s, out of sync with MsDOS\n"
+					,info.fake.len, info.fake.fname);
+				umsdos_delentry (dir, &info, S_ISDIR (info.entry.mode));
+			} else {
+				Printk ((KERN_DEBUG "umsdos_lookup_x /mn/ debug: ino=%li\n", inode->i_ino));
+
+				/* we've found it. now put inode in dentry */
+				d_add (dentry, inode);
+
+				umsdos_lookup_patch (dir, inode, &info.entry, info.f_pos);
+				Printk (("lookup ino %ld flags %d\n", inode->i_ino, info.entry.flags));
+				if (info.entry.flags & UMSDOS_HLINK) {
+					Printk ((KERN_DEBUG "umsdos_lookup_x: here goes HLINK\n"));
+					ret = umsdos_hlink2inode (inode, &dentry->d_inode);
+				}
+				if (pseudo_root && dentry->d_inode == pseudo_root && !nopseudo) {
+					/* #Specification: pseudo root / dir lookup
+					 * For the same reason as readdir, a lookup in /DOS for
+					 * the pseudo root directory (linux) will fail.
+					 */
+					/*
+					 * This has to be allowed for resolving hard link
+					 * which are recorded independently of the pseudo-root
+					 * mode.
+					 */
+					Printk ((KERN_ERR "umsdos_lookup_x: warning: untested /mn/ Pseudo_root thingy\n"));
+					iput (pseudo_root); /* FIXME?? */
+					d_instantiate (dentry, NULL);		/* FIXME: should be dput(dentry) ? */
+					ret = -ENOENT;
+				}
+			}
+		}
+	}
+	umsdos_endlookup (dir);
+	PRINTK ((KERN_DEBUG "umsdos_lookup_x: returning %d : name=%.*s (i_count=%d), dir=%lu (i_count=%d)\n", ret, (int) dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_count, dir->i_ino, dir->i_count));
+	Printk ((KERN_ERR "umsdos_lookup_x (CNT!): exiting root_count=%d, dir %lu _count=%d\n", root_inode->i_count, dir->i_ino, dir->i_count));	/* FIXME: DEBUG, DELME */
+	return ret;
+}
+
+
+/*
+ * Check if a file exist in the current directory.
+ * Return 0 if ok, negative error code if not (ex: -ENOENT).
+ * 
+ * 
+ */
+
 int UMSDOS_lookup (
-		   struct inode *dir,
-		   struct dentry *dentry)
+			  struct inode *dir,
+			  struct dentry *dentry)
 {
-  int ret;
-  ret = umsdos_lookup_x(dir,dentry,0);
-  
+	int ret;
+
+	check_dentry (dentry);
+	ret = umsdos_lookup_x (dir, dentry, 0);
+	check_dentry (dentry);
+
 #if 1
-  if (ret == -ENOENT) {
-    Printk ((KERN_INFO "UMSDOS_lookup: converting -ENOENT to negative dentry !\n"));
-    d_add (dentry, NULL);	/* create negative dentry if not found */
-    ret = 0;
-  }
+	if (ret == -ENOENT) {
+		Printk ((KERN_DEBUG "UMSDOS_lookup: converting -ENOENT to negative dentry !\n"));
+		d_add (dentry, NULL);	/* create negative dentry if not found */
+		ret = 0;
+	}
 #endif
-  
-  return ret;
+
+	return ret;
 }
 
 
 
 /*
-  Locate the inode pointed by a (pseudo) hard link
-  Return 0 if ok, a negative error code if not.
-*/
+ * Locate the inode pointed by a (pseudo) hard link
+ * Return 0 if ok, a negative error code if not.
+ */
+
 int umsdos_hlink2inode (struct inode *hlink, struct inode **result)
 {
-  struct inode *root_inode;
-  int ret = -EIO;
-  struct dentry *dentry_src, *dentry_dst;
-  char *path;
-  
-#if 0  	/* FIXME: DELME */
-  Printk (("FIXME: just test. hlink2inode returning -ENOENT\n /mn/\n"));
-  return -ENOENT;	/* /mn/ FIXME just for test */
+	struct inode *root_inode;
+	int ret = -EIO;
+	struct dentry *dentry_src, *dentry_dst;
+	char *path;
+
+#if 0				/* FIXME: DELME */
+	Printk (("FIXME: just test. hlink2inode returning -ENOENT\n /mn/\n"));
+	return -ENOENT;		/* /mn/ FIXME just for test */
 #endif
-  
-  path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
-
-  root_inode = iget(hlink->i_sb,UMSDOS_ROOT_INO);
-  *result = NULL;
-  if (path == NULL){
-    ret = -ENOMEM;
-    /* iput (hlink); FIXME */
-  }else{
-    struct file filp;
-    loff_t offs = 0;
-
-    fill_new_filp (&filp, NULL);
-      
-
-    dentry_src = creat_dentry ("hlink-mn", 8, hlink, NULL);
-
-    memset (&filp, 0, sizeof (filp));
-
-    filp.f_pos = 0;
-    filp.f_reada = 1;
-    filp.f_flags = O_RDONLY;
-    filp.f_dentry = dentry_src;
-    filp.f_op = &umsdos_file_operations;	/* /mn/ - we have to fill it with dummy values so we won't segfault */
-    
-    Printk (("hlink2inode "));
-    if (umsdos_file_read_kmem (hlink, &filp, path, hlink->i_size, &offs) == hlink->i_size)
-      {
-	struct inode *dir;
-	char *pt = path;
-	dir = root_inode;
-	path[hlink->i_size] = '\0';
-/*	iput (hlink); / * FIXME! /mn/ */
-	dir->i_count++;
-	while (1)
-	  {
-	    char *start = pt;
-	    int len;
-	    while (*pt != '\0' && *pt != '/') pt++;
-	    len = (int)(pt - start);
-	    if (*pt == '/') *pt++ = '\0';
-	    /* FIXME. /mn/ fixed ? */
 
-            dentry_dst = creat_dentry (start, len, NULL, NULL);
+	path = (char *) kmalloc (PATH_MAX, GFP_KERNEL);
 
-	    if (dir->u.umsdos_i.i_emd_dir == 0){
-	      /* This is a DOS directory */
-		
-	      Printk (("hlink2inode /mn/: doing umsdos_rlookup_x on %.*s\n", (int) dentry_dst->d_name.len, dentry_dst->d_name.name));
-	      ret = umsdos_rlookup_x(dir,dentry_dst,1);
-	    }else{
-	      Printk (("hlink2inode /mn/: doing umsdos_lookup_x on %.*s\n", (int) dentry_dst->d_name.len, dentry_dst->d_name.name));
-	      ret = umsdos_lookup_x(dir,dentry_dst,1);
-	    }
-	    Printk (("  returned %d\n", ret));
-	    *result = dentry_dst->d_inode;	/* /mn/ ok ? */
-
-	    Printk (("h2n lookup :%s: -> %d ",start,ret));
-	    if (ret == 0 && *pt != '\0'){
-	      dir = *result;
-	    }else{
-	      break;
-	    }
-	  }
-      }else{
-	  Printk (("umsdos_hlink2inode: all those iput's() frighten me /mn/. Whatabout dput() ? FIXME!\n"));
-	  /* iput (hlink); / * FIXME */
-      }
-    Printk (("hlink2inode ret = %d %p -> %p\n", ret, hlink, *result));
-    kfree (path);
-  }
-  return ret;
+	root_inode = iget (hlink->i_sb, UMSDOS_ROOT_INO);
+	*result = NULL;
+	if (path == NULL) {
+		ret = -ENOMEM;
+		iput (hlink); /* FIXME? */
+	} else {
+		struct file filp;
+		loff_t offs = 0;
+
+		dentry_src = creat_dentry ("hlink-mn", 8, hlink, NULL);
+
+		fill_new_filp (&filp, dentry_src);
+		filp.f_flags = O_RDONLY;
+
+		Printk (("hlink2inode "));
+		if (umsdos_file_read_kmem (hlink, &filp, path, hlink->i_size, &offs) == hlink->i_size) {
+			struct inode *dir;
+			char *pt = path;
+
+			dir = root_inode;
+			path[hlink->i_size] = '\0';
+			iput (hlink); /* FIXME? */
+			inc_count (dir);
+			while (1) {
+				char *start = pt;
+				int len;
+
+				while (*pt != '\0' && *pt != '/')
+					pt++;
+				len = (int) (pt - start);
+				if (*pt == '/')
+					*pt++ = '\0';
+				/* FIXME. /mn/ fixed ? */
+
+				dentry_dst = creat_dentry (start, len, NULL, NULL);
+
+				if (dir->u.umsdos_i.i_emd_dir == 0) {
+					/* This is a DOS directory */
+
+					Printk (("hlink2inode /mn/: doing umsdos_rlookup_x on %.*s\n", (int) dentry_dst->d_name.len, dentry_dst->d_name.name));
+					ret = umsdos_rlookup_x (dir, dentry_dst, 1);
+				} else {
+					Printk (("hlink2inode /mn/: doing umsdos_lookup_x on %.*s\n", (int) dentry_dst->d_name.len, dentry_dst->d_name.name));
+					ret = umsdos_lookup_x (dir, dentry_dst, 1);
+				}
+				Printk (("  returned %d\n", ret));
+				*result = dentry_dst->d_inode;	/* /mn/ ok ? */
+
+				Printk (("h2n lookup :%s: -> %d ", start, ret));
+				if (ret == 0 && *pt != '\0') {
+					dir = *result;
+				} else {
+					break;
+				}
+			}
+		} else {
+			Printk (("umsdos_hlink2inode: all those iput's() frighten me /mn/. Whatabout dput() ? FIXME!\n"));
+			iput (hlink); /* FIXME? */
+		}
+		Printk (("hlink2inode ret = %d %p -> %p\n", ret, hlink, *result));
+		kfree (path);
+	}
+	return ret;
 }
 
 
-static struct file_operations umsdos_dir_operations = {
-	NULL,				/* lseek - default */
-	UMSDOS_dir_read,		/* read */
-	NULL,				/* write - bad */
-	UMSDOS_readdir,			/* readdir */
-	NULL,				/* poll - default */
-	UMSDOS_ioctl_dir,		/* ioctl - default */
-	NULL,				/* mmap */
-	NULL,				/* no special open code */
-	NULL,				/* no special release code */
-	NULL				/* fsync */	/* in original NULL. changed to file_fsync. FIXME? /mn/ */
+static struct file_operations umsdos_dir_operations =
+{
+	NULL,			/* lseek - default */
+	UMSDOS_dir_read,	/* read */
+	NULL,			/* write - bad */
+	UMSDOS_readdir,		/* readdir */
+	NULL,			/* poll - default */
+	UMSDOS_ioctl_dir,	/* ioctl - default */
+	NULL,			/* mmap */
+	NULL,			/* no special open code */
+	NULL,			/* no special release code */
+	NULL			/* fsync *//* in original NULL. changed to file_fsync. FIXME? /mn/ */
 };
 
-struct inode_operations umsdos_dir_inode_operations = {
+struct inode_operations umsdos_dir_inode_operations =
+{
 	&umsdos_dir_operations,	/* default directory file-ops */
 	UMSDOS_create,		/* create */
 	UMSDOS_lookup,		/* lookup */
@@ -955,22 +1039,14 @@
 	UMSDOS_mknod,		/* mknod */
 	UMSDOS_rename,		/* rename */
 	NULL,			/* readlink */
-	NULL,                   /* followlink */
-	generic_readpage,	/* readpage */	/* in original NULL. changed to generic_readpage. FIXME? /mn/ */
+	NULL,			/* followlink */
+	generic_readpage,	/* readpage *//* in original NULL. changed to generic_readpage. FIXME? /mn/ */
 	NULL,			/* writepage */
-	fat_bmap,		/* bmap */	/* in original NULL. changed to fat_bmap. FIXME? /mn/ */
+	fat_bmap,		/* bmap *//* in original NULL. changed to fat_bmap. FIXME? /mn/ */
 	NULL,			/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
 	NULL,			/* updatepage */
 	NULL,			/* revalidate */
-	
-};
-
-
-
-
-
-
-
 
+};
diff -u --recursive --new-file v2.1.102/linux/fs/umsdos/emd.c linux/fs/umsdos/emd.c
--- v2.1.102/linux/fs/umsdos/emd.c	Wed Apr  8 19:36:28 1998
+++ linux/fs/umsdos/emd.c	Tue May 19 15:07:53 1998
@@ -24,200 +24,118 @@
 #define Printk(x) printk x
 
 /*
- * makes empty filp
- *
+ *    Read a file into kernel space memory
+ *      returns how many bytes read (from fat_file_read)
  */
- 
-void fill_new_filp (struct file *filp, struct dentry *dentry)
-{
-    Printk (("/mn/ fill_new_filp: filling empty filp at %p\n", filp));
-    if (dentry) 
-      Printk (("     dentry=%.*s\n", (int) dentry->d_name.len, dentry->d_name.name));
-    else
-      Printk (("     dentry is NULL ! you must fill it later...\n"));
-
-    memset (filp, 0, sizeof (struct file));
-
-    filp->f_pos = 0;
-    filp->f_reada = 1;
-    filp->f_flags = O_RDWR;
-    filp->f_dentry = dentry;
-    filp->f_op = &umsdos_file_operations;        /* /mn/ - we have to fill it with SOMETHING */
-} 
 
-
-/*
- * makes dentry. for name name with length len. /mn/
- * if inode is not NULL, puts it also.
- *
- */
- 
-struct dentry *creat_dentry (const char *name, const int len, struct inode *inode, struct dentry *parent)
+ssize_t umsdos_file_read_kmem (	struct inode *emd_dir,
+				struct file *filp,
+				char *buf,
+				size_t count,
+				loff_t *offs)
 {
-/* FIXME /mn/: parent is not passed many times... if it is not, dentry should be destroyed before someone else gets to use it */
-
-    struct dentry *ret;
-    struct qstr qname;
-    
-    if (inode)
-      Printk ((KERN_DEBUG "/mn/ creat_dentry: creating dentry with inode=%lu for %.*s\n", inode->i_ino, len, name));
-    else
-      Printk ((KERN_DEBUG "/mn/ creat_dentry: creating empty dentry for %.*s\n", len, name));
+	int ret;
 
-    qname.name = name;
-    qname.len = len;
-    qname.hash = 0;
+	struct dentry *old_dentry;
+	mm_segment_t old_fs = get_fs ();
 
-    ret = d_alloc (parent,&qname);	/* create new dentry */
-    ret->d_inode = NULL;
+	set_fs (KERNEL_DS);
 
-    if (inode) d_add (ret, inode);
-      
-    return ret;
-}
+	old_dentry = filp->f_dentry;	/* save it */
+	filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir, NULL);
+	*offs = filp->f_pos;
 
+	PRINTK ((KERN_DEBUG "umsdos_file_read_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d, offs=%p\n", filp, buf, count, offs));
+	PRINTK ((KERN_DEBUG "  using emd=%ld\n", emd_dir->i_ino));
+	PRINTK ((KERN_DEBUG "  inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size));
+	PRINTK ((KERN_DEBUG "  ofs=%ld\n", (unsigned long) *offs));
+	PRINTK ((KERN_DEBUG "  f_pos=%Lu\n", filp->f_pos));
+	PRINTK ((KERN_DEBUG "  name=%.*s\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name));
+	PRINTK ((KERN_DEBUG "  i_binary(sb)=%d\n", MSDOS_I (filp->f_dentry->d_inode)->i_binary));
+	PRINTK ((KERN_DEBUG "  f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags));
+	PRINTK ((KERN_DEBUG "  f_owner=%d\n", filp->f_owner.uid));
+	PRINTK ((KERN_DEBUG "  f_version=%ld\n", filp->f_version));
+	PRINTK ((KERN_DEBUG "  f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin));
+
+	MSDOS_I (filp->f_dentry->d_inode)->i_binary = 2;
+	ret = fat_file_read (filp, buf, count, offs);
+	PRINTK ((KERN_DEBUG "fat_file_read returned with %d!\n", ret));
+
+	filp->f_pos = *offs;	/* we needed *filp only for this? grrrr... /mn/ */
+	/* FIXME: I have no idea what f_pos is used for. It seems to be used this way before offs was introduced.
+	 * this probably needs fixing /mn/ */
+
+	d_drop (filp->f_dentry);	/* FIXME: hmmmm... we should not dispose of it in this way ? */
+	filp->f_dentry = old_dentry;	/* restore orig. dentry (it is dentry of file we need info about. Dunno why it gets passed to us
+					 * since we have no use for it, expect to store totally unrelated data of offset of EMD_FILE
+					 * end not directory in it. But what the hell now... fat_file_read requires it also, but prolly expects
+					 * it to be file* of EMD not file we want to read EMD entry about... ugh. complicated to explain :) /mn/ */
+
+	/* FIXME: we probably need to destroy original filp->f_dentry first ? Do we ? And how ? this way we leave all sorts of dentries, inodes etc. lying around */
+	/* Also FIXME: all the same problems in umsdos_file_write_kmem */
+
+	PRINTK ((KERN_DEBUG "  (ret) using emd=%lu\n", emd_dir->i_ino));
+	PRINTK ((KERN_DEBUG "  (ret) inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size));
+	PRINTK ((KERN_DEBUG "  (ret) ofs=%Lu\n", *offs));
+	PRINTK ((KERN_DEBUG "  (ret) f_pos=%Lu\n", filp->f_pos));
+	PRINTK ((KERN_DEBUG "  (ret) name=%.*s\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name));
+	PRINTK ((KERN_DEBUG "  (ret) i_binary(sb)=%d\n", MSDOS_I (filp->f_dentry->d_inode)->i_binary));
+	PRINTK ((KERN_DEBUG "  (ret) f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags));
+	PRINTK ((KERN_DEBUG "  (ret) f_owner=%d\n", filp->f_owner.uid));
+	PRINTK ((KERN_DEBUG "  (ret) f_version=%ld\n", filp->f_version));
+	PRINTK ((KERN_DEBUG "  (ret) f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin));
 
-/*
- * removes temporary dentry created by creat_dentry
- *
- */
- 
-void kill_dentry (struct dentry *dentry)
-{
-    if (dentry) {
-      Printk (("/mn/ kill_dentry: kill_dentry %.*s :", (int) dentry->d_name.len, dentry->d_name.name));
-      if (dentry->d_inode) 
-        Printk (("inode=%lu\n", dentry->d_inode->i_ino));
-      else
-        Printk (("inode is NULL\n"));
+#if 0
+	{
+		struct umsdos_dirent *mydirent = buf;
 
-      /* FIXME: is this ok ?! /mn/ */
-      /* d_invalidate (dentry); */
-      /*dput (dentry);*/
-    } else {
-      Printk (("/mn/ kill_dentry: dentry is NULL ?!\n"));
-    }
+		PRINTK ((KERN_DEBUG "  (DDD) uid=%d\n", mydirent->uid));
+		PRINTK ((KERN_DEBUG "  (DDD) gid=%d\n", mydirent->gid));
+		PRINTK ((KERN_DEBUG "  (DDD) name=>%.20s<\n", mydirent->name));
+	}
+#endif
 
-    
-    Printk ((KERN_DEBUG "/mn/ kill_dentry: exiting...\n"));
-    return;
+	set_fs (old_fs);
+	return ret;
 }
 
 
-
 /*
- *	Read a file into kernel space memory
- *	returns how many bytes read (from fat_file_read)
+ *    Write to file from kernel space. 
+ *      Does the real job, assumes all structures are initialized !
  */
 
-ssize_t umsdos_file_read_kmem (struct inode *emd_dir,
-			    struct file *filp,
-			    char *buf,
-			    size_t count,
-			    loff_t *offs
-			    )
-{
-    int ret;
-
-    struct dentry *old_dentry;
-    mm_segment_t old_fs = get_fs();
-
-    set_fs (KERNEL_DS);
-
-    old_dentry=filp->f_dentry;	/* save it */
-    filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir, NULL);
-    *offs = filp->f_pos;
-    
-    PRINTK ((KERN_DEBUG "umsdos_file_read_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d, offs=%p\n", filp, buf, count, offs));
-    PRINTK ((KERN_DEBUG "  using emd=%ld\n", emd_dir->i_ino));
-    PRINTK ((KERN_DEBUG "  inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size));
-    PRINTK ((KERN_DEBUG "  ofs=%ld\n",(unsigned long) *offs));
-    PRINTK ((KERN_DEBUG "  f_pos=%Lu\n", filp->f_pos));
-    PRINTK ((KERN_DEBUG "  name=%.*s\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name));
-    PRINTK ((KERN_DEBUG "  i_binary(sb)=%d\n", MSDOS_I(filp->f_dentry->d_inode)->i_binary ));
-    PRINTK ((KERN_DEBUG "  f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags));
-    PRINTK ((KERN_DEBUG "  f_owner=%d\n", filp->f_owner.uid));
-    PRINTK ((KERN_DEBUG "  f_version=%ld\n", filp->f_version));
-    PRINTK ((KERN_DEBUG "  f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin));
-
-    MSDOS_I(filp->f_dentry->d_inode)->i_binary=2;
-    ret = fat_file_read(filp,buf,count,offs);
-    PRINTK ((KERN_DEBUG "fat_file_read returned with %d!\n", ret));
-
-    filp->f_pos = *offs;	/* we needed *filp only for this? grrrr... /mn/ */
-    				/* FIXME: I have no idea what f_pos is used for. It seems to be used this way before offs was introduced.
-    				   this probably needs fixing /mn/ */
-
-    filp->f_dentry=old_dentry;			/* restore orig. dentry (it is dentry of file we need info about. Dunno why it gets passed to us
-    						   since we have no use for it, expect to store totally unrelated data of offset of EMD_FILE
-    						   end not directory in it. But what the hell now... fat_file_read requires it also, but prolly expects
-    						   it to be file* of EMD not file we want to read EMD entry about... ugh. complicated to explain :) /mn/ */
-    						   
-    						 /* FIXME: we probably need to destroy originl filp->f_dentry first ? Do we ? And how ? this way we leave all sorts of dentries, inodes etc. lying around */
-    						 /* Also FIXME: all the same problems in umsdos_file_write_kmem */
-
-    PRINTK ((KERN_DEBUG "  (ret) using emd=%lu\n", emd_dir->i_ino));
-    PRINTK ((KERN_DEBUG "  (ret) inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size));
-    PRINTK ((KERN_DEBUG "  (ret) ofs=%Lu\n", *offs));
-    PRINTK ((KERN_DEBUG "  (ret) f_pos=%Lu\n", filp->f_pos));
-    PRINTK ((KERN_DEBUG "  (ret) name=%.*s\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name));
-    PRINTK ((KERN_DEBUG "  (ret) i_binary(sb)=%d\n", MSDOS_I(filp->f_dentry->d_inode)->i_binary ));
-    PRINTK ((KERN_DEBUG "  (ret) f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags));
-    PRINTK ((KERN_DEBUG "  (ret) f_owner=%d\n", filp->f_owner.uid));
-    PRINTK ((KERN_DEBUG "  (ret) f_version=%ld\n", filp->f_version));
-    PRINTK ((KERN_DEBUG "  (ret) f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin));
-
-#if 0
-    {
-      struct umsdos_dirent *mydirent=buf;
 
-      PRINTK ((KERN_DEBUG "  (DDD) uid=%d\n",mydirent->uid));
-      PRINTK ((KERN_DEBUG "  (DDD) gid=%d\n",mydirent->gid));
-      PRINTK ((KERN_DEBUG "  (DDD) name=>%.20s<\n",mydirent->name));
-    }
-#endif  
-    
-    set_fs (old_fs);
-    return ret;
-}
-
-
-/*
- *	Write to file from kernel space. 
- *	Does the real job, assumes all structures are initialized !
- */
-	
-
-ssize_t umsdos_file_write_kmem_real (struct file *filp,
-				const char *buf,
-				size_t  count,
-				loff_t *offs)
+ssize_t umsdos_file_write_kmem_real (struct file * filp,
+				     const char *buf,
+				     size_t count,
+				     loff_t * offs)
 {
 	ssize_t ret;
-	mm_segment_t old_fs = get_fs();
-	
+	mm_segment_t old_fs = get_fs ();
+
 	set_fs (KERNEL_DS);
 
-        Printk ((KERN_DEBUG "umsdos_file_write_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d, offs=%p\n", filp, buf, count, offs));
-        Printk ((KERN_DEBUG "  struct dentry=%p\n", filp->f_dentry));
-        Printk ((KERN_DEBUG "  struct inode=%p\n", filp->f_dentry->d_inode));
-        Printk ((KERN_DEBUG "  inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size));
-        Printk ((KERN_DEBUG "  ofs=%ld\n",(unsigned long) *offs));
-        Printk ((KERN_DEBUG "  f_pos=%Lu\n", filp->f_pos));
-        Printk ((KERN_DEBUG "  name=%.*s\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name));
-        Printk ((KERN_DEBUG "  i_binary(sb)=%d\n", MSDOS_I(filp->f_dentry->d_inode)->i_binary ));
-        Printk ((KERN_DEBUG "  f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags));
-        Printk ((KERN_DEBUG "  f_owner=%d\n", filp->f_owner.uid));
-        Printk ((KERN_DEBUG "  f_version=%ld\n", filp->f_version));
-        Printk ((KERN_DEBUG "  f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin));
+	PRINTK ((KERN_DEBUG "umsdos_file_write_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d, offs=%p\n", filp, buf, count, offs));
+	PRINTK ((KERN_DEBUG "  struct dentry=%p\n", filp->f_dentry));
+	PRINTK ((KERN_DEBUG "  struct inode=%p\n", filp->f_dentry->d_inode));
+	PRINTK ((KERN_DEBUG "  inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size));
+	PRINTK ((KERN_DEBUG "  ofs=%ld\n", (unsigned long) *offs));
+	PRINTK ((KERN_DEBUG "  f_pos=%Lu\n", filp->f_pos));
+	PRINTK ((KERN_DEBUG "  name=%.*s\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name));
+	PRINTK ((KERN_DEBUG "  i_binary(sb)=%d\n", MSDOS_I (filp->f_dentry->d_inode)->i_binary));
+	PRINTK ((KERN_DEBUG "  f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags));
+	PRINTK ((KERN_DEBUG "  f_owner=%d\n", filp->f_owner.uid));
+	PRINTK ((KERN_DEBUG "  f_version=%ld\n", filp->f_version));
+	PRINTK ((KERN_DEBUG "  f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin));
 
 	/* note: i_binary=2 is for CVF-FAT. We put it here, instead of
-	   umsdos_file_write_kmem, since it is also wise not to compress symlinks
-	   (in unlikely event that they are > 512 bytes and can be compressed 
-	   FIXME: should we set it when reading symlink too ? */
+	 * umsdos_file_write_kmem, since it is also wise not to compress symlinks
+	 * (in unlikely event that they are > 512 bytes and can be compressed 
+	 * FIXME: should we set it when reading symlink too ? */
+
+	MSDOS_I (filp->f_dentry->d_inode)->i_binary = 2;
 
-        MSDOS_I(filp->f_dentry->d_inode)->i_binary=2;
-        
 	ret = fat_file_write (filp, buf, count, offs);
 	PRINTK ((KERN_DEBUG "fat_file_write returned with %ld!\n", ret));
 
@@ -227,32 +145,32 @@
 
 
 /*
- *	Write to a file from kernel space
+ *    Write to a file from kernel space
  */
- 
-ssize_t umsdos_file_write_kmem (struct inode *emd_dir,
-				struct file *filp,
+
+ssize_t umsdos_file_write_kmem (struct inode * emd_dir,
+				struct file * filp,
 				const char *buf,
-				size_t  count,
-				loff_t *offs
-				)
+				size_t count,
+				loff_t * offs)
 {
 	int ret;
 	struct dentry *old_dentry;
 
-	
+
 	Printk ((KERN_DEBUG " STARTED WRITE_KMEM /mn/\n"));
-        Printk ((KERN_DEBUG "  using emd=%ld\n", emd_dir->i_ino));
+	Printk ((KERN_DEBUG "  using emd=%ld\n", emd_dir->i_ino));
 
-	old_dentry=filp->f_dentry;	/* save it */
+	old_dentry = filp->f_dentry;	/* save it */
 	filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir, NULL);
 
 	*offs = filp->f_pos;	/* FIXME, in read_kmem also: offs is not used so why pass it ?!!! /mn/ */
 
-        ret=umsdos_file_write_kmem_real (filp, buf, count, offs);
+	ret = umsdos_file_write_kmem_real (filp, buf, count, offs);
 
+	d_drop (filp->f_dentry);
 	filp->f_pos = *offs;
-	filp->f_dentry=old_dentry;
+	filp->f_dentry = old_dentry;
 
 	return ret;
 }
@@ -261,26 +179,27 @@
 
 
 /*
-	Write a block of bytes into one EMD file.
-	The block of data is NOT in user space.
+ * Write a block of bytes into one EMD file.
+ * The block of data is NOT in user space.
+ * 
+ * Return 0 if ok, a negative error code if not.
+ */
 
-	Return 0 if ok, a negative error code if not.
-*/
-ssize_t umsdos_emd_dir_write (struct inode *emd_dir,
-			   struct file *filp,
-			   char *buf,	/* buffer in kernel memory, not in user space */
-			   size_t  count,
-			   loff_t *offs
-			   )
+ssize_t umsdos_emd_dir_write (	struct inode * emd_dir,
+				struct file * filp,
+				char *buf,	/* buffer in kernel memory, not in user space */
+				size_t count,
+				loff_t * offs)
 {
 	int written;
-	loff_t myofs=0;
-	
+	loff_t myofs = 0;
+
 #ifdef __BIG_ENDIAN
-	struct umsdos_dirent *d = (struct umsdos_dirent *)buf;
+	struct umsdos_dirent *d = (struct umsdos_dirent *) buf;
+
 #endif
 	filp->f_flags = 0;
-#ifdef __BIG_ENDIAN	
+#ifdef __BIG_ENDIAN
 	d->nlink = cpu_to_le16 (d->nlink);
 	d->uid = cpu_to_le16 (d->uid);
 	d->gid = cpu_to_le16 (d->gid);
@@ -289,15 +208,17 @@
 	d->ctime = cpu_to_le32 (d->ctime);
 	d->rdev = cpu_to_le16 (d->rdev);
 	d->mode = cpu_to_le16 (d->mode);
-#endif	
-	
-	if (offs) myofs=*offs;	/* if offs is not NULL, read it */
+#endif
+
+	if (offs)
+		myofs = *offs;	/* if offs is not NULL, read it */
 	Printk (("umsdos_emd_dir_write /mn/: calling write_kmem with %p, %p, %p, %d, %Ld\n", emd_dir, filp, buf, count, myofs));
 	written = umsdos_file_write_kmem (emd_dir, filp, buf, count, &myofs);
 	Printk (("umsdos_emd_dir_write /mn/: write_kmem returned\n"));
-	if (offs) *offs=myofs;	/* if offs is not NULL, store myofs there */
-	
-#ifdef __BIG_ENDIAN	
+	if (offs)
+		*offs = myofs;	/* if offs is not NULL, store myofs there */
+
+#ifdef __BIG_ENDIAN
 	d->nlink = le16_to_cpu (d->nlink);
 	d->uid = le16_to_cpu (d->uid);
 	d->gid = le16_to_cpu (d->gid);
@@ -306,12 +227,12 @@
 	d->ctime = le32_to_cpu (d->ctime);
 	d->rdev = le16_to_cpu (d->rdev);
 	d->mode = le16_to_cpu (d->mode);
-#endif	
-
-#ifdef 1
-	if (written != count) Printk ((KERN_ERR "umsdos_emd_dir_write: ERROR: written (%d) != count (%d)\n", written, count));
 #endif
 
+#if 1
+	if (written != count)
+		Printk ((KERN_ERR "umsdos_emd_dir_write: ERROR: written (%d) != count (%d)\n", written, count));
+#endif
 
 	return written != count ? -EIO : 0;
 }
@@ -319,36 +240,36 @@
 
 
 /*
- *	Read a block of bytes from one EMD file.
- *	The block of data is NOT in user space.
- *	Return 0 if ok, -EIO if any error.
- */
- 
-ssize_t umsdos_emd_dir_read (struct inode *emd_dir,
-	struct file *filp,
-	char *buf,	/* buffer in kernel memory, not in user space */
-	size_t count,
-	loff_t *offs
-	)
+ *    Read a block of bytes from one EMD file.
+ *      The block of data is NOT in user space.
+ *      Return 0 if ok, -EIO if any error.
+ */
+
+ssize_t umsdos_emd_dir_read (struct inode * emd_dir,
+			     struct file * filp,
+			     char *buf,		/* buffer in kernel memory, not in user space */
+			     size_t count,
+			     loff_t * offs)
 {
-	loff_t myofs=0;
+	loff_t myofs = 0;
 	long int ret = 0;
 	int sizeread;
-	
-	
+
+
 #ifdef __BIG_ENDIAN
-	struct umsdos_dirent *d = (struct umsdos_dirent *)buf;
+	struct umsdos_dirent *d = (struct umsdos_dirent *) buf;
+
 #endif
 
-	if (offs) myofs=*offs;	/* if offs is not NULL, read it */
+	if (offs)
+		myofs = *offs;	/* if offs is not NULL, read it */
 	filp->f_flags = 0;
 	sizeread = umsdos_file_read_kmem (emd_dir, filp, buf, count, &myofs);
-	if (sizeread != count){
-		printk ("UMSDOS: problem with EMD file. Can't read pos = %Ld (%d != %d)\n"
-			,filp->f_pos,sizeread,count);
+	if (sizeread != count) {
+		printk ("UMSDOS: problem with EMD file. Can't read pos = %Ld (%d != %d)\n", filp->f_pos, sizeread, count);
 		ret = -EIO;
 	}
-#ifdef __BIG_ENDIAN	
+#ifdef __BIG_ENDIAN
 	d->nlink = le16_to_cpu (d->nlink);
 	d->uid = le16_to_cpu (d->uid);
 	d->gid = le16_to_cpu (d->gid);
@@ -357,8 +278,9 @@
 	d->ctime = le32_to_cpu (d->ctime);
 	d->rdev = le16_to_cpu (d->rdev);
 	d->mode = le16_to_cpu (d->mode);
-#endif	
-	if (offs) *offs=myofs;	/* if offs is not NULL, store myofs there */
+#endif
+	if (offs)
+		*offs = myofs;	/* if offs is not NULL, store myofs there */
 	return ret;
 
 }
@@ -367,92 +289,95 @@
 
 
 /*
-	Locate the EMD file in a directory .
+ * Locate the EMD file in a directory .
+ * 
+ * Return NULL if error. If ok, dir->u.umsdos_i.emd_inode 
+ */
 
-	Return NULL if error. If ok, dir->u.umsdos_i.emd_inode 
-*/
 struct inode *umsdos_emd_dir_lookup (struct inode *dir, int creat)
 {
-    struct inode *ret = NULL;
-    int res;
-    PRINTK ((KERN_DEBUG "Entering umsdos_emd_dir_lookup\n"));
-    if (dir->u.umsdos_i.i_emd_dir != 0){
-	ret = iget (dir->i_sb,dir->u.umsdos_i.i_emd_dir);
-	Printk (("umsdos_emd_dir_lookup: deja trouve %ld %p\n"
-		 ,dir->u.umsdos_i.i_emd_dir,ret));
-    } else {
-      PRINTK ((KERN_DEBUG "umsdos /mn/: Looking for %.*s -", UMSDOS_EMD_NAMELEN, UMSDOS_EMD_FILE));
-      res = compat_umsdos_real_lookup (dir, UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, &ret);
-      PRINTK ((KERN_DEBUG "-returned %d\n", res));
-	Printk ((KERN_INFO "emd_dir_lookup "));
-	if (ret != NULL){
-	    Printk (("Found --linux "));
-	    dir->u.umsdos_i.i_emd_dir = ret->i_ino;
-	} else if (creat) {
-                        int code;
-                        Printk ((" * ERROR * /mn/: creat not yet implemented!!!!" ));
-                        Printk ((KERN_DEBUG "avant create "));
-                        dir->i_count++;
-
-                        code = compat_msdos_create (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN
-                                ,S_IFREG|0777,&ret);
-                        Printk ((KERN_WARNING "Creat EMD code %d ret %p ", code, ret));
-                        if (ret != NULL){
-                                dir->u.umsdos_i.i_emd_dir = ret->i_ino;
-                        }else{
-                                printk (KERN_WARNING "UMSDOS: Can't create EMD file\n");
-                        }
-	}
-	
-	if (ret != NULL){
-	  /* Disable UMSDOS_notify_change() for EMD file */
-	  ret->u.umsdos_i.i_emd_owner = 0xffffffff;
+	struct inode *ret = NULL;
+	int res;
+
+	Printk ((KERN_DEBUG "Entering umsdos_emd_dir_lookup\n"));
+	if (dir->u.umsdos_i.i_emd_dir != 0) {
+		ret = iget (dir->i_sb, dir->u.umsdos_i.i_emd_dir);
+		Printk (("umsdos_emd_dir_lookup: deja trouve %ld %p\n"
+			 ,dir->u.umsdos_i.i_emd_dir, ret));
+	} else {
+		PRINTK ((KERN_DEBUG "umsdos /mn/: Looking for %.*s -", UMSDOS_EMD_NAMELEN, UMSDOS_EMD_FILE));
+		res = compat_umsdos_real_lookup (dir, UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, &ret);
+		PRINTK ((KERN_DEBUG "-returned %d\n", res));
+		Printk ((KERN_INFO "emd_dir_lookup "));
+		if (ret != NULL) {
+			Printk (("Found --linux "));
+			dir->u.umsdos_i.i_emd_dir = ret->i_ino;
+		} else if (creat) {
+			int code;
+
+			Printk ((" * ERROR * /mn/: creat not yet implemented? not fixed? "));
+			Printk (("avant create "));
+			inc_count (dir);
+
+			check_inode (ret);
+			code = compat_msdos_create (dir, UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, S_IFREG | 0777, &ret);
+			check_inode (ret);
+			Printk (("Creat EMD code %d ret %p ", code, ret));
+			if (ret != NULL) {
+				Printk ((" ino=%lu", ret->i_ino));
+				dir->u.umsdos_i.i_emd_dir = ret->i_ino;
+			} else {
+				printk (KERN_WARNING "UMSDOS: Can't create EMD file\n");
+			}
+		}
+		if (ret != NULL) {
+			/* Disable UMSDOS_notify_change() for EMD file */
+			ret->u.umsdos_i.i_emd_owner = 0xffffffff;
+		}
+		
 	}
 
-    }
-    
-#if 0
-    PRINTK ((KERN_DEBUG "umsdos_emd_dir_lookup returning %p /mn/\n", ret));
-    if (ret != NULL) PRINTK ((KERN_DEBUG " debug : returning ino=%lu\n", ret->i_ino));
-#endif    
-    return ret;
+#if 1
+	Printk ((KERN_DEBUG "umsdos_emd_dir_lookup returning %p /mn/\n", ret));
+	if (ret != NULL)
+		Printk ((KERN_DEBUG " returning ino=%lu\n", ret->i_ino));
+#endif
+	return ret;
 }
 
-/*
-	creates an EMD file
 
-	Return NULL if error. If ok, dir->u.umsdos_i.emd_inode 
-*/
 
-struct inode *umsdos_emd_dir_create(struct inode *dir, struct dentry *dentry,int mode)
+/*
+ * creates an EMD file
+ * 
+ * Return NULL if error. If ok, dir->u.umsdos_i.emd_inode 
+ */
+
+struct inode *umsdos_emd_dir_create (struct inode *dir, struct dentry *dentry, int mode)
 {
 	struct inode *ret = NULL;
-	if (dir->u.umsdos_i.i_emd_dir != 0){
-		ret = iget (dir->i_sb,dir->u.umsdos_i.i_emd_dir);
+
+	if (dir->u.umsdos_i.i_emd_dir != 0) {
+		ret = iget (dir->i_sb, dir->u.umsdos_i.i_emd_dir);
 		Printk (("deja trouve %lu %p", dir->u.umsdos_i.i_emd_dir, ret));
-	}else{
-	    
-	    int code;
-	    Printk (("avant create "));
-	    dir->i_count++;
-	    /*			
-	       code = msdos_create (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN
-	       ,S_IFREG|0777,&ret);
-	       
-	       FIXME, I think I need a new dentry here
-	    */
-	    code = compat_msdos_create (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN, S_IFREG|0777, &ret);
-	    Printk (("Creat EMD code %d ret %p ", code, ret));
-	    if (ret != NULL){
-		dir->u.umsdos_i.i_emd_dir = ret->i_ino;
-	    }else{
-		printk ("UMSDOS: Can't create EMD file\n");
-	    }
+	} else {
+
+		int code;
+
+		Printk (("avant create "));
+		inc_count (dir);
+		code = compat_msdos_create (dir, UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, S_IFREG | 0777, &ret);
+		Printk (("Creat EMD code %d ret %p ", code, ret));
+		if (ret != NULL) {
+			dir->u.umsdos_i.i_emd_dir = ret->i_ino;
+		} else {
+			printk ("UMSDOS: Can't create EMD file\n");
+		}
 	}
 
-	if (ret != NULL){
-	    /* Disable UMSDOS_notify_change() for EMD file */
-	    ret->u.umsdos_i.i_emd_owner = 0xffffffff;
+	if (ret != NULL) {
+		/* Disable UMSDOS_notify_change() for EMD file */
+		ret->u.umsdos_i.i_emd_owner = 0xffffffff;
 	}
 	return ret;
 }
@@ -460,28 +385,29 @@
 
 
 /*
-	Read an entry from the EMD file.
-	Support variable length record.
-	Return -EIO if error, 0 if ok.
-*/
+ * Read an entry from the EMD file.
+ * Support variable length record.
+ * Return -EIO if error, 0 if ok.
+ */
+
 int umsdos_emd_dir_readentry (
-	struct inode *emd_dir,
-	struct file *filp,
-	struct umsdos_dirent *entry)
+				     struct inode *emd_dir,
+				     struct file *filp,
+				     struct umsdos_dirent *entry)
 {
 	int ret;
+
 	Printk ((KERN_DEBUG "umsdos_emd_dir_readentry /mn/: entering.\n"));
 	Printk (("umsdos_emd_dir_readentry /mn/: trying to lookup %.*s (ino=%lu) using EMD %lu\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name, filp->f_dentry->d_inode->i_ino, emd_dir->i_ino));
-    
-	ret = umsdos_emd_dir_read(emd_dir, filp, (char*)entry, UMSDOS_REC_SIZE, NULL);
-	if (ret == 0){ /* note /mn/: is this wrong? ret is allways 0 or -EIO. but who knows. It used to work this way... */
+
+	ret = umsdos_emd_dir_read (emd_dir, filp, (char *) entry, UMSDOS_REC_SIZE, NULL);
+	if (ret == 0) {		/* note /mn/: is this wrong? ret is always 0 or -EIO. but who knows. It used to work this way... */
 		/* Variable size record. Maybe, we have to read some more */
 		int recsize = umsdos_evalrecsize (entry->name_len);
-		Printk ((KERN_DEBUG "umsdos_emd_dir_readentry /mn/: FIXME if %d > %d?\n",recsize, UMSDOS_REC_SIZE));
-		if (recsize > UMSDOS_REC_SIZE){
-			ret = umsdos_emd_dir_read(emd_dir, filp
-				,((char*)entry)+UMSDOS_REC_SIZE,recsize - UMSDOS_REC_SIZE,NULL);
-			
+
+		Printk ((KERN_DEBUG "umsdos_emd_dir_readentry /mn/: FIXME if %d > %d?\n", recsize, UMSDOS_REC_SIZE));
+		if (recsize > UMSDOS_REC_SIZE) {
+			ret = umsdos_emd_dir_read (emd_dir, filp, ((char *) entry) + UMSDOS_REC_SIZE, recsize - UMSDOS_REC_SIZE, NULL);
 		}
 	}
 	Printk (("umsdos_emd_dir_readentry /mn/: returning %d.\n", ret));
@@ -492,61 +418,62 @@
 
 
 /*
-	Write an entry in the EMD file.
-	Return 0 if ok, -EIO if some error.
-*/
+ * Write an entry in the EMD file.
+ * Return 0 if ok, -EIO if some error.
+ */
+
 int umsdos_writeentry (
-	struct inode *dir,
-	struct inode *emd_dir,
-	struct umsdos_info *info,
-	int free_entry)		/* This entry is deleted, so Write all 0's */
-{
+			      struct inode *dir,
+			      struct inode *emd_dir,
+			      struct umsdos_info *info,
+			      int free_entry)
+
+{				/* This entry is deleted, so Write all 0's */
 	int ret = 0;
 	struct dentry *emd_dentry;
 	struct file filp;
 	struct umsdos_dirent *entry = &info->entry;
 	struct umsdos_dirent entry0;
 
-        fill_new_filp (&filp, NULL);
+	fill_new_filp (&filp, NULL);
 
 	Printk (("umsdos_writeentry /mn/: entering...\n"));
-	emd_dentry=creat_dentry ("wremd_mn", 8, emd_dir, NULL);
-	
-	if (free_entry){
+	emd_dentry = creat_dentry ("wremd_mn", 8, emd_dir, NULL);
+
+	if (free_entry) {
 		/* #Specification: EMD file / empty entries
-			Unused entry in the EMD file are identify
-			by the name_len field equal to 0. However to
-			help future extension (or bug correction :-( ),
-			empty entries are filled with 0.
-		*/
-		memset (&entry0,0,sizeof(entry0));
+		 * Unused entry in the EMD file are identify
+		 * by the name_len field equal to 0. However to
+		 * help future extension (or bug correction :-( ),
+		 * empty entries are filled with 0.
+		 */
+		memset (&entry0, 0, sizeof (entry0));
 		entry = &entry0;
-	}else if (entry->name_len > 0){
-		memset (entry->name+entry->name_len,'\0'
-			,sizeof(entry->name)-entry->name_len);
+	} else if (entry->name_len > 0) {
+		memset (entry->name + entry->name_len, '\0', sizeof (entry->name) - entry->name_len);
 		/* #Specification: EMD file / spare bytes
-			10 bytes are unused in each record of the EMD. They
-			are set to 0 all the time. So it will be possible
-			to do new stuff and rely on the state of those
-			bytes in old EMD file around.
-		*/
-		memset (entry->spare,0,sizeof(entry->spare));
+		 * 10 bytes are unused in each record of the EMD. They
+		 * are set to 0 all the time. So it will be possible
+		 * to do new stuff and rely on the state of those
+		 * bytes in old EMD file around.
+		 */
+		memset (entry->spare, 0, sizeof (entry->spare));
 	}
-
 	Printk (("umsdos_writeentry /mn/: if passed...\n"));
 
-	if (!info) printk (KERN_ERR "umsdosfs: /mn/ info is empty ! ooops...\n");
+	if (!info)
+		printk (KERN_ERR "umsdosfs: /mn/ info is empty ! ooops...\n");
 	filp.f_pos = info->f_pos;
 	filp.f_reada = 0;
 	filp.f_flags = O_RDWR;
 	filp.f_dentry = emd_dentry;
-       	filp.f_op = &umsdos_file_operations;	/* /mn/ - we have to fill it with dummy values so we won't segfault */
-       	
-	ret = umsdos_emd_dir_write (emd_dir, &filp, (char*)entry, info->recsize, NULL);
+	filp.f_op = &umsdos_file_operations;	/* /mn/ - we have to fill it with dummy values so we won't segfault */
+
+	ret = umsdos_emd_dir_write (emd_dir, &filp, (char *) entry, info->recsize, NULL);
 	Printk (("emd_dir_write returned with %d!\n", ret));
-	if (ret != 0){
+	if (ret != 0) {
 		printk ("UMSDOS: problem with EMD file. Can't write\n");
-	}else{
+	} else {
 		dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 		/* dir->i_dirt = 1; FIXME iput/dput ??? */
 	}
@@ -558,10 +485,10 @@
 
 
 #define CHUNK_SIZE (8*UMSDOS_REC_SIZE)
-struct find_buffer{
+struct find_buffer {
 	char buffer[CHUNK_SIZE];
-	int pos;	/* read offset in buffer */
-	int size;	/* Current size of buffer */
+	int pos;		/* read offset in buffer */
+	int size;		/* Current size of buffer */
 	struct file filp;
 };
 
@@ -570,34 +497,36 @@
 
 
 /*
-	Fill the read buffer and take care of the byte remaining inside.
-	Unread bytes are simply move to the beginning.
+ * Fill the read buffer and take care of the byte remaining inside.
+ * Unread bytes are simply move to the beginning.
+ * 
+ * Return -ENOENT if EOF, 0 if ok, a negative error code if any problem.
+ */
 
-	Return -ENOENT if EOF, 0 if ok, a negative error code if any problem.
-*/
 static int umsdos_fillbuf (
-	struct inode *inode,
-	struct find_buffer *buf)
+				  struct inode *inode,
+				  struct find_buffer *buf)
 {
 	int ret = -ENOENT;
 	int mustmove = buf->size - buf->pos;
 	int mustread;
 	int remain;
-	
+
 	PRINTK ((KERN_DEBUG "Entering umsdos_fillbuf, for inode %lu, buf=%p\n", inode->i_ino, buf));
-	
-	if (mustmove > 0){
-		memcpy (buf->buffer,buf->buffer+buf->pos,mustmove);
+
+	if (mustmove > 0) {
+		memcpy (buf->buffer, buf->buffer + buf->pos, mustmove);
 	}
 	buf->pos = 0;
 	mustread = CHUNK_SIZE - mustmove;
 	remain = inode->i_size - buf->filp.f_pos;
-	if (remain < mustread) mustread = remain;
-	if (mustread > 0){
-		ret = umsdos_emd_dir_read (inode, &buf->filp,buf->buffer+mustmove
-			,mustread,NULL);
-		if (ret == 0) buf->size = mustmove + mustread;		
-	}else if (mustmove){
+	if (remain < mustread)
+		mustread = remain;
+	if (mustread > 0) {
+		ret = umsdos_emd_dir_read (inode, &buf->filp, buf->buffer + mustmove, mustread, NULL);
+		if (ret == 0)
+			buf->size = mustmove + mustread;
+	} else if (mustmove) {
 		buf->size = mustmove;
 		ret = 0;
 	}
@@ -607,61 +536,61 @@
 
 
 /*
-	General search, locate a name in the EMD file or an empty slot to
-	store it. if info->entry.name_len == 0, search the first empty
-	slot (of the proper size).
-
-	Caller must do iput on *pt_emd_dir.
-
-	Return 0 if found, -ENOENT if not found, another error code if
-	other problem.
-
-	So this routine is used to either find an existing entry or to
-	create a new one, while making sure it is a new one. After you
-	get -ENOENT, you make sure the entry is stuffed correctly and
-	call umsdos_writeentry().
-
-	To delete an entry, you find it, zero out the entry (memset)
-	and call umsdos_writeentry().
-
-	All this to say that umsdos_writeentry must be call after this
-	function since it rely on the f_pos field of info.
-*/
+ * General search, locate a name in the EMD file or an empty slot to
+ * store it. if info->entry.name_len == 0, search the first empty
+ * slot (of the proper size).
+ * 
+ * Caller must do iput on *pt_emd_dir.
+ * 
+ * Return 0 if found, -ENOENT if not found, another error code if
+ * other problem.
+ * 
+ * So this routine is used to either find an existing entry or to
+ * create a new one, while making sure it is a new one. After you
+ * get -ENOENT, you make sure the entry is stuffed correctly and
+ * call umsdos_writeentry().
+ * 
+ * To delete an entry, you find it, zero out the entry (memset)
+ * and call umsdos_writeentry().
+ * 
+ * All this to say that umsdos_writeentry must be call after this
+ * function since it rely on the f_pos field of info.
+ */
+
 static int umsdos_find (
-	struct inode *dir,
-	struct umsdos_info *info,		/* Hold name and name_len */
-									/* Will hold the entry found */
-	struct inode **pt_emd_dir)		/* Will hold the emd_dir inode */
-									/* or NULL if not found */
+			       struct inode *dir,
+			       struct umsdos_info *info,	/* Hold name and name_len */
+								/* Will hold the entry found */
+			       struct inode **pt_emd_dir)	/* Will hold the emd_dir inode or NULL if not found */
+
 {
 	/* #Specification: EMD file structure
-		The EMD file uses a fairly simple layout. It is made of records
-		(UMSDOS_REC_SIZE == 64). When a name can't be written is a single
-		record, multiple contiguous record are allocated.
-	*/
+	 * The EMD file uses a fairly simple layout. It is made of records
+	 * (UMSDOS_REC_SIZE == 64). When a name can't be written is a single
+	 * record, multiple contiguous record are allocated.
+	 */
 	int ret = -ENOENT;
 	struct inode *emd_dir;
 	struct umsdos_dirent *entry = &info->entry;
-	
+
 	Printk (("umsdos_find: locating %.*s in dir %lu\n", entry->name_len, entry->name, dir->i_ino));
-	
+
 	emd_dir = umsdos_emd_dir_lookup (dir, 1);
-	if (emd_dir != NULL){
+	if (emd_dir != NULL) {
 		int recsize = info->recsize;
 		struct {
 			off_t posok;	/* Position available to store the entry */
-			int found;		/* A valid empty position has been found */
-			off_t one;		/* One empty position -> maybe <- large enough */
+			int found;	/* A valid empty position has been found */
+			off_t one;	/* One empty position -> maybe <- large enough */
 			int onesize;	/* size of empty region starting at one */
-		}empty;
+		} empty;
+
 		/* Read several entries at a time to speed up the search */
 		struct find_buffer buf;
 		struct dentry *dentry;
 
-		memset (&buf.filp, 0, sizeof (buf.filp));
-
 		dentry = creat_dentry ("umsfind-mn", 10, emd_dir, NULL);
-	
+
 		fill_new_filp (&buf.filp, dentry);
 
 		buf.pos = 0;
@@ -670,218 +599,225 @@
 		empty.found = 0;
 		empty.posok = emd_dir->i_size;
 		empty.onesize = 0;
-		while (1){
-			struct umsdos_dirent *rentry = (struct umsdos_dirent*)
-				(buf.buffer + buf.pos);
+		while (1) {
+			struct umsdos_dirent *rentry = (struct umsdos_dirent *)
+			(buf.buffer + buf.pos);
 			int file_pos = buf.filp.f_pos - buf.size + buf.pos;
-			if (buf.pos == buf.size){
-				ret = umsdos_fillbuf (emd_dir,&buf);
-				if (ret < 0){
+
+			if (buf.pos == buf.size) {
+				ret = umsdos_fillbuf (emd_dir, &buf);
+				if (ret < 0) {
 					/* Not found, so note where it can be added */
 					info->f_pos = empty.posok;
 					break;
 				}
-			}else if (rentry->name_len == 0){
+			} else if (rentry->name_len == 0) {
 				/* We are looking for an empty section at least */
 				/* recsize large */
-				if (entry->name_len == 0){
+				if (entry->name_len == 0) {
 					info->f_pos = file_pos;
 					ret = 0;
 					break;
-				}else if (!empty.found){
-					if (empty.onesize == 0){
+				} else if (!empty.found) {
+					if (empty.onesize == 0) {
 						/* This is the first empty record of a section */
 						empty.one = file_pos;
 					}
 					/* grow the empty section */
 					empty.onesize += UMSDOS_REC_SIZE;
-					if (empty.onesize == recsize){
+					if (empty.onesize == recsize) {
 						/* here is a large enough section */
 						empty.posok = empty.one;
 						empty.found = 1;
 					}
 				}
 				buf.pos += UMSDOS_REC_SIZE;
-			}else{
-				int entry_size = umsdos_evalrecsize(rentry->name_len);
-				if (buf.pos+entry_size > buf.size){
-					ret = umsdos_fillbuf (emd_dir,&buf);
-					if (ret < 0){
+			} else {
+				int entry_size = umsdos_evalrecsize (rentry->name_len);
+
+				if (buf.pos + entry_size > buf.size) {
+					ret = umsdos_fillbuf (emd_dir, &buf);
+					if (ret < 0) {
 						/* Not found, so note where it can be added */
 						info->f_pos = empty.posok;
 						break;
 					}
-				}else{
+				} else {
 					empty.onesize = 0;	/* Reset the free slot search */
 					if (entry->name_len == rentry->name_len
-						&& memcmp(entry->name,rentry->name,rentry->name_len)
-							==0){
+					    && memcmp (entry->name, rentry->name, rentry->name_len)
+					    == 0) {
 						info->f_pos = file_pos;
 						*entry = *rentry;
 						ret = 0;
 						break;
-					}else{
+					} else {
 						buf.pos += entry_size;
 					}
 				}
-			}	
+			}
 		}
-		umsdos_manglename(info);
+		umsdos_manglename (info);
 	}
 	*pt_emd_dir = emd_dir;
-	
+
 	Printk (("umsdos_find: returning %d\n", ret));
 	return ret;
 }
 
+
 /*
-	Add a new entry in the emd file
-	Return 0 if ok or a negative error code.
-	Return -EEXIST if the entry already exist.
+ * Add a new entry in the emd file
+ * Return 0 if ok or a negative error code.
+ * Return -EEXIST if the entry already exist.
+ * 
+ * Complete the information missing in info.
+ */
 
-	Complete the information missing in info.
-*/
 int umsdos_newentry (
-	struct inode *dir,
-	struct umsdos_info *info)
+			    struct inode *dir,
+			    struct umsdos_info *info)
 {
 	struct inode *emd_dir;
-	int ret = umsdos_find (dir,info,&emd_dir);
-	if (ret == 0){
+	int ret = umsdos_find (dir, info, &emd_dir);
+
+	if (ret == 0) {
 		ret = -EEXIST;
-	}else if (ret == -ENOENT){
-		ret = umsdos_writeentry(dir,emd_dir,info,0);
-		Printk (("umsdos_newentry EMD ret = %d\n",ret));
+	} else if (ret == -ENOENT) {
+		ret = umsdos_writeentry (dir, emd_dir, info, 0);
+		Printk (("umsdos_writeentry EMD ret = %d\n", ret));
 	}
-	/* iput (emd_dir); FIXME */
+	iput (emd_dir); /* FIXME? */
 	return ret;
 }
 
+
 /*
-	Create a new hidden link.
-	Return 0 if ok, an error code if not.
-*/
+ * Create a new hidden link.
+ * Return 0 if ok, an error code if not.
+ */
+
 int umsdos_newhidden (
-	struct inode *dir,
-	struct umsdos_info *info)
+			     struct inode *dir,
+			     struct umsdos_info *info)
 {
 	struct inode *emd_dir;
 	int ret;
-	umsdos_parse ("..LINK",6,info);
+
+	umsdos_parse ("..LINK", 6, info);
 	info->entry.name_len = 0;
-	ret = umsdos_find (dir,info,&emd_dir);
-	/* iput (emd_dir); FIXME */
-	if (ret == -ENOENT || ret == 0){
+	ret = umsdos_find (dir, info, &emd_dir);
+	iput (emd_dir); /* FIXME? */
+	if (ret == -ENOENT || ret == 0) {
 		/* #Specification: hard link / hidden name
-			When a hard link is created, the original file is renamed
-			to a hidden name. The name is "..LINKNNN" where NNN is a
-			number define from the entry offset in the EMD file.
-		*/
-		info->entry.name_len = sprintf (info->entry.name,"..LINK%ld"
-			,info->f_pos);
+		 * When a hard link is created, the original file is renamed
+		 * to a hidden name. The name is "..LINKNNN" where NNN is a
+		 * number define from the entry offset in the EMD file.
+		 */
+		info->entry.name_len = sprintf (info->entry.name, "..LINK%ld"
+						,info->f_pos);
 		ret = 0;
 	}
 	return ret;
 }
 /*
-	Remove an entry from the emd file
-	Return 0 if ok, a negative error code otherwise.
+ * Remove an entry from the emd file
+ * Return 0 if ok, a negative error code otherwise.
+ * 
+ * Complete the information missing in info.
+ */
 
-	Complete the information missing in info.
-*/
 int umsdos_delentry (
-	struct inode *dir,
-	struct umsdos_info *info,
-	int isdir)
+			    struct inode *dir,
+			    struct umsdos_info *info,
+			    int isdir)
 {
 	struct inode *emd_dir;
-	int ret = umsdos_find (dir,info,&emd_dir);
-	if (ret == 0){
-		if (info->entry.name_len != 0){
-			if ((isdir != 0) != (S_ISDIR(info->entry.mode) != 0)){
-				if (S_ISDIR(info->entry.mode)){
+	int ret = umsdos_find (dir, info, &emd_dir);
+
+	if (ret == 0) {
+		if (info->entry.name_len != 0) {
+			if ((isdir != 0) != (S_ISDIR (info->entry.mode) != 0)) {
+				if (S_ISDIR (info->entry.mode)) {
 					ret = -EISDIR;
-				}else{
+				} else {
 					ret = -ENOTDIR;
 				}
-			}else{
-				ret = umsdos_writeentry(dir,emd_dir,info,1);
+			} else {
+				ret = umsdos_writeentry (dir, emd_dir, info, 1);
 			}
 		}
 	}
-	/* iput(emd_dir); FIXME */
+	iput(emd_dir); /* FIXME? */
 	return ret;
 }
 
 
 /*
-	Verify is a EMD directory is empty.
-	Return 0 if not empty
-		   1 if empty
-		   2 if empty, no EMD file.
-*/
+ * Verify is a EMD directory is empty.
+ * Return 0 if not empty
+ * 1 if empty
+ * 2 if empty, no EMD file.
+ */
+
 int umsdos_isempty (struct inode *dir)
 {
 	struct dentry *dentry;
-	
+
 	int ret = 2;
-	struct inode *emd_dir = umsdos_emd_dir_lookup(dir,0);
+	struct inode *emd_dir = umsdos_emd_dir_lookup (dir, 0);
+
 	/* If the EMD file does not exist, it is certainly empty :-) */
-	if (emd_dir != NULL){
+	if (emd_dir != NULL) {
 		struct file filp;
-                fill_new_filp (&filp, NULL);
-
-		/* Find an empty slot */
-		memset (&filp, 0, sizeof (filp));
 
 		dentry = creat_dentry ("isempty-mn", 10, dir, NULL);
-	
-		filp.f_pos = 0;
-		filp.f_reada = 1;
+		fill_new_filp (&filp, dentry);
 		filp.f_flags = O_RDONLY;
-		filp.f_dentry = dentry;
-        	filp.f_op = &umsdos_file_operations;	/* /mn/ - we have to fill it with dummy values so we won't segfault */
-        	
+
 		ret = 1;
-		while (filp.f_pos < emd_dir->i_size){
+		while (filp.f_pos < emd_dir->i_size) {
 			struct umsdos_dirent entry;
-			if (umsdos_emd_dir_readentry(emd_dir,&filp,&entry)!=0){
+
+			if (umsdos_emd_dir_readentry (emd_dir, &filp, &entry) != 0) {
 				ret = 0;
 				break;
-			}else if (entry.name_len != 0){
+			} else if (entry.name_len != 0) {
 				ret = 0;
 				break;
-			}	
+			}
 		}
-		/* iput (emd_dir); FIXME */
+		iput (emd_dir); /* FIXME? */
 	}
 	return ret;
 }
 
 /*
-	Locate an entry in a EMD directory.
-	Return 0 if ok, errcod if not, generally -ENOENT.
-*/
+ * Locate an entry in a EMD directory.
+ * Return 0 if ok, errcod if not, generally -ENOENT.
+ */
+
 int umsdos_findentry (
-	struct inode *dir,
-	struct umsdos_info *info,
-	int expect)		/* 0: anything */
-					/* 1: file */
-					/* 2: directory */
-{
+			     struct inode *dir,
+			     struct umsdos_info *info,
+			     int expect)
+{				/* 0: anything */
+	/* 1: file */
+	/* 2: directory */
 	struct inode *emd_dir;
-	int ret = umsdos_find (dir,info,&emd_dir);
-	if (ret == 0){
-		if (expect != 0){
-			if (S_ISDIR(info->entry.mode)){
-				if (expect != 2) ret = -EISDIR;
-			}else if (expect == 2){
+	int ret = umsdos_find (dir, info, &emd_dir);
+
+	if (ret == 0) {
+		if (expect != 0) {
+			if (S_ISDIR (info->entry.mode)) {
+				if (expect != 2)
+					ret = -EISDIR;
+			} else if (expect == 2) {
 				ret = -ENOTDIR;
 			}
 		}
 	}
-	/* iput (emd_dir); FIXME */
+	iput (emd_dir); /* FIXME? */
 	Printk (("umsdos_findentry: returning %d\n", ret));
 	return ret;
 }
-
diff -u --recursive --new-file v2.1.102/linux/fs/umsdos/file.c linux/fs/umsdos/file.c
--- v2.1.102/linux/fs/umsdos/file.c	Wed Apr  8 19:36:28 1998
+++ linux/fs/umsdos/file.c	Tue May 19 15:06:49 1998
@@ -2,7 +2,7 @@
  *  linux/fs/umsdos/file.c
  *
  *  Written 1993 by Jacques Gelinas
- *	inspired from linux/fs/msdos/file.c Werner Almesberger
+ *      inspired from linux/fs/msdos/file.c Werner Almesberger
  *
  *  Extended MS-DOS regular file handling primitives
  */
@@ -24,71 +24,74 @@
 
 
 /*
-	Read a file into user space memory
-*/
-static ssize_t UMSDOS_file_read(
-	struct file *filp,
-	char *buf,
-	size_t  count,
-	loff_t *ppos
-	)
+ * Read a file into user space memory
+ */
+static ssize_t UMSDOS_file_read (
+					struct file *filp,
+					char *buf,
+					size_t count,
+					loff_t * ppos
+)
 {
-	struct dentry * dentry = filp->f_dentry;
+	struct dentry *dentry = filp->f_dentry;
 	struct inode *inode = dentry->d_inode;
-	
+
 	/* We have to set the access time because msdos don't care */
 	/* FIXME */
-	int ret = fat_file_read(filp,buf,count,ppos);
-	if (!IS_RDONLY(inode)){
+	int ret = fat_file_read (filp, buf, count, ppos);
+
+	if (!IS_RDONLY (inode)) {
 		inode->i_atime = CURRENT_TIME;
 		/* FIXME 
-		inode->i_dirt = 1;
-		*/
+		 * inode->i_dirt = 1;
+		 */
 	}
 	return ret;
 }
 
 
 /*
-	Write a file from user space memory
-*/
-static ssize_t UMSDOS_file_write(
-	struct file *filp,
-	const char *buf,
-	size_t count,
-	loff_t *ppos)
+ * Write a file from user space memory
+ */
+static ssize_t UMSDOS_file_write (
+					 struct file *filp,
+					 const char *buf,
+					 size_t count,
+					 loff_t * ppos)
 {
-	return fat_file_write(filp,buf,count,ppos);
+	return fat_file_write (filp, buf, count, ppos);
 }
 
 
 /*
-	Truncate a file to 0 length.
-*/
-static void UMSDOS_truncate(struct inode *inode)
+ * Truncate a file to 0 length.
+ */
+static void UMSDOS_truncate (struct inode *inode)
 {
 	Printk (("UMSDOS_truncate\n"));
 	fat_truncate (inode);
 	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
-	
-	/*FIXME	inode->i_dirt = 1; */
+
+	/*FIXME inode->i_dirt = 1; */
 }
 
 /* Function for normal file system (512 bytes hardware sector size) */
-struct file_operations umsdos_file_operations = {
-	NULL,				/* lseek - default */
+struct file_operations umsdos_file_operations =
+{
+	NULL,			/* lseek - default */
 	UMSDOS_file_read,	/* read */
 	UMSDOS_file_write,	/* write */
-	NULL,				/* readdir - bad */
-	NULL,				/* poll - default */
-	NULL,				/* ioctl - default */
-	generic_file_mmap,		/* mmap */
-	NULL,				/* no special open is needed */
-	NULL,				/* release */
-	file_fsync			/* fsync */
+	NULL,			/* readdir - bad */
+	NULL,			/* poll - default */
+	NULL,			/* ioctl - default */
+	generic_file_mmap,	/* mmap */
+	NULL,			/* no special open is needed */
+	NULL,			/* release */
+	file_fsync		/* fsync */
 };
 
-struct inode_operations umsdos_file_inode_operations = {
+struct inode_operations umsdos_file_inode_operations =
+{
 	&umsdos_file_operations,	/* default file operations */
 	NULL,			/* create */
 	NULL,			/* lookup */
@@ -110,20 +113,22 @@
 };
 
 /* For other with larger and unaligned file system */
-struct file_operations umsdos_file_operations_no_bmap = {
-	NULL,				/* lseek - default */
-	UMSDOS_file_read,		/* read */
-	UMSDOS_file_write,		/* write */
-	NULL,				/* readdir - bad */
-	NULL,				/* poll - default */
-	NULL,				/* ioctl - default */
-	fat_mmap,			/* mmap */
-	NULL,				/* no special open is needed */
-	NULL,				/* release */
-	file_fsync			/* fsync */
+struct file_operations umsdos_file_operations_no_bmap =
+{
+	NULL,			/* lseek - default */
+	UMSDOS_file_read,	/* read */
+	UMSDOS_file_write,	/* write */
+	NULL,			/* readdir - bad */
+	NULL,			/* poll - default */
+	NULL,			/* ioctl - default */
+	fat_mmap,		/* mmap */
+	NULL,			/* no special open is needed */
+	NULL,			/* release */
+	file_fsync		/* fsync */
 };
 
-struct inode_operations umsdos_file_inode_operations_no_bmap = {
+struct inode_operations umsdos_file_inode_operations_no_bmap =
+{
 	&umsdos_file_operations_no_bmap,	/* default file operations */
 	NULL,			/* create */
 	NULL,			/* lookup */
@@ -135,7 +140,7 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,                   /* follow link */
+	NULL,			/* follow link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -145,20 +150,22 @@
 };
 
 /* For other with larger and unaligned file system with readpage */
-struct file_operations umsdos_file_operations_readpage = {
-	NULL,				/* lseek - default */
-	UMSDOS_file_read,		/* read */
-	UMSDOS_file_write,		/* write */
-	NULL,				/* readdir - bad */
-	NULL,				/* poll - default */
-	NULL,				/* ioctl - default */
-	generic_file_mmap,		/* mmap */
-	NULL,				/* no special open is needed */
-	NULL,				/* release */
-	file_fsync			/* fsync */
+struct file_operations umsdos_file_operations_readpage =
+{
+	NULL,			/* lseek - default */
+	UMSDOS_file_read,	/* read */
+	UMSDOS_file_write,	/* write */
+	NULL,			/* readdir - bad */
+	NULL,			/* poll - default */
+	NULL,			/* ioctl - default */
+	generic_file_mmap,	/* mmap */
+	NULL,			/* no special open is needed */
+	NULL,			/* release */
+	file_fsync		/* fsync */
 };
 
-struct inode_operations umsdos_file_inode_operations_readpage = {
+struct inode_operations umsdos_file_inode_operations_readpage =
+{
 	&umsdos_file_operations_readpage,	/* default file operations */
 	NULL,			/* create */
 	NULL,			/* lookup */
@@ -170,7 +177,7 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,                   /* follow link */
+	NULL,			/* follow link */
 	fat_readpage,		/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -178,4 +185,3 @@
 	NULL,			/* permission */
 	NULL,			/* smap */
 };
-
diff -u --recursive --new-file v2.1.102/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c
--- v2.1.102/linux/fs/umsdos/inode.c	Wed Apr  8 19:36:28 1998
+++ linux/fs/umsdos/inode.c	Tue May 19 15:06:49 1998
@@ -1,8 +1,8 @@
 /*
  *  linux/fs/umsdos/inode.c
  *
- *	Written 1993 by Jacques Gelinas
- *	Inspired from linux/fs/msdos/... by Werner Almesberger
+ *      Written 1993 by Jacques Gelinas
+ *      Inspired from linux/fs/msdos/... by Werner Almesberger
  *
  */
 
@@ -18,122 +18,348 @@
 #include <linux/string.h>
 #include <linux/stat.h>
 #include <linux/umsdos_fs.h>
+#include <linux/list.h>
 
-struct inode *pseudo_root=NULL;	/* Useful to simulate the pseudo DOS */
-                                /* directory. See UMSDOS_readdir_x() */
+extern struct inode_operations umsdos_rdir_inode_operations;
+
+
+struct inode *pseudo_root = NULL;	/* Useful to simulate the pseudo DOS */
+
+				/* directory. See UMSDOS_readdir_x() */
 
 /* #Specification: convention / PRINTK Printk and printk
-   Here is the convention for the use of printk inside fs/umsdos
-   
-   printk carry important message (error or status).
-   Printk is for debugging (it is a macro defined at the beginning of
-   most source.
-   PRINTK is a nulled Printk macro.
-   
-   This convention makes the source easier to read, and Printk easier
-   to shut off.
-*/
+ * Here is the convention for the use of printk inside fs/umsdos
+ * 
+ * printk carry important message (error or status).
+ * Printk is for debugging (it is a macro defined at the beginning of
+ * most source.
+ * PRINTK is a nulled Printk macro.
+ * 
+ * This convention makes the source easier to read, and Printk easier
+ * to shut off.
+ */
 #define PRINTK(x)
 #define Printk(x) printk x
 
-void UMSDOS_put_inode(struct inode *inode)
+
+
+
+/*
+ * makes return inode->i_dentry
+ *
+ */
+
+inline struct dentry *geti_dentry (struct inode *inode)
 {
-  PRINTK ((KERN_DEBUG "put inode %p (%lu) owner %lu pos %lu dir %lu\n", inode, inode->i_ino
-	   ,inode->u.umsdos_i.i_emd_owner, inode->u.umsdos_i.pos
-	   ,inode->u.umsdos_i.i_emd_dir));
-  if (inode && pseudo_root && inode == pseudo_root){
-    printk (KERN_ERR "Umsdos: Oops releasing pseudo_root. Notify jacques@solucorp.qc.ca\n");
-  }
-
-#if 1
-  fat_put_inode(inode);
-#else  
-  Printk ((KERN_WARNING "UMSDOS_put_inode: skipping ! FIXME /mn/\n"));
-#endif
+	struct dentry *ret;
+	if (!inode) {
+		printk (KERN_ERR "geti_dentry: inode is NULL!\n");
+		return NULL;
+	}
+	ret = list_entry (inode->i_dentry.next, struct dentry, d_alias); /* FIXME: does this really work ? :) */
+	Printk ((KERN_DEBUG "geti_dentry : inode %lu: i_dentry is %p\n", inode->i_ino, ret));
+	return ret;
 }
 
+/*
+ * makes inode->i_count++
+ *
+ */
 
-void UMSDOS_put_super(struct super_block *sb)
+inline void inc_count (struct inode *inode)
 {
-  Printk ((KERN_DEBUG "UMSDOS_put_super: entering\n"));
-  msdos_put_super(sb);
-  MOD_DEC_USE_COUNT;
+	inode->i_count++;
+	Printk ((KERN_DEBUG "inc_count: inode %lu incremented count to %d\n", inode->i_ino, inode->i_count));
 }
 
 
+/*
+ * makes empty filp
+ *
+ */
+
+void fill_new_filp (struct file *filp, struct dentry *dentry)
+{
+	Printk (("/mn/ fill_new_filp: filling empty filp at %p\n", filp));
+	if (dentry)
+		Printk (("     dentry=%.*s\n", (int) dentry->d_name.len, dentry->d_name.name));
+	else
+		Printk (("     dentry is NULL ! you must fill it later...\n"));
+
+	memset (filp, 0, sizeof (struct file));
+
+	filp->f_pos = 0;
+	filp->f_reada = 1;
+	filp->f_flags = O_RDWR;
+	filp->f_dentry = dentry;
+	filp->f_op = &umsdos_file_operations;	/* /mn/ - we have to fill it with SOMETHING */
+}
+
+/*
+ * check a superblock
+ */
+
+void check_sb (struct super_block *sb, const char c)
+{
+	if (sb) {
+		Printk ((" (has %c_sb=%d, %d)", c, MAJOR (sb->s_dev), MINOR (sb->s_dev)));
+	} else {
+		Printk ((" (%c_sb is NULL)", c));
+	}
+} 
+
+/*
+ * check an inode
+ */
+
+void check_inode (struct inode *inode)
+{
+	if (inode) {
+		Printk ((KERN_DEBUG "*   inode is %lu (i_count=%d)", inode->i_ino, inode->i_count));
+		check_sb (inode->i_sb, 'i');
+		
+		if (inode->i_dentry.next) {	/* FIXME: does this work ? */
+			Printk ((" (has i_dentry)"));
+		} else {
+			Printk ((" (NO i_dentry)"));
+		}
+		
+		if (inode->i_op == NULL) {
+			Printk ((" (i_op is NULL)\n"));
+		} else if (inode->i_op == &umsdos_dir_inode_operations) {
+			Printk ((" (i_op is umsdos_dir_inode_operations)\n"));
+		} else if (inode->i_op == &umsdos_file_inode_operations) {
+			Printk ((" (i_op is umsdos_file_inode_operations)\n"));
+		} else if (inode->i_op == &umsdos_file_inode_operations_no_bmap) {
+			Printk ((" (i_op is umsdos_file_inode_operations_no_bmap)\n"));
+		} else if (inode->i_op == &umsdos_file_inode_operations_readpage) {
+			Printk ((" (i_op is umsdos_file_inode_operations_readpage)\n"));
+		} else if (inode->i_op == &umsdos_rdir_inode_operations) {
+			Printk ((" (i_op is umsdos_rdir_inode_operations)\n"));
+		} else if (inode->i_op == &umsdos_symlink_inode_operations) {
+			Printk ((" (i_op is umsdos_symlink_inode_operations)\n"));
+		} else {
+			Printk ((" (i_op is UNKNOWN: %p)\n", inode->i_op));
+		}
+	} else {
+		Printk ((KERN_DEBUG "*   inode is NULL\n"));
+	}
+}
+
 
 /*
-  Call msdos_lookup, but set back the original msdos function table.
-  Return 0 if ok, or a negative error code if not.
-*/
+ * internal part of check_dentry. does the real job.
+ *
+ */
+
+void check_dent_int (struct dentry *dentry, int parent)
+{
+	if (parent) {
+		Printk ((KERN_DEBUG "*  parent dentry: %.*s\n", (int) dentry->d_name.len, dentry->d_name.name));
+	} else {
+		Printk ((KERN_DEBUG "\n*** checking dentry: %.*s\n", (int) dentry->d_name.len, dentry->d_name.name));
+	}
+	check_inode (dentry->d_inode);
+	Printk ((KERN_DEBUG "*   d_count=%d", dentry->d_count));
+	check_sb (dentry->d_sb, 'd');
+	if (dentry->d_op == NULL) {
+		Printk ((" (d_op is NULL)\n"));
+	} else {
+		Printk ((" (d_op is UNKNOWN: %p)\n", dentry->d_op));
+	}
+}
+
+/*
+ * checks dentry and prints info
+ *
+ */
+
+void check_dentry (struct dentry *dentry)
+{
+	if (!dentry) {
+		Printk ((KERN_DEBUG "\n*** checking dentry... it is NULL !\n"));
+		return;
+	}
+	check_dent_int (dentry, 0);
+
+	if (dentry->d_parent) {
+		check_dent_int (dentry->d_parent, 1);
+	} else {
+		Printk ((KERN_DEBUG "*   has no parent.\n"));
+	}
+
+	Printk ((KERN_DEBUG "*** end checking dentry\n"));
+}
+
+
+/*
+ * makes dentry. for name name with length len. /mn/
+ * if inode is not NULL, puts it also.
+ *
+ */
+
+struct dentry *creat_dentry (const char *name, const int len, struct inode *inode, struct dentry *parent)
+{
+/* FIXME /mn/: parent is not passed many times... if it is not, dentry should be destroyed before someone else gets to use it */
+
+	struct dentry *ret;
+	struct qstr qname;
+
+	if (inode)
+		Printk ((KERN_DEBUG "/mn/ creat_dentry: creating dentry with inode=%lu for %.*s\n", inode->i_ino, len, name));
+	else
+		Printk ((KERN_DEBUG "/mn/ creat_dentry: creating empty dentry for %.*s\n", len, name));
+
+	qname.name = name;
+	qname.len = len;
+	qname.hash = 0;
+
+	ret = d_alloc (parent, &qname);		/* create new dentry */
+	ret->d_inode = NULL;
+
+	if (!parent) {
+		ret->d_parent = ret;
+		Printk ((KERN_WARNING "creat_dentry: WARNING: NO parent! faking! beware !\n"));
+	}
+
+
+	if (inode) {
+		ret->d_sb = inode->i_sb;	/* try to fill it in if avalaible. If avalaible in parent->d_sb, d_alloc will add it automatically */
+		d_add (ret, inode);
+	}
+
+	return ret;
+}
+
+
+/*
+ * removes temporary dentry created by creat_dentry
+ *
+ */
+
+void kill_dentry (struct dentry *dentry)
+{
+	if (dentry) {
+		Printk (("/mn/ kill_dentry: kill_dentry %.*s :", (int) dentry->d_name.len, dentry->d_name.name));
+		if (dentry->d_inode)
+			Printk (("inode=%lu (i_count=%d)\n", dentry->d_inode->i_ino, dentry->d_inode->i_count));
+		else
+			Printk (("inode is NULL\n"));
+
+		/* FIXME: is this ok ?! /mn/ */
+		/* d_drop (dentry); */
+		/* d_invalidate (dentry); */
+		/*dput (dentry); */
+		/*d_delete (dentry) */
+	} else {
+		Printk (("/mn/ kill_dentry: dentry is NULL ?!\n"));
+	}
+
+
+	Printk ((KERN_DEBUG "/mn/ kill_dentry: exiting...\n"));
+	return;
+}
+
+
+
+
+
+
+void UMSDOS_put_inode (struct inode *inode)
+{
+	PRINTK ((KERN_DEBUG "put inode %p (%lu) owner %lu pos %lu dir %lu count=%d\n", inode, inode->i_ino
+		 ,inode->u.umsdos_i.i_emd_owner, inode->u.umsdos_i.pos
+		 ,inode->u.umsdos_i.i_emd_dir, inode->i_count));
+
+	if (inode && pseudo_root && inode == pseudo_root) {
+		printk (KERN_ERR "Umsdos: Oops releasing pseudo_root. Notify jacques@solucorp.qc.ca\n");
+	}
+
+	fat_put_inode (inode);
+}
+
+
+void UMSDOS_put_super (struct super_block *sb)
+{
+	Printk ((KERN_DEBUG "UMSDOS_put_super: entering\n"));
+	msdos_put_super (sb);
+	MOD_DEC_USE_COUNT;
+}
+
+
+
+/*
+ * Call msdos_lookup, but set back the original msdos function table.
+ * Return 0 if ok, or a negative error code if not.
+ */
 int umsdos_real_lookup (
-			struct inode *dir,
-			struct dentry *dentry
-			)	/* Will hold inode of the file, if successful */
-{
-  int ret;
-  
-  PRINTK ((KERN_DEBUG "umsdos_real_lookup /mn/: looking for %s /",dentry->d_name.name));
-  dir->i_count++;  /* /mn/ what is this and why ? locking? */
-  ret = msdos_lookup (dir,dentry);
-  PRINTK (("/ returned %d\n", ret));
-  
-  return ret;
+			       struct inode *dir,
+			       struct dentry *dentry
+)
+{				/* Will hold inode of the file, if successful */
+	int ret;
+
+	PRINTK ((KERN_DEBUG "umsdos_real_lookup: looking for %s /", dentry->d_name.name));
+	inc_count (dir);	/* should be here ? Causes all kind of missing iput()'s all around, but panics w/o it /mn/ */
+	ret = msdos_lookup (dir, dentry);
+	PRINTK (("/ returned %d\n", ret));
+
+	return ret;
 }
 
 /*
-  Complete the setup of an directory inode.
-  First, it completes the function pointers, then
-  it locates the EMD file. If the EMD is there, then plug the
-  umsdos function table. If not, use the msdos one.
-*/
+ * Complete the setup of an directory inode.
+ * First, it completes the function pointers, then
+ * it locates the EMD file. If the EMD is there, then plug the
+ * umsdos function table. If not, use the msdos one.
+ */
 void umsdos_setup_dir_inode (struct inode *inode)
 {
-  inode->u.umsdos_i.i_emd_dir = 0;
-  {
-    struct inode *emd_dir = NULL;
-    extern struct inode_operations umsdos_rdir_inode_operations;
-
-    emd_dir = umsdos_emd_dir_lookup (inode,0);
-    Printk ((KERN_DEBUG "umsdos_setup_dir_inode: umsdos_emd_dir_lookup for inode=%p returned %p\n",inode,emd_dir));
-
-    if (emd_dir == NULL) {
-      Printk ((KERN_DEBUG "umsdos_setup_dir_inode /mn/: Setting up dir_inode_ops --> eg. NOT using EMD.\n"));
-      inode->i_op = &umsdos_rdir_inode_operations;
-    } else {
-      Printk ((KERN_DEBUG "umsdos_setup_dir_inode /mn/: Setting up rdir_inode_ops --> eg. using EMD.\n"));
-      inode->i_op = &umsdos_dir_inode_operations;
-    }
-    
-/*    iput (emd_dir); FIXME /mn/ ! */
-  }
+	inode->u.umsdos_i.i_emd_dir = 0;
+	{
+		struct inode *emd_dir;
+
+		emd_dir = umsdos_emd_dir_lookup (inode, 0);
+		Printk ((KERN_DEBUG "umsdos_setup_dir_inode: umsdos_emd_dir_lookup for inode=%p returned %p\n", inode, emd_dir));
+
+		if (emd_dir == NULL) {
+			Printk ((KERN_DEBUG "umsdos_setup_dir_inode /mn/: Setting up rdir_inode_ops --> eg. NOT using EMD.\n"));
+			inode->i_op = &umsdos_rdir_inode_operations;
+		} else {
+			Printk ((KERN_DEBUG "umsdos_setup_dir_inode /mn/: Setting up dir_inode_ops --> eg. using EMD.\n"));
+			inode->i_op = &umsdos_dir_inode_operations;
+		}
+
+		iput (emd_dir);	/* FIXME? OK? */
+	}
 }
 
 
 /*
-	Add some info into an inode so it can find its owner quickly
-*/
-void umsdos_set_dirinfo(
-			struct inode *inode,
-			struct inode *dir,
-			off_t f_pos)
-{
-    struct inode *emd_owner;
-    /* FIXME, I don't have a clue on this one - /mn/ hmmm ? ok ? */
-/*    Printk ((KERN_WARNING "umsdos_set_dirinfo: /mn/ FIXME: no clue. inode=%lu dir=%lu\n", inode->i_ino, dir->i_ino));*/
-    emd_owner = umsdos_emd_dir_lookup(dir,1);
-    Printk (("umsdos_set_dirinfo: emd_owner is %lu for dir %lu\n", emd_owner->i_ino, dir->i_ino));
-    inode->u.umsdos_i.i_dir_owner = dir->i_ino;
-    inode->u.umsdos_i.i_emd_owner = emd_owner->i_ino;
-    /* iput (emd_owner); FIXME */
-    inode->u.umsdos_i.pos = f_pos;
+ * Add some info into an inode so it can find its owner quickly
+ */
+void umsdos_set_dirinfo (
+				struct inode *inode,
+				struct inode *dir,
+				off_t f_pos)
+{
+	struct inode *emd_owner;
+
+	/* FIXME, I don't have a clue on this one - /mn/ hmmm ? ok ? */
+/*    Printk ((KERN_WARNING "umsdos_set_dirinfo: /mn/ FIXME: no clue. inode=%lu dir=%lu\n", inode->i_ino, dir->i_ino)); */
+	emd_owner = umsdos_emd_dir_lookup (dir, 1);
+	Printk (("umsdos_set_dirinfo: emd_owner is %lu for dir %lu\n", emd_owner->i_ino, dir->i_ino));
+	inode->u.umsdos_i.i_dir_owner = dir->i_ino;
+	inode->u.umsdos_i.i_emd_owner = emd_owner->i_ino;
+	iput (emd_owner); /* FIXME? */
+	inode->u.umsdos_i.pos = f_pos;
 }
 
 
 /*
-	Tells if an Umsdos inode has been "patched" once.
-	Return != 0 if so.
-*/
+ * Tells if an Umsdos inode has been "patched" once.
+ * Return != 0 if so.
+ */
 int umsdos_isinit (struct inode *inode)
 {
 #if	1
@@ -141,125 +367,129 @@
 #elif 0
 	return inode->i_atime != 0;
 #else
-	return atomic_read(&inode->i_count) > 1;
+	return atomic_read (&inode->i_count) > 1;
 #endif
 }
 
 
 /*
-  Connect the proper tables in the inode and add some info.
-*/
+ * Connect the proper tables in the inode and add some info.
+ */
 void umsdos_patch_inode (
-			 struct inode *inode,
-			 struct inode *dir,		/* May be NULL */
-			 off_t f_pos)
-{
-  /*
-    This function is called very early to setup the inode, somewhat
-    too early (called by UMSDOS_read_inode). At this point, we can't
-    do to much, such as lookup up EMD files and so on. This causes
-    confusion in the kernel. This is why some initialisation
-    will be done when dir != NULL only.
-    
-    UMSDOS do run piggy back on top of msdos fs. It looks like something
-    is missing in the VFS to accommodate stacked fs. Still unclear what
-    (quite honestly).
-    
-    Well, maybe one! A new entry "may_unmount" which would allow
-    the stacked fs to allocate some inode permanently and release
-    them at the end. Doing that now introduce a problem. unmount
-    always fail because some inodes are in use.
-  */
-  
-  Printk ((KERN_DEBUG "Entering umsdos_patch_inode for inode=%lu\n", inode->i_ino));
-  
-  if (!umsdos_isinit(inode)){
-    inode->u.umsdos_i.i_emd_dir = 0;
-    if (S_ISREG(inode->i_mode)){
-       if (MSDOS_SB(inode->i_sb)->cvf_format){
-         if (MSDOS_SB(inode->i_sb)->cvf_format->flags&CVF_USE_READPAGE){
-           Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_readpage\n"));
-           inode->i_op = &umsdos_file_inode_operations_readpage;
-         }else{
-           Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_no_bmap\n"));
-           inode->i_op = &umsdos_file_inode_operations_no_bmap;
-         }
-       }else{      
-         if (inode->i_op->bmap != NULL){
-           Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations\n"));
-	   inode->i_op = &umsdos_file_inode_operations;
-         }else{
-           Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_no_bmap\n"));
-           inode->i_op = &umsdos_file_inode_operations_no_bmap;
-         }
-      }
-    }else if (S_ISDIR(inode->i_mode)){
-      if (dir != NULL){
-	umsdos_setup_dir_inode(inode);
-      }
-    }else if (S_ISLNK(inode->i_mode)){
-      Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_symlink_inode_operations\n"));
-      inode->i_op = &umsdos_symlink_inode_operations;
-    }else if (S_ISCHR(inode->i_mode)){
-      Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = chrdev_inode_operations\n"));
-      inode->i_op = &chrdev_inode_operations;
-    }else if (S_ISBLK(inode->i_mode)){
-      Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = blkdev_inode_operations\n"));
-      inode->i_op = &blkdev_inode_operations;
-    }else if (S_ISFIFO(inode->i_mode)){
-      Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: uhm, init_fifo\n"));
-      init_fifo(inode);
-    }
-    if (dir != NULL){
-      /* #Specification: inode / umsdos info
-	 The first time an inode is seen (inode->i_count == 1),
-	 the inode number of the EMD file which control this inode
-	 is tagged to this inode. It allows operation such
-	 as notify_change to be handled.
-      */
-      /*
-	This is done last because it also control the
-	status of umsdos_isinit()
-      */
-      PRINTK ((KERN_DEBUG "umsdos_patch_inode /mn/: here we go: calling umsdos_set_dirinfo (%p,%p,%lu)\n", inode, dir, f_pos));
-      umsdos_set_dirinfo (inode,dir,f_pos);
-    }
-  }else if (dir != NULL){
-    /*
-      Test to see if the info is maintained.
-      This should be removed when the file system will be proven.
-    */
-      /* FIXME, again, not a clue */
-      struct inode *emd_owner;
-      Printk ((KERN_WARNING "umsdos_patch_inode: /mn/ Warning: untested emd_owner thingy...\n"));
-      emd_owner = umsdos_emd_dir_lookup(dir,1);
-      /* iput (emd_owner); FIXME */
-      if (emd_owner->i_ino != inode->u.umsdos_i.i_emd_owner){
-	  printk ("UMSDOS: *** EMD_OWNER ??? *** ino = %ld %ld <> %ld "
-		  ,inode->i_ino,emd_owner->i_ino,inode->u.umsdos_i.i_emd_owner);
-    }
-  }
-}
-
-
-/*
-  Get the inode of the directory which owns this inode.
-  Return 0 if ok, -EIO if error.
-*/
-int umsdos_get_dirowner(
-	struct inode *inode,
-	struct inode **result)	/* Hold NULL if any error */
-							/* else, the inode of the directory */
+				struct inode *inode,
+				struct inode *dir,	/* May be NULL */
+				off_t f_pos)
 {
+	/*
+	 * This function is called very early to setup the inode, somewhat
+	 * too early (called by UMSDOS_read_inode). At this point, we can't
+	 * do to much, such as lookup up EMD files and so on. This causes
+	 * confusion in the kernel. This is why some initialisation
+	 * will be done when dir != NULL only.
+	 * 
+	 * UMSDOS do run piggy back on top of msdos fs. It looks like something
+	 * is missing in the VFS to accommodate stacked fs. Still unclear what
+	 * (quite honestly).
+	 * 
+	 * Well, maybe one! A new entry "may_unmount" which would allow
+	 * the stacked fs to allocate some inode permanently and release
+	 * them at the end. Doing that now introduce a problem. unmount
+	 * always fail because some inodes are in use.
+	 */
+
+	Printk ((KERN_DEBUG "Entering umsdos_patch_inode for inode=%lu\n", inode->i_ino));
+
+	if (!umsdos_isinit (inode)) {
+		inode->u.umsdos_i.i_emd_dir = 0;
+		if (S_ISREG (inode->i_mode)) {
+			if (MSDOS_SB (inode->i_sb)->cvf_format) {
+				if (MSDOS_SB (inode->i_sb)->cvf_format->flags & CVF_USE_READPAGE) {
+					Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_readpage\n"));
+					inode->i_op = &umsdos_file_inode_operations_readpage;
+				} else {
+					Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_no_bmap\n"));
+					inode->i_op = &umsdos_file_inode_operations_no_bmap;
+				}
+			} else {
+				if (inode->i_op->bmap != NULL) {
+					Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations\n"));
+					inode->i_op = &umsdos_file_inode_operations;
+				} else {
+					Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_no_bmap\n"));
+					inode->i_op = &umsdos_file_inode_operations_no_bmap;
+				}
+			}
+		} else if (S_ISDIR (inode->i_mode)) {
+			if (dir != NULL) {
+				umsdos_setup_dir_inode (inode);
+			}
+		} else if (S_ISLNK (inode->i_mode)) {
+			Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_symlink_inode_operations\n"));
+			inode->i_op = &umsdos_symlink_inode_operations;
+		} else if (S_ISCHR (inode->i_mode)) {
+			Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = chrdev_inode_operations\n"));
+			inode->i_op = &chrdev_inode_operations;
+		} else if (S_ISBLK (inode->i_mode)) {
+			Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = blkdev_inode_operations\n"));
+			inode->i_op = &blkdev_inode_operations;
+		} else if (S_ISFIFO (inode->i_mode)) {
+			Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: uhm, init_fifo\n"));
+			init_fifo (inode);
+		}
+		if (dir != NULL) {
+			/* #Specification: inode / umsdos info
+			 * The first time an inode is seen (inode->i_count == 1),
+			 * the inode number of the EMD file which control this inode
+			 * is tagged to this inode. It allows operation such
+			 * as notify_change to be handled.
+			 */
+			/*
+			 * This is done last because it also control the
+			 * status of umsdos_isinit()
+			 */
+			Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: here we go: calling umsdos_set_dirinfo (%p,%p,%lu)\n", inode, dir, f_pos));
+			umsdos_set_dirinfo (inode, dir, f_pos);
+		}
+	} else if (dir != NULL) {
+		/*
+		 * Test to see if the info is maintained.
+		 * This should be removed when the file system will be proven.
+		 */
+		/* FIXME, again, not a clue */
+		struct inode *emd_owner;
+
+		Printk ((KERN_WARNING "umsdos_patch_inode: /mn/ Warning: untested emd_owner thingy...\n"));
+		emd_owner = umsdos_emd_dir_lookup (dir, 1);
+		iput (emd_owner); /* FIXME? */
+		if (emd_owner->i_ino != inode->u.umsdos_i.i_emd_owner) {
+			printk ("UMSDOS: *** EMD_OWNER ??? *** ino = %ld %ld <> %ld "
+				,inode->i_ino, emd_owner->i_ino, inode->u.umsdos_i.i_emd_owner);
+		}
+	}
+}
+
+
+/*
+ * Get the inode of the directory which owns this inode.
+ * Return 0 if ok, -EIO if error.
+ */
+int umsdos_get_dirowner (
+				struct inode *inode,
+				struct inode **result)
+{				/* Hold NULL if any error */
+	/* else, the inode of the directory */
 	int ret = -EIO;
 	unsigned long ino = inode->u.umsdos_i.i_dir_owner;
+
 	*result = NULL;
-	if (ino == 0){
+	if (ino == 0) {
 		printk ("UMSDOS: umsdos_get_dirowner ino == 0\n");
-	}else{
-		struct inode *dir = *result = iget(inode->i_sb,ino);
-		if (dir != NULL){
-			umsdos_patch_inode (dir,NULL,0);
+	} else {
+		struct inode *dir = *result = iget (inode->i_sb, ino);
+
+		if (dir != NULL) {
+			umsdos_patch_inode (dir, NULL, 0);
+			/* iput (dir);	/ * FIXME: /mn/ added this. Is it ok ? */
 			ret = 0;
 		}
 	}
@@ -269,366 +499,369 @@
 
 
 /*
-	Load an inode from disk.
-*/
-void UMSDOS_read_inode(struct inode *inode)
-{
-	PRINTK ((KERN_DEBUG "UMSDOS_read_inode %p ino = %lu ",inode,inode->i_ino));
-	msdos_read_inode(inode);
-	PRINTK (("ino after msdos_read_inode= %lu\n",inode->i_ino));
-	if (S_ISDIR(inode->i_mode)
-		&& (inode->u.umsdos_i.u.dir_info.creating != 0
-			|| inode->u.umsdos_i.u.dir_info.looking != 0
-			|| waitqueue_active(&inode->u.umsdos_i.u.dir_info.p))){
-		PRINTK (("read inode %d %d %p\n"
-			,inode->u.umsdos_i.u.dir_info.creating
-			,inode->u.umsdos_i.u.dir_info.looking
-			,inode->u.umsdos_i.u.dir_info.p));
+ * Load an inode from disk.
+ */
+void UMSDOS_read_inode (struct inode *inode)
+{
+	Printk ((KERN_DEBUG "UMSDOS_read_inode %p ino = %lu ", inode, inode->i_ino));
+	msdos_read_inode (inode);
+	Printk (("ino after msdos_read_inode= %lu i_count=%d\n", inode->i_ino, inode->i_count));
+	if (S_ISDIR (inode->i_mode)
+	    && (inode->u.umsdos_i.u.dir_info.creating != 0
+		|| inode->u.umsdos_i.u.dir_info.looking != 0
+		|| waitqueue_active (&inode->u.umsdos_i.u.dir_info.p))) {
+		Printk (("read inode %d %d %p\n"
+			 ,inode->u.umsdos_i.u.dir_info.creating
+			 ,inode->u.umsdos_i.u.dir_info.looking
+			 ,inode->u.umsdos_i.u.dir_info.p));
 	}
 	/* #Specification: Inode / post initialisation
-		To completely initialise an inode, we need access to the owner
-		directory, so we can locate more info in the EMD file. This is
-		not available the first time the inode is access, we use
-		a value in the inode to tell if it has been finally initialised.
-
-		At first, we have tried testing i_count but it was causing
-		problem. It is possible that two or more process use the
-		newly accessed inode. While the first one block during
-		the initialisation (probably while reading the EMD file), the
-		others believe all is well because i_count > 1. They go banana
-		with a broken inode. See umsdos_lookup_patch and umsdos_patch_inode.
-	*/
-	umsdos_patch_inode(inode,NULL,0);
+	 * To completely initialise an inode, we need access to the owner
+	 * directory, so we can locate more info in the EMD file. This is
+	 * not available the first time the inode is access, we use
+	 * a value in the inode to tell if it has been finally initialised.
+	 * 
+	 * At first, we have tried testing i_count but it was causing
+	 * problem. It is possible that two or more process use the
+	 * newly accessed inode. While the first one block during
+	 * the initialisation (probably while reading the EMD file), the
+	 * others believe all is well because i_count > 1. They go banana
+	 * with a broken inode. See umsdos_lookup_patch and umsdos_patch_inode.
+	 */
+	umsdos_patch_inode (inode, NULL, 0);
+}
+
+
+int internal_notify_change (struct inode *inode, struct iattr *attr)
+{
+	int ret = 0;
+	struct inode *root;
+
+	PRINTK ((KERN_DEBUG "UMSDOS_notify_change: entering\n"));
+
+	if ((ret = inode_change_ok (inode, attr)) != 0)
+		return ret;
+
+	if (inode->i_nlink > 0) {
+		/* #Specification: notify_change / i_nlink > 0
+		 * notify change is only done for inode with nlink > 0. An inode
+		 * with nlink == 0 is no longer associated with any entry in
+		 * the EMD file, so there is nothing to update.
+		 */
+		unsigned long i_emd_owner = inode->u.umsdos_i.i_emd_owner;
+
+		root = iget (inode->i_sb, UMSDOS_ROOT_INO);
+		if (inode == root) {
+			/* #Specification: root inode / attributes
+			 * I don't know yet how this should work. Normally
+			 * the attributes (permissions bits, owner, times) of
+			 * a directory are stored in the EMD file of its parent.
+			 * 
+			 * One thing we could do is store the attributes of the root
+			 * inode in its own EMD file. A simple entry named "." could
+			 * be used for this special case. It would be read once
+			 * when the file system is mounted and update in
+			 * UMSDOS_notify_change() (right here).
+			 * 
+			 * I am not sure of the behavior of the root inode for
+			 * a real UNIX file system. For now, this is a nop.
+			 */
+		} else if (i_emd_owner != 0xffffffff && i_emd_owner != 0) {
+			/* This inode is not a EMD file nor an inode used internally
+			 * by MSDOS, so we can update its status.
+			 * See emd.c
+			 */
+			struct inode *emd_owner;
+
+			emd_owner = iget (inode->i_sb, i_emd_owner);
+			Printk (("notify change %p ", inode));
+			if (emd_owner == NULL) {
+				printk ("UMSDOS: emd_owner = NULL ???");
+				ret = -EPERM;
+			} else {
+				struct file filp;
+				struct umsdos_dirent entry;
+				struct dentry *emd_dentry;
+				loff_t offs;
+
+				emd_dentry = creat_dentry ("notify_emd", 10, emd_owner, NULL);
+				fill_new_filp (&filp, emd_dentry);
+
+				filp.f_pos = inode->u.umsdos_i.pos;
+				filp.f_reada = 0;
+				offs = filp.f_pos;	/* FIXME: /mn/ is this ok ? */
+				Printk (("pos = %Lu ", filp.f_pos));
+				/* Read only the start of the entry since we don't touch */
+				/* the name */
+				ret = umsdos_emd_dir_read (emd_owner, &filp, (char *) &entry, UMSDOS_REC_SIZE, &offs);
+				if (ret == 0) {
+					if (attr->ia_valid & ATTR_UID)
+						entry.uid = attr->ia_uid;
+					if (attr->ia_valid & ATTR_GID)
+						entry.gid = attr->ia_gid;
+					if (attr->ia_valid & ATTR_MODE)
+						entry.mode = attr->ia_mode;
+					if (attr->ia_valid & ATTR_ATIME)
+						entry.atime = attr->ia_atime;
+					if (attr->ia_valid & ATTR_MTIME)
+						entry.mtime = attr->ia_mtime;
+					if (attr->ia_valid & ATTR_CTIME)
+						entry.ctime = attr->ia_ctime;
+
+					entry.nlink = inode->i_nlink;
+					filp.f_pos = inode->u.umsdos_i.pos;
+					offs = filp.f_pos;	/* FIXME: /mn/ is this ok ? */
+					ret = umsdos_emd_dir_write (emd_owner, &filp, (char *) &entry, UMSDOS_REC_SIZE, &offs);
+
+					Printk (("notify pos %lu ret %d nlink %d "
+						 ,inode->u.umsdos_i.pos
+						 ,ret, entry.nlink));
+					/* #Specification: notify_change / msdos fs
+					 * notify_change operation are done only on the
+					 * EMD file. The msdos fs is not even called.
+					 */
+				}
+				iput (emd_owner);	/* FIXME? /mn/ */
+			}
+			Printk (("\n"));
+		}
+		iput (root);	/* FIXME - /mn/ this is hopefully ok */
+	}
+	if (ret == 0)
+		inode_setattr (inode, attr);
+
+	return ret;
 }
 
 
+int UMSDOS_notify_change (struct dentry *dentry, struct iattr *attr)
+{
+	return internal_notify_change (dentry->d_inode, attr);
+}
+
 /*
-	Update the disk with the inode content
-*/
-void UMSDOS_write_inode(struct inode *inode)
+ * Update the disk with the inode content
+ */
+void UMSDOS_write_inode (struct inode *inode)
 {
 	struct iattr newattrs;
 
-	PRINTK (("UMSDOS_write_inode emd %d (FIXME: missing notify_change)\n",inode->u.umsdos_i.i_emd_owner));
-	fat_write_inode(inode);
+	PRINTK (("UMSDOS_write_inode emd %d (FIXME: missing notify_change)\n", inode->u.umsdos_i.i_emd_owner));
+	fat_write_inode (inode);
 	newattrs.ia_mtime = inode->i_mtime;
 	newattrs.ia_atime = inode->i_atime;
 	newattrs.ia_ctime = inode->i_ctime;
 	newattrs.ia_valid = ATTR_MTIME | ATTR_ATIME | ATTR_CTIME;
 	/*
-		UMSDOS_notify_change is convenient to call here
-		to update the EMD entry associated with this inode.
-		But it has the side effect to re"dirt" the inode.
-	*/
-	/* FIXME, notify_change now takes a dentry, not an
-	   inode so, the emd update needs to be done here
-	UMSDOS_notify_change (inode, &newattrs);
-	*/
-	
-	/* FIXME inode->i_dirt = 0; */
-}
-
-
-int internal_notify_change(struct inode *inode, struct iattr *attr)
-{
-  int ret = 0;
-  
-  PRINTK ((KERN_DEBUG "UMSDOS_notify_change: entering\n"));
-  
-  if ((ret = inode_change_ok(inode, attr)) != 0)
-    return ret;
-  
-  if (inode->i_nlink > 0){
-    /* #Specification: notify_change / i_nlink > 0
-       notify change is only done for inode with nlink > 0. An inode
-       with nlink == 0 is no longer associated with any entry in
-       the EMD file, so there is nothing to update.
-    */
-    unsigned long i_emd_owner = inode->u.umsdos_i.i_emd_owner;
-    if (inode == iget(inode->i_sb,UMSDOS_ROOT_INO)){
-      /* #Specification: root inode / attributes
-	 I don't know yet how this should work. Normally
-	 the attributes (permissions bits, owner, times) of
-	 a directory are stored in the EMD file of its parent.
-	 
-	 One thing we could do is store the attributes of the root
-	 inode in its own EMD file. A simple entry named "." could
-	 be used for this special case. It would be read once
-	 when the file system is mounted and update in
-	 UMSDOS_notify_change() (right here).
-	 
-	 I am not sure of the behavior of the root inode for
-	 a real UNIX file system. For now, this is a nop.
-      */
-    }else if (i_emd_owner != 0xffffffff && i_emd_owner != 0){
-      /* This inode is not a EMD file nor an inode used internally
-	 by MSDOS, so we can update its status.
-	 See emd.c
-      */
-      struct inode *emd_owner = iget (inode->i_sb,i_emd_owner);
-      Printk (("notify change %p ",inode));
-      if (emd_owner == NULL){
-	printk ("UMSDOS: emd_owner = NULL ???");
-	ret = -EPERM;
-      }else{
-	struct file filp;
-	struct umsdos_dirent entry;
-	struct dentry *emd_dentry;
-	loff_t offs;
-	
-	emd_dentry = creat_dentry ("notify_emd", 10, emd_owner, NULL);
-	fill_new_filp (&filp, emd_dentry);
-	
-	filp.f_pos = inode->u.umsdos_i.pos;
-	filp.f_reada = 0;
-	offs = filp.f_pos;	/* FIXME: /mn/ is this ok ? */
-	Printk (("pos = %Lu ", filp.f_pos));
-	/* Read only the start of the entry since we don't touch */
-	/* the name */
-	ret = umsdos_emd_dir_read (emd_owner, &filp, (char*)&entry, UMSDOS_REC_SIZE, &offs);
-	if (ret == 0){
-	  if (attr->ia_valid & ATTR_UID)
-	    entry.uid = attr->ia_uid;
-	  if (attr->ia_valid & ATTR_GID)
-	    entry.gid = attr->ia_gid;
-	  if (attr->ia_valid & ATTR_MODE)
-	    entry.mode = attr->ia_mode;
-	  if (attr->ia_valid & ATTR_ATIME)
-	    entry.atime = attr->ia_atime;
-	  if (attr->ia_valid & ATTR_MTIME)
-	    entry.mtime = attr->ia_mtime;
-	  if (attr->ia_valid & ATTR_CTIME)
-	    entry.ctime = attr->ia_ctime;
-	  
-	  entry.nlink = inode->i_nlink;
-	  filp.f_pos = inode->u.umsdos_i.pos;
-	  offs = filp.f_pos;	/* FIXME: /mn/ is this ok ? */
-	  ret = umsdos_emd_dir_write (emd_owner, &filp, (char*)&entry, UMSDOS_REC_SIZE, &offs);
-	  
-	  Printk (("notify pos %lu ret %d nlink %d "
-		   ,inode->u.umsdos_i.pos
-		   ,ret, entry.nlink));
-	  /* #Specification: notify_change / msdos fs
-	     notify_change operation are done only on the
-	     EMD file. The msdos fs is not even called.
-	  */
-	}
-	/* iput (emd_owner); FIXME */
-      }
-      Printk (("\n"));
-    }
-  }
-  if (ret == 0)
-    inode_setattr(inode, attr);
-  return ret;
+	 * UMSDOS_notify_change is convenient to call here
+	 * to update the EMD entry associated with this inode.
+	 * But it has the side effect to re"dirt" the inode.
+	 */
+
+/*      
+ * internal_notify_change (inode, &newattrs);
+ * inode->i_state &= ~I_DIRTY; / * FIXME: this doesn't work... we need to remove ourselfs from list on dirty inodes /mn/ */
 }
 
 
-int UMSDOS_notify_change(struct dentry *dentry, struct iattr *attr)
-{
-  return internal_notify_change (dentry->d_inode, attr);
-}
-
 
 
 
 /* #Specification: function name / convention
-   A simple convention for function name has been used in
-   the UMSDOS file system. First all function use the prefix
-   umsdos_ to avoid name clash with other part of the kernel.
-   
-   And standard VFS entry point use the prefix UMSDOS (upper case)
-   so it's easier to tell them apart.
-   N.B. (FIXME) PTW, the order and contents of this struct changed
-*/
-
-static struct super_operations umsdos_sops = {
-    UMSDOS_read_inode,		/* read_inode */
-    UMSDOS_write_inode,		/* write_inode */
-    UMSDOS_put_inode,		/* put_inode */
-    NULL,			/* delete_inode */ 
-    UMSDOS_notify_change,	/* notify_change */
-    UMSDOS_put_super,		/* put_super */
-    NULL,			/* write_super */
-    fat_statfs,			/* statfs */
-    NULL			/* remount_fs*/
+ * A simple convention for function name has been used in
+ * the UMSDOS file system. First all function use the prefix
+ * umsdos_ to avoid name clash with other part of the kernel.
+ * 
+ * And standard VFS entry point use the prefix UMSDOS (upper case)
+ * so it's easier to tell them apart.
+ * N.B. (FIXME) PTW, the order and contents of this struct changed
+ */
+
+static struct super_operations umsdos_sops =
+{
+	UMSDOS_read_inode,	/* read_inode */
+	UMSDOS_write_inode,	/* write_inode */
+	UMSDOS_put_inode,	/* put_inode */
+	fat_delete_inode,	/* delete_inode */
+	UMSDOS_notify_change,	/* notify_change */
+	UMSDOS_put_super,	/* put_super */
+	NULL,			/* write_super */
+	fat_statfs,		/* statfs */
+	NULL			/* remount_fs */
 };
 
 /*
-  Read the super block of an Extended MS-DOS FS.
-*/
-struct super_block *UMSDOS_read_super(
-				      struct super_block *sb,
-				      void *data,
-				      int silent)
-{
-  /* #Specification: mount / options
-     Umsdos run on top of msdos. Currently, it supports no
-     mount option, but happily pass all option received to
-     the msdos driver. I am not sure if all msdos mount option
-     make sense with Umsdos. Here are at least those who
-     are useful.
-     uid=
-     gid=
-     
-     These options affect the operation of umsdos in directories
-     which do not have an EMD file. They behave like normal
-     msdos directory, with all limitation of msdos.
-  */
-    struct super_block *res;
-    struct inode *pseudo=NULL;
-    Printk ((KERN_DEBUG "UMSDOS /mn/: starting UMSDOS_read_super\n"));
-    MOD_INC_USE_COUNT;
-    PRINTK ((KERN_DEBUG "UMSDOS /mn/: sb = %p\n",sb));
-    res = msdos_read_super(sb,data,silent);
-    PRINTK ((KERN_DEBUG "UMSDOS /mn/: res = %p\n",res));
-    printk (KERN_INFO "UMSDOS dentry-WIP-Beta 0.82-3 (compatibility level %d.%d, fast msdos)\n", UMSDOS_VERSION, UMSDOS_RELEASE);
-	  
-    if (res == NULL) { MOD_DEC_USE_COUNT; return NULL; }
-
-    MSDOS_SB(res)->options.dotsOK = 0;  /* disable hidden==dotfile */
-    res->s_op = &umsdos_sops;
-    Printk ((KERN_DEBUG "umsdos /mn/: here goes the iget ROOT_INO\n"));
-
-    pseudo = iget(res,UMSDOS_ROOT_INO);
-    Printk ((KERN_DEBUG "umsdos_read_super %p\n",pseudo));
-
-    umsdos_setup_dir_inode (pseudo);
-    
-#if 0	/* disabled /mn/ test FIXME */    
-
-    /* if (s == super_blocks){ FIXME, super_blocks no longer exported */
-    if(pseudo) {
-      /* #Specification: pseudo root / mount
-	 When a umsdos fs is mounted, a special handling is done
-	 if it is the root partition. We check for the presence
-	 of the file /linux/etc/init or /linux/etc/rc or
-	 /linux/sbin/init. If one is there, we do a chroot("/linux").
-	 
-	 We check both because (see init/main.c) the kernel
-	 try to exec init at different place and if it fails
-	 it tries /bin/sh /etc/rc. To be consistent with
-	 init/main.c, many more test would have to be done
-	 to locate init. Any complain ?
-	 
-	 The chroot is done manually in init/main.c but the
-	 info (the inode) is located at mount time and store
-	 in a global variable (pseudo_root) which is used at
-	 different place in the umsdos driver. There is no
-	 need to store this variable elsewhere because it
-	 will always be one, not one per mount.
-	 
-	 This feature allows the installation
-	 of a linux system within a DOS system in a subdirectory.
-	 
-	 A user may install its linux stuff in c:\linux
-	 avoiding any clash with existing DOS file and subdirectory.
-	 When linux boots, it hides this fact, showing a normal
-	 root directory with /etc /bin /tmp ...
-	 
-	 The word "linux" is hardcoded in /usr/include/linux/umsdos_fs.h
-	 in the macro UMSDOS_PSDROOT_NAME.
-      */
-      struct dentry *root, *etc, *etc_rc, *init, *sbin;
-
-      root = creat_dentry (UMSDOS_PSDROOT_NAME, strlen(UMSDOS_PSDROOT_NAME), NULL, NULL);
-      sbin = creat_dentry ("sbin", 4, NULL, NULL);
-      
-      Printk ((KERN_DEBUG "Mounting root\n"));
-      if (umsdos_real_lookup (pseudo,root)==0
-          && (root->d_inode != NULL)
-	  && S_ISDIR(root->d_inode->i_mode)){
-	
-	int pseudo_ok = 0;
-	Printk ((KERN_DEBUG "/%s is there\n",UMSDOS_PSDROOT_NAME));
-	etc = creat_dentry ("etc", 3, NULL, NULL);
-	
-	
-	/* if (umsdos_real_lookup (pseudo,"etc",3,etc)==0 */
-	if(umsdos_real_lookup(pseudo, etc) == 0
-	   && S_ISDIR(etc->d_inode->i_mode)){
-
-	    Printk ((KERN_DEBUG "/%s/etc is there\n",UMSDOS_PSDROOT_NAME));
-	    
-	    init = creat_dentry ("init", 4, NULL, NULL);
-	    etc_rc = creat_dentry ("rc", 2, NULL, NULL);
-	  
-	    /* if ((umsdos_real_lookup (etc,"init",4,init)==0*/
-	    if((umsdos_real_lookup(pseudo, init) == 0
-		&& S_ISREG(init->d_inode->i_mode))
-	       /*	|| (umsdos_real_lookup (etc,"rc",2,&rc)==0*/
-	       || (umsdos_real_lookup(pseudo, etc_rc) == 0
-		   && S_ISREG(etc_rc->d_inode->i_mode))){
-		pseudo_ok = 1;
-	  }
-	    /* FIXME !!!!!! */
-	    /* iput(init); */
-	    /* iput(rc); */
-	}
-	if (!pseudo_ok
-	/* && umsdos_real_lookup (pseudo, "sbin", 4, sbin)==0*/
-	    && umsdos_real_lookup(pseudo, sbin) == 0
-	    && S_ISDIR(sbin->d_inode->i_mode)){
-	  
-	  Printk ((KERN_DEBUG "/%s/sbin is there\n",UMSDOS_PSDROOT_NAME));
-	  /* if (umsdos_real_lookup (sbin,"init",4,init)==0 */
-	  if(umsdos_real_lookup(pseudo, init) == 0	
-	     && S_ISREG(init->d_inode->i_mode)){
-	    pseudo_ok = 1;
-	  }
-	  /* FIXME !!! 
-	     iput (init); */
-	}
-	if (pseudo_ok){
-	  umsdos_setup_dir_inode (pseudo);
-	  Printk ((KERN_INFO "Activating pseudo root /%s\n",UMSDOS_PSDROOT_NAME));
-	  pseudo_root = pseudo;
-	  pseudo->i_count++;
-	  pseudo = NULL;
-	}
-	/* FIXME 
-	
-	iput (sbin);
-	iput (etc);
-	*/
-      }
-      
-      Printk ((KERN_WARNING "umsdos_read_super /mn/: Pseudo should be iput-ed here...\n"));
-
-      /* iput (pseudo); / * FIXME */
-    }
-
-#endif /* disabled */
-
-    PRINTK ((KERN_DEBUG "umsdos_read_super /mn/: returning %p\n",res));
-    return res;
-}
-
-
-
-static struct file_system_type umsdos_fs_type = {
-  "umsdos",
-  FS_REQUIRES_DEV,
-  UMSDOS_read_super,
-  NULL
+ * Read the super block of an Extended MS-DOS FS.
+ */
+struct super_block *UMSDOS_read_super (
+					      struct super_block *sb,
+					      void *data,
+					      int silent)
+{
+	/* #Specification: mount / options
+	 * Umsdos run on top of msdos. Currently, it supports no
+	 * mount option, but happily pass all option received to
+	 * the msdos driver. I am not sure if all msdos mount option
+	 * make sense with Umsdos. Here are at least those who
+	 * are useful.
+	 * uid=
+	 * gid=
+	 * 
+	 * These options affect the operation of umsdos in directories
+	 * which do not have an EMD file. They behave like normal
+	 * msdos directory, with all limitation of msdos.
+	 */
+	struct super_block *res;
+	struct inode *pseudo = NULL;
+
+	Printk ((KERN_DEBUG "UMSDOS /mn/: starting UMSDOS_read_super\n"));
+	MOD_INC_USE_COUNT;
+	PRINTK ((KERN_DEBUG "UMSDOS /mn/: sb = %p\n", sb));
+	res = msdos_read_super (sb, data, silent);
+	PRINTK ((KERN_DEBUG "UMSDOS /mn/: res = %p\n", res));
+	printk (KERN_INFO "UMSDOS dentry-WIP-Beta 0.82-4 (compatibility level %d.%d, fast msdos)\n", UMSDOS_VERSION, UMSDOS_RELEASE);
+
+	if (res == NULL) {
+		MOD_DEC_USE_COUNT;
+		return NULL;
+	}
+	MSDOS_SB (res)->options.dotsOK = 0;	/* disable hidden==dotfile */
+	res->s_op = &umsdos_sops;
+	Printk ((KERN_DEBUG "umsdos /mn/: here goes the iget ROOT_INO\n"));
+
+	pseudo = iget (res, UMSDOS_ROOT_INO);
+	Printk ((KERN_DEBUG "umsdos_read_super %p\n", pseudo));
+
+	umsdos_setup_dir_inode (pseudo);
+	Printk ((KERN_DEBUG "umsdos_setup_dir_inode passed. pseudo i_count=%d\n", pseudo->i_count));
+
+	/* if (s == super_blocks){ FIXME, super_blocks no longer exported */
+	if (pseudo) {
+		/* #Specification: pseudo root / mount
+		 * When a umsdos fs is mounted, a special handling is done
+		 * if it is the root partition. We check for the presence
+		 * of the file /linux/etc/init or /linux/etc/rc or
+		 * /linux/sbin/init. If one is there, we do a chroot("/linux").
+		 * 
+		 * We check both because (see init/main.c) the kernel
+		 * try to exec init at different place and if it fails
+		 * it tries /bin/sh /etc/rc. To be consistent with
+		 * init/main.c, many more test would have to be done
+		 * to locate init. Any complain ?
+		 * 
+		 * The chroot is done manually in init/main.c but the
+		 * info (the inode) is located at mount time and store
+		 * in a global variable (pseudo_root) which is used at
+		 * different place in the umsdos driver. There is no
+		 * need to store this variable elsewhere because it
+		 * will always be one, not one per mount.
+		 * 
+		 * This feature allows the installation
+		 * of a linux system within a DOS system in a subdirectory.
+		 * 
+		 * A user may install its linux stuff in c:\linux
+		 * avoiding any clash with existing DOS file and subdirectory.
+		 * When linux boots, it hides this fact, showing a normal
+		 * root directory with /etc /bin /tmp ...
+		 * 
+		 * The word "linux" is hardcoded in /usr/include/linux/umsdos_fs.h
+		 * in the macro UMSDOS_PSDROOT_NAME.
+		 */
+		struct dentry *root, *etc, *etc_rc, *sbin, *init = NULL;
+
+		root = creat_dentry (UMSDOS_PSDROOT_NAME, strlen (UMSDOS_PSDROOT_NAME), NULL, NULL);
+		sbin = creat_dentry ("sbin", 4, NULL, NULL);
+
+		Printk ((KERN_DEBUG "Mounting root\n"));
+		if (umsdos_real_lookup (pseudo, root) == 0
+		    && (root->d_inode != NULL)
+		    && S_ISDIR (root->d_inode->i_mode)) {
+
+			int pseudo_ok = 0;
+
+			Printk ((KERN_DEBUG "/%s is there\n", UMSDOS_PSDROOT_NAME));
+			etc = creat_dentry ("etc", 3, NULL, root);
+
+
+			if (umsdos_real_lookup (pseudo, etc) == 0
+			    && S_ISDIR (etc->d_inode->i_mode)) {
+
+				Printk ((KERN_DEBUG "/%s/etc is there\n", UMSDOS_PSDROOT_NAME));
+
+				init = creat_dentry ("init", 4, NULL, etc);
+				etc_rc = creat_dentry ("rc", 2, NULL, etc);
+
+				/* if ((umsdos_real_lookup (etc,"init",4,init)==0 */
+				if ((umsdos_real_lookup (pseudo, init) == 0
+				     && S_ISREG (init->d_inode->i_mode))
+				/*       || (umsdos_real_lookup (etc,"rc",2,&rc)==0 */
+				    || (umsdos_real_lookup (pseudo, etc_rc) == 0
+				 && S_ISREG (etc_rc->d_inode->i_mode))) {
+					pseudo_ok = 1;
+				}
+				/* FIXME !!!!!! */
+				/* iput(init); */
+				/* iput(rc); */
+			}
+			if (!pseudo_ok
+			/* && umsdos_real_lookup (pseudo, "sbin", 4, sbin)==0 */
+			    && umsdos_real_lookup (pseudo, sbin) == 0
+			    && S_ISDIR (sbin->d_inode->i_mode)) {
+
+				Printk ((KERN_DEBUG "/%s/sbin is there\n", UMSDOS_PSDROOT_NAME));
+				/* if (umsdos_real_lookup (sbin,"init",4,init)==0 */
+				if (umsdos_real_lookup (pseudo, init) == 0
+				    && S_ISREG (init->d_inode->i_mode)) {
+					pseudo_ok = 1;
+				}
+				/* FIXME !!! 
+				 * iput (init); */
+			}
+			if (pseudo_ok) {
+				umsdos_setup_dir_inode (pseudo);
+				Printk ((KERN_INFO "Activating pseudo root /%s\n", UMSDOS_PSDROOT_NAME));
+				pseudo_root = pseudo;
+				inc_count (pseudo);
+				pseudo = NULL;
+			}
+			/* FIXME 
+			 * 
+			 * iput (sbin);
+			 * iput (etc);
+			 */
+		}
+		iput (pseudo);
+	}
+	Printk ((KERN_DEBUG "umsdos_read_super /mn/: (pseudo=%lu, i_count=%d) returning %p\n", pseudo->i_ino, pseudo->i_count, res));
+	return res;
+}
+
+
+
+static struct file_system_type umsdos_fs_type =
+{
+	"umsdos",
+	FS_REQUIRES_DEV,
+	UMSDOS_read_super,
+	NULL
 };
 
-__initfunc(int init_umsdos_fs(void))
+__initfunc (int init_umsdos_fs (void))
 {
-  return register_filesystem(&umsdos_fs_type);
+	return register_filesystem (&umsdos_fs_type);
 }
 
 #ifdef MODULE
 EXPORT_NO_SYMBOLS;
 
-int init_module(void)
+int init_module (void)
 {
-  return init_umsdos_fs();
+	return init_umsdos_fs ();
 }
 
-void cleanup_module(void)
+void cleanup_module (void)
 {
-  unregister_filesystem(&umsdos_fs_type);
+	unregister_filesystem (&umsdos_fs_type);
 }
 
 #endif
diff -u --recursive --new-file v2.1.102/linux/fs/umsdos/ioctl.c linux/fs/umsdos/ioctl.c
--- v2.1.102/linux/fs/umsdos/ioctl.c	Wed Apr  8 19:36:28 1998
+++ linux/fs/umsdos/ioctl.c	Tue May 19 15:06:49 1998
@@ -24,326 +24,336 @@
 };
 
 /*
-	Record a single entry the first call.
-	Return -EINVAL the next one.
-*/
-static int umsdos_ioctl_fill(
-	void * buf,
-	const char * name,
-	int name_len,
-	off_t offset,
-	ino_t ino)
+ * Record a single entry the first call.
+ * Return -EINVAL the next one.
+ */
+static int umsdos_ioctl_fill (
+				     void *buf,
+				     const char *name,
+				     int name_len,
+				     off_t offset,
+				     ino_t ino)
 {
-  int ret = -EINVAL;
-  struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *)buf;
-  if (d->count == 0){
-    copy_to_user (d->ent->d_name,name,name_len);
-    put_user ('\0',d->ent->d_name+name_len);
-    put_user (name_len,&d->ent->d_reclen);
-    put_user (ino,&d->ent->d_ino);
-    put_user (offset,&d->ent->d_off);
-    d->count = 1;
-    ret = 0;
-  }
-  return ret;
+	int ret = -EINVAL;
+	struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *) buf;
+
+	if (d->count == 0) {
+		copy_to_user (d->ent->d_name, name, name_len);
+		put_user ('\0', d->ent->d_name + name_len);
+		put_user (name_len, &d->ent->d_reclen);
+		put_user (ino, &d->ent->d_ino);
+		put_user (offset, &d->ent->d_off);
+		d->count = 1;
+		ret = 0;
+	}
+	return ret;
 }
 
 
 /*
-	Perform special function on a directory
-*/
+ * Perform special function on a directory
+ */
 int UMSDOS_ioctl_dir (
-		      struct inode *dir,
-		      struct file *filp,
-		      unsigned int cmd,
-		      unsigned long data)
+			     struct inode *dir,
+			     struct file *filp,
+			     unsigned int cmd,
+			     unsigned long data)
 {
-  int ret = -EPERM;
-  int err;
+	int ret = -EPERM;
+	int err;
 
-       /* forward non-umsdos ioctls - this hopefully doesn't cause conflicts */
-       if(cmd!=UMSDOS_GETVERSION
-          &&cmd!=UMSDOS_READDIR_DOS
-          &&cmd!=UMSDOS_READDIR_EMD
-          &&cmd!=UMSDOS_INIT_EMD
-          &&cmd!=UMSDOS_CREAT_EMD
-          &&cmd!=UMSDOS_RENAME_DOS
-          &&cmd!=UMSDOS_UNLINK_EMD
-          &&cmd!=UMSDOS_UNLINK_DOS
-          &&cmd!=UMSDOS_RMDIR_DOS
-          &&cmd!=UMSDOS_STAT_DOS
-          &&cmd!=UMSDOS_DOS_SETUP)
-              return fat_dir_ioctl(dir,filp,cmd,data);
-
-  /* #Specification: ioctl / acces
-     Only root (effective id) is allowed to do IOCTL on directory
-     in UMSDOS. EPERM is returned for other user.
-  */
-  /*
-    Well, not all cases require write access, but it simplifies
-    the code, and let's face it, there is only one client (umssync)
-    for all this.
-  */
-  if ((err = verify_area(VERIFY_WRITE,(void*)data,sizeof(struct umsdos_ioctl))) < 0) {
-    ret = err;
-  }else if (current->euid == 0
-	    || cmd == UMSDOS_GETVERSION){
-    struct umsdos_ioctl *idata = (struct umsdos_ioctl *)data;
-    ret = -EINVAL;
-    /* #Specification: ioctl / prototypes
-       The official prototype for the umsdos ioctl on directory
-       is:
-       
-       int ioctl (
-       int fd,		// File handle of the directory
-       int cmd,	// command
-       struct umsdos_ioctl *data)
-       
-       The struct and the commands are defined in linux/umsdos_fs.h.
-       
-       umsdos_progs/umsdosio.c provide an interface in C++ to all
-       these ioctl. umsdos_progs/udosctl is a small utility showing
-       all this.
-       
-       These ioctl generally allow one to work on the EMD or the
-       DOS directory independently. These are essential to implement
-       the synchronise.
-    */
-    Printk (("ioctl %d ",cmd));
-    if (cmd == UMSDOS_GETVERSION){
-      /* #Specification: ioctl / UMSDOS_GETVERSION
-	 The field version and release of the structure
-	 umsdos_ioctl are filled with the version and release
-	 number of the fs code in the kernel. This will allow
-	 some form of checking. Users won't be able to run
-	 incompatible utility such as the synchroniser (umssync).
-	 umsdos_progs/umsdosio.c enforce this checking.
-	 
-	 Return always 0.
-      */
-      put_user(UMSDOS_VERSION,&idata->version);
-      put_user(UMSDOS_RELEASE,&idata->release);
-      ret = 0;
-    }else if (cmd == UMSDOS_READDIR_DOS){
-      /* #Specification: ioctl / UMSDOS_READDIR_DOS
-	 One entry is read from the DOS directory at the current
-	 file position. The entry is put as is in the dos_dirent
-	 field of struct umsdos_ioctl.
-	 
-	 Return > 0 if success.
-      */
-      struct UMSDOS_DIR_ONCE bufk;
-      bufk.count = 0;
-      bufk.ent = &idata->dos_dirent;
-  
-      fat_readdir(filp,&bufk,umsdos_ioctl_fill); 
-     
-      ret = bufk.count == 1 ? 1 : 0;
-    }else if (cmd == UMSDOS_READDIR_EMD){
-      /* #Specification: ioctl / UMSDOS_READDIR_EMD
-	 One entry is read from the EMD at the current
-	 file position. The entry is put as is in the umsdos_dirent
-	 field of struct umsdos_ioctl. The corresponding mangled
-	 DOS entry name is put in the dos_dirent field.
-	 
-	 All entries are read including hidden links. Blank
-	 entries are skipped.
-	 
-	 Return > 0 if success.
-      */
-      struct inode *emd_dir = umsdos_emd_dir_lookup (dir,0);
-      if (emd_dir != NULL){
-	while (1){
-	  if (filp->f_pos >= emd_dir->i_size){
-	    ret = 0;
-	    break;
-	  }else{
-	    struct umsdos_dirent entry;
-	    off_t f_pos = filp->f_pos;
-	    ret = umsdos_emd_dir_readentry (emd_dir,filp,&entry);
-	    if (ret < 0){
-	      break;
-	    }else if (entry.name_len > 0){
-	      struct umsdos_info info;
-	      ret = entry.name_len;
-	      umsdos_parse (entry.name,entry.name_len,&info);
-	      info.f_pos = f_pos;
-	      umsdos_manglename(&info);
-	      copy_to_user(&idata->umsdos_dirent,&entry
-			   ,sizeof(entry));
-	      copy_to_user(&idata->dos_dirent.d_name
-			   ,info.fake.fname,info.fake.len+1);
-	      break;
-	    }
-	  }
-	}
-	/* iput (emd_dir); FIXME */
-      }else{
-				/* The absence of the EMD is simply seen as an EOF */
-	ret = 0;
-      }
-    }else if (cmd == UMSDOS_INIT_EMD){
-      /* #Specification: ioctl / UMSDOS_INIT_EMD
-	 The UMSDOS_INIT_EMD command make sure the EMD
-	 exist for a directory. If it does not, it is
-	 created. Also, it makes sure the directory functions
-	 table (struct inode_operations) is set to the UMSDOS
-	 semantic. This mean that umssync may be applied to
-	 an "opened" msdos directory, and it will change behavior
-	 on the fly.
-	 
-	 Return 0 if success.
-      */
-      extern struct inode_operations umsdos_rdir_inode_operations;
-      struct inode *emd_dir = umsdos_emd_dir_lookup (dir,1);
-      ret = emd_dir != NULL;
-      /* iput (emd_dir); FIXME */
-      
-      dir->i_op = ret
-	? &umsdos_dir_inode_operations
-	: &umsdos_rdir_inode_operations;
-    }else{
-      struct umsdos_ioctl data;
-      copy_from_user (&data,idata,sizeof(data));
-      if (cmd == UMSDOS_CREAT_EMD){
-	/* #Specification: ioctl / UMSDOS_CREAT_EMD
-	   The umsdos_dirent field of the struct umsdos_ioctl is used
-	   as is to create a new entry in the EMD of the directory.
-	   The DOS directory is not modified.
-	   No validation is done (yet).
-	   
-	   Return 0 if success.
-	*/
-	struct umsdos_info info;
-	/* This makes sure info.entry and info in general is correctly */
-	/* initialised */
-	memcpy (&info.entry,&data.umsdos_dirent
-		,sizeof(data.umsdos_dirent));
-	umsdos_parse (data.umsdos_dirent.name
-		      ,data.umsdos_dirent.name_len,&info);
-	ret = umsdos_newentry (dir,&info);
-      }else if (cmd == UMSDOS_RENAME_DOS){
-	struct dentry *old_dentry,*new_dentry; /* FIXME */
-	/* #Specification: ioctl / UMSDOS_RENAME_DOS
-	   A file or directory is rename in a DOS directory
-	   (not moved across directory). The source name
-	   is in the dos_dirent.name field and the destination
-	   is in umsdos_dirent.name field.
-	   
-	   This ioctl allows umssync to rename a mangle file
-	   name before syncing it back in the EMD.
-	*/
-	dir->i_count+=2;
-	/*
-	  ret = msdos_rename (dir
-	  ,data.dos_dirent.d_name,data.dos_dirent.d_reclen
-	  ,dir
-	  ,data.umsdos_dirent.name,data.umsdos_dirent.name_len);
-	*/
-	old_dentry = creat_dentry (data.dos_dirent.d_name, data.dos_dirent.d_reclen, NULL, NULL);	/* FIXME: prolly should fill inode part */
-	new_dentry = creat_dentry (data.umsdos_dirent.name, data.umsdos_dirent.name_len, NULL, NULL);
-	ret = msdos_rename(dir,old_dentry,dir,new_dentry);
-      }else if (cmd == UMSDOS_UNLINK_EMD){
-       /* #Specification: ioctl / UMSDOS_UNLINK_EMD
-	  The umsdos_dirent field of the struct umsdos_ioctl is used
-	  as is to remove an entry from the EMD of the directory.
-	  No validation is done (yet). The mode field is used
-	  to validate S_ISDIR or S_ISREG.
-	  
-	  Return 0 if success.
-       */
-	struct umsdos_info info;
-       /* This makes sure info.entry and info in general is correctly */
-       /* initialised */
-	memcpy (&info.entry,&data.umsdos_dirent
-		,sizeof(data.umsdos_dirent));
-	umsdos_parse (data.umsdos_dirent.name
-		      ,data.umsdos_dirent.name_len,&info);
-	ret = umsdos_delentry (dir,&info
-			       ,S_ISDIR(data.umsdos_dirent.mode));
-      }else if (cmd == UMSDOS_UNLINK_DOS){
-	struct dentry *dentry; /* FIXME */
-	/* #Specification: ioctl / UMSDOS_UNLINK_DOS
-	   The dos_dirent field of the struct umsdos_ioctl is used to
-	   execute a msdos_unlink operation. The d_name and d_reclen
-	   fields are used.
-	   
-	   Return 0 if success.
-	*/
-	dir->i_count++;
-	/*
-	  ret = msdos_unlink (dir,data.dos_dirent.d_name,data.dos_dirent.d_reclen);
-	*/
-	ret = msdos_unlink(dir,dentry);
-      }else if (cmd == UMSDOS_RMDIR_DOS){
-	struct dentry *dentry; /* FIXME */
-	/* #Specification: ioctl / UMSDOS_RMDIR_DOS
-	   The dos_dirent field of the struct umsdos_ioctl is used to
-	   execute a msdos_unlink operation. The d_name and d_reclen
-	   fields are used.
-	   
-	   Return 0 if success.
-	*/
-	dir->i_count++;
+	/* forward non-umsdos ioctls - this hopefully doesn't cause conflicts */
+	if (cmd != UMSDOS_GETVERSION
+	    && cmd != UMSDOS_READDIR_DOS
+	    && cmd != UMSDOS_READDIR_EMD
+	    && cmd != UMSDOS_INIT_EMD
+	    && cmd != UMSDOS_CREAT_EMD
+	    && cmd != UMSDOS_RENAME_DOS
+	    && cmd != UMSDOS_UNLINK_EMD
+	    && cmd != UMSDOS_UNLINK_DOS
+	    && cmd != UMSDOS_RMDIR_DOS
+	    && cmd != UMSDOS_STAT_DOS
+	    && cmd != UMSDOS_DOS_SETUP)
+		return fat_dir_ioctl (dir, filp, cmd, data);
+
+	/* #Specification: ioctl / acces
+	 * Only root (effective id) is allowed to do IOCTL on directory
+	 * in UMSDOS. EPERM is returned for other user.
+	 */
 	/*
-	  ret = msdos_rmdir (dir,data.dos_dirent.d_name
-	  ,data.dos_dirent.d_reclen);
-	*/
-	ret = msdos_rmdir(dir,dentry);
-      }else if (cmd == UMSDOS_STAT_DOS){
-       /* #Specification: ioctl / UMSDOS_STAT_DOS
-	  The dos_dirent field of the struct umsdos_ioctl is
-	  used to execute a stat operation in the DOS directory.
-	  The d_name and d_reclen fields are used.
-	  
-	  The following field of umsdos_ioctl.stat are filled.
-	  
-	  st_ino,st_mode,st_size,st_atime,st_mtime,st_ctime,
-	  Return 0 if success.
-       */
-	struct inode *inode;
-
-	  ret = compat_umsdos_real_lookup (dir, data.dos_dirent.d_name, data.dos_dirent.d_reclen, &inode);
-	if (ret == 0){
-	  data.stat.st_ino = inode->i_ino;
-	  data.stat.st_mode = inode->i_mode;
-	  data.stat.st_size = inode->i_size;
-	  data.stat.st_atime = inode->i_atime;
-	  data.stat.st_ctime = inode->i_ctime;
-	  data.stat.st_mtime = inode->i_mtime;
-	  copy_to_user (&idata->stat,&data.stat,sizeof(data.stat));
-	  /* iput (inode); FIXME */
-	}
-      }else if (cmd == UMSDOS_DOS_SETUP){
-      /* #Specification: ioctl / UMSDOS_DOS_SETUP
-	 The UMSDOS_DOS_SETUP ioctl allow changing the
-	 default permission of the MsDOS file system driver
-	 on the fly. The MsDOS driver apply global permission
-	 to every file and directory. Normally these permissions
-	 are controlled by a mount option. This is not
-	 available for root partition, so a special utility
-	 (umssetup) is provided to do this, normally in
-	 /etc/rc.local.
-	 
-	 Be aware that this apply ONLY to MsDOS directory
-	 (those without EMD --linux-.---). Umsdos directory
-	 have independent (standard) permission for each
-	 and every file.
-	 
-	 The field umsdos_dirent provide the information needed.
-	 umsdos_dirent.uid and gid sets the owner and group.
-	 umsdos_dirent.mode set the permissions flags.
-      */
-	dir->i_sb->u.msdos_sb.options.fs_uid = data.umsdos_dirent.uid;
-	dir->i_sb->u.msdos_sb.options.fs_gid = data.umsdos_dirent.gid;
-	dir->i_sb->u.msdos_sb.options.fs_umask = data.umsdos_dirent.mode;
-	ret = 0;
-      }
-    }
-  }
-  Printk (("ioctl return %d\n",ret));
-  return ret;
-}
+	 * Well, not all cases require write access, but it simplifies
+	 * the code, and let's face it, there is only one client (umssync)
+	 * for all this.
+	 */
+	if ((err = verify_area (VERIFY_WRITE, (void *) data, sizeof (struct umsdos_ioctl))) < 0) {
+		ret = err;
+	} else if (current->euid == 0
+		   || cmd == UMSDOS_GETVERSION) {
+		struct umsdos_ioctl *idata = (struct umsdos_ioctl *) data;
+
+		ret = -EINVAL;
+		/* #Specification: ioctl / prototypes
+		 * The official prototype for the umsdos ioctl on directory
+		 * is:
+		 * 
+		 * int ioctl (
+		 * int fd,          // File handle of the directory
+		 * int cmd, // command
+		 * struct umsdos_ioctl *data)
+		 * 
+		 * The struct and the commands are defined in linux/umsdos_fs.h.
+		 * 
+		 * umsdos_progs/umsdosio.c provide an interface in C++ to all
+		 * these ioctl. umsdos_progs/udosctl is a small utility showing
+		 * all this.
+		 * 
+		 * These ioctl generally allow one to work on the EMD or the
+		 * DOS directory independently. These are essential to implement
+		 * the synchronise.
+		 */
+		Printk (("ioctl %d ", cmd));
+		if (cmd == UMSDOS_GETVERSION) {
+			/* #Specification: ioctl / UMSDOS_GETVERSION
+			 * The field version and release of the structure
+			 * umsdos_ioctl are filled with the version and release
+			 * number of the fs code in the kernel. This will allow
+			 * some form of checking. Users won't be able to run
+			 * incompatible utility such as the synchroniser (umssync).
+			 * umsdos_progs/umsdosio.c enforce this checking.
+			 * 
+			 * Return always 0.
+			 */
+			put_user (UMSDOS_VERSION, &idata->version);
+			put_user (UMSDOS_RELEASE, &idata->release);
+			ret = 0;
+		} else if (cmd == UMSDOS_READDIR_DOS) {
+			/* #Specification: ioctl / UMSDOS_READDIR_DOS
+			 * One entry is read from the DOS directory at the current
+			 * file position. The entry is put as is in the dos_dirent
+			 * field of struct umsdos_ioctl.
+			 * 
+			 * Return > 0 if success.
+			 */
+			struct UMSDOS_DIR_ONCE bufk;
+
+			bufk.count = 0;
+			bufk.ent = &idata->dos_dirent;
 
+			fat_readdir (filp, &bufk, umsdos_ioctl_fill);
 
+			ret = bufk.count == 1 ? 1 : 0;
+		} else if (cmd == UMSDOS_READDIR_EMD) {
+			/* #Specification: ioctl / UMSDOS_READDIR_EMD
+			 * One entry is read from the EMD at the current
+			 * file position. The entry is put as is in the umsdos_dirent
+			 * field of struct umsdos_ioctl. The corresponding mangled
+			 * DOS entry name is put in the dos_dirent field.
+			 * 
+			 * All entries are read including hidden links. Blank
+			 * entries are skipped.
+			 * 
+			 * Return > 0 if success.
+			 */
+			struct inode *emd_dir = umsdos_emd_dir_lookup (dir, 0);
 
+			if (emd_dir != NULL) {
+				while (1) {
+					if (filp->f_pos >= emd_dir->i_size) {
+						ret = 0;
+						break;
+					} else {
+						struct umsdos_dirent entry;
+						off_t f_pos = filp->f_pos;
+
+						ret = umsdos_emd_dir_readentry (emd_dir, filp, &entry);
+						if (ret < 0) {
+							break;
+						} else if (entry.name_len > 0) {
+							struct umsdos_info info;
+
+							ret = entry.name_len;
+							umsdos_parse (entry.name, entry.name_len, &info);
+							info.f_pos = f_pos;
+							umsdos_manglename (&info);
+							copy_to_user (&idata->umsdos_dirent, &entry
+							,sizeof (entry));
+							copy_to_user (&idata->dos_dirent.d_name
+								      ,info.fake.fname, info.fake.len + 1);
+							break;
+						}
+					}
+				}
+				iput (emd_dir); /* FIXME? */
+			} else {
+				/* The absence of the EMD is simply seen as an EOF */
+				ret = 0;
+			}
+		} else if (cmd == UMSDOS_INIT_EMD) {
+			/* #Specification: ioctl / UMSDOS_INIT_EMD
+			 * The UMSDOS_INIT_EMD command make sure the EMD
+			 * exist for a directory. If it does not, it is
+			 * created. Also, it makes sure the directory functions
+			 * table (struct inode_operations) is set to the UMSDOS
+			 * semantic. This mean that umssync may be applied to
+			 * an "opened" msdos directory, and it will change behavior
+			 * on the fly.
+			 * 
+			 * Return 0 if success.
+			 */
+			extern struct inode_operations umsdos_rdir_inode_operations;
+			struct inode *emd_dir = umsdos_emd_dir_lookup (dir, 1);
+
+			ret = emd_dir != NULL;
+			iput (emd_dir); /* FIXME?? */
+
+			dir->i_op = ret
+			    ? &umsdos_dir_inode_operations
+			    : &umsdos_rdir_inode_operations;
+		} else {
+			struct umsdos_ioctl data;
+
+			copy_from_user (&data, idata, sizeof (data));
+			if (cmd == UMSDOS_CREAT_EMD) {
+				/* #Specification: ioctl / UMSDOS_CREAT_EMD
+				 * The umsdos_dirent field of the struct umsdos_ioctl is used
+				 * as is to create a new entry in the EMD of the directory.
+				 * The DOS directory is not modified.
+				 * No validation is done (yet).
+				 * 
+				 * Return 0 if success.
+				 */
+				struct umsdos_info info;
+
+				/* This makes sure info.entry and info in general is correctly */
+				/* initialised */
+				memcpy (&info.entry, &data.umsdos_dirent
+					,sizeof (data.umsdos_dirent));
+				umsdos_parse (data.umsdos_dirent.name
+				    ,data.umsdos_dirent.name_len, &info);
+				ret = umsdos_newentry (dir, &info);
+			} else if (cmd == UMSDOS_RENAME_DOS) {
+				struct dentry *old_dentry, *new_dentry;		/* FIXME */
+
+				/* #Specification: ioctl / UMSDOS_RENAME_DOS
+				 * A file or directory is rename in a DOS directory
+				 * (not moved across directory). The source name
+				 * is in the dos_dirent.name field and the destination
+				 * is in umsdos_dirent.name field.
+				 * 
+				 * This ioctl allows umssync to rename a mangle file
+				 * name before syncing it back in the EMD.
+				 */
+				inc_count (dir);
+				inc_count (dir);
+				/*
+				 * ret = msdos_rename (dir
+				 * ,data.dos_dirent.d_name,data.dos_dirent.d_reclen
+				 * ,dir
+				 * ,data.umsdos_dirent.name,data.umsdos_dirent.name_len);
+				 */
+				old_dentry = creat_dentry (data.dos_dirent.d_name, data.dos_dirent.d_reclen, NULL, geti_dentry (dir));	/* FIXME: prolly should fill inode part */
+				new_dentry = creat_dentry (data.umsdos_dirent.name, data.umsdos_dirent.name_len, NULL, geti_dentry (dir));
+				ret = msdos_rename (dir, old_dentry, dir, new_dentry);
+			} else if (cmd == UMSDOS_UNLINK_EMD) {
+				/* #Specification: ioctl / UMSDOS_UNLINK_EMD
+				 * The umsdos_dirent field of the struct umsdos_ioctl is used
+				 * as is to remove an entry from the EMD of the directory.
+				 * No validation is done (yet). The mode field is used
+				 * to validate S_ISDIR or S_ISREG.
+				 * 
+				 * Return 0 if success.
+				 */
+				struct umsdos_info info;
+
+				/* This makes sure info.entry and info in general is correctly */
+				/* initialised */
+				memcpy (&info.entry, &data.umsdos_dirent
+					,sizeof (data.umsdos_dirent));
+				umsdos_parse (data.umsdos_dirent.name
+				    ,data.umsdos_dirent.name_len, &info);
+				ret = umsdos_delentry (dir, &info
+				     ,S_ISDIR (data.umsdos_dirent.mode));
+			} else if (cmd == UMSDOS_UNLINK_DOS) {
+				struct dentry *dentry, *dp;
+
+				/* #Specification: ioctl / UMSDOS_UNLINK_DOS
+				 * The dos_dirent field of the struct umsdos_ioctl is used to
+				 * execute a msdos_unlink operation. The d_name and d_reclen
+				 * fields are used.
+				 * 
+				 * Return 0 if success.
+				 */
+				inc_count (dir);
+				dp = creat_dentry (data.dos_dirent.d_name, data.dos_dirent.d_reclen, dir, NULL);
+				dentry = creat_dentry ("ioctl_unlink", 12, NULL, dp);
+				ret = msdos_unlink (dir, dentry);
+
+			} else if (cmd == UMSDOS_RMDIR_DOS) {
+				struct dentry *dentry, *dp;
+
+				/* #Specification: ioctl / UMSDOS_RMDIR_DOS
+				 * The dos_dirent field of the struct umsdos_ioctl is used to
+				 * execute a msdos_unlink operation. The d_name and d_reclen
+				 * fields are used.
+				 * 
+				 * Return 0 if success.
+				 */
+				inc_count (dir);
+				dp = creat_dentry (data.dos_dirent.d_name, data.dos_dirent.d_reclen, dir, NULL);
+				dentry = creat_dentry ("ioctl_unlink", 12, NULL, dp);
+				ret = msdos_rmdir (dir, dentry);
+
+			} else if (cmd == UMSDOS_STAT_DOS) {
+				/* #Specification: ioctl / UMSDOS_STAT_DOS
+				 * The dos_dirent field of the struct umsdos_ioctl is
+				 * used to execute a stat operation in the DOS directory.
+				 * The d_name and d_reclen fields are used.
+				 * 
+				 * The following field of umsdos_ioctl.stat are filled.
+				 * 
+				 * st_ino,st_mode,st_size,st_atime,st_mtime,st_ctime,
+				 * Return 0 if success.
+				 */
+				struct inode *inode;
+
+				ret = compat_umsdos_real_lookup (dir, data.dos_dirent.d_name, data.dos_dirent.d_reclen, &inode);
+				if (ret == 0) {
+					data.stat.st_ino = inode->i_ino;
+					data.stat.st_mode = inode->i_mode;
+					data.stat.st_size = inode->i_size;
+					data.stat.st_atime = inode->i_atime;
+					data.stat.st_ctime = inode->i_ctime;
+					data.stat.st_mtime = inode->i_mtime;
+					copy_to_user (&idata->stat, &data.stat, sizeof (data.stat));
+					/* iput (inode); FIXME */
+				}
+			} else if (cmd == UMSDOS_DOS_SETUP) {
+				/* #Specification: ioctl / UMSDOS_DOS_SETUP
+				 * The UMSDOS_DOS_SETUP ioctl allow changing the
+				 * default permission of the MsDOS file system driver
+				 * on the fly. The MsDOS driver apply global permission
+				 * to every file and directory. Normally these permissions
+				 * are controlled by a mount option. This is not
+				 * available for root partition, so a special utility
+				 * (umssetup) is provided to do this, normally in
+				 * /etc/rc.local.
+				 * 
+				 * Be aware that this apply ONLY to MsDOS directory
+				 * (those without EMD --linux-.---). Umsdos directory
+				 * have independent (standard) permission for each
+				 * and every file.
+				 * 
+				 * The field umsdos_dirent provide the information needed.
+				 * umsdos_dirent.uid and gid sets the owner and group.
+				 * umsdos_dirent.mode set the permissions flags.
+				 */
+				dir->i_sb->u.msdos_sb.options.fs_uid = data.umsdos_dirent.uid;
+				dir->i_sb->u.msdos_sb.options.fs_gid = data.umsdos_dirent.gid;
+				dir->i_sb->u.msdos_sb.options.fs_umask = data.umsdos_dirent.mode;
+				ret = 0;
+			}
+		}
+	}
+	Printk (("ioctl return %d\n", ret));
+	return ret;
+}
diff -u --recursive --new-file v2.1.102/linux/fs/umsdos/mangle.c linux/fs/umsdos/mangle.c
--- v2.1.102/linux/fs/umsdos/mangle.c	Tue Feb 17 13:12:48 1998
+++ linux/fs/umsdos/mangle.c	Tue May 19 15:06:49 1998
@@ -1,7 +1,7 @@
 /*
  *  linux/fs/umsdos/mangle.c
  *
- *	Written 1993 by Jacques Gelinas 
+ *      Written 1993 by Jacques Gelinas 
  *
  * Control the mangling of file name to fit msdos name space.
  * Many optimisation by GLU == dglaude@is1.vub.ac.be (GLAUDE DAVID)
@@ -13,474 +13,507 @@
 #include <linux/umsdos_fs.h>
 
 /*
-  Complete the mangling of the MSDOS fake name
-  based on the position of the entry in the EMD file.
-
-  Simply complete the job of umsdos_parse; fill the extension.
-
-  Beware that info->f_pos must be set.
-*/
+ * Complete the mangling of the MSDOS fake name
+ * based on the position of the entry in the EMD file.
+ * 
+ * Simply complete the job of umsdos_parse; fill the extension.
+ * 
+ * Beware that info->f_pos must be set.
+ */
 void umsdos_manglename (struct umsdos_info *info)
 {
-  if (info->msdos_reject){
-    /* #Specification: file name / non MSDOS conforming / mangling
-       Each non MSDOS conforming file has a special extension
-       build from the entry position in the EMD file.
-
-       This number is then transform in a base 32 number, where
-       each digit is expressed like hexadecimal number, using
-       digit and letter, except it uses 22 letters from 'a' to 'v'.
-       The number 32 comes from 2**5. It is faster to split a binary
-       number using a base which is a power of two. And I was 32
-       when I started this project. Pick your answer :-) .
-
-       If the result is '0', it is replace with '_', simply
-       to make it odd.
-
-       This is true for the first two character of the extension.
-       The last one is taken from a list of odd character, which
-       are:
-
-       { } ( ) ! ` ^ & @
-       
-       With this scheme, we can produce 9216 ( 9* 32 * 32)
-       different extensions which should not clash with any useful
-       extension already popular or meaningful. Since most directory
-       have much less than 32 * 32 files in it, the first character
-       of the extension of any mangle name will be {.
-       
-       Here are the reason to do this (this kind of mangling).
-       
-       -The mangling is deterministic. Just by the extension, we
-       are able to locate the entry in the EMD file.
-
-       -By keeping to beginning of the file name almost unchanged,
-       we are helping the MSDOS user.
-       
-       -The mangling produces names not too ugly, so an msdos user
-       may live with it (remember it, type it, etc...).
-       
-       -The mangling produces names ugly enough so no one will
-       ever think of using such a name in real life. This is not
-       fool proof. I don't think there is a total solution to this.
-    */
-    union {
-      int entry_num;
-      struct {
-	unsigned num1:5,num2:5,num3:5;
-      }num;
-    } u;
-    char *pt = info->fake.fname + info->fake.len;
-    /* lookup for encoding the last character of the extension */
-    /* It contain valid character after the ugly one to make sure */
-    /* even if someone overflow the 32 * 32 * 9 limit, it still do */
-    /* something */
+	if (info->msdos_reject) {
+		/* #Specification: file name / non MSDOS conforming / mangling
+		 * Each non MSDOS conforming file has a special extension
+		 * build from the entry position in the EMD file.
+		 * 
+		 * This number is then transform in a base 32 number, where
+		 * each digit is expressed like hexadecimal number, using
+		 * digit and letter, except it uses 22 letters from 'a' to 'v'.
+		 * The number 32 comes from 2**5. It is faster to split a binary
+		 * number using a base which is a power of two. And I was 32
+		 * when I started this project. Pick your answer :-) .
+		 * 
+		 * If the result is '0', it is replace with '_', simply
+		 * to make it odd.
+		 * 
+		 * This is true for the first two character of the extension.
+		 * The last one is taken from a list of odd character, which
+		 * are:
+		 * 
+		 * { } ( ) ! ` ^ & @
+		 * 
+		 * With this scheme, we can produce 9216 ( 9* 32 * 32)
+		 * different extensions which should not clash with any useful
+		 * extension already popular or meaningful. Since most directory
+		 * have much less than 32 * 32 files in it, the first character
+		 * of the extension of any mangle name will be {.
+		 * 
+		 * Here are the reason to do this (this kind of mangling).
+		 * 
+		 * -The mangling is deterministic. Just by the extension, we
+		 * are able to locate the entry in the EMD file.
+		 * 
+		 * -By keeping to beginning of the file name almost unchanged,
+		 * we are helping the MSDOS user.
+		 * 
+		 * -The mangling produces names not too ugly, so an msdos user
+		 * may live with it (remember it, type it, etc...).
+		 * 
+		 * -The mangling produces names ugly enough so no one will
+		 * ever think of using such a name in real life. This is not
+		 * fool proof. I don't think there is a total solution to this.
+		 */
+		union {
+			int entry_num;
+			struct {
+				unsigned num1:5, num2:5, num3:5;
+			} num;
+		} u;
+		char *pt = info->fake.fname + info->fake.len;
+
+		/* lookup for encoding the last character of the extension */
+		/* It contain valid character after the ugly one to make sure */
+		/* even if someone overflow the 32 * 32 * 9 limit, it still do */
+		/* something */
 #define SPECIAL_MANGLING '{','}','(',')','!','`','^','&','@'
-    static char lookup3[]={
-      SPECIAL_MANGLING,
-      /* This is the start of lookup12 */
-      '_','1','2','3','4','5','6','7','8','9',
-      'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
-      'p','q','r','s','t','u','v' 
-    };
+		static char lookup3[] =
+		{
+			SPECIAL_MANGLING,
+		/* This is the start of lookup12 */
+			'_', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+			'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+			'p', 'q', 'r', 's', 't', 'u', 'v'
+		};
+
 #define lookup12 (lookup3+9)
-    u.entry_num = info->f_pos / UMSDOS_REC_SIZE;
-    if (u.entry_num > (9* 32 * 32)){
-      printk ("UMSDOS: More than 9216 file in a directory.\n"
-	      "This may break the mangling strategy.\n"
-	      "Not a killer problem. See doc.\n");
-    }
-    *pt++ = '.';
-    *pt++ = lookup3 [u.num.num3];
-    *pt++ = lookup12[u.num.num2];
-    *pt++ = lookup12[u.num.num1];
-    *pt = '\0';		/* help doing printk */	
-    info->fake.len += 4;
-    info->msdos_reject = 0;		/* Avoid mangling twice */
-  }
+		u.entry_num = info->f_pos / UMSDOS_REC_SIZE;
+		if (u.entry_num > (9 * 32 * 32)) {
+			printk ("UMSDOS: More than 9216 file in a directory.\n"
+				"This may break the mangling strategy.\n"
+				"Not a killer problem. See doc.\n");
+		}
+		*pt++ = '.';
+		*pt++ = lookup3[u.num.num3];
+		*pt++ = lookup12[u.num.num2];
+		*pt++ = lookup12[u.num.num1];
+		*pt = '\0';	/* help doing printk */
+		info->fake.len += 4;
+		info->msdos_reject = 0;		/* Avoid mangling twice */
+	}
 }
 
 /*
-  Evaluate the record size needed to store of name of len character.
-  The value returned is a multiple of UMSDOS_REC_SIZE.
-*/
+ * Evaluate the record size needed to store of name of len character.
+ * The value returned is a multiple of UMSDOS_REC_SIZE.
+ */
 int umsdos_evalrecsize (int len)
 {
-  struct umsdos_dirent dirent;
-  int nbrec = 1+((len-1+(dirent.name-(char*)&dirent))
-		 / UMSDOS_REC_SIZE);
-  return nbrec * UMSDOS_REC_SIZE;
-  /*
-    GLU	This should be inlined or something to speed it up to the max.
-    GLU	nbrec is absolutely not needed to return the value.
-  */
+	struct umsdos_dirent dirent;
+	int nbrec = 1 + ((len - 1 + (dirent.name - (char *) &dirent))
+			 / UMSDOS_REC_SIZE);
+
+	return nbrec * UMSDOS_REC_SIZE;
+	/*
+	 * GLU        This should be inlined or something to speed it up to the max.
+	 * GLU        nbrec is absolutely not needed to return the value.
+	 */
 }
 #ifdef TEST
 int umsdos_evalrecsize_old (int len)
 {
-  struct umsdos_dirent dirent;
-  int size = len + (dirent.name-(char*)&dirent);
-  int nbrec = size / UMSDOS_REC_SIZE;
-  int extra = size % UMSDOS_REC_SIZE;
-  if (extra > 0) nbrec++;
-  return nbrec * UMSDOS_REC_SIZE;
+	struct umsdos_dirent dirent;
+	int size = len + (dirent.name - (char *) &dirent);
+	int nbrec = size / UMSDOS_REC_SIZE;
+	int extra = size % UMSDOS_REC_SIZE;
+
+	if (extra > 0)
+		nbrec++;
+	return nbrec * UMSDOS_REC_SIZE;
 }
 #endif
 
 
 /*
-  Fill the struct info with the full and msdos name of a file
-  Return 0 if all is ok, a negative error code otherwise.
-*/
+ * Fill the struct info with the full and msdos name of a file
+ * Return 0 if all is ok, a negative error code otherwise.
+ */
 int umsdos_parse (
-		  const char *fname,
-		  int len,
-		  struct umsdos_info *info)
+			 const char *fname,
+			 int len,
+			 struct umsdos_info *info)
 {
-  int ret = -ENAMETOOLONG;
-  /* #Specification: file name / too long
-     If a file name exceed UMSDOS maxima, the file name is silently
-     truncated. This makes it conformant with the other file system
-     of Linux (minix and ext2 at least).
-  */
-  if (len > UMSDOS_MAXNAME) len = UMSDOS_MAXNAME;
-  {
-    const char *firstpt=NULL;	/* First place we saw a . in fname */
-    /* #Specification: file name / non MSDOS conforming / base length 0
-       file name beginning with a period '.' are invalid for MsDOS.
-       It needs absolutely a base name. So the file name is mangled
-    */
-    int ivldchar = fname[0] == '.';/* At least one invalid character */
-    int msdos_len = len;
-    int base_len;
-    /*
-      cardinal_per_size tells if there exist at least one
-      DOS pseudo devices on length n. See the test below.
-    */
-    static const char cardinal_per_size[9]={
-      0, 0, 0, 1, 1, 0, 1, 0, 1
-    };
-    /*
-      lkp translate all character to acceptable character (for DOS).
-      When lkp[n] == n, it means also it is an acceptable one.
-      So it serve both as a flag and as a translator.
-    */
-    static char lkp[256];
-    static char is_init=0;
-    if (!is_init){
-      /*
-	Initialisation of the array is easier and less error prone
-	like this.
-      */
-      int i;
-      static const char *spc = "\"*+,/:;<=>?[\\]|~";
-      is_init = 1;
-      for (i=0; i<=32; i++) lkp[i] = '#';
-      for (i=33; i<'A'; i++) lkp[i] = (char)i;
-      for (i='A'; i<='Z'; i++) lkp[i] = (char)(i+('a'-'A'));
-      for (i='Z'+1; i<127; i++) lkp[i] = (char)i;
-      for (i=128; i<256; i++) lkp[i] = '#';
-      
-      lkp['.'] = '_';
-      while (*spc != '\0') lkp[(unsigned char)(*spc++)] = '#';
-    }
-    /*	GLU
-	file name which are longer than 8+'.'+3 are invalid for MsDOS.
-	So the file name is to be mangled no more test needed.
-	This Speed Up for long and very long name.
-	The position of the last point is no more necessary anyway.
-    */
-    if (len<=(8+1+3)){
-      const char *pt = fname;
-      const char *endpt = fname + len;
-      while (pt < endpt){
-	if (*pt == '.'){
-	  if (firstpt != NULL){
-	    /* 2 . in a file name. Reject */
-	    ivldchar = 1;
-	    break;
-	  }else{
-	    int extlen = (int)(endpt - pt);
-	    firstpt = pt;
-	    if (firstpt - fname > 8){
-	      /* base name longer than 8: reject */
-	      ivldchar = 1;
-	      break;
-	    }else if (extlen > 4){
-	      /* Extension longer than 4 (including .): reject */
-	      ivldchar = 1;
-	      break;
-	    }else if (extlen == 1){
-	      /* #Specification: file name / non MSDOS conforming / last char == .
-		 If the last character of a file name is
-		 a period, mangling is applied. MsDOS do
-		 not support those file name.
-	      */
-	      ivldchar = 1;
-	      break;
-	    }else if (extlen == 4){
-	      /* #Specification: file name / non MSDOS conforming / mangling clash
-		 To avoid clash with	the umsdos mangling, any file
-		 with a special character as the first character
-		 of the extension will be mangled. This solve the
-		 following problem:
-		 
-		 #
-		 touch FILE
-		 # FILE is invalid for DOS, so mangling is applied
-		 # file.{_1 is created in the DOS directory
-		 touch file.{_1
-		 # To UMSDOS file point to a single DOS entry.
-		 # So file.{_1 has to be mangled.
-		 #
-	      */	
-	      static char special[]={
-		SPECIAL_MANGLING,'\0'
-	      };
-	      if (strchr(special,firstpt[1])!= NULL){
-		ivldchar = 1;
-		break;
-	      }
-	    }
-	  }
-	}else if (lkp[(unsigned char)(*pt)] != *pt){
-	  ivldchar = 1;
-	  break;
-	}
-	pt++;
-      }
-    }else{
-      ivldchar = 1;
-    }
-    if (ivldchar
-	|| (firstpt == NULL && len > 8)
-	|| (len == UMSDOS_EMD_NAMELEN
-	    && memcmp(fname,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN)==0)){
-      /* #Specification: file name / --linux-.---
-	 The name of the EMD file --linux-.--- is map to a mangled
-	 name. So UMSDOS does not restrict its use.
-      */
-      /* #Specification: file name / non MSDOS conforming / mangling
-	 Non MSDOS conforming file name must use some alias to fit
-	 in the MSDOS name space.
-	 
-	 The strategy is simple. The name is simply truncated to
-	 8 char. points are replace with underscore and a
-	 number is given as an extension. This number correspond
-	 to the entry number in the EMD file. The EMD file
-	 only need to carry the real name.
-	 
-	 Upper case is also convert to lower case.
-	 Control character are converted to #.
-	 Space are converted to #.
-	 The following character are also converted to #.
-	 #
-	 " * + , / : ; < = > ? [ \ ] | ~
-	 #
-	 
-	 Sometime, the problem is not in MsDOS itself but in
-	 command.com.
-      */
-      int i;
-      char *pt = info->fake.fname;
-      base_len = msdos_len = (msdos_len>8) ? 8 : msdos_len;
-      /*
-	There is no '.' any more so we know for a fact that
-	the base length is the length.
-      */
-      memcpy (info->fake.fname,fname,msdos_len);
-      for (i=0; i<msdos_len; i++, pt++) *pt = lkp[(unsigned char)(*pt)];
-      *pt = '\0';	/* GLU	C'est sur on a un 0 a la fin */
-      info->msdos_reject = 1;
-      /*
-	The numeric extension is added only when we know
-	the position in the EMD file, in umsdos_newentry(),
-	umsdos_delentry(), and umsdos_findentry().
-	See umsdos_manglename().
-      */
-    }else{
-      /* Conforming MSDOS file name */
-      strncpy (info->fake.fname,fname,len);
-      info->msdos_reject = 0;
-      base_len = firstpt != NULL ? (int)(firstpt - fname) : len;
-    }
-    if (cardinal_per_size[base_len]){
-      /* #Specification: file name / MSDOS devices / mangling
-	 To avoid unreachable file from MsDOS, any MsDOS conforming
-	 file with a basename equal to one of the MsDOS pseudo
-	 devices will be mangled.
-	 
-	 If a file such as "prn" was created, it would be unreachable
-	 under MsDOS because prn is assumed to be the printer, even
-	 if the file does have an extension.
-	 
-	 Since the extension is unimportant to MsDOS, we must patch
-	 the basename also. We simply insert a minus '-'. To avoid
-	 conflict with valid file with a minus in front (such as
-	 "-prn"), we add an mangled extension like any other
-	 mangled file name.
-	 
-	 Here is the list of DOS pseudo devices:
-	 
-	 #
-	 "prn","con","aux","nul",
-	 "lpt1","lpt2","lpt3","lpt4",
-	 "com1","com2","com3","com4",
-	 "clock$"
-	 #
-	 
-	 and some standard ones for common DOS programs
-	 
-	 "emmxxxx0","xmsxxxx0","setverxx"
-	 
-	 (Thanks to Chris Hall <CAH17@PHOENIX.CAMBRIDGE.AC.UK>
-	 for pointing these to me).
-	 
-	 Is there one missing ?
-      */
-      /* This table must be ordered by length */
-      static const char *tbdev[]={
-	"prn","con","aux","nul",
-	"lpt1","lpt2","lpt3","lpt4",
-	"com1","com2","com3","com4",
-	"clock$",
-	"emmxxxx0","xmsxxxx0","setverxx"
-      };
-      /* Tell where to find in tbdev[], the first name of */
-      /* a certain length */
-      static const char start_ind_dev[9]={
-	0, 0, 0, 4, 12, 12, 13, 13, 16 
-      };
-      char basen[9];
-      int i;
-      for (i=start_ind_dev[base_len-1]; i<start_ind_dev[base_len]; i++){
-	if (memcmp(info->fake.fname,tbdev[i],base_len)==0){
-	  memcpy (basen,info->fake.fname,base_len);
-	  basen[base_len] = '\0';		/* GLU	C'est sur on a un 0 a la fin */
-	  /*
-	    GLU	On ne fait cela que si necessaire, on essaye d'etre le
-	    GLU	simple dans le cas general (le plus frequent).
-	  */
-	  info->fake.fname[0] = '-';
-	  strcpy (info->fake.fname+1,basen);	/* GLU	C'est sur on a un 0 a la fin */
-	  msdos_len = (base_len==8) ? 8 : base_len + 1;
-	  info->msdos_reject = 1;
-	  break;
+	int ret = -ENAMETOOLONG;
+
+	/* #Specification: file name / too long
+	 * If a file name exceed UMSDOS maxima, the file name is silently
+	 * truncated. This makes it conformant with the other file system
+	 * of Linux (minix and ext2 at least).
+	 */
+	if (len > UMSDOS_MAXNAME)
+		len = UMSDOS_MAXNAME;
+	{
+		const char *firstpt = NULL;	/* First place we saw a . in fname */
+
+		/* #Specification: file name / non MSDOS conforming / base length 0
+		 * file name beginning with a period '.' are invalid for MsDOS.
+		 * It needs absolutely a base name. So the file name is mangled
+		 */
+		int ivldchar = fname[0] == '.';		/* At least one invalid character */
+		int msdos_len = len;
+		int base_len;
+
+		/*
+		 * cardinal_per_size tells if there exist at least one
+		 * DOS pseudo devices on length n. See the test below.
+		 */
+		static const char cardinal_per_size[9] =
+		{
+			0, 0, 0, 1, 1, 0, 1, 0, 1
+		};
+
+		/*
+		 * lkp translate all character to acceptable character (for DOS).
+		 * When lkp[n] == n, it means also it is an acceptable one.
+		 * So it serve both as a flag and as a translator.
+		 */
+		static char lkp[256];
+		static char is_init = 0;
+
+		if (!is_init) {
+			/*
+			 * Initialisation of the array is easier and less error prone
+			 * like this.
+			 */
+			int i;
+			static const char *spc = "\"*+,/:;<=>?[\\]|~";
+
+			is_init = 1;
+			for (i = 0; i <= 32; i++)
+				lkp[i] = '#';
+			for (i = 33; i < 'A'; i++)
+				lkp[i] = (char) i;
+			for (i = 'A'; i <= 'Z'; i++)
+				lkp[i] = (char) (i + ('a' - 'A'));
+			for (i = 'Z' + 1; i < 127; i++)
+				lkp[i] = (char) i;
+			for (i = 128; i < 256; i++)
+				lkp[i] = '#';
+
+			lkp['.'] = '_';
+			while (*spc != '\0')
+				lkp[(unsigned char) (*spc++)] = '#';
+		}
+		/*  GLU
+		 * file name which are longer than 8+'.'+3 are invalid for MsDOS.
+		 * So the file name is to be mangled no more test needed.
+		 * This Speed Up for long and very long name.
+		 * The position of the last point is no more necessary anyway.
+		 */
+		if (len <= (8 + 1 + 3)) {
+			const char *pt = fname;
+			const char *endpt = fname + len;
+
+			while (pt < endpt) {
+				if (*pt == '.') {
+					if (firstpt != NULL) {
+						/* 2 . in a file name. Reject */
+						ivldchar = 1;
+						break;
+					} else {
+						int extlen = (int) (endpt - pt);
+
+						firstpt = pt;
+						if (firstpt - fname > 8) {
+							/* base name longer than 8: reject */
+							ivldchar = 1;
+							break;
+						} else if (extlen > 4) {
+							/* Extension longer than 4 (including .): reject */
+							ivldchar = 1;
+							break;
+						} else if (extlen == 1) {
+							/* #Specification: file name / non MSDOS conforming / last char == .
+							 * If the last character of a file name is
+							 * a period, mangling is applied. MsDOS do
+							 * not support those file name.
+							 */
+							ivldchar = 1;
+							break;
+						} else if (extlen == 4) {
+							/* #Specification: file name / non MSDOS conforming / mangling clash
+							 * To avoid clash with    the umsdos mangling, any file
+							 * with a special character as the first character
+							 * of the extension will be mangled. This solve the
+							 * following problem:
+							 * 
+							 * #
+							 * touch FILE
+							 * # FILE is invalid for DOS, so mangling is applied
+							 * # file.{_1 is created in the DOS directory
+							 * touch file.{_1
+							 * # To UMSDOS file point to a single DOS entry.
+							 * # So file.{_1 has to be mangled.
+							 * #
+							 */
+							static char special[] =
+							{
+								SPECIAL_MANGLING, '\0'
+							};
+
+							if (strchr (special, firstpt[1]) != NULL) {
+								ivldchar = 1;
+								break;
+							}
+						}
+					}
+				} else if (lkp[(unsigned char) (*pt)] != *pt) {
+					ivldchar = 1;
+					break;
+				}
+				pt++;
+			}
+		} else {
+			ivldchar = 1;
+		}
+		if (ivldchar
+		    || (firstpt == NULL && len > 8)
+		    || (len == UMSDOS_EMD_NAMELEN
+			&& memcmp (fname, UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN) == 0)) {
+			/* #Specification: file name / --linux-.---
+			 * The name of the EMD file --linux-.--- is map to a mangled
+			 * name. So UMSDOS does not restrict its use.
+			 */
+			/* #Specification: file name / non MSDOS conforming / mangling
+			 * Non MSDOS conforming file name must use some alias to fit
+			 * in the MSDOS name space.
+			 * 
+			 * The strategy is simple. The name is simply truncated to
+			 * 8 char. points are replace with underscore and a
+			 * number is given as an extension. This number correspond
+			 * to the entry number in the EMD file. The EMD file
+			 * only need to carry the real name.
+			 * 
+			 * Upper case is also convert to lower case.
+			 * Control character are converted to #.
+			 * Space are converted to #.
+			 * The following character are also converted to #.
+			 * #
+			 * " * + , / : ; < = > ? [ \ ] | ~
+			 * #
+			 * 
+			 * Sometime, the problem is not in MsDOS itself but in
+			 * command.com.
+			 */
+			int i;
+			char *pt = info->fake.fname;
+
+			base_len = msdos_len = (msdos_len > 8) ? 8 : msdos_len;
+			/*
+			 * There is no '.' any more so we know for a fact that
+			 * the base length is the length.
+			 */
+			memcpy (info->fake.fname, fname, msdos_len);
+			for (i = 0; i < msdos_len; i++, pt++)
+				*pt = lkp[(unsigned char) (*pt)];
+			*pt = '\0';	/* GLU  C'est sur on a un 0 a la fin */
+			info->msdos_reject = 1;
+			/*
+			 * The numeric extension is added only when we know
+			 * the position in the EMD file, in umsdos_newentry(),
+			 * umsdos_delentry(), and umsdos_findentry().
+			 * See umsdos_manglename().
+			 */
+		} else {
+			/* Conforming MSDOS file name */
+			strncpy (info->fake.fname, fname, len);
+			info->msdos_reject = 0;
+			base_len = firstpt != NULL ? (int) (firstpt - fname) : len;
+		}
+		if (cardinal_per_size[base_len]) {
+			/* #Specification: file name / MSDOS devices / mangling
+			 * To avoid unreachable file from MsDOS, any MsDOS conforming
+			 * file with a basename equal to one of the MsDOS pseudo
+			 * devices will be mangled.
+			 * 
+			 * If a file such as "prn" was created, it would be unreachable
+			 * under MsDOS because prn is assumed to be the printer, even
+			 * if the file does have an extension.
+			 * 
+			 * Since the extension is unimportant to MsDOS, we must patch
+			 * the basename also. We simply insert a minus '-'. To avoid
+			 * conflict with valid file with a minus in front (such as
+			 * "-prn"), we add an mangled extension like any other
+			 * mangled file name.
+			 * 
+			 * Here is the list of DOS pseudo devices:
+			 * 
+			 * #
+			 * "prn","con","aux","nul",
+			 * "lpt1","lpt2","lpt3","lpt4",
+			 * "com1","com2","com3","com4",
+			 * "clock$"
+			 * #
+			 * 
+			 * and some standard ones for common DOS programs
+			 * 
+			 * "emmxxxx0","xmsxxxx0","setverxx"
+			 * 
+			 * (Thanks to Chris Hall <CAH17@PHOENIX.CAMBRIDGE.AC.UK>
+			 * for pointing these to me).
+			 * 
+			 * Is there one missing ?
+			 */
+			/* This table must be ordered by length */
+			static const char *tbdev[] =
+			{
+				"prn", "con", "aux", "nul",
+				"lpt1", "lpt2", "lpt3", "lpt4",
+				"com1", "com2", "com3", "com4",
+				"clock$",
+				"emmxxxx0", "xmsxxxx0", "setverxx"
+			};
+
+			/* Tell where to find in tbdev[], the first name of */
+			/* a certain length */
+			static const char start_ind_dev[9] =
+			{
+				0, 0, 0, 4, 12, 12, 13, 13, 16
+			};
+			char basen[9];
+			int i;
+
+			for (i = start_ind_dev[base_len - 1]; i < start_ind_dev[base_len]; i++) {
+				if (memcmp (info->fake.fname, tbdev[i], base_len) == 0) {
+					memcpy (basen, info->fake.fname, base_len);
+					basen[base_len] = '\0';		/* GLU  C'est sur on a un 0 a la fin */
+					/*
+					 * GLU        On ne fait cela que si necessaire, on essaye d'etre le
+					 * GLU        simple dans le cas general (le plus frequent).
+					 */
+					info->fake.fname[0] = '-';
+					strcpy (info->fake.fname + 1, basen);	/* GLU  C'est sur on a un 0 a la fin */
+					msdos_len = (base_len == 8) ? 8 : base_len + 1;
+					info->msdos_reject = 1;
+					break;
+				}
+			}
+		}
+		info->fake.fname[msdos_len] = '\0';	/* Help doing printk */
+		/* GLU      Ce zero devrais deja y etre ! (invariant ?) */
+		info->fake.len = msdos_len;
+		/* Pourquoi ne pas utiliser info->fake.len partout ??? plus long ? */
+		memcpy (info->entry.name, fname, len);
+		info->entry.name_len = len;
+		ret = 0;
 	}
-      }
-    }
-    info->fake.fname[msdos_len] = '\0';	/* Help doing printk */
-    /* GLU	Ce zero devrais deja y etre ! (invariant ?) */
-    info->fake.len = msdos_len;
-    /* Pourquoi ne pas utiliser info->fake.len partout ??? plus long ?*/
-    memcpy (info->entry.name,fname,len);
-    info->entry.name_len = len;
-    ret = 0;
-  }
-  /*
-    Evaluate how many record are needed to store this entry.
-  */
-  info->recsize = umsdos_evalrecsize (len);
-  return ret;
+	/*
+	 * Evaluate how many record are needed to store this entry.
+	 */
+	info->recsize = umsdos_evalrecsize (len);
+	return ret;
 }
 
 #ifdef TEST
 
-struct MANG_TEST{
-  char *fname;		/* Name to validate */
-  int msdos_reject;	/* Expected msdos_reject flag */
-  char *msname;		/* Expected msdos name */
+struct MANG_TEST {
+	char *fname;		/* Name to validate */
+	int msdos_reject;	/* Expected msdos_reject flag */
+	char *msname;		/* Expected msdos name */
 };
 
-struct MANG_TEST tb[]={
-  "hello",		0,	"hello",
-  "hello.1",		0,	"hello.1",
-  "hello.1_",		0,	"hello.1_",
-  "prm",		0,	"prm",
-  
+struct MANG_TEST tb[] =
+{
+	"hello", 0, "hello",
+	"hello.1", 0, "hello.1",
+	"hello.1_", 0, "hello.1_",
+	"prm", 0, "prm",
+
 #ifdef PROPOSITION
-  "HELLO",		1,	"hello",
-  "Hello.1",		1,	"hello.1",
-  "Hello.c",		1,	"hello.c",
+	"HELLO", 1, "hello",
+	"Hello.1", 1, "hello.1",
+	"Hello.c", 1, "hello.c",
 #elseif
 /*
-  Je trouve les trois exemples ci-dessous tres "malheureux".
-  Je propose de mettre en minuscule dans un passe preliminaire,
-  et de tester apres si il y a d'autres caracters "mechants".
-  Bon, je ne l'ai pas fait, parceque ce n'est pas si facilement
-  modifiable que ca. Mais c'est pour le principe.
-  Evidemment cela augmente les chances de "Collision",
-  par exemple: entre "HELLO" et "Hello", mais ces problemes
-  peuvent etre traiter ailleur avec les autres collisions.
-*/
-  "HELLO",		1,	"hello",
-  "Hello.1",		1,	"hello_1",
-  "Hello.c",		1,	"hello_c",
+ * Je trouve les trois exemples ci-dessous tres "malheureux".
+ * Je propose de mettre en minuscule dans un passe preliminaire,
+ * et de tester apres si il y a d'autres caracters "mechants".
+ * Bon, je ne l'ai pas fait, parceque ce n'est pas si facilement
+ * modifiable que ca. Mais c'est pour le principe.
+ * Evidemment cela augmente les chances de "Collision",
+ * par exemple: entre "HELLO" et "Hello", mais ces problemes
+ * peuvent etre traiter ailleur avec les autres collisions.
+ */
+	"HELLO", 1, "hello",
+	"Hello.1", 1, "hello_1",
+	"Hello.c", 1, "hello_c",
 #endif
-  
-  "hello.{_1",		1,	"hello_{_",
-  "hello\t",		1,	"hello#",
-  "hello.1.1",		1,	"hello_1_",
-  "hel,lo",		1,	"hel#lo",
-  "Salut.Tu.vas.bien?",	1,	"salut_tu",
-  ".profile",		1,	"_profile",
-  ".xv",			1,	"_xv",
-  "toto.",		1,	"toto_",
-  "clock$.x",		1,	"-clock$",
-  "emmxxxx0",		1,	"-emmxxxx",
-  "emmxxxx0.abcd",	1,	"-emmxxxx",
-  "aux",			1,	"-aux",
-  "prn",			1,	"-prn",
-  "prn.abc",		1,	"-prn",
-  "PRN",			1,	"-prn",
+
+	"hello.{_1", 1, "hello_{_",
+	"hello\t", 1, "hello#",
+	"hello.1.1", 1, "hello_1_",
+	"hel,lo", 1, "hel#lo",
+	"Salut.Tu.vas.bien?", 1, "salut_tu",
+	".profile", 1, "_profile",
+	".xv", 1, "_xv",
+	"toto.", 1, "toto_",
+	"clock$.x", 1, "-clock$",
+	"emmxxxx0", 1, "-emmxxxx",
+	"emmxxxx0.abcd", 1, "-emmxxxx",
+	"aux", 1, "-aux",
+	"prn", 1, "-prn",
+	"prn.abc", 1, "-prn",
+	"PRN", 1, "-prn",
   /* 
-     GLU	ATTENTION : Le resultat de ceux-ci sont differents avec ma version
-     GLU	du mangle par rapport au mangle originale.
-     GLU	CAUSE: La maniere de calculer la variable baselen. 
-     GLU		Pour toi c'est toujours 3
-     GLU		Pour moi c'est respectivement 7, 8 et 8
-  */
-  "PRN.abc",		1,	"prn_abc",
-  "Prn.abcd",		1,	"prn_abcd",
-  "prn.abcd",		1,	"prn_abcd",
-  "Prn.abcdefghij",	1,	"prn_abcd"
+   * GLU        ATTENTION : Le resultat de ceux-ci sont differents avec ma version
+   * GLU        du mangle par rapport au mangle originale.
+   * GLU        CAUSE: La maniere de calculer la variable baselen. 
+   * GLU                Pour toi c'est toujours 3
+   * GLU                Pour moi c'est respectivement 7, 8 et 8
+   */
+	"PRN.abc", 1, "prn_abc",
+	"Prn.abcd", 1, "prn_abcd",
+	"prn.abcd", 1, "prn_abcd",
+	"Prn.abcdefghij", 1, "prn_abcd"
 };
 
 int main (int argc, char *argv[])
 {
-  int i,rold,rnew;
-  printf ("Testing the umsdos_parse.\n");
-  for (i=0; i<sizeof(tb)/sizeof(tb[0]); i++){
-    struct MANG_TEST *pttb = tb+i;
-    struct umsdos_info info;
-    int ok = umsdos_parse (pttb->fname,strlen(pttb->fname),&info);
-    if (strcmp(info.fake.fname,pttb->msname)!=0){
-      printf ("**** %s -> ",pttb->fname);
-      printf ("%s <> %s\n",info.fake.fname,pttb->msname);
-    }else if (info.msdos_reject != pttb->msdos_reject){
-      printf ("**** %s -> %s ",pttb->fname,pttb->msname);
-      printf ("%d <> %d\n",info.msdos_reject,pttb->msdos_reject);
-    }else{
-      printf ("     %s -> %s %d\n",pttb->fname,pttb->msname
-	      ,pttb->msdos_reject);
-    }
-  }
-  printf ("Testing the new umsdos_evalrecsize.");
-  for (i=0; i<UMSDOS_MAXNAME ; i++){
-    rnew=umsdos_evalrecsize (i);
-    rold=umsdos_evalrecsize_old (i);
-    if (!(i%UMSDOS_REC_SIZE)){
-      printf ("\n%d:\t",i);
-    }
-    if (rnew!=rold){
-      printf ("**** %d newres: %d != %d \n", i, rnew, rold);
-    }else{
-      printf(".");
-    }
-  }
-  printf ("\nEnd of Testing.\n");
-  
-  return 0;
+	int i, rold, rnew;
+
+	printf ("Testing the umsdos_parse.\n");
+	for (i = 0; i < sizeof (tb) / sizeof (tb[0]); i++) {
+		struct MANG_TEST *pttb = tb + i;
+		struct umsdos_info info;
+		int ok = umsdos_parse (pttb->fname, strlen (pttb->fname), &info);
+
+		if (strcmp (info.fake.fname, pttb->msname) != 0) {
+			printf ("**** %s -> ", pttb->fname);
+			printf ("%s <> %s\n", info.fake.fname, pttb->msname);
+		} else if (info.msdos_reject != pttb->msdos_reject) {
+			printf ("**** %s -> %s ", pttb->fname, pttb->msname);
+			printf ("%d <> %d\n", info.msdos_reject, pttb->msdos_reject);
+		} else {
+			printf ("     %s -> %s %d\n", pttb->fname, pttb->msname
+				,pttb->msdos_reject);
+		}
+	}
+	printf ("Testing the new umsdos_evalrecsize.");
+	for (i = 0; i < UMSDOS_MAXNAME; i++) {
+		rnew = umsdos_evalrecsize (i);
+		rold = umsdos_evalrecsize_old (i);
+		if (!(i % UMSDOS_REC_SIZE)) {
+			printf ("\n%d:\t", i);
+		}
+		if (rnew != rold) {
+			printf ("**** %d newres: %d != %d \n", i, rnew, rold);
+		} else {
+			printf (".");
+		}
+	}
+	printf ("\nEnd of Testing.\n");
+
+	return 0;
 }
 
 #endif
diff -u --recursive --new-file v2.1.102/linux/fs/umsdos/namei.c linux/fs/umsdos/namei.c
--- v2.1.102/linux/fs/umsdos/namei.c	Thu May  7 22:51:54 1998
+++ linux/fs/umsdos/namei.c	Tue May 19 15:06:50 1998
@@ -1,8 +1,8 @@
 /*
  *  linux/fs/umsdos/namei.c
  *
- *	Written 1993 by Jacques Gelinas 
- *	Inspired from linux/fs/msdos/... by Werner Almesberger
+ *      Written 1993 by Jacques Gelinas 
+ *      Inspired from linux/fs/msdos/... by Werner Almesberger
  *
  * Maintain and access the --linux alternate directory file.
  */
@@ -23,291 +23,306 @@
 
 #if 1
 /*
-	Wait for creation exclusivity.
-	Return 0 if the dir was already available.
-	Return 1 if a wait was necessary.
-		When 1 is return, it means a wait was done. It does not
-		mean the directory is available.
-*/
-static int umsdos_waitcreate(struct inode *dir)
+ * Wait for creation exclusivity.
+ * Return 0 if the dir was already available.
+ * Return 1 if a wait was necessary.
+ * When 1 is return, it means a wait was done. It does not
+ * mean the directory is available.
+ */
+static int umsdos_waitcreate (struct inode *dir)
 {
-  int ret = 0;
-  if (dir->u.umsdos_i.u.dir_info.creating
-      && dir->u.umsdos_i.u.dir_info.pid != current->pid){
-    sleep_on(&dir->u.umsdos_i.u.dir_info.p);
-    ret = 1;
-  }
-  return ret;
+	int ret = 0;
+
+	if (dir->u.umsdos_i.u.dir_info.creating
+	    && dir->u.umsdos_i.u.dir_info.pid != current->pid) {
+		sleep_on (&dir->u.umsdos_i.u.dir_info.p);
+		ret = 1;
+	}
+	return ret;
 }
 
 /*
-	Wait for any lookup process to finish
-*/
+ * Wait for any lookup process to finish
+ */
 static void umsdos_waitlookup (struct inode *dir)
 {
-  while (dir->u.umsdos_i.u.dir_info.looking){
-    sleep_on(&dir->u.umsdos_i.u.dir_info.p);
-  }
+	while (dir->u.umsdos_i.u.dir_info.looking) {
+		sleep_on (&dir->u.umsdos_i.u.dir_info.p);
+	}
 }
 
 /*
-	Lock all other process out of this directory.
-*/
+ * Lock all other process out of this directory.
+ */
 void umsdos_lockcreate (struct inode *dir)
 {
-  /* #Specification: file creation / not atomic
-     File creation is a two step process. First we create (allocate)
-     an entry in the EMD file and then (using the entry offset) we
-     build a unique name for MSDOS. We create this name in the msdos
-     space.
-     
-     We have to use semaphore (sleep_on/wake_up) to prevent lookup
-     into a directory when we create a file or directory and to
-     prevent creation while a lookup is going on. Since many lookup
-     may happen at the same time, the semaphore is a counter.
-
-     Only one creation is allowed at the same time. This protection
-     may not be necessary. The problem arise mainly when a lookup
-     or a readdir is done while a file is partially created. The
-     lookup process see that as a "normal" problem and silently
-     erase the file from the EMD file. Normal because a file
-     may be erased during a MSDOS session, but not removed from
-     the EMD file.
-     
-     The locking is done on a directory per directory basis. Each
-     directory inode has its wait_queue.
-     
-     For some operation like hard link, things even get worse. Many
-     creation must occur at once (atomic). To simplify the design
-     a process is allowed to recursively lock the directory for
-     creation. The pid of the locking process is kept along with
-     a counter so a second level of locking is granted or not.
-  */
-  /*
-    Wait for any creation process to finish except
-    if we (the process) own the lock
-  */
-  while (umsdos_waitcreate(dir)!=0);
-  dir->u.umsdos_i.u.dir_info.creating++;
-  dir->u.umsdos_i.u.dir_info.pid = current->pid;
-  umsdos_waitlookup (dir);
+	/* #Specification: file creation / not atomic
+	 * File creation is a two step process. First we create (allocate)
+	 * an entry in the EMD file and then (using the entry offset) we
+	 * build a unique name for MSDOS. We create this name in the msdos
+	 * space.
+	 * 
+	 * We have to use semaphore (sleep_on/wake_up) to prevent lookup
+	 * into a directory when we create a file or directory and to
+	 * prevent creation while a lookup is going on. Since many lookup
+	 * may happen at the same time, the semaphore is a counter.
+	 * 
+	 * Only one creation is allowed at the same time. This protection
+	 * may not be necessary. The problem arise mainly when a lookup
+	 * or a readdir is done while a file is partially created. The
+	 * lookup process see that as a "normal" problem and silently
+	 * erase the file from the EMD file. Normal because a file
+	 * may be erased during a MSDOS session, but not removed from
+	 * the EMD file.
+	 * 
+	 * The locking is done on a directory per directory basis. Each
+	 * directory inode has its wait_queue.
+	 * 
+	 * For some operation like hard link, things even get worse. Many
+	 * creation must occur at once (atomic). To simplify the design
+	 * a process is allowed to recursively lock the directory for
+	 * creation. The pid of the locking process is kept along with
+	 * a counter so a second level of locking is granted or not.
+	 */
+	/*
+	 * Wait for any creation process to finish except
+	 * if we (the process) own the lock
+	 */
+	while (umsdos_waitcreate (dir) != 0);
+	dir->u.umsdos_i.u.dir_info.creating++;
+	dir->u.umsdos_i.u.dir_info.pid = current->pid;
+	umsdos_waitlookup (dir);
 }
 
 /*
-	Lock all other process out of those two directories.
-*/
+ * Lock all other process out of those two directories.
+ */
 static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
 {
-  /*
-    We must check that both directory are available before
-    locking anyone of them. This is to avoid some deadlock.
-    Thanks to dglaude@is1.vub.ac.be (GLAUDE DAVID) for pointing
-    this to me.
-  */
-  while (1){
-    if (umsdos_waitcreate(dir1)==0
-	&& umsdos_waitcreate(dir2)==0){
-      /* We own both now */
-      dir1->u.umsdos_i.u.dir_info.creating++;
-      dir1->u.umsdos_i.u.dir_info.pid = current->pid;
-      dir2->u.umsdos_i.u.dir_info.creating++;
-      dir2->u.umsdos_i.u.dir_info.pid = current->pid;
-      break;
-    }
-  }
-  umsdos_waitlookup(dir1);
-  umsdos_waitlookup(dir2);
+	/*
+	 * We must check that both directory are available before
+	 * locking anyone of them. This is to avoid some deadlock.
+	 * Thanks to dglaude@is1.vub.ac.be (GLAUDE DAVID) for pointing
+	 * this to me.
+	 */
+	while (1) {
+		if (umsdos_waitcreate (dir1) == 0
+		    && umsdos_waitcreate (dir2) == 0) {
+			/* We own both now */
+			dir1->u.umsdos_i.u.dir_info.creating++;
+			dir1->u.umsdos_i.u.dir_info.pid = current->pid;
+			dir2->u.umsdos_i.u.dir_info.creating++;
+			dir2->u.umsdos_i.u.dir_info.pid = current->pid;
+			break;
+		}
+	}
+	umsdos_waitlookup (dir1);
+	umsdos_waitlookup (dir2);
 }
 
 /*
-	Wait until creation is finish in this directory.
-*/
+ * Wait until creation is finish in this directory.
+ */
 void umsdos_startlookup (struct inode *dir)
 {
-  while (umsdos_waitcreate (dir) != 0);
-  dir->u.umsdos_i.u.dir_info.looking++;
+	while (umsdos_waitcreate (dir) != 0);
+	dir->u.umsdos_i.u.dir_info.looking++;
 }
 
 /*
-	Unlock the directory.
-*/
+ * Unlock the directory.
+ */
 void umsdos_unlockcreate (struct inode *dir)
 {
-  dir->u.umsdos_i.u.dir_info.creating--;
-  if (dir->u.umsdos_i.u.dir_info.creating < 0){
-    printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.creating < 0: %d"
-	    ,dir->u.umsdos_i.u.dir_info.creating);
-  }
-  wake_up (&dir->u.umsdos_i.u.dir_info.p);
+	dir->u.umsdos_i.u.dir_info.creating--;
+	if (dir->u.umsdos_i.u.dir_info.creating < 0) {
+		printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.creating < 0: %d"
+			,dir->u.umsdos_i.u.dir_info.creating);
+	}
+	wake_up (&dir->u.umsdos_i.u.dir_info.p);
 }
 
 /*
-	Tell directory lookup is over.
-*/
+ * Tell directory lookup is over.
+ */
 void umsdos_endlookup (struct inode *dir)
 {
-  dir->u.umsdos_i.u.dir_info.looking--;
-  if (dir->u.umsdos_i.u.dir_info.looking < 0){
-    printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.looking < 0: %d"
-	    ,dir->u.umsdos_i.u.dir_info.looking);
-  }
-  wake_up (&dir->u.umsdos_i.u.dir_info.p);
+	dir->u.umsdos_i.u.dir_info.looking--;
+	if (dir->u.umsdos_i.u.dir_info.looking < 0) {
+		printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.looking < 0: %d"
+			,dir->u.umsdos_i.u.dir_info.looking);
+	}
+	wake_up (&dir->u.umsdos_i.u.dir_info.p);
 }
 
 #else
-static void umsdos_lockcreate (struct inode *dir){}
-static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2){}
-void umsdos_startlookup (struct inode *dir){}
-static void umsdos_unlockcreate (struct inode *dir){}
-void umsdos_endlookup (struct inode *dir){}
+static void umsdos_lockcreate (struct inode *dir)
+{
+}
+static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
+{
+}
+void umsdos_startlookup (struct inode *dir)
+{
+}
+static void umsdos_unlockcreate (struct inode *dir)
+{
+}
+void umsdos_endlookup (struct inode *dir)
+{
+}
+
 #endif
 
-static int umsdos_nevercreat(
-			     struct inode *dir,
-			     struct dentry *dentry,
-			     int errcod)				/* Length of the name */
-{
-  const char *name = dentry->d_name.name;
-  int len = dentry->d_name.len;
-  int ret = 0;
-  if (umsdos_is_pseudodos(dir,dentry)){
-    /* #Specification: pseudo root / any file creation /DOS
-       The pseudo sub-directory /DOS can't be created!
-       EEXIST is returned.
-       
-       The pseudo sub-directory /DOS can't be removed!
-       EPERM is returned.
-    */
-    ret = -EPERM;
-    ret = errcod;
-  }else if (name[0] == '.'
-	    && (len == 1 || (len == 2 && name[1] == '.'))){
-    /* #Specification: create / . and ..
-       If one try to creates . or .., it always fail and return
-       EEXIST.
-       
-       If one try to delete . or .., it always fail and return
-       EPERM.
-       
-       This should be test at the VFS layer level to avoid
-       duplicating this in all file systems. Any comments ?
-    */
-    ret = errcod;
-  }
-  return ret;
+static int umsdos_nevercreat (
+				     struct inode *dir,
+				     struct dentry *dentry,
+				     int errcod)
+{				/* Length of the name */
+	const char *name = dentry->d_name.name;
+	int len = dentry->d_name.len;
+	int ret = 0;
+
+	if (umsdos_is_pseudodos (dir, dentry)) {
+		/* #Specification: pseudo root / any file creation /DOS
+		 * The pseudo sub-directory /DOS can't be created!
+		 * EEXIST is returned.
+		 * 
+		 * The pseudo sub-directory /DOS can't be removed!
+		 * EPERM is returned.
+		 */
+		ret = -EPERM;
+		ret = errcod;
+	} else if (name[0] == '.'
+		   && (len == 1 || (len == 2 && name[1] == '.'))) {
+		/* #Specification: create / . and ..
+		 * If one try to creates . or .., it always fail and return
+		 * EEXIST.
+		 * 
+		 * If one try to delete . or .., it always fail and return
+		 * EPERM.
+		 * 
+		 * This should be test at the VFS layer level to avoid
+		 * duplicating this in all file systems. Any comments ?
+		 */
+		ret = errcod;
+	}
+	return ret;
 }
-	
+
 /*
-  Add a new file (ordinary or special) into the alternate directory.
-  The file is added to the real MSDOS directory. If successful, it
-  is then added to the EDM file.
-  
-  Return the status of the operation. 0 mean success.
-*/
+ * Add a new file (ordinary or special) into the alternate directory.
+ * The file is added to the real MSDOS directory. If successful, it
+ * is then added to the EDM file.
+ * 
+ * Return the status of the operation. 0 mean success.
+ */
 static int umsdos_create_any (
-   struct inode *dir,
-   struct dentry *dentry,  /* name/length etc*/
-   int mode,		   /* Permission bit + file type ??? */
-   int rdev,		   /* major, minor or 0 for ordinary file */
-   /* and symlinks */
-   char flags
-   )	/* Will hold the inode of the newly created */
-     /* file */
-{
-    
-  int ret;
-  struct dentry *fake;
-  
-  Printk (("umsdos_create_any /mn/: create %.*s in dir=%lu - nevercreat=/", (int) dentry->d_name.len, dentry->d_name.name, dir->i_ino));
-  ret = umsdos_nevercreat(dir,dentry,-EEXIST);
-  Printk (("%d/\n", ret));
-  if (ret == 0){
-    struct umsdos_info info;
-    ret = umsdos_parse(dentry->d_name.name,dentry->d_name.len,&info);
-  
-    if (ret == 0){
-      info.entry.mode = mode;
-      info.entry.rdev = rdev;
-      info.entry.flags = flags;
-      info.entry.uid = current->fsuid;
-      info.entry.gid = (dir->i_mode & S_ISGID)
-	? dir->i_gid : current->fsgid;
-      info.entry.ctime = info.entry.atime = info.entry.mtime
-	= CURRENT_TIME;
-      info.entry.nlink = 1;
-      umsdos_lockcreate(dir);
-      ret = umsdos_newentry (dir,&info);
-      if (ret == 0){
-	dir->i_count++;
-        fake = creat_dentry (info.fake.fname, info.fake.len, NULL, dentry->d_parent);	/* create short name dentry */
-	ret = msdos_create (dir, fake, S_IFREG|0777);
-	if (ret == 0){
-	  struct inode *inode = fake->d_inode;
-	  umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
-	  Printk (("inode %p[%lu], count=%d ",inode, inode->i_ino, inode->i_count));
-	  Printk (("Creation OK: [dir %lu] %.*s pid=%d pos %ld\n", dir->i_ino,
-		   info.fake.len, info.fake.fname, current->pid, info.f_pos));
-	  
-	  d_instantiate(dentry, inode);	/* long name also gets inode info */
-	}else{
-	  /* #Specification: create / file exist in DOS
-	     Here is a situation. Trying to create a file with
-	     UMSDOS. The file is unknown to UMSDOS but already
-	     exist in the DOS directory.
-	     
-	     Here is what we are NOT doing:
-	     
-	     We could silently assume that everything is fine
-	     and allows the creation to succeed.
-	     
-	     It is possible not all files in the partition
-	     are mean to be visible from linux. By trying to create
-	     those file in some directory, one user may get access
-	     to those file without proper permissions. Looks like
-	     a security hole to me. Off course sharing a file system
-	     with DOS is some kind of security hole :-)
-	     
-	     So ?
-	     
-	     We return EEXIST in this case.
-	     The same is true for directory creation.
-	  */
-	  if (ret == -EEXIST){
-	    printk ("UMSDOS: out of sync, Creation error [%ld], "
-		    "deleting %.*s %d %d pos %ld\n",dir->i_ino
-		    ,info.fake.len,info.fake.fname,-ret,current->pid,info.f_pos);
-	  }
-	  umsdos_delentry (dir,&info,0);
+				     struct inode *dir,
+				     struct dentry *dentry,	/* name/length etc */
+				     int mode,	/* Permission bit + file type ??? */
+				     int rdev,	/* major, minor or 0 for ordinary file and symlinks */
+				     char flags
+)
+{				/* Will hold the inode of the newly created file */
+
+	int ret;
+	struct dentry *fake;
+
+	Printk (("umsdos_create_any /mn/: create %.*s in dir=%lu - nevercreat=/", (int) dentry->d_name.len, dentry->d_name.name, dir->i_ino));
+	check_dentry (dentry);
+	ret = umsdos_nevercreat (dir, dentry, -EEXIST);
+	Printk (("%d/\n", ret));
+	if (ret == 0) {
+		struct umsdos_info info;
+
+		ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
+
+		if (ret == 0) {
+			info.entry.mode = mode;
+			info.entry.rdev = rdev;
+			info.entry.flags = flags;
+			info.entry.uid = current->fsuid;
+			info.entry.gid = (dir->i_mode & S_ISGID)
+			    ? dir->i_gid : current->fsgid;
+			info.entry.ctime = info.entry.atime = info.entry.mtime
+			    = CURRENT_TIME;
+			info.entry.nlink = 1;
+			umsdos_lockcreate (dir);
+			ret = umsdos_newentry (dir, &info);
+			if (ret == 0) {
+				inc_count (dir);
+				fake = creat_dentry (info.fake.fname, info.fake.len, NULL, dentry->d_parent);	/* create short name dentry */
+				ret = msdos_create (dir, fake, S_IFREG | 0777);
+				if (ret == 0) {
+					struct inode *inode = fake->d_inode;
+
+					umsdos_lookup_patch (dir, inode, &info.entry, info.f_pos);
+					Printk (("inode %p[%lu], count=%d ", inode, inode->i_ino, inode->i_count));
+					Printk (("Creation OK: [dir %lu] %.*s pid=%d pos %ld\n", dir->i_ino,
+						 info.fake.len, info.fake.fname, current->pid, info.f_pos));
+
+					d_instantiate (dentry, inode);	/* long name also gets inode info */
+					dput (fake);	/* FIXME: is this ok ? we try to kill short name dentry that we don't need */
+				} else {
+					/* #Specification: create / file exist in DOS
+					 * Here is a situation. Trying to create a file with
+					 * UMSDOS. The file is unknown to UMSDOS but already
+					 * exist in the DOS directory.
+					 * 
+					 * Here is what we are NOT doing:
+					 * 
+					 * We could silently assume that everything is fine
+					 * and allows the creation to succeed.
+					 * 
+					 * It is possible not all files in the partition
+					 * are mean to be visible from linux. By trying to create
+					 * those file in some directory, one user may get access
+					 * to those file without proper permissions. Looks like
+					 * a security hole to me. Off course sharing a file system
+					 * with DOS is some kind of security hole :-)
+					 * 
+					 * So ?
+					 * 
+					 * We return EEXIST in this case.
+					 * The same is true for directory creation.
+					 */
+					if (ret == -EEXIST) {
+						printk ("UMSDOS: out of sync, Creation error [%ld], "
+							"deleting %.*s %d %d pos %ld\n", dir->i_ino
+							,info.fake.len, info.fake.fname, -ret, current->pid, info.f_pos);
+					}
+					umsdos_delentry (dir, &info, 0);
+				}
+				Printk (("umsdos_create %.*s ret = %d pos %ld\n",
+					 info.fake.len, info.fake.fname, ret, info.f_pos));
+			}
+			umsdos_unlockcreate (dir);
+		}
 	}
-	Printk (("umsdos_create %.*s ret = %d pos %ld\n",
-		 info.fake.len, info.fake.fname, ret, info.f_pos));
-      }
-      umsdos_unlockcreate(dir);
-    }
-  }
-  /* d_add(dentry,dir); /mn/ FIXME: msdos_create already did this for short name ! */
-  return ret;
+	/* d_add(dentry,dir); /mn/ FIXME: msdos_create already did this for short name ! */
+	return ret;
 }
 
 /*
-	Initialise the new_entry from the old for a rename operation.
-	(Only useful for umsdos_rename_f() below).
-*/
-static void umsdos_ren_init(
-      struct umsdos_info *new_info,
-      struct umsdos_info *old_info,
-      int flags)		/* 0 == copy flags from old_name */
-     /* != 0, this is the value of flags */
-{
-  new_info->entry.mode = old_info->entry.mode;
-  new_info->entry.rdev = old_info->entry.rdev;
-  new_info->entry.uid = old_info->entry.uid;
-  new_info->entry.gid = old_info->entry.gid;
-  new_info->entry.ctime = old_info->entry.ctime;
-  new_info->entry.atime = old_info->entry.atime;
-  new_info->entry.mtime = old_info->entry.mtime;
-  new_info->entry.flags = flags ? flags : old_info->entry.flags;
-  new_info->entry.nlink = old_info->entry.nlink;
+ * Initialise the new_entry from the old for a rename operation.
+ * (Only useful for umsdos_rename_f() below).
+ */
+static void umsdos_ren_init (
+				    struct umsdos_info *new_info,
+				    struct umsdos_info *old_info,
+				    int flags)
+{				/* 0 == copy flags from old_name */
+	/* != 0, this is the value of flags */
+	new_info->entry.mode = old_info->entry.mode;
+	new_info->entry.rdev = old_info->entry.rdev;
+	new_info->entry.uid = old_info->entry.uid;
+	new_info->entry.gid = old_info->entry.gid;
+	new_info->entry.ctime = old_info->entry.ctime;
+	new_info->entry.atime = old_info->entry.atime;
+	new_info->entry.mtime = old_info->entry.mtime;
+	new_info->entry.flags = flags ? flags : old_info->entry.flags;
+	new_info->entry.nlink = old_info->entry.nlink;
 }
 
 #define chkstk() \
@@ -319,870 +334,909 @@
 }
 
 #undef chkstk
-#define chkstk() do { } while (0)
-	
+#define chkstk() do { } while (0);
+
 /*
-	Rename a file (move) in the file system.
-*/
-static int umsdos_rename_f(
-			   struct inode * old_dir,
-			   struct dentry *old_dentry,
-			   struct inode * new_dir,
-			   struct dentry *new_dentry,
-			   int flags)		/* 0 == copy flags from old_name */
-     /* != 0, this is the value of flags */
-{
-  int ret = -EPERM;
-  struct umsdos_info old_info;
-  int old_ret = umsdos_parse (old_dentry->d_name.name,
-			      old_dentry->d_name.len,&old_info);
-  struct umsdos_info new_info;
-  int new_ret = umsdos_parse (new_dentry->d_name.name,
-			      new_dentry->d_name.len,&new_info);
-  chkstk();
-  Printk (("umsdos_rename %d %d ",old_ret,new_ret));
-  if (old_ret == 0 && new_ret == 0){
-    umsdos_lockcreate2(old_dir,new_dir);
-    chkstk();
-    Printk (("old findentry "));
-    ret = umsdos_findentry(old_dir,&old_info,0);
-    chkstk();
-    Printk (("ret %d ",ret));
-    if (ret == 0){
-      /* check sticky bit on old_dir */
-      if ( !(old_dir->i_mode & S_ISVTX) || capable(CAP_FOWNER) ||
-	   current->fsuid == old_info.entry.uid ||
-	   current->fsuid == old_dir->i_uid ) {
-	/* Does new_name already exist? */
-	PRINTK(("new findentry "));
-	ret = umsdos_findentry(new_dir,&new_info,0);
-	if (ret != 0 || /* if destination file exists, are we allowed to replace it ? */
-	    !(new_dir->i_mode & S_ISVTX) || capable(CAP_FOWNER) ||
-	    current->fsuid == new_info.entry.uid ||
-	    current->fsuid == new_dir->i_uid ) {
-	  PRINTK (("new newentry "));
-	  umsdos_ren_init(&new_info,&old_info,flags);
-	  ret = umsdos_newentry (new_dir,&new_info);
-	  chkstk();
-	  PRINTK (("ret %d %d ",ret,new_info.fake.len));
-	  if (ret == 0){
-	    struct dentry *old, *new;
-	    old = creat_dentry (old_info.fake.fname, old_info.fake.len, NULL, NULL);
-	    new = creat_dentry (new_info.fake.fname, new_info.fake.len, NULL, NULL);
-
-	    PRINTK (("msdos_rename "));
-	    old_dir->i_count++;
-	    new_dir->i_count++;	/* Both inode are needed later */
-	    ret = msdos_rename (old_dir,
-				old,
-				new_dir,
-				new);
-	    chkstk();
-	    PRINTK (("after m_rename ret %d ",ret));
-	    if (ret != 0){
-	      umsdos_delentry (new_dir,&new_info
-			       ,S_ISDIR(new_info.entry.mode));
-	      chkstk();
-	    }else{
-	      ret = umsdos_delentry (old_dir,&old_info
-				     ,S_ISDIR(old_info.entry.mode));
-	      chkstk();
-	      if (ret == 0){
-		/*
-		  This umsdos_lookup_x does not look very useful.
-		  It makes sure that the inode of the file will
-		  be correctly setup (umsdos_patch_inode()) in
-		  case it is already in use.
-		  
-		  Not very efficient ...
-		*/
-		struct inode *inode;
-		new_dir->i_count++;
-		PRINTK ((KERN_DEBUG "rename lookup len %d %d -- ",new_len,new_info.entry.flags));
-		ret = umsdos_lookup_x (new_dir, new_dentry, 0);
-		inode = new_dentry->d_inode;
-		chkstk();
-		if (ret != 0){
-		  printk ("UMSDOS: partial rename for file %.*s\n"
-			  ,new_info.entry.name_len,new_info.entry.name);
-		}else{
-		  /*
-		    Update f_pos so notify_change will succeed
-		    if the file was already in use.
-		  */
-		  umsdos_set_dirinfo (inode,new_dir,new_info.f_pos);
-		  chkstk();
-		  /* iput (inode); FIXME */
+ * Rename a file (move) in the file system.
+ */
+ 
+static int umsdos_rename_f (
+				   struct inode *old_dir,
+				   struct dentry *old_dentry,
+				   struct inode *new_dir,
+				   struct dentry *new_dentry,
+				   int flags)
+{				/* 0 == copy flags from old_name */
+				/* != 0, this is the value of flags */
+	int ret = -EPERM;
+	struct umsdos_info old_info;
+	int old_ret = umsdos_parse (old_dentry->d_name.name,
+				    old_dentry->d_name.len, &old_info);
+	struct umsdos_info new_info;
+	int new_ret = umsdos_parse (new_dentry->d_name.name,
+				    new_dentry->d_name.len, &new_info);
+
+	check_dentry (old_dentry);
+	check_dentry (new_dentry);
+
+	chkstk ();
+	Printk (("umsdos_rename %d %d ", old_ret, new_ret));
+	if (old_ret == 0 && new_ret == 0) {
+		umsdos_lockcreate2 (old_dir, new_dir);
+		chkstk ();
+		Printk (("old findentry "));
+		ret = umsdos_findentry (old_dir, &old_info, 0);
+		chkstk ();
+		Printk (("ret %d ", ret));
+		if (ret == 0) {
+			/* check sticky bit on old_dir */
+			if (!(old_dir->i_mode & S_ISVTX) || capable (CAP_FOWNER) ||
+			    current->fsuid == old_info.entry.uid ||
+			    current->fsuid == old_dir->i_uid) {
+				/* Does new_name already exist? */
+				Printk (("new findentry "));
+				ret = umsdos_findentry (new_dir, &new_info, 0);
+				if (ret != 0 ||		/* if destination file exists, are we allowed to replace it ? */
+				    !(new_dir->i_mode & S_ISVTX) || capable (CAP_FOWNER) ||
+				  current->fsuid == new_info.entry.uid ||
+				    current->fsuid == new_dir->i_uid) {
+					Printk (("new newentry "));
+					umsdos_ren_init (&new_info, &old_info, flags);
+					ret = umsdos_newentry (new_dir, &new_info);
+					chkstk ();
+					Printk (("ret %d %d ", ret, new_info.fake.len));
+					if (ret == 0) {
+						struct dentry *old, *new;
+						struct inode *oldid = NULL;
+
+						ret = compat_umsdos_real_lookup (old_dir, old_info.fake.fname, old_info.fake.len, &oldid);
+						old = creat_dentry (old_info.fake.fname, old_info.fake.len, oldid, old_dentry->d_parent);
+
+						new = creat_dentry (new_info.fake.fname, new_info.fake.len, NULL, new_dentry->d_parent);
+
+						Printk (("msdos_rename "));
+						inc_count (old_dir);
+						inc_count (new_dir);	/* Both inode are needed later */
+						
+						check_dentry (old); check_dentry (new);	/* FIXME: debug only */
+						ret = msdos_rename (old_dir, old, new_dir, new);
+						chkstk ();
+						Printk (("after m_rename ret %d ", ret));
+						kill_dentry (old);
+						kill_dentry (new);
+
+						if (ret != 0) {
+							umsdos_delentry (new_dir, &new_info, S_ISDIR (new_info.entry.mode));
+							chkstk ();
+						} else {
+							ret = umsdos_delentry (old_dir, &old_info, S_ISDIR (old_info.entry.mode));
+							chkstk ();
+							if (ret == 0) {
+								/*
+								 * This umsdos_lookup_x does not look very useful.
+								 * It makes sure that the inode of the file will
+								 * be correctly setup (umsdos_patch_inode()) in
+								 * case it is already in use.
+								 * 
+								 * Not very efficient ...
+								 */
+								struct inode *inode;
+
+								inc_count (new_dir);
+								PRINTK ((KERN_DEBUG "rename lookup len %d %d -- ", new_len, new_info.entry.flags));
+								ret = umsdos_lookup_x (new_dir, new_dentry, 0);
+								inode = new_dentry->d_inode;
+								chkstk ();
+								if (ret != 0) {
+									printk ("UMSDOS: partial rename for file %.*s\n"
+										,new_info.entry.name_len, new_info.entry.name);
+								} else {
+									/*
+									 * Update f_pos so notify_change will succeed
+									 * if the file was already in use.
+									 */
+									umsdos_set_dirinfo (inode, new_dir, new_info.f_pos);
+									d_move (old_dentry, new_dentry);
+									chkstk ();
+									/* iput (inode); FIXME */
+								}
+							}
+						}
+					}
+				} else {
+					/* sticky bit set on new_dir */
+					Printk (("sticky set on new "));
+					ret = -EPERM;
+				}
+			} else {
+				/* sticky bit set on old_dir */
+				Printk (("sticky set on old "));
+				ret = -EPERM;
+			}
 		}
-	      }
-	    }
-	  }
-	}else{
-	  /* sticky bit set on new_dir */
-	  Printk(("sticky set on new "));
-	  ret = -EPERM;
+		Printk ((KERN_DEBUG "umsdos_rename_f: unlocking dirs...\n"));
+		umsdos_unlockcreate (old_dir);
+		umsdos_unlockcreate (new_dir);
 	}
-      }else{
-	/* sticky bit set on old_dir */
-	Printk(("sticky set on old "));
-	ret = -EPERM;
-      }
-    }
-    umsdos_unlockcreate(old_dir);
-    umsdos_unlockcreate(new_dir);
-  }
-  d_move(old_dentry,new_dentry);
-  Printk (("\n"));
-  return ret;
+	check_dentry (old_dentry);
+	check_dentry (new_dentry);
+
+	Printk ((" _ret=%d\n", ret));
+	return ret;
 }
 
 /*
-	Setup un Symbolic link or a (pseudo) hard link
-	Return a negative error code or 0 if ok.
-*/
-static int umsdos_symlink_x(
-			    struct inode * dir,
-			    struct dentry *dentry,
-			    const char * symname,	/* name will point to this path */
-			    int mode,
-			    char flags)
+ * Setup un Symbolic link or a (pseudo) hard link
+ * Return a negative error code or 0 if ok.
+ */
+static int umsdos_symlink_x (
+				    struct inode *dir,
+				    struct dentry *dentry,
+				    const char *symname,	/* name will point to this path */
+				    int mode,
+				    char flags)
 {
-  /* #Specification: symbolic links / strategy
-     A symbolic link is simply a file which hold a path. It is
-     implemented as a normal MSDOS file (not very space efficient :-()
-     
-     I see 2 different way to do it. One is to place the link data
-     in unused entry of the EMD file. The other is to have a separate
-     file dedicated to hold all symbolic links data.
-     
-     Let's go for simplicity...
-  */
-  
-  
-  int ret;
-  dir->i_count++;/* We keep the inode in case we need it */
-  /* later */
-  ret = umsdos_create_any (dir,dentry,mode,0,flags);
-  Printk (("umsdos_symlink ret %d ",ret));
-  if (ret == 0){
-    int len = strlen(symname);
-    struct file filp;
-    loff_t myofs=0;
-    fill_new_filp (&filp, dentry);
-
-    /* Make the inode acceptable to MSDOS FIXME */
-    Printk ((KERN_WARNING "umsdos_symlink_x: /mn/ Is this ok?\n"));
-    Printk ((KERN_WARNING "   symname=%s ; dentry name=%.*s (ino=%lu)\n", symname, (int) dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_ino));
-    ret = umsdos_file_write_kmem_real (&filp, symname, len, &myofs);
-    /* dput(dentry); ?? where did this come from FIXME */
-    if (ret >= 0){
-      if (ret != len){
-	ret = -EIO;
-	printk ("UMSDOS: "
-		"Can't write symbolic link data\n");
-      }else{
-	ret = 0;
-      }
-    }
-    if (ret != 0){
-      UMSDOS_unlink (dir,dentry);
-      dir = NULL;
-    }
-  }
-  /* d_instantiate(dentry,dir);   //already done in umsdos_create_any */
-  Printk (("\n"));
-  return ret;
+	/* #Specification: symbolic links / strategy
+	 * A symbolic link is simply a file which hold a path. It is
+	 * implemented as a normal MSDOS file (not very space efficient :-()
+	 * 
+	 * I see 2 different way to do it. One is to place the link data
+	 * in unused entry of the EMD file. The other is to have a separate
+	 * file dedicated to hold all symbolic links data.
+	 * 
+	 * Let's go for simplicity...
+	 */
+
+
+	int ret;
+
+	inc_count (dir);	/* We keep the inode in case we need it */
+	/* later */
+	ret = umsdos_create_any (dir, dentry, mode, 0, flags);
+	Printk (("umsdos_symlink ret %d ", ret));
+	if (ret == 0) {
+		int len = strlen (symname);
+		struct file filp;
+		loff_t myofs = 0;
+
+		fill_new_filp (&filp, dentry);
+
+		/* Make the inode acceptable to MSDOS FIXME */
+		Printk ((KERN_WARNING "umsdos_symlink_x: /mn/ Is this ok?\n"));
+		Printk ((KERN_WARNING "   symname=%s ; dentry name=%.*s (ino=%lu)\n", symname, (int) dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_ino));
+		ret = umsdos_file_write_kmem_real (&filp, symname, len, &myofs);
+		/* dput(dentry); ?? where did this come from FIXME */
+		
+		if (ret >= 0) {
+			if (ret != len) {
+				ret = -EIO;
+				printk ("UMSDOS: "
+				     "Can't write symbolic link data\n");
+			} else {
+				ret = 0;
+			}
+		}
+		if (ret != 0) {
+			UMSDOS_unlink (dir, dentry);
+			dir = NULL;
+		}
+	}
+	/* d_instantiate(dentry,dir);   //already done in umsdos_create_any. */
+	Printk (("\n"));
+	return ret;
 }
 
 /*
-  Setup un Symbolic link.
-  Return a negative error code or 0 if ok.
-*/
-int UMSDOS_symlink(
-   struct inode * dir,
-   struct dentry *dentry,
-   const char * symname
-   )
+ * Setup un Symbolic link.
+ * Return a negative error code or 0 if ok.
+ */
+int UMSDOS_symlink (
+			   struct inode *dir,
+			   struct dentry *dentry,
+			   const char *symname
+)
 {
-  return umsdos_symlink_x (dir,dentry,symname,S_IFLNK|0777,0);
+	return umsdos_symlink_x (dir, dentry, symname, S_IFLNK | 0777, 0);
 }
 
 /*
-  Add a link to an inode in a directory
-*/
+ * Add a link to an inode in a directory
+ */
 int UMSDOS_link (
-		 struct dentry * olddentry,
-		 struct inode * dir,
-		 struct dentry *dentry)
+			struct dentry *olddentry,
+			struct inode *dir,
+			struct dentry *dentry)
 {
-    struct inode *oldinode = olddentry->d_inode;
-  /* #Specification: hard link / strategy
-     Well ... hard link are difficult to implement on top of an
-     MsDOS fat file system. Unlike UNIX file systems, there are no
-     inode. A directory entry hold the functionality of the inode
-     and the entry.
-     
-     We will used the same strategy as a normal Unix file system
-     (with inode) except we will do it symbolically (using paths).
-     
-     Because anything can happen during a DOS session (defragment,
-     directory sorting, etc...), we can't rely on MsDOS pseudo
-     inode number to record the link. For this reason, the link
-     will be done using hidden symbolic links. The following
-     scenario illustrate how it work.
-     
-     Given a file /foo/file
-     
-     #
-     ln /foo/file /tmp/file2
-     
-     become internally
-     
-     mv /foo/file /foo/-LINK1
-     ln -s /foo/-LINK1 /foo/file
-     ln -s /foo/-LINK1 /tmp/file2
-     #
-     
-     Using this strategy, we can operate on /foo/file or /foo/file2.
-     We can remove one and keep the other, like a normal Unix hard link.
-     We can rename /foo/file or /tmp/file2 independently.
-     
-     The entry -LINK1 will be hidden. It will hold a link count.
-     When all link are erased, the hidden file is erased too.
-  */
-  /* #Specification: weakness / hard link
-     The strategy for hard link introduces a side effect that
-     may or may not be acceptable. Here is the sequence
-     
-     #
-     mkdir subdir1
-     touch subdir1/file
-     mkdir subdir2
-     ln    subdir1/file subdir2/file
-     rm    subdir1/file
-     rmdir subdir1
-     rmdir: subdir1: Directory not empty
-     #
-     
-     This happen because there is an invisible file (--link) in
-     subdir1 which is referenced by subdir2/file.
-     
-     Any idea ?
-  */
-  /* #Specification: weakness / hard link / rename directory
-     Another weakness of hard link come from the fact that
-     it is based on hidden symbolic links. Here is an example.
-     
-     #
-     mkdir /subdir1
-     touch /subdir1/file
-     mkdir /subdir2
-     ln    /subdir1/file subdir2/file
-     mv    /subdir1 subdir3
-     ls -l /subdir2/file
-     #
-     
-     Since /subdir2/file is a hidden symbolic link
-     to /subdir1/..hlinkNNN, accessing it will fail since
-     /subdir1 does not exist anymore (has been renamed).
-  */
-  int ret = 0;
-  if (S_ISDIR(oldinode->i_mode)){
-    /* #Specification: hard link / directory
-       A hard link can't be made on a directory. EPERM is returned
-       in this case.
-    */
-    ret = -EPERM;
-  }else if ((ret = umsdos_nevercreat(dir,dentry,-EPERM))==0){
-    struct inode *olddir;
-    ret = umsdos_get_dirowner(oldinode,&olddir);
-    Printk (("umsdos_link dir_owner = %lu -> %p [%d] ",
-	     oldinode->u.umsdos_i.i_dir_owner, olddir, olddir->i_count));
-    if (ret == 0){
-      struct umsdos_dirent entry;
-      umsdos_lockcreate2(dir,olddir);
-      ret = umsdos_inode2entry (olddir,oldinode,&entry);
-      if (ret == 0){
-	Printk (("umsdos_link :%.*s: ino %lu flags %d "
-		 ,entry.name_len, entry.name
-		 ,oldinode->i_ino, entry.flags));
-	if (!(entry.flags & UMSDOS_HIDDEN)){
-	  /* #Specification: hard link / first hard link
-	     The first time a hard link is done on a file, this
-	     file must be renamed and hidden. Then an internal
-	     symbolic link must be done on the hidden file.
-	     
-	     The second link is done after on this hidden file.
-	     
-	     It is expected that the Linux MSDOS file system
-	     keeps the same pseudo inode when a rename operation
-	     is done on a file in the same directory.
-	  */
-	  struct umsdos_info info;
-	  ret = umsdos_newhidden (olddir,&info);
-	  if (ret == 0){
-	    Printk (("olddir[%d] ",olddir->i_count));
-	    ret = umsdos_rename_f( 
-				  olddentry->d_inode,
-				  olddentry,
-				  dir,
-				  dentry,
-				   UMSDOS_HIDDEN);
-	    if (ret == 0){
-	      char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
-	      if (path == NULL){
-		ret = -ENOMEM;
-	      }else{
-		struct dentry *temp;
-		temp = creat_dentry (entry.name, entry.name_len, NULL, NULL);
-		Printk (("olddir[%d] ",olddir->i_count));
-		ret = umsdos_locate_path (oldinode,path);
-		Printk (("olddir[%d] ",olddir->i_count));
-		if (ret == 0){
-		  olddir->i_count++;
-		  ret = umsdos_symlink_x (olddir
-					  ,temp
-					  ,path
-					  ,S_IFREG|0777,UMSDOS_HLINK);
-		  if (ret == 0){
-		    dir->i_count++;
-		    ret = umsdos_symlink_x (dir,dentry,
-					    path,
-					    S_IFREG|0777,UMSDOS_HLINK);
-		  }
+	struct inode *oldinode = olddentry->d_inode;
+
+	/* #Specification: hard link / strategy
+	 * Well ... hard link are difficult to implement on top of an
+	 * MsDOS fat file system. Unlike UNIX file systems, there are no
+	 * inode. A directory entry hold the functionality of the inode
+	 * and the entry.
+	 * 
+	 * We will used the same strategy as a normal Unix file system
+	 * (with inode) except we will do it symbolically (using paths).
+	 * 
+	 * Because anything can happen during a DOS session (defragment,
+	 * directory sorting, etc...), we can't rely on MsDOS pseudo
+	 * inode number to record the link. For this reason, the link
+	 * will be done using hidden symbolic links. The following
+	 * scenario illustrate how it work.
+	 * 
+	 * Given a file /foo/file
+	 * 
+	 * #
+	 * ln /foo/file /tmp/file2
+	 * 
+	 * become internally
+	 * 
+	 * mv /foo/file /foo/-LINK1
+	 * ln -s /foo/-LINK1 /foo/file
+	 * ln -s /foo/-LINK1 /tmp/file2
+	 * #
+	 * 
+	 * Using this strategy, we can operate on /foo/file or /foo/file2.
+	 * We can remove one and keep the other, like a normal Unix hard link.
+	 * We can rename /foo/file or /tmp/file2 independently.
+	 * 
+	 * The entry -LINK1 will be hidden. It will hold a link count.
+	 * When all link are erased, the hidden file is erased too.
+	 */
+	/* #Specification: weakness / hard link
+	 * The strategy for hard link introduces a side effect that
+	 * may or may not be acceptable. Here is the sequence
+	 * 
+	 * #
+	 * mkdir subdir1
+	 * touch subdir1/file
+	 * mkdir subdir2
+	 * ln    subdir1/file subdir2/file
+	 * rm    subdir1/file
+	 * rmdir subdir1
+	 * rmdir: subdir1: Directory not empty
+	 * #
+	 * 
+	 * This happen because there is an invisible file (--link) in
+	 * subdir1 which is referenced by subdir2/file.
+	 * 
+	 * Any idea ?
+	 */
+	/* #Specification: weakness / hard link / rename directory
+	 * Another weakness of hard link come from the fact that
+	 * it is based on hidden symbolic links. Here is an example.
+	 * 
+	 * #
+	 * mkdir /subdir1
+	 * touch /subdir1/file
+	 * mkdir /subdir2
+	 * ln    /subdir1/file subdir2/file
+	 * mv    /subdir1 subdir3
+	 * ls -l /subdir2/file
+	 * #
+	 * 
+	 * Since /subdir2/file is a hidden symbolic link
+	 * to /subdir1/..hlinkNNN, accessing it will fail since
+	 * /subdir1 does not exist anymore (has been renamed).
+	 */
+	int ret = 0;
+
+	if (S_ISDIR (oldinode->i_mode)) {
+		/* #Specification: hard link / directory
+		 * A hard link can't be made on a directory. EPERM is returned
+		 * in this case.
+		 */
+		ret = -EPERM;
+	} else if ((ret = umsdos_nevercreat (dir, dentry, -EPERM)) == 0) {
+		struct inode *olddir;
+
+		ret = umsdos_get_dirowner (oldinode, &olddir);
+		Printk (("umsdos_link dir_owner = %lu -> %p [%d] ",
+			 oldinode->u.umsdos_i.i_dir_owner, olddir, olddir->i_count));
+		if (ret == 0) {
+			struct umsdos_dirent entry;
+
+			umsdos_lockcreate2 (dir, olddir);
+			ret = umsdos_inode2entry (olddir, oldinode, &entry);
+			if (ret == 0) {
+				Printk (("umsdos_link :%.*s: ino %lu flags %d "
+					 ,entry.name_len, entry.name
+					 ,oldinode->i_ino, entry.flags));
+				if (!(entry.flags & UMSDOS_HIDDEN)) {
+					/* #Specification: hard link / first hard link
+					 * The first time a hard link is done on a file, this
+					 * file must be renamed and hidden. Then an internal
+					 * symbolic link must be done on the hidden file.
+					 * 
+					 * The second link is done after on this hidden file.
+					 * 
+					 * It is expected that the Linux MSDOS file system
+					 * keeps the same pseudo inode when a rename operation
+					 * is done on a file in the same directory.
+					 */
+					struct umsdos_info info;
+
+					ret = umsdos_newhidden (olddir, &info);
+					if (ret == 0) {
+						Printk (("olddir[%d] ", olddir->i_count));
+						ret = umsdos_rename_f (olddentry->d_inode, olddentry, dir, dentry, UMSDOS_HIDDEN);
+						if (ret == 0) {
+							char *path = (char *) kmalloc (PATH_MAX, GFP_KERNEL);
+
+							if (path == NULL) {
+								ret = -ENOMEM;
+							} else {
+								struct dentry *temp;
+
+								temp = creat_dentry (entry.name, entry.name_len, NULL, NULL);
+								Printk (("olddir[%d] ", olddir->i_count));
+								ret = umsdos_locate_path (oldinode, path);
+								Printk (("olddir[%d] ", olddir->i_count));
+								if (ret == 0) {
+									inc_count (olddir);
+									ret = umsdos_symlink_x (olddir, temp, path, S_IFREG | 0777, UMSDOS_HLINK);
+									if (ret == 0) {
+										inc_count (dir);
+										ret = umsdos_symlink_x (dir, dentry, path, S_IFREG | 0777, UMSDOS_HLINK);
+									}
+								}
+								kfree (path);
+							}
+						}
+					}
+				} else {
+					char *path = (char *) kmalloc (PATH_MAX, GFP_KERNEL);
+
+					if (path == NULL) {
+						ret = -ENOMEM;
+					} else {
+						ret = umsdos_locate_path (oldinode, path);
+						if (ret == 0) {
+							inc_count (dir);
+							ret = umsdos_symlink_x (dir, dentry, path, S_IFREG | 0777, UMSDOS_HLINK);
+						}
+						kfree (path);
+					}
+				}
+			}
+			umsdos_unlockcreate (olddir);
+			umsdos_unlockcreate (dir);
 		}
-		kfree (path);
-	      }
-	    }
-	  }
-	}else{
-	  char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
-	  if (path == NULL){
-	    ret = -ENOMEM;
-	  }else{
-	    ret = umsdos_locate_path (oldinode,path);
-	    if (ret == 0){
-	      dir->i_count++;
-	      ret = umsdos_symlink_x (dir,dentry,path
-				      ,S_IFREG|0777,UMSDOS_HLINK);
-	    }
-	    kfree (path);
-	  }
+		/* iput (olddir); FIXME */
 	}
-      }
-      umsdos_unlockcreate(olddir);
-      umsdos_unlockcreate(dir);
-    }
-    /* iput (olddir); FIXME */
-  }
-  if (ret == 0){
-    struct iattr newattrs;
-    oldinode->i_nlink++;
-    newattrs.ia_valid = 0;
-    ret = UMSDOS_notify_change(olddentry, &newattrs);
-  }
+	if (ret == 0) {
+		struct iattr newattrs;
 
+		oldinode->i_nlink++;
+		newattrs.ia_valid = 0;
+		ret = UMSDOS_notify_change (olddentry, &newattrs);
+	}
 /*  dput (olddentry);
-  dput (dentry); FIXME.... */
-  
-  Printk (("umsdos_link %d\n",ret));
-  return ret;
+ * dput (dentry); FIXME.... */
+
+	Printk (("umsdos_link %d\n", ret));
+	return ret;
 }
 
 
 
 /*
-  Add a new file into the alternate directory.
-  The file is added to the real MSDOS directory. If successful, it
-  is then added to the EDM file.
-  
-  Return the status of the operation. 0 mean success.
-*/
+ * Add a new file into the alternate directory.
+ * The file is added to the real MSDOS directory. If successful, it
+ * is then added to the EDM file.
+ * 
+ * Return the status of the operation. 0 mean success.
+ */
 int UMSDOS_create (
-		   struct inode *dir,
-		   struct dentry *dentry,
-		   int mode		  /* Permission bit + file type ??? */
-		   )	/* Will hold the inode of the newly created */
-							/* file */
-{
-  return umsdos_create_any (dir,dentry,mode,0,0);
+			  struct inode *dir,
+			  struct dentry *dentry,
+			  int mode	/* Permission bit + file type ??? */
+)
+{				/* Will hold the inode of the newly created file */
+	Printk ((KERN_ERR "UMSDOS_create: entering\n"));
+	check_dentry (dentry);
+	return umsdos_create_any (dir, dentry, mode, 0, 0);
 }
 
 
 
 /*
-	Add a sub-directory in a directory
-*/
-int UMSDOS_mkdir(
-		 struct inode * dir,
-		 struct dentry *dentry,
-		 int mode)
+ * Add a sub-directory in a directory
+ */
+int UMSDOS_mkdir (
+			 struct inode *dir,
+			 struct dentry *dentry,
+			 int mode)
 {
-  int ret = umsdos_nevercreat(dir,dentry,-EEXIST);
-  if (ret == 0){
-    struct umsdos_info info;
-    ret = umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info);
-    Printk (("umsdos_mkdir %d\n",ret));
-    if (ret == 0){
-      info.entry.mode = mode | S_IFDIR;
-      info.entry.rdev = 0;
-      info.entry.uid = current->fsuid;
-      info.entry.gid = (dir->i_mode & S_ISGID)
-	? dir->i_gid : current->fsgid;
-      info.entry.ctime = info.entry.atime = info.entry.mtime
-	= CURRENT_TIME;
-      info.entry.flags = 0;
-      umsdos_lockcreate(dir);
-      info.entry.nlink = 1;
-      ret = umsdos_newentry (dir,&info);
-      Printk (("newentry %d ",ret));
-      if (ret == 0){
-	struct dentry *temp, *tdir;
-	tdir = creat_dentry ("mkd-dir", 7, dir, NULL);
-	temp = creat_dentry (info.fake.fname, info.fake.len, NULL, tdir);
-	dir->i_count++;
-	ret = msdos_mkdir (dir, temp, mode);
-	
-	if (ret != 0){
-	  umsdos_delentry (dir,&info,1);
-	  /* #Specification: mkdir / Directory already exist in DOS
-	     We do the same thing as for file creation.
-	     For all user it is an error.
-	  */
-	}else{
-	  /* #Specification: mkdir / umsdos directory / create EMD
-	     When we created a new sub-directory in a UMSDOS
-	     directory (one with full UMSDOS semantic), we
-	     create immediately an EMD file in the new
-	     sub-directory so it inherit UMSDOS semantic.
-	  */
-	  struct inode *subdir;
-	  ret = compat_umsdos_real_lookup (dir,info.fake.fname,
-					   info.fake.len,&subdir);
-	  if (ret == 0){
-	    struct dentry *tdentry, *tdsub;
-	    tdsub = creat_dentry ("mkd-emd", 7, subdir, NULL);
-	    tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, tdsub);
-	    ret = msdos_create (subdir, tdentry, S_IFREG|0777);
-	    kill_dentry (tdentry);	/* we don't want empty EMD file to be visible ! too bad kill_dentry does nothing at the moment :-)  FIXME */
-	    kill_dentry (tdsub);
-	    umsdos_setup_dir_inode (subdir);	/* this should setup dir so it is promoted to EMD, and EMD file is not visible inside it */
-	    subdir = NULL;
-	    d_instantiate(dentry, temp->d_inode);
-	    /* iput (result); FIXME */
-	  }
-	  if (ret < 0){
-	    printk ("UMSDOS: Can't create empty --linux-.---\n");
-	  }
-	  
-	
-	  /* iput (subdir); FIXME */
+	int ret = umsdos_nevercreat (dir, dentry, -EEXIST);
+
+	if (ret == 0) {
+		struct umsdos_info info;
+
+		ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
+		Printk (("umsdos_mkdir %d\n", ret));
+		if (ret == 0) {
+			info.entry.mode = mode | S_IFDIR;
+			info.entry.rdev = 0;
+			info.entry.uid = current->fsuid;
+			info.entry.gid = (dir->i_mode & S_ISGID)
+			    ? dir->i_gid : current->fsgid;
+			info.entry.ctime = info.entry.atime = info.entry.mtime
+			    = CURRENT_TIME;
+			info.entry.flags = 0;
+			umsdos_lockcreate (dir);
+			info.entry.nlink = 1;
+			ret = umsdos_newentry (dir, &info);
+			Printk (("newentry %d ", ret));
+			if (ret == 0) {
+				struct dentry *temp, *tdir;
+
+				tdir = creat_dentry ("mkd-dir", 7, dir, NULL);
+				temp = creat_dentry (info.fake.fname, info.fake.len, NULL, tdir);
+				inc_count (dir);
+				ret = msdos_mkdir (dir, temp, mode);
+
+				if (ret != 0) {
+					umsdos_delentry (dir, &info, 1);
+					/* #Specification: mkdir / Directory already exist in DOS
+					 * We do the same thing as for file creation.
+					 * For all user it is an error.
+					 */
+				} else {
+					/* #Specification: mkdir / umsdos directory / create EMD
+					 * When we created a new sub-directory in a UMSDOS
+					 * directory (one with full UMSDOS semantic), we
+					 * create immediately an EMD file in the new
+					 * sub-directory so it inherit UMSDOS semantic.
+					 */
+					struct inode *subdir;
+
+					ret = compat_umsdos_real_lookup (dir, info.fake.fname,
+						 info.fake.len, &subdir);
+					if (ret == 0) {
+						struct dentry *tdentry,
+						*tdsub;
+
+						tdsub = creat_dentry ("mkd-emd", 7, subdir, NULL);
+						tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, tdsub);
+						ret = msdos_create (subdir, tdentry, S_IFREG | 0777);
+						kill_dentry (tdentry);	/* we don't want empty EMD file to be visible ! too bad kill_dentry does nothing at the moment :-)  FIXME */
+						kill_dentry (tdsub);
+						umsdos_setup_dir_inode (subdir);	/* this should setup dir so it is promoted to EMD, and EMD file is not visible inside it */
+						subdir = NULL;
+						d_instantiate (dentry, temp->d_inode);
+						/* iput (result); FIXME */
+					}
+					if (ret < 0) {
+						printk ("UMSDOS: Can't create empty --linux-.---\n");
+					}
+					/* iput (subdir); FIXME */
+				}
+			}
+			umsdos_unlockcreate (dir);
+		}
 	}
-      }
-      umsdos_unlockcreate(dir);
-    }
-  }
-  Printk (("umsdos_mkdir %d\n",ret));
-  /* dput (dentry); / * FIXME /mn/ */
-  return ret;
+	Printk (("umsdos_mkdir %d\n", ret));
+	/* dput (dentry); / * FIXME /mn/ */
+	return ret;
 }
 
 /*
-	Add a new device special file into a directory.
-*/
-int UMSDOS_mknod(
-	struct inode * dir,
-	struct dentry *dentry,         
-	int mode,
-	int rdev)
+ * Add a new device special file into a directory.
+ */
+int UMSDOS_mknod (
+			 struct inode *dir,
+			 struct dentry *dentry,
+			 int mode,
+			 int rdev)
 {
-  /* #Specification: Special files / strategy
-     Device special file, pipes, etc ... are created like normal
-     file in the msdos file system. Of course they remain empty.
-     
-     One strategy was to create those files only in the EMD file
-     since they were not important for MSDOS. The problem with
-     that, is that there were not getting inode number allocated.
-     The MSDOS filesystems is playing a nice game to fake inode
-     number, so why not use it.
-     
-     The absence of inode number compatible with those allocated
-     for ordinary files was causing major trouble with hard link
-     in particular and other parts of the kernel I guess.
-  */
-
-  int ret = umsdos_create_any (dir,dentry,mode,rdev,0);
-  /* dput(dentry); / * /mn/ FIXME! */
-  return ret;
+	/* #Specification: Special files / strategy
+	 * Device special file, pipes, etc ... are created like normal
+	 * file in the msdos file system. Of course they remain empty.
+	 * 
+	 * One strategy was to create those files only in the EMD file
+	 * since they were not important for MSDOS. The problem with
+	 * that, is that there were not getting inode number allocated.
+	 * The MSDOS filesystems is playing a nice game to fake inode
+	 * number, so why not use it.
+	 * 
+	 * The absence of inode number compatible with those allocated
+	 * for ordinary files was causing major trouble with hard link
+	 * in particular and other parts of the kernel I guess.
+	 */
+
+	int ret;
+	
+	check_dentry (dentry);
+	ret = umsdos_create_any (dir, dentry, mode, rdev, 0);
+	check_dentry (dentry);
+
+	/* dput(dentry); / * /mn/ FIXME! */
+	return ret;
 }
 
 /*
-  Remove a sub-directory.
-*/
-int UMSDOS_rmdir(
-	struct inode * dir,
-	struct dentry *dentry)
+ * Remove a sub-directory.
+ */
+int UMSDOS_rmdir (
+			 struct inode *dir,
+			 struct dentry *dentry)
 {
-  /* #Specification: style / iput strategy
-     In the UMSDOS project, I am trying to apply a single
-     programming style regarding inode management. Many
-     entry point are receiving an inode to act on, and must
-     do an iput() as soon as they are finished with
-     the inode.
-     
-     For simple case, there is no problem. When you introduce
-     error checking, you end up with many iput placed around the
-     code.
-     
-     The coding style I use all around is one where I am trying
-     to provide independent flow logic (I don't know how to
-     name this). With this style, code is easier to understand
-     but you rapidly get iput() all around. Here is an exemple
-     of what I am trying to avoid.
-     
-     #
-     if (a){
-     ...
-     if(b){
-     ...
-     }
-     ...
-     if (c){
-     // Complex state. Was b true ? 
-     ...
-     }
-     ...
-     }
-     // Weird state
-     if (d){
-     // ...
-     }
-     // Was iput finally done ?
-     return status;
-     #
-     
-     Here is the style I am using. Still sometime I do the
-     first when things are very simple (or very complicated :-( )
-     
-     #
-     if (a){
-     if (b){
-     ...
-     }else if (c){
-     // A single state gets here
-     }
-     }else if (d){
-     ...
-     }
-     return status;
-     #
-     
-     Again, while this help clarifying the code, I often get a lot
-     of iput(), unlike the first style, where I can place few 
-     "strategic" iput(). "strategic" also mean, more difficult
-     to place.
-     
-     So here is the style I will be using from now on in this project.
-     There is always an iput() at the end of a function (which has
-     to do an iput()). One iput by inode. There is also one iput()
-     at the places where a successful operation is achieved. This
-     iput() is often done by a sub-function (often from the msdos
-     file system). So I get one too many iput() ? At the place
-     where an iput() is done, the inode is simply nulled, disabling
-     the last one.
-     
-     #
-     if (a){
-     if (b){
-     ...
-     }else if (c){
-     msdos_rmdir(dir,...);
-     dir = NULL;
-     }
-     }else if (d){
-     ...
-     }
-     iput (dir);
-     return status;
-     #
-     
-     Note that the umsdos_lockcreate() and umsdos_unlockcreate() function
-     pair goes against this practice of "forgetting" the inode as soon
-     as possible.
-  */		
-
-  int ret;
-  
-  ret = umsdos_nevercreat(dir,dentry,-EPERM);
-  if (ret == 0){
-    volatile struct inode *sdir;
-    dir->i_count++;
-    ret = umsdos_lookup_x (dir, dentry, 0);
-    sdir = dentry->d_inode;
-    Printk (("rmdir lookup %d ",ret));
-    if (ret == 0){
-      int empty;
-      umsdos_lockcreate(dir);
-      if (sdir->i_count > 1){
-        Printk ((" /mn/ rmdir: FIXME EBUSY: hmmm, i_count is %d > 1\n", sdir->i_count));
-	ret = -EBUSY;
-      }else if ((empty = umsdos_isempty (sdir)) != 0){
-	struct dentry *tdentry, *tedir;
-	tedir = creat_dentry ("emd-rmd", 7, dir, NULL);
-	tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, tedir);
-        umsdos_real_lookup (dir, tdentry);	/* fill inode part */
-	Printk (("isempty %d i_count %d ",empty,sdir->i_count));
+	/* #Specification: style / iput strategy
+	 * In the UMSDOS project, I am trying to apply a single
+	 * programming style regarding inode management. Many
+	 * entry point are receiving an inode to act on, and must
+	 * do an iput() as soon as they are finished with
+	 * the inode.
+	 * 
+	 * For simple case, there is no problem. When you introduce
+	 * error checking, you end up with many iput placed around the
+	 * code.
+	 * 
+	 * The coding style I use all around is one where I am trying
+	 * to provide independent flow logic (I don't know how to
+	 * name this). With this style, code is easier to understand
+	 * but you rapidly get iput() all around. Here is an exemple
+	 * of what I am trying to avoid.
+	 * 
+	 * #
+	 * if (a){
+	 * ...
+	 * if(b){
+	 * ...
+	 * }
+	 * ...
+	 * if (c){
+	 * // Complex state. Was b true ? 
+	 * ...
+	 * }
+	 * ...
+	 * }
+	 * // Weird state
+	 * if (d){
+	 * // ...
+	 * }
+	 * // Was iput finally done ?
+	 * return status;
+	 * #
+	 * 
+	 * Here is the style I am using. Still sometime I do the
+	 * first when things are very simple (or very complicated :-( )
+	 * 
+	 * #
+	 * if (a){
+	 * if (b){
+	 * ...
+	 * }else if (c){
+	 * // A single state gets here
+	 * }
+	 * }else if (d){
+	 * ...
+	 * }
+	 * return status;
+	 * #
+	 * 
+	 * Again, while this help clarifying the code, I often get a lot
+	 * of iput(), unlike the first style, where I can place few 
+	 * "strategic" iput(). "strategic" also mean, more difficult
+	 * to place.
+	 * 
+	 * So here is the style I will be using from now on in this project.
+	 * There is always an iput() at the end of a function (which has
+	 * to do an iput()). One iput by inode. There is also one iput()
+	 * at the places where a successful operation is achieved. This
+	 * iput() is often done by a sub-function (often from the msdos
+	 * file system). So I get one too many iput() ? At the place
+	 * where an iput() is done, the inode is simply nulled, disabling
+	 * the last one.
+	 * 
+	 * #
+	 * if (a){
+	 * if (b){
+	 * ...
+	 * }else if (c){
+	 * msdos_rmdir(dir,...);
+	 * dir = NULL;
+	 * }
+	 * }else if (d){
+	 * ...
+	 * }
+	 * iput (dir);
+	 * return status;
+	 * #
+	 * 
+	 * Note that the umsdos_lockcreate() and umsdos_unlockcreate() function
+	 * pair goes against this practice of "forgetting" the inode as soon
+	 * as possible.
+	 */
+
+	int ret;
+
+	ret = umsdos_nevercreat (dir, dentry, -EPERM);
+	if (ret == 0) {
+		volatile struct inode *sdir;
+
+		inc_count (dir);
+		ret = umsdos_lookup_x (dir, dentry, 0);
+		sdir = dentry->d_inode;
+		Printk (("rmdir lookup %d ", ret));
+		if (ret == 0) {
+			int empty;
+
+			umsdos_lockcreate (dir);
+
+			Printk ((" /mn/ rmdir: FIXME EBUSY TEST: hmmm, i_count is %d > 1 -- FAKING!\n", sdir->i_count));
+			sdir->i_count = 1;	/* /mn/ FIXME! DELME! FOR TEST ONLY ! */
+
+			if (sdir->i_count > 1) {
+				Printk ((" /mn/ rmdir: FIXME EBUSY: hmmm, i_count is %d > 1 -- FAKING!\n", sdir->i_count));
+				ret = -EBUSY;
+			} else if ((empty = umsdos_isempty (sdir)) != 0) {
+				struct dentry *tdentry, *tedir;
+
+				tedir = creat_dentry ("emd-rmd", 7, dir, NULL);
+				tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, tedir);
+				umsdos_real_lookup (dir, tdentry);	/* fill inode part */
+				Printk (("isempty %d i_count %d ", empty, sdir->i_count));
 				/* check sticky bit */
-	if ( !(dir->i_mode & S_ISVTX) || capable(CAP_FOWNER) ||
-	     current->fsuid == sdir->i_uid ||
-	     current->fsuid == dir->i_uid ) {
-	  if (empty == 1){
-	    /* We have to remove the EMD file */
-	    ret = msdos_unlink (sdir, tdentry);
-	    Printk (("UMSDOS_rmdir: unlinking empty EMD ret=%d", ret));
-	    sdir = NULL;
-	  }
-	  /* sdir must be free before msdos_rmdir() */
-	  /* iput (sdir); FIXME */
-	  sdir = NULL;
-	  Printk (("isempty ret %d nlink %d ",ret,dir->i_nlink));
-	  if (ret == 0){
-	    struct umsdos_info info;
-	    struct dentry *temp, *tdir;
-	    dir->i_count++;
-	    umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info);
-	    /* The findentry is there only to complete */
-	    /* the mangling */
-	    umsdos_findentry (dir,&info,2);
-
-            tdir = creat_dentry ("dir-rmd", 7, dir, NULL);
-            temp = creat_dentry (info.fake.fname, info.fake.len, NULL, tdir);
-            umsdos_real_lookup (dir, temp);	/* fill inode part */
-            
-	      Printk ((KERN_ERR "  rmdir start dir=%lu, dir->sb=%p\n", dir->i_ino, dir->i_sb)); /* FIXME: /mn/ debug only */
-	      Printk ((KERN_ERR "    dentry=%.*s d_count=%d ino=%lu\n", (int) temp->d_name.len, temp->d_name.name, temp->d_count, temp->d_inode->i_ino));
-	      Printk ((KERN_ERR "    d_parent=%.*s d_count=%d ino=%lu\n", (int) temp->d_parent->d_name.len, temp->d_parent->d_name.name, temp->d_parent->d_count, temp->d_parent->d_inode->i_ino));
-
-	    ret = msdos_rmdir (dir, temp);
-
-	      Printk ((KERN_ERR "  rmdir passed %d\n", ret)); /* FIXME: /mn/ debug only */
-	      Printk ((KERN_ERR "  rmdir end dir=%lu, dir->sb=%p\n", dir->i_ino, dir->i_sb));
-	      Printk ((KERN_ERR "    dentry=%.*s d_count=%d ino=%p\n", (int) temp->d_name.len, temp->d_name.name, temp->d_count, temp->d_inode));
-	      Printk ((KERN_ERR "    d_parent=%.*s d_count=%d ino=%lu\n", (int) temp->d_parent->d_name.len, temp->d_parent->d_name.name, temp->d_parent->d_count, temp->d_parent->d_inode->i_ino));
-
-            kill_dentry (tdir);
-            kill_dentry (temp);
-            
-	    if (ret == 0){
-	      ret = umsdos_delentry (dir,&info,1);
-              d_delete (dentry);
-	    }
-	  }
-	}else{
-	  /* sticky bit set and we don't have permission */
-	  Printk(("sticky set "));
-	  ret = -EPERM;
+				if (!(dir->i_mode & S_ISVTX) || capable (CAP_FOWNER) ||
+				    current->fsuid == sdir->i_uid ||
+				    current->fsuid == dir->i_uid) {
+					if (empty == 1) {
+						/* We have to remove the EMD file */
+						ret = msdos_unlink (sdir, tdentry);
+						Printk (("UMSDOS_rmdir: unlinking empty EMD ret=%d", ret));
+						sdir = NULL;
+					}
+					/* sdir must be free before msdos_rmdir() */
+					/* iput (sdir); FIXME */
+					sdir = NULL;
+					Printk (("isempty ret %d nlink %d ", ret, dir->i_nlink));
+					if (ret == 0) {
+						struct umsdos_info info;
+						struct dentry *temp, *tdir;
+
+						inc_count (dir);
+						umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
+						/* The findentry is there only to complete */
+						/* the mangling */
+						umsdos_findentry (dir, &info, 2);
+
+						tdir = creat_dentry ("dir-rmd", 7, dir, NULL);
+						temp = creat_dentry (info.fake.fname, info.fake.len, NULL, tdir);
+						umsdos_real_lookup (dir, temp);		/* fill inode part */
+
+						Printk ((KERN_ERR "  rmdir start dir=%lu, dir->sb=%p\n", dir->i_ino, dir->i_sb));	/* FIXME: /mn/ debug only */
+						Printk ((KERN_ERR "    dentry=%.*s d_count=%d ino=%lu\n", (int) temp->d_name.len, temp->d_name.name, temp->d_count, temp->d_inode->i_ino));
+						Printk ((KERN_ERR "    d_parent=%.*s d_count=%d ino=%lu\n", (int) temp->d_parent->d_name.len, temp->d_parent->d_name.name, temp->d_parent->d_count, temp->d_parent->d_inode->i_ino));
+
+						ret = msdos_rmdir (dir, temp);
+
+						Printk ((KERN_ERR "  rmdir passed %d\n", ret));		/* FIXME: /mn/ debug only */
+						Printk ((KERN_ERR "  rmdir end dir=%lu, dir->sb=%p\n", dir->i_ino, dir->i_sb));
+						Printk ((KERN_ERR "    dentry=%.*s d_count=%d ino=%p\n", (int) temp->d_name.len, temp->d_name.name, temp->d_count, temp->d_inode));
+						Printk ((KERN_ERR "    d_parent=%.*s d_count=%d ino=%lu\n", (int) temp->d_parent->d_name.len, temp->d_parent->d_name.name, temp->d_parent->d_count, temp->d_parent->d_inode->i_ino));
+
+						kill_dentry (tdir);
+						kill_dentry (temp);
+
+						if (ret == 0) {
+							ret = umsdos_delentry (dir, &info, 1);
+							d_delete (dentry);
+						}
+					}
+				} else {
+					/* sticky bit set and we don't have permission */
+					Printk (("sticky set "));
+					ret = -EPERM;
+				}
+			} else {
+				/*
+				 * The subdirectory is not empty, so leave it there
+				 */
+				ret = -ENOTEMPTY;
+			}
+			/* iput(sdir); FIXME */
+			umsdos_unlockcreate (dir);
+		}
 	}
-      }else{	
-	/*
-	  The subdirectory is not empty, so leave it there
-	*/
-	ret = -ENOTEMPTY;
-      }
-      /* iput(sdir); FIXME */
-      umsdos_unlockcreate(dir);
-    }	
-  }
- /*  dput(dentry); FIXME /mn/ */
-  Printk (("umsdos_rmdir %d\n",ret));
-  return ret;
+	/*  dput(dentry); FIXME /mn/ */
+	Printk (("umsdos_rmdir %d\n", ret));
+	return ret;
 }
 
 
 
 /*
-  Remove a file from the directory.
-*/
+ * Remove a file from the directory.
+ */
 int UMSDOS_unlink (
-	struct inode * dir,
-	struct dentry *dentry)
+			  struct inode *dir,
+			  struct dentry *dentry)
 {
-  int ret;
-  Printk ((" *** UMSDOS_unlink entering /mn/ *** \n"));
+	int ret;
+
+	Printk ((" *** UMSDOS_unlink entering /mn/ *** \n"));
 
-  ret = umsdos_nevercreat(dir,dentry,-EPERM);
-  
-  Printk (("UMSDOS_unlink /mn/: nevercreat=%d\n", ret));
-  
-  if (ret == 0){
-    struct umsdos_info info;
-    ret = umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info);
-    if (ret == 0){
-      umsdos_lockcreate(dir);
-      ret = umsdos_findentry(dir,&info,1);
-      Printk (("UMSDOS_unlink: findentry returned %d\n", ret));
-      if (ret == 0){
-	Printk (("UMSDOS_unlink %.*s ",info.fake.len,info.fake.fname));
+	ret = umsdos_nevercreat (dir, dentry, -EPERM);
+
+	Printk (("UMSDOS_unlink /mn/: nevercreat=%d\n", ret));
+
+	if (ret == 0) {
+		struct umsdos_info info;
+
+		ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
+		if (ret == 0) {
+			umsdos_lockcreate (dir);
+			ret = umsdos_findentry (dir, &info, 1);
+			Printk (("UMSDOS_unlink: findentry returned %d\n", ret));
+			if (ret == 0) {
+				Printk (("UMSDOS_unlink %.*s ", info.fake.len, info.fake.fname));
 				/* check sticky bit */
-	if ( !(dir->i_mode & S_ISVTX) || capable(CAP_FOWNER) ||
-	     current->fsuid == info.entry.uid ||
-	     current->fsuid == dir->i_uid ) {
-	  if (info.entry.flags & UMSDOS_HLINK){
-	    /* #Specification: hard link / deleting a link
-	       When we deletes a file, and this file is a link
-	       we must subtract 1 to the nlink field of the
-	       hidden link.
-	       
-	       If the count goes to 0, we delete this hidden
-	       link too.
-	    */
-	    /*
-	      First, get the inode of the hidden link
-	      using the standard lookup function.
-	    */
-	    struct inode *inode;
-	    dir->i_count++;
-	    ret = umsdos_lookup_x (dir, dentry, 0);
-	    inode = dentry->d_inode;
-	    if (ret == 0){
-	      Printk (("unlink nlink = %d ",inode->i_nlink));
-	      inode->i_nlink--;
-	      if (inode->i_nlink == 0){
-		struct inode *hdir = iget(inode->i_sb
-					  ,inode->u.umsdos_i.i_dir_owner);
-		struct umsdos_dirent entry;
-		ret = umsdos_inode2entry (hdir,inode,&entry);
-		if (ret == 0){
-		  ret = UMSDOS_unlink (hdir,dentry);
-		}else{
-		    /* iput (hdir); FIXME */
+				if (!(dir->i_mode & S_ISVTX) || capable (CAP_FOWNER) ||
+				    current->fsuid == info.entry.uid ||
+				    current->fsuid == dir->i_uid) {
+					if (info.entry.flags & UMSDOS_HLINK) {
+						/* #Specification: hard link / deleting a link
+						 * When we deletes a file, and this file is a link
+						 * we must subtract 1 to the nlink field of the
+						 * hidden link.
+						 * 
+						 * If the count goes to 0, we delete this hidden
+						 * link too.
+						 */
+						/*
+						 * First, get the inode of the hidden link
+						 * using the standard lookup function.
+						 */
+						struct inode *inode;
+
+						inc_count (dir);
+						ret = umsdos_lookup_x (dir, dentry, 0);
+						inode = dentry->d_inode;
+						if (ret == 0) {
+							Printk (("unlink nlink = %d ", inode->i_nlink));
+							inode->i_nlink--;
+							if (inode->i_nlink == 0) {
+								struct inode *hdir = iget (inode->i_sb
+											   ,inode->u.umsdos_i.i_dir_owner);
+								struct umsdos_dirent entry;
+
+								ret = umsdos_inode2entry (hdir, inode, &entry);
+								if (ret == 0) {
+									ret = UMSDOS_unlink (hdir, dentry);
+								} else {
+									/* iput (hdir); FIXME */
+								}
+							} else {
+								struct iattr newattrs;
+
+								newattrs.ia_valid = 0;
+								ret = UMSDOS_notify_change (dentry, &newattrs);
+							}
+							/* iput (inode); FIXME */
+						}
+					}
+					if (ret == 0) {
+						ret = umsdos_delentry (dir, &info, 0);
+						if (ret == 0) {
+							struct dentry *temp,
+							*tdir;
+
+							Printk (("Avant msdos_unlink %.*s ", info.fake.len, info.fake.fname));
+							inc_count (dir);	/* FIXME /mn/ is this needed anymore now that msdos_unlink locks dir using d_parent ? */
+							tdir = creat_dentry ("dir-del", 7, dir, NULL);	/* FIXME /mn/: do we need iget(dir->i_ino) or would dir itself suffice ? */
+							temp = creat_dentry (info.fake.fname, info.fake.len, NULL, tdir);
+							umsdos_real_lookup (dir, temp);		/* fill inode part */
+
+							ret = msdos_unlink_umsdos (dir, temp);
+							Printk (("msdos_unlink %.*s %o ret %d ", info.fake.len, info.fake.fname
+								 ,info.entry.mode, ret));
+
+							d_delete (dentry);
+
+							kill_dentry (tdir);
+							kill_dentry (temp);
+						}
+					}
+				} else {
+					/* sticky bit set and we've not got permission */
+					Printk (("sticky set "));
+					ret = -EPERM;
+				}
+			}
+			umsdos_unlockcreate (dir);
 		}
-	      }else{
-		struct iattr newattrs;
-		newattrs.ia_valid = 0;
-		ret = UMSDOS_notify_change (dentry, &newattrs);
-	      }
-	      /* iput (inode); FIXME */
-	    }
-	  }
-	  if (ret == 0){
-	    ret = umsdos_delentry (dir,&info,0);
-	    if (ret == 0){
-	      struct dentry *temp, *tdir;
-	      Printk (("Avant msdos_unlink %.*s ",info.fake.len,info.fake.fname));
-	      dir->i_count++;  /* FIXME /mn/ is this needed anymore now that msdos_unlink locks dir using d_parent ? */
-	      tdir = creat_dentry ("dir-del", 7, dir, NULL);	/* FIXME /mn/: do we need iget(dir->i_ino) or would dir itself suffice ? */
-	      temp = creat_dentry (info.fake.fname, info.fake.len, NULL, tdir);
-	      umsdos_real_lookup (dir, temp);	/* fill inode part */
-	      
-	      ret = msdos_unlink_umsdos (dir, temp);
-	      Printk (("msdos_unlink %.*s %o ret %d ",info.fake.len,info.fake.fname
-		       ,info.entry.mode,ret));
-
-	      d_delete (dentry);
-	      
-	      kill_dentry (tdir);
-	      kill_dentry (temp);
-	    }
-	  }
-	}else{
-	  /* sticky bit set and we've not got permission */
-	  Printk(("sticky set "));
-	  ret = -EPERM;
 	}
-      }
-      umsdos_unlockcreate(dir);
-    }
-  }	
-  /* dput(dentry); FIXME: shouldn't this be done in msdos_unlink ? */
-  Printk (("umsdos_unlink %d\n",ret));
-  return ret;
+	/* dput(dentry); FIXME: shouldn't this be done in msdos_unlink ? */
+	Printk (("umsdos_unlink %d\n", ret));
+	return ret;
 }
 
 
 
 /*
-	Rename a file (move) in the file system.
-*/
-int UMSDOS_rename(
-		  struct inode * old_dir,
-		  struct dentry * old_dentry,
-		  struct inode * new_dir,
-		  struct dentry * new_dentry)
+ * Rename a file (move) in the file system.
+ */
+int UMSDOS_rename (
+			  struct inode *old_dir,
+			  struct dentry *old_dentry,
+			  struct inode *new_dir,
+			  struct dentry *new_dentry)
 {
-  /* #Specification: weakness / rename
-     There is a case where UMSDOS rename has a different behavior
-     than normal UNIX file system. Renaming an open file across
-     directory boundary does not work. Renaming an open file within
-     a directory does work however.
-     
-     The problem (not sure) is in the linux VFS msdos driver.
-     I believe this is not a bug but a design feature, because
-     an inode number represent some sort of directory address
-     in the MSDOS directory structure. So moving the file into
-     another directory does not preserve the inode number.
-  */
-  int ret = umsdos_nevercreat(new_dir,new_dentry,-EEXIST);
-  if (ret == 0){
-    /* umsdos_rename_f eat the inode and we may need those later */
-    old_dir->i_count++;
-    new_dir->i_count++;
-    ret = umsdos_rename_f (old_dir,old_dentry,new_dir,new_dentry,0);
-    if (ret == -EEXIST){
-      /* #Specification: rename / new name exist
-	 If the destination name already exist, it will
-	 silently be removed. EXT2 does it this way
-	 and this is the spec of SUNOS. So does UMSDOS.
-	 
-	 If the destination is an empty directory it will
-	 also be removed.
-      */
-      /* #Specification: rename / new name exist / possible flaw
-	 The code to handle the deletion of the target (file
-	 and directory) use to be in umsdos_rename_f, surrounded
-	 by proper directory locking. This was insuring that only
-	 one process could achieve a rename (modification) operation
-	 in the source and destination directory. This was also
-	 insuring the operation was "atomic".
-	 
-	 This has been changed because this was creating a kernel
-	 stack overflow (stack is only 4k in the kernel). To avoid
-	 the code doing the deletion of the target (if exist) has
-	 been moved to a upper layer. umsdos_rename_f is tried
-	 once and if it fails with EEXIST, the target is removed
-	 and umsdos_rename_f is done again.
-	 
-	 This makes the code cleaner and (not sure) solve a
-	 deadlock problem one tester was experiencing.
-	 
-	 The point is to mention that possibly, the semantic of
-	 "rename" may be wrong. Anyone dare to check that :-)
-	 Be aware that IF it is wrong, to produce the problem you
-	 will need two process trying to rename a file to the
-	 same target at the same time. Again, I am not sure it
-	 is a problem at all.
-      */
-      /* This is not super efficient but should work */
-      new_dir->i_count++;
-      ret = UMSDOS_unlink (new_dir,new_dentry);
-      chkstk();
-      Printk (("rename unlink ret %d -- ",ret));
-      if (ret == -EISDIR){
-	new_dir->i_count++;
-	ret = UMSDOS_rmdir (new_dir,new_dentry);
-	chkstk();
-	Printk (("rename rmdir ret %d -- ",ret));
-      }
-      if (ret == 0){
-	ret = umsdos_rename_f(old_dir,old_dentry,
-			      new_dir,new_dentry,0);
-	new_dir = old_dir = NULL;
-      }
-    }
-  }
-  /*
-  dput (new_dentry);
-  dput (old_dentry); FIXME /mn/ */
-  return ret;
+	/* #Specification: weakness / rename
+	 * There is a case where UMSDOS rename has a different behavior
+	 * than normal UNIX file system. Renaming an open file across
+	 * directory boundary does not work. Renaming an open file within
+	 * a directory does work however.
+	 * 
+	 * The problem (not sure) is in the linux VFS msdos driver.
+	 * I believe this is not a bug but a design feature, because
+	 * an inode number represent some sort of directory address
+	 * in the MSDOS directory structure. So moving the file into
+	 * another directory does not preserve the inode number.
+	 */
+	int ret = umsdos_nevercreat (new_dir, new_dentry, -EEXIST);
+
+	if (ret == 0) {
+		/* umsdos_rename_f eat the inode and we may need those later */
+		inc_count (old_dir);
+		inc_count (new_dir);
+		ret = umsdos_rename_f (old_dir, old_dentry, new_dir, new_dentry, 0);
+		if (ret == -EEXIST) {
+			/* #Specification: rename / new name exist
+			 * If the destination name already exist, it will
+			 * silently be removed. EXT2 does it this way
+			 * and this is the spec of SUNOS. So does UMSDOS.
+			 * 
+			 * If the destination is an empty directory it will
+			 * also be removed.
+			 */
+			/* #Specification: rename / new name exist / possible flaw
+			 * The code to handle the deletion of the target (file
+			 * and directory) use to be in umsdos_rename_f, surrounded
+			 * by proper directory locking. This was insuring that only
+			 * one process could achieve a rename (modification) operation
+			 * in the source and destination directory. This was also
+			 * insuring the operation was "atomic".
+			 * 
+			 * This has been changed because this was creating a kernel
+			 * stack overflow (stack is only 4k in the kernel). To avoid
+			 * the code doing the deletion of the target (if exist) has
+			 * been moved to a upper layer. umsdos_rename_f is tried
+			 * once and if it fails with EEXIST, the target is removed
+			 * and umsdos_rename_f is done again.
+			 * 
+			 * This makes the code cleaner and (not sure) solve a
+			 * deadlock problem one tester was experiencing.
+			 * 
+			 * The point is to mention that possibly, the semantic of
+			 * "rename" may be wrong. Anyone dare to check that :-)
+			 * Be aware that IF it is wrong, to produce the problem you
+			 * will need two process trying to rename a file to the
+			 * same target at the same time. Again, I am not sure it
+			 * is a problem at all.
+			 */
+			/* This is not super efficient but should work */
+			inc_count (new_dir);
+			ret = UMSDOS_unlink (new_dir, new_dentry);
+			chkstk ();
+			Printk (("rename unlink ret %d -- ", ret));
+			if (ret == -EISDIR) {
+				inc_count (new_dir);
+				ret = UMSDOS_rmdir (new_dir, new_dentry);
+				chkstk ();
+				Printk (("rename rmdir ret %d -- ", ret));
+			}
+			if (ret == 0) {
+				ret = umsdos_rename_f (old_dir, old_dentry,
+						 new_dir, new_dentry, 0);
+				new_dir = old_dir = NULL;
+			}
+		}
+	}
+	/*
+	 * dput (new_dentry);
+	 * dput (old_dentry); FIXME /mn/ */
+	return ret;
 }
-
diff -u --recursive --new-file v2.1.102/linux/fs/umsdos/rdir.c linux/fs/umsdos/rdir.c
--- v2.1.102/linux/fs/umsdos/rdir.c	Wed Apr  8 19:36:28 1998
+++ linux/fs/umsdos/rdir.c	Tue May 19 15:06:50 1998
@@ -30,276 +30,284 @@
 	int real_root;
 };
 
-static int rdir_filldir(
-	void * buf,
-	const char *name,
-	int name_len,
-	off_t offset,
-	ino_t ino)
+static int rdir_filldir (
+				void *buf,
+				const char *name,
+				int name_len,
+				off_t offset,
+				ino_t ino)
 {
-  int ret = 0;
-  struct RDIR_FILLDIR *d = (struct RDIR_FILLDIR*) buf;
-  PRINTK ((KERN_DEBUG "rdir_filldir /mn/: entering\n"));
-  if (d->real_root){
-    PRINTK ((KERN_DEBUG "rdir_filldir /mn/: real root!\n"));
-    /* real root of a pseudo_rooted partition */
-    if (name_len != UMSDOS_PSDROOT_LEN
-	|| memcmp(name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN)!=0){
-      /* So it is not the /linux directory */
-      if (name_len == 2
-	  && name[0] == '.'
-	  && name[1] == '.'){
+	int ret = 0;
+	struct RDIR_FILLDIR *d = (struct RDIR_FILLDIR *) buf;
+
+	PRINTK ((KERN_DEBUG "rdir_filldir /mn/: entering\n"));
+	if (d->real_root) {
+		PRINTK ((KERN_DEBUG "rdir_filldir /mn/: real root!\n"));
+		/* real root of a pseudo_rooted partition */
+		if (name_len != UMSDOS_PSDROOT_LEN
+		    || memcmp (name, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN) != 0) {
+			/* So it is not the /linux directory */
+			if (name_len == 2
+			    && name[0] == '.'
+			    && name[1] == '.') {
 				/* Make sure the .. entry points back to the pseudo_root */
-	ino = pseudo_root->i_ino;
-      }
-      ret = d->filldir (d->dirbuf,name,name_len,offset,ino);
-    }
-  }else{
-    /* Any DOS directory */
-    PRINTK ((KERN_DEBUG "rdir_filldir /mn/: calling d->filldir (%p) for %.*s (%lu)\n", d->filldir, name_len, name, ino));
-    ret = d->filldir (d->dirbuf, name, name_len, offset, ino);
-  }
-  return ret;
+				ino = pseudo_root->i_ino;
+			}
+			ret = d->filldir (d->dirbuf, name, name_len, offset, ino);
+		}
+	} else {
+		/* Any DOS directory */
+		PRINTK ((KERN_DEBUG "rdir_filldir /mn/: calling d->filldir (%p) for %.*s (%lu)\n", d->filldir, name_len, name, ino));
+		ret = d->filldir (d->dirbuf, name, name_len, offset, ino);
+	}
+	return ret;
 }
 
 
 static int UMSDOS_rreaddir (
-	struct file *filp,
-	void *dirbuf,
-	filldir_t filldir)
+				   struct file *filp,
+				   void *dirbuf,
+				   filldir_t filldir)
 {
-  struct RDIR_FILLDIR bufk;
-  struct inode *dir = filp->f_dentry->d_inode;
-  
-  PRINTK ((KERN_DEBUG "UMSDOS_rreaddir /mn/: entering %p %p\n", filldir, dirbuf));
-
-  
-  bufk.filldir = filldir;
-  bufk.dirbuf = dirbuf;
-  bufk.real_root = pseudo_root
-    && dir == iget(dir->i_sb,UMSDOS_ROOT_INO)
-    && dir == iget(pseudo_root->i_sb,UMSDOS_ROOT_INO);
-  PRINTK ((KERN_DEBUG "UMSDOS_rreaddir /mn/: calling fat_readdir with filldir=%p and exiting\n",filldir));
-  return fat_readdir(filp, &bufk, rdir_filldir);
+	struct RDIR_FILLDIR bufk;
+	struct inode *dir = filp->f_dentry->d_inode;
+
+	PRINTK ((KERN_DEBUG "UMSDOS_rreaddir /mn/: entering %p %p\n", filldir, dirbuf));
+
+
+	bufk.filldir = filldir;
+	bufk.dirbuf = dirbuf;
+	bufk.real_root = pseudo_root
+	    && dir == iget (dir->i_sb, UMSDOS_ROOT_INO)
+	    && dir == iget (pseudo_root->i_sb, UMSDOS_ROOT_INO);
+	PRINTK ((KERN_DEBUG "UMSDOS_rreaddir /mn/: calling fat_readdir with filldir=%p and exiting\n", filldir));
+	return fat_readdir (filp, &bufk, rdir_filldir);
 }
 
 
 /*
-  Lookup into a non promoted directory.
-  If the result is a directory, make sure we find out if it is
-  a promoted one or not (calling umsdos_setup_dir_inode(inode)).
-*/
-int umsdos_rlookup_x(
-   struct inode *dir,
-   struct dentry *dentry,
-   int nopseudo)   /* Don't care about pseudo root mode */
-     /* so locating "linux" will work */
-{
-  int len = dentry->d_name.len;
-  const char *name = dentry->d_name.name;
-  struct inode *inode;
-  int ret;
-  if (pseudo_root
-      && len == 2
-      && name[0] == '.'
-      && name[1] == '.'
-      && dir == iget(dir->i_sb,UMSDOS_ROOT_INO)
-      && dir == iget(pseudo_root->i_sb,UMSDOS_ROOT_INO) ){
-    /*    *result = pseudo_root;*/
-    Printk ((KERN_WARNING "umsdos_rlookup_x: we are at pseudo-root thingy?\n"));
-    pseudo_root->i_count++;
-    ret = 0;
-    /* #Specification: pseudo root / DOS/..
-       In the real root directory (c:\), the directory ..
-       is the pseudo root (c:\linux).
-    */
-  }else{
-    ret = umsdos_real_lookup (dir, dentry); inode=dentry->d_inode;
+ * Lookup into a non promoted directory.
+ * If the result is a directory, make sure we find out if it is
+ * a promoted one or not (calling umsdos_setup_dir_inode(inode)).
+ */
+int umsdos_rlookup_x (
+			     struct inode *dir,
+			     struct dentry *dentry,
+			     int nopseudo)
+{				/* Don't care about pseudo root mode */
+	/* so locating "linux" will work */
+	int len = dentry->d_name.len;
+	const char *name = dentry->d_name.name;
+	struct inode *inode;
+	int ret;
+
+	if (pseudo_root
+	    && len == 2
+	    && name[0] == '.'
+	    && name[1] == '.'
+	    && dir == iget (dir->i_sb, UMSDOS_ROOT_INO)
+	    && dir == iget (pseudo_root->i_sb, UMSDOS_ROOT_INO)) {
+		/*    *result = pseudo_root; */
+		Printk ((KERN_WARNING "umsdos_rlookup_x: we are at pseudo-root thingy?\n"));
+		inc_count (pseudo_root);
+		ret = 0;
+		/* #Specification: pseudo root / DOS/..
+		 * In the real root directory (c:\), the directory ..
+		 * is the pseudo root (c:\linux).
+		 */
+	} else {
+		ret = umsdos_real_lookup (dir, dentry);
+		inode = dentry->d_inode;
 
 #if 0
-    Printk ((KERN_DEBUG "umsdos_rlookup_x: umsdos_real_lookup for %.*s in %lu returned %d\n", len, name, dir->i_ino, ret));
-    Printk ((KERN_DEBUG "umsdos_rlookup_x: umsdos_real_lookup: inode is %p resolving to ", inode));
-    if (inode) {	/* /mn/ FIXME: DEL_ME */
-        Printk ((KERN_DEBUG "i_ino=%lu\n", inode->i_ino));
-    } else {
-        Printk ((KERN_DEBUG "NONE!\n"));
-    }
+		Printk ((KERN_DEBUG "umsdos_rlookup_x: umsdos_real_lookup for %.*s in %lu returned %d\n", len, name, dir->i_ino, ret));
+		Printk ((KERN_DEBUG "umsdos_rlookup_x: umsdos_real_lookup: inode is %p resolving to ", inode));
+		if (inode) {	/* /mn/ FIXME: DEL_ME */
+			Printk ((KERN_DEBUG "i_ino=%lu\n", inode->i_ino));
+		} else {
+			Printk ((KERN_DEBUG "NONE!\n"));
+		}
 #endif
-    
-    if ((ret == 0) && inode){
-      
-      if (pseudo_root && inode == pseudo_root && !nopseudo){
-      /* #Specification: pseudo root / DOS/linux
-	 Even in the real root directory (c:\), the directory
-	 /linux won't show
-      */
-        Printk ((KERN_WARNING "umsdos_rlookup_x: do the pseudo-thingy...\n"));
-	ret = -ENOENT;
-	/* iput (pseudo_root); FIXME */
-       
-      }else if (S_ISDIR(inode->i_mode)){
-	/* We must place the proper function table */
-	/* depending if this is a MsDOS directory or an UMSDOS directory */
-        Printk ((KERN_DEBUG "umsdos_rlookup_x: setting up setup_dir_inode %lu...\n", inode->i_ino));
-	umsdos_setup_dir_inode (inode);
-      }
-    }
-  }
-  /* iput (dir); FIXME */
-  PRINTK ((KERN_DEBUG "umsdos_rlookup_x: returning %d\n", ret));
-  return ret;
+
+		if ((ret == 0) && inode) {
+
+			if (pseudo_root && inode == pseudo_root && !nopseudo) {
+				/* #Specification: pseudo root / DOS/linux
+				 * Even in the real root directory (c:\), the directory
+				 * /linux won't show
+				 */
+				Printk ((KERN_WARNING "umsdos_rlookup_x: do the pseudo-thingy...\n"));
+				ret = -ENOENT;
+				iput (pseudo_root); /* FIXME? */
+
+			} else if (S_ISDIR (inode->i_mode)) {
+				/* We must place the proper function table */
+				/* depending if this is a MsDOS directory or an UMSDOS directory */
+				Printk ((KERN_DEBUG "umsdos_rlookup_x: setting up setup_dir_inode %lu...\n", inode->i_ino));
+				umsdos_setup_dir_inode (inode);
+			}
+		}
+	}
+	iput (dir); /* FIXME? */
+	PRINTK ((KERN_DEBUG "umsdos_rlookup_x: returning %d\n", ret));
+	return ret;
 }
 
 
-int UMSDOS_rlookup(
-	struct inode *dir,
-	struct dentry *dentry
-	)
+int UMSDOS_rlookup (
+			   struct inode *dir,
+			   struct dentry *dentry
+)
 {
-  PRINTK ((KERN_DEBUG "UMSDOS_rlookup /mn/: executing umsdos_rlookup_x for ino=%lu in %.*s\n", dir->i_ino, (int) dentry->d_name.len, dentry->d_name.name));
-  return umsdos_rlookup_x(dir,dentry,0);
+	PRINTK ((KERN_DEBUG "UMSDOS_rlookup /mn/: executing umsdos_rlookup_x for ino=%lu in %.*s\n", dir->i_ino, (int) dentry->d_name.len, dentry->d_name.name));
+	return umsdos_rlookup_x (dir, dentry, 0);
 }
 
 
 static int UMSDOS_rrmdir (
-	struct inode *dir,
-	struct dentry *dentry)
+				 struct inode *dir,
+				 struct dentry *dentry)
 {
-  /* #Specification: dual mode / rmdir in a DOS directory
-     In a DOS (not EMD in it) directory, we use a reverse strategy
-     compared with an Umsdos directory. We assume that a subdirectory
-     of a DOS directory is also a DOS directory. This is not always
-     true (umssync may be used anywhere), but make sense.
-     
-     So we call msdos_rmdir() directly. If it failed with a -ENOTEMPTY
-     then we check if it is a Umsdos directory. We check if it is
-     really empty (only . .. and --linux-.--- in it). If it is true
-     we remove the EMD and do a msdos_rmdir() again.
-
-     In a Umsdos directory, we assume all subdirectory are also
-     Umsdos directory, so we check the EMD file first.
-  */
-  int ret;
-  if (umsdos_is_pseudodos(dir,dentry)){
-    /* #Specification: pseudo root / rmdir /DOS
-       The pseudo sub-directory /DOS can't be removed!
-       This is done even if the pseudo root is not a Umsdos
-       directory anymore (very unlikely), but an accident (under
-       MsDOS) is always possible.
-       
-       EPERM is returned.
-    */
-    ret = -EPERM;
-  }else{
-    umsdos_lockcreate (dir);
-    dir->i_count++;
-    ret = msdos_rmdir (dir,dentry);
-    if (ret == -ENOTEMPTY){
-      struct inode *sdir;
-      dir->i_count++;
-      
-      ret = UMSDOS_rlookup (dir,dentry);
-      sdir = dentry->d_inode;
-      PRINTK (("rrmdir lookup %d ",ret));
-      if (ret == 0){
-	int empty;
-	if ((empty = umsdos_isempty (sdir)) != 0){
-	  PRINTK (("isempty %d i_count %d ",empty,
-		   atomic_read(&sdir->i_count)));
-	  if (empty == 2){
-	    /*
-	      Not a Umsdos directory, so the previous msdos_rmdir
-	      was not lying :-)
-	    */
-	    ret = -ENOTEMPTY;
-	  }else if (empty == 1){
-	    /* We have to removed the EMD file */
-	    struct dentry *temp;
-	    temp = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, NULL); /* FIXME: prolly should fill inode part ? */
-	    ret = msdos_unlink(sdir, temp);
-	    sdir = NULL;
-	    if (ret == 0){
-	      dir->i_count++;
-	      ret = msdos_rmdir (dir,dentry);
-	    }
-	  }
-	}else{
-	  ret = -ENOTEMPTY;
+	/* #Specification: dual mode / rmdir in a DOS directory
+	 * In a DOS (not EMD in it) directory, we use a reverse strategy
+	 * compared with an Umsdos directory. We assume that a subdirectory
+	 * of a DOS directory is also a DOS directory. This is not always
+	 * true (umssync may be used anywhere), but make sense.
+	 * 
+	 * So we call msdos_rmdir() directly. If it failed with a -ENOTEMPTY
+	 * then we check if it is a Umsdos directory. We check if it is
+	 * really empty (only . .. and --linux-.--- in it). If it is true
+	 * we remove the EMD and do a msdos_rmdir() again.
+	 * 
+	 * In a Umsdos directory, we assume all subdirectory are also
+	 * Umsdos directory, so we check the EMD file first.
+	 */
+	int ret;
+
+	if (umsdos_is_pseudodos (dir, dentry)) {
+		/* #Specification: pseudo root / rmdir /DOS
+		 * The pseudo sub-directory /DOS can't be removed!
+		 * This is done even if the pseudo root is not a Umsdos
+		 * directory anymore (very unlikely), but an accident (under
+		 * MsDOS) is always possible.
+		 * 
+		 * EPERM is returned.
+		 */
+		ret = -EPERM;
+	} else {
+		umsdos_lockcreate (dir);
+		inc_count (dir);
+		ret = msdos_rmdir (dir, dentry);
+		if (ret == -ENOTEMPTY) {
+			struct inode *sdir;
+
+			inc_count (dir);
+
+			ret = UMSDOS_rlookup (dir, dentry);
+			sdir = dentry->d_inode;
+			PRINTK (("rrmdir lookup %d ", ret));
+			if (ret == 0) {
+				int empty;
+
+				if ((empty = umsdos_isempty (sdir)) != 0) {
+					PRINTK (("isempty %d i_count %d ", empty,
+					  atomic_read (&sdir->i_count)));
+					if (empty == 2) {
+						/*
+						 * Not a Umsdos directory, so the previous msdos_rmdir
+						 * was not lying :-)
+						 */
+						ret = -ENOTEMPTY;
+					} else if (empty == 1) {
+						/* We have to removed the EMD file */
+						struct dentry *temp;
+
+						Printk ((KERN_WARNING "UMSDOS_rmdir: hmmm... whatabout inode ? FIXME\n"));
+						temp = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, NULL);	/* FIXME: prolly should fill inode part ? */
+						ret = msdos_unlink (sdir, temp);
+						sdir = NULL;
+						if (ret == 0) {
+							inc_count (dir);
+							ret = msdos_rmdir (dir, dentry);
+						}
+					}
+				} else {
+					ret = -ENOTEMPTY;
+				}
+				/* iput (sdir); FIXME */
+			}
+		}
+		umsdos_unlockcreate (dir);
 	}
-	/* iput (sdir); FIXME */
-      }
-    }
-    umsdos_unlockcreate (dir);
-  }
-  /* iput (dir); FIXME */
-  return ret;
+	/* iput (dir); FIXME */
+	return ret;
 }
 
 /* #Specification: dual mode / introduction
-   One goal of UMSDOS is to allow a practical and simple coexistence
-   between MsDOS and Linux in a single partition. Using the EMD file
-   in each directory, UMSDOS add Unix semantics and capabilities to
-   normal DOS file system. To help and simplify coexistence, here is
-   the logic related to the EMD file.
-   
-   If it is missing, then the directory is managed by the MsDOS driver.
-   The names are limited to DOS limits (8.3). No links, no device special
-   and pipe and so on.
-
-   If it is there, it is the directory. If it is there but empty, then
-   the directory looks empty. The utility umssync allows synchronisation
-   of the real DOS directory and the EMD.
-
-   Whenever umssync is applied to a directory without EMD, one is
-   created on the fly. The directory is promoted to full unix semantic.
-   Of course, the ls command will show exactly the same content as before
-   the umssync session.
-
-   It is believed that the user/admin will promote directories to unix
-   semantic as needed.
-
-   The strategy to implement this is to use two function table (struct
-   inode_operations). One for true UMSDOS directory and one for directory
-   with missing EMD.
-
-   Functions related to the DOS semantic (but aware of UMSDOS) generally
-   have a "r" prefix (r for real) such as UMSDOS_rlookup, to differentiate
-   from the one with full UMSDOS semantic.
-*/
-static struct file_operations umsdos_rdir_operations = {
-  NULL,				/* lseek - default */
-  UMSDOS_dir_read,		/* read */
-  NULL,				/* write - bad */
-  UMSDOS_rreaddir,		/* readdir */
-  NULL,				/* poll - default */
-  UMSDOS_ioctl_dir,		/* ioctl - default */
-  NULL,				/* mmap */
-  NULL,				/* no special open code */
-  NULL,				/* no special release code */
-  NULL				/* fsync */
+ * One goal of UMSDOS is to allow a practical and simple coexistence
+ * between MsDOS and Linux in a single partition. Using the EMD file
+ * in each directory, UMSDOS add Unix semantics and capabilities to
+ * normal DOS file system. To help and simplify coexistence, here is
+ * the logic related to the EMD file.
+ * 
+ * If it is missing, then the directory is managed by the MsDOS driver.
+ * The names are limited to DOS limits (8.3). No links, no device special
+ * and pipe and so on.
+ * 
+ * If it is there, it is the directory. If it is there but empty, then
+ * the directory looks empty. The utility umssync allows synchronisation
+ * of the real DOS directory and the EMD.
+ * 
+ * Whenever umssync is applied to a directory without EMD, one is
+ * created on the fly. The directory is promoted to full unix semantic.
+ * Of course, the ls command will show exactly the same content as before
+ * the umssync session.
+ * 
+ * It is believed that the user/admin will promote directories to unix
+ * semantic as needed.
+ * 
+ * The strategy to implement this is to use two function table (struct
+ * inode_operations). One for true UMSDOS directory and one for directory
+ * with missing EMD.
+ * 
+ * Functions related to the DOS semantic (but aware of UMSDOS) generally
+ * have a "r" prefix (r for real) such as UMSDOS_rlookup, to differentiate
+ * from the one with full UMSDOS semantic.
+ */
+static struct file_operations umsdos_rdir_operations =
+{
+	NULL,			/* lseek - default */
+	UMSDOS_dir_read,	/* read */
+	NULL,			/* write - bad */
+	UMSDOS_rreaddir,	/* readdir */
+	NULL,			/* poll - default */
+	UMSDOS_ioctl_dir,	/* ioctl - default */
+	NULL,			/* mmap */
+	NULL,			/* no special open code */
+	NULL,			/* no special release code */
+	NULL			/* fsync */
 };
 
-struct inode_operations umsdos_rdir_inode_operations = {
-  &umsdos_rdir_operations,	/* default directory file-ops */
-  msdos_create,			/* create */
-  UMSDOS_rlookup,		/* lookup */
-  NULL,				/* link */
-  msdos_unlink,			/* unlink */
-  NULL,				/* symlink */
-  msdos_mkdir,			/* mkdir */
-  UMSDOS_rrmdir,		/* rmdir */
-  NULL,				/* mknod */
-  msdos_rename,			/* rename */
-  NULL,				/* readlink */
-  NULL,				/* followlink */
-  NULL,				/* readpage */
-  NULL,				/* writepage */
-  NULL,				/* bmap */
-  NULL,				/* truncate */
-  NULL,				/* permission */
-  NULL,				/* smap */
-  NULL,				/* updatepage */
-  NULL,				/* revalidate */
+struct inode_operations umsdos_rdir_inode_operations =
+{
+	&umsdos_rdir_operations,	/* default directory file-ops */
+	msdos_create,		/* create */
+	UMSDOS_rlookup,		/* lookup */
+	NULL,			/* link */
+	msdos_unlink,		/* unlink */
+	NULL,			/* symlink */
+	msdos_mkdir,		/* mkdir */
+	UMSDOS_rrmdir,		/* rmdir */
+	NULL,			/* mknod */
+	msdos_rename,		/* rename */
+	NULL,			/* readlink */
+	NULL,			/* followlink */
+	NULL,			/* readpage */
+	NULL,			/* writepage */
+	NULL,			/* bmap */
+	NULL,			/* truncate */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL,			/* updatepage */
+	NULL,			/* revalidate */
 };
-
-
diff -u --recursive --new-file v2.1.102/linux/fs/umsdos/symlink.c linux/fs/umsdos/symlink.c
--- v2.1.102/linux/fs/umsdos/symlink.c	Tue Mar 17 22:18:15 1998
+++ linux/fs/umsdos/symlink.c	Tue May 19 15:06:50 1998
@@ -2,7 +2,7 @@
  *  linux/fs/umsdos/file.c
  *
  *  Written 1992 by Jacques Gelinas
- *	inspired from linux/fs/msdos/file.c Werner Almesberger
+ *      inspired from linux/fs/msdos/file.c Werner Almesberger
  *
  *  Extended MS-DOS regular file handling primitives
  */
@@ -26,59 +26,57 @@
 
 
 /*
-	Read the data associate with the symlink.
-	Return length read in buffer or  a negative error code.
-	
-*/
+ * Read the data associate with the symlink.
+ * Return length read in buffer or  a negative error code.
+ * 
+ */
 
 static int umsdos_readlink_x (
-	struct dentry *dentry,
-	char *buffer,
-	int bufsiz)
+				     struct dentry *dentry,
+				     char *buffer,
+				     int bufsiz)
 {
 	int ret;
 	loff_t loffs = 0;
 	struct file filp;
 
-        fill_new_filp (&filp, NULL);
-	
 	ret = dentry->d_inode->i_size;
-	
-	memset (&filp, 0, sizeof (filp));
-	
-	filp.f_pos = 0;
+
+	check_dentry (dentry);
+	fill_new_filp (&filp, dentry);
+
 	filp.f_reada = 0;
 	filp.f_flags = O_RDONLY;
-	filp.f_dentry = dentry;
-        filp.f_op = &umsdos_symlink_operations;	 /* /mn/ - we have to fill it with dummy values so we won't segfault */
+	filp.f_op = &umsdos_symlink_operations;		/* /mn/ - we have to fill it with dummy values so we won't segfault */
 
-	if (ret > bufsiz) ret = bufsiz;
+	if (ret > bufsiz)
+		ret = bufsiz;
 
-        PRINTK ((KERN_DEBUG "umsdos_readlink_x /mn/: Checkin: filp=%p, buffer=%p, size=%d, offs=%Lu\n", &filp, buffer, ret, loffs));
-        PRINTK ((KERN_DEBUG "  f_op=%p\n", filp.f_op));
-        PRINTK ((KERN_DEBUG "  inode=%lu, i_size=%lu\n", filp.f_dentry->d_inode->i_ino, filp.f_dentry->d_inode->i_size));
-        PRINTK ((KERN_DEBUG "  f_pos=%Lu\n", filp.f_pos));
-        PRINTK ((KERN_DEBUG "  name=%.*s\n", (int) filp.f_dentry->d_name.len, filp.f_dentry->d_name.name));
-        PRINTK ((KERN_DEBUG "  i_binary(sb)=%d\n", MSDOS_I(filp.f_dentry->d_inode)->i_binary ));
-        PRINTK ((KERN_DEBUG "  f_count=%d, f_flags=%d\n", filp.f_count, filp.f_flags));
-        PRINTK ((KERN_DEBUG "  f_owner=%d\n", filp.f_owner.uid));
-        PRINTK ((KERN_DEBUG "  f_version=%ld\n", filp.f_version));
-        PRINTK ((KERN_DEBUG "  f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp.f_reada, filp.f_ramax, filp.f_raend, filp.f_ralen, filp.f_rawin));
+	PRINTK ((KERN_DEBUG "umsdos_readlink_x /mn/: Checkin: filp=%p, buffer=%p, size=%d, offs=%Lu\n", &filp, buffer, ret, loffs));
+	PRINTK ((KERN_DEBUG "  f_op=%p\n", filp.f_op));
+	PRINTK ((KERN_DEBUG "  inode=%lu, i_size=%lu\n", filp.f_dentry->d_inode->i_ino, filp.f_dentry->d_inode->i_size));
+	PRINTK ((KERN_DEBUG "  f_pos=%Lu\n", filp.f_pos));
+	PRINTK ((KERN_DEBUG "  name=%.*s\n", (int) filp.f_dentry->d_name.len, filp.f_dentry->d_name.name));
+	PRINTK ((KERN_DEBUG "  i_binary(sb)=%d\n", MSDOS_I (filp.f_dentry->d_inode)->i_binary));
+	PRINTK ((KERN_DEBUG "  f_count=%d, f_flags=%d\n", filp.f_count, filp.f_flags));
+	PRINTK ((KERN_DEBUG "  f_owner=%d\n", filp.f_owner.uid));
+	PRINTK ((KERN_DEBUG "  f_version=%ld\n", filp.f_version));
+	PRINTK ((KERN_DEBUG "  f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp.f_reada, filp.f_ramax, filp.f_raend, filp.f_ralen, filp.f_rawin));
 
 
-	PRINTK ((KERN_DEBUG"umsdos_readlink_x: FIXME /mn/: running fat_file_read (%p, %p, %d, %Lu)\n", &filp, buffer, ret, loffs));
-	if (fat_file_read (&filp, buffer, (size_t) ret, &loffs) != ret){
+	PRINTK ((KERN_DEBUG "umsdos_readlink_x: FIXME /mn/: running fat_file_read (%p, %p, %d, %Lu)\n", &filp, buffer, ret, loffs));
+	if (fat_file_read (&filp, buffer, (size_t) ret, &loffs) != ret) {
 		ret = -EIO;
 	}
-#if 0	/* DEBUG */
-    {
-      struct umsdos_dirent *mydirent=buffer;
-
-      PRINTK ((KERN_DEBUG "  (DDD) uid=%d\n",mydirent->uid));
-      PRINTK ((KERN_DEBUG "  (DDD) gid=%d\n",mydirent->gid));
-      PRINTK ((KERN_DEBUG "  (DDD) name=>%.20s<\n",mydirent->name));
-    }
-#endif  
+#if 0				/* DEBUG */
+	{
+		struct umsdos_dirent *mydirent = buffer;
+
+		PRINTK ((KERN_DEBUG "  (DDD) uid=%d\n", mydirent->uid));
+		PRINTK ((KERN_DEBUG "  (DDD) gid=%d\n", mydirent->gid));
+		PRINTK ((KERN_DEBUG "  (DDD) name=>%.20s<\n", mydirent->name));
+	}
+#endif
 
 	PRINTK ((KERN_DEBUG "umsdos_readlink_x: FIXME /mn/: fat_file_read returned offs=%Lu ret=%d\n", loffs, ret));
 	return ret;
@@ -86,7 +84,7 @@
 
 
 
-static int UMSDOS_readlink(struct dentry *dentry, char *buffer, int buflen)
+static int UMSDOS_readlink (struct dentry *dentry, char *buffer, int buflen)
 {
 	int ret;
 
@@ -96,67 +94,69 @@
 	/* dput(dentry); / * FIXME /mn/ */
 	Printk ((KERN_WARNING "UMSDOS_readlink /mn/: FIXME! skipped dput(dentry). returning %d\n", ret));
 	return ret;
-	
+
 }
 
 /* this one mostly stolen from romfs :) */
-static struct dentry *UMSDOS_followlink(struct dentry *dentry, struct dentry *base)
+static struct dentry *UMSDOS_followlink (struct dentry *dentry, struct dentry *base)
 {
 	struct inode *inode = dentry->d_inode;
-	char *symname=NULL;
+	char *symname = NULL;
 	int len, cnt;
-	mm_segment_t old_fs = get_fs();
+	mm_segment_t old_fs = get_fs ();
+
 	Printk ((KERN_DEBUG "UMSDOS_followlink /mn/: (%.*s/%.*s)\n", (int) dentry->d_parent->d_name.len, dentry->d_parent->d_name.name, (int) dentry->d_name.len, dentry->d_name.name));
 
 	len = inode->i_size;
 
-	if (!(symname = kmalloc(len+1, GFP_KERNEL))) {
-		dentry = ERR_PTR(-EAGAIN);			/* correct? */
+	if (!(symname = kmalloc (len + 1, GFP_KERNEL))) {
+		dentry = ERR_PTR (-EAGAIN);	/* correct? */
 		goto outnobuf;
 	}
-
 	set_fs (KERNEL_DS);	/* we read into kernel space this time */
 	PRINTK ((KERN_DEBUG "UMSDOS_followlink /mn/: Here goes umsdos_readlink_x %p, %p, %d\n", dentry, symname, len));
 	cnt = umsdos_readlink_x (dentry, symname, len);
 	PRINTK ((KERN_DEBUG "UMSDOS_followlink /mn/: back from umsdos_readlink_x %p, %p, %d!\n", dentry, symname, len));
 	set_fs (old_fs);
 	Printk ((KERN_DEBUG "UMSDOS_followlink /mn/: link name is %.*s with len %d\n", cnt, symname, cnt));
-	
+
 	if (len != cnt) {
-		dentry = ERR_PTR(-EIO);
+		dentry = ERR_PTR (-EIO);
 		goto out;
 	} else
 		symname[len] = 0;
 
-	dentry = lookup_dentry(symname, base, 1);
-	kfree(symname);
+	dentry = lookup_dentry (symname, base, 1);
+	kfree (symname);
 
 	if (0) {
-out:
-		kfree(symname);
-outnobuf:
-		dput(base);
+	      out:
+		kfree (symname);
+	      outnobuf:
+		dput (base);
 	}
 	return dentry;
 }
 
 
-static struct file_operations umsdos_symlink_operations = {
-	NULL,				/* lseek - default */
-	NULL,				/* read */
-	NULL,				/* write */
-	NULL,				/* readdir - bad */
-	NULL,				/* poll - default */
-	NULL,				/* ioctl - default */
-	NULL,				/* mmap */
-	NULL,				/* no special open is needed */
-	NULL,				/* release */
-	NULL				/* fsync */
+static struct file_operations umsdos_symlink_operations =
+{
+	NULL,			/* lseek - default */
+	NULL,			/* read */
+	NULL,			/* write */
+	NULL,			/* readdir - bad */
+	NULL,			/* poll - default */
+	NULL,			/* ioctl - default */
+	NULL,			/* mmap */
+	NULL,			/* no special open is needed */
+	NULL,			/* release */
+	NULL			/* fsync */
 };
 
 
-struct inode_operations umsdos_symlink_inode_operations = {
-	NULL,	/* default file operations */
+struct inode_operations umsdos_symlink_inode_operations =
+{
+	NULL,			/* default file operations */
 	NULL,			/* create */
 	NULL,			/* lookup */
 	NULL,			/* link */
@@ -167,17 +167,14 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	UMSDOS_readlink,	/* readlink */
-	UMSDOS_followlink,	/* followlink */	/* /mn/ is this REALLY needed ? I recall seeing it working w/o it... */
-	generic_readpage,	/* readpage */	/* in original NULL. changed to generic_readpage. FIXME? /mn/ */
+	UMSDOS_followlink,	/* followlink *//* /mn/ is this REALLY needed ? I recall seeing it working w/o it... */
+	generic_readpage,	/* readpage *//* in original NULL. changed to generic_readpage. FIXME? /mn/ */
 	NULL,			/* writepage */
-	fat_bmap,		/* bmap */	/* in original NULL. changed to fat_bmap. FIXME? /mn/ */
+	fat_bmap,		/* bmap *//* in original NULL. changed to fat_bmap. FIXME? /mn/ */
 	NULL,			/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
 	NULL,			/* updatepage */
 	NULL			/* revalidate */
-	
-};
-
-
 
+};
diff -u --recursive --new-file v2.1.102/linux/include/asm-i386/processor.h linux/include/asm-i386/processor.h
--- v2.1.102/linux/include/asm-i386/processor.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-i386/processor.h	Tue May 19 09:59:41 1998
@@ -71,6 +71,9 @@
 extern unsigned int machine_submodel_id;
 extern unsigned int BIOS_revision;
 
+/* Lazy FPU handling on uni-processor */
+extern struct task_struct *last_task_used_math;
+
 /*
  * User space process size: 3GB (default).
  */
diff -u --recursive --new-file v2.1.102/linux/include/asm-mips/mipsregs.h linux/include/asm-mips/mipsregs.h
--- v2.1.102/linux/include/asm-mips/mipsregs.h	Fri May  8 23:14:55 1998
+++ linux/include/asm-mips/mipsregs.h	Thu May 14 19:01:21 1998
@@ -317,20 +317,20 @@
 #define  CAUSEF_BD		(1   << 31)
 
 /*
- * Bits in the coprozessor 0 config register.
+ * Bits in the coprocessor 0 config register.
  */
-#define CONFIG_CM_CACHABLE_NO_WA	0
-#define CONFIG_CM_CACHABLE_WA		1
-#define CONFIG_CM_UNCACHED		2
-#define CONFIG_CM_CACHABLE_NONCOHERENT	3
-#define CONFIG_CM_CACHABLE_CE		4
-#define CONFIG_CM_CACHABLE_COW		5
-#define CONFIG_CM_CACHABLE_CUW		6
-#define CONFIG_CM_CACHABLE_ACCELERATED	7
-#define CONFIG_CM_CMASK			7
-#define CONFIG_DB			(1 <<  4)
-#define CONFIG_IB			(1 <<  5)
-#define CONFIG_SC			(1 << 17)
+#define CONF_REG_CM_CACHABLE_NO_WA	0
+#define CONF_REG_CM_CACHABLE_WA		1
+#define CONF_REG_CM_UNCACHED		2
+#define CONF_REG_CM_CACHABLE_NONCOHERENT	3
+#define CONF_REG_CM_CACHABLE_CE		4
+#define CONF_REG_CM_CACHABLE_COW		5
+#define CONF_REG_CM_CACHABLE_CUW		6
+#define CONF_REG_CM_CACHABLE_ACCELERATED	7
+#define CONF_REG_CM_CMASK			7
+#define CONF_REG_DB			(1 <<  4)
+#define CONF_REG_IB			(1 <<  5)
+#define CONF_REG_SC			(1 << 17)
 
 /*
  * R10000 performance counter definitions.
diff -u --recursive --new-file v2.1.102/linux/include/linux/arcdevice.h linux/include/linux/arcdevice.h
--- v2.1.102/linux/include/linux/arcdevice.h	Sun Dec 21 17:27:17 1997
+++ linux/include/linux/arcdevice.h	Thu May 14 18:57:36 1998
@@ -114,10 +114,11 @@
 /* macros to simplify debug checking */
 #define BUGLVL(x) if ((ARCNET_DEBUG_MAX)&arcnet_debug&(x))
 #define BUGMSG2(x,msg,args...) BUGLVL(x) printk(msg, ## args)
-#define BUGMSG(x,msg,args...) BUGMSG2(x,"%s%6s: " msg, \
+#define BUGMSG(x,msg,args...) do { \
+	BUGMSG2(x,"%s%6s: " msg, \
             x==D_NORMAL	? KERN_WARNING : \
       x<=D_INIT_REASONS	? KERN_INFO    : KERN_DEBUG , \
-	dev->name , ## args)
+	dev->name , ## args); } while (0)
 
 
 #define SETMASK AINTMASK(lp->intmask)
diff -u --recursive --new-file v2.1.102/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.1.102/linux/include/linux/pci.h	Thu May  7 22:51:55 1998
+++ linux/include/linux/pci.h	Thu May 14 18:58:56 1998
@@ -1,25 +1,17 @@
 /*
- *	$Id: pci.h,v 1.70 1998/05/02 19:20:03 mj Exp $
+ *	$Id: pci.h,v 1.72 1998/05/12 07:35:54 mj Exp $
  *
  *	PCI defines and function prototypes
  *	Copyright 1994, Drew Eckhardt
- *	Copyright 1997, Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *	Copyright 1997, 1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
  *
- *	For more information, please consult 
- * 
- *	PCI BIOS Specification Revision
+ *	For more information, please consult the following manuals (look at
+ *	http://www.pcisig.com/ for how to get them):
+ *
+ *	PCI BIOS Specification
  *	PCI Local Bus Specification
+ *	PCI to PCI Bridge Specification
  *	PCI System Design Guide
- *
- *	PCI Special Interest Group
- *	M/S HF3-15A
- *	5200 N.E. Elam Young Parkway
- *	Hillsboro, Oregon 97124-6497
- *	+1 (503) 696-2000 
- *	+1 (800) 433-5177
- * 
- *	Manuals are $25 each or $50 for all three, plus $7 shipping 
- *	within the United States, $35 abroad.
  */
 
 #ifndef LINUX_PCI_H
@@ -1081,6 +1073,7 @@
 	struct pci_dev	*next;		/* chain of all devices */
 
 	void		*sysdata;	/* hook for sys-specific extension */
+	struct proc_dir_entry *procent;	/* device entry in /proc/bus/pci */
 
 	unsigned int	devfn;		/* encoded device & function index */
 	unsigned short	vendor;
@@ -1117,6 +1110,7 @@
 	struct pci_dev	*devices;	/* devices behind this bridge */
 
 	void		*sysdata;	/* hook for sys-specific extension */
+	struct proc_dir_entry *procdir;	/* directory entry in /proc/bus/pci */
 
 	unsigned char	number;		/* bus number */
 	unsigned char	primary;	/* number of primary bridge */
@@ -1134,6 +1128,8 @@
 void pci_proc_init(void);
 void proc_old_pci_init(void);
 int get_pci_list(char *buf);
+int pci_proc_attach_device(struct pci_dev *dev);
+int pci_proc_detach_device(struct pci_dev *dev);
 
 struct pci_dev *pci_find_device (unsigned int vendor, unsigned int device, struct pci_dev *from);
 struct pci_dev *pci_find_class (unsigned int class, struct pci_dev *from);
diff -u --recursive --new-file v2.1.102/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.1.102/linux/include/linux/sched.h	Thu May  7 22:51:55 1998
+++ linux/include/linux/sched.h	Wed May 20 16:21:43 1998
@@ -378,7 +378,6 @@
 
 extern struct   mm_struct init_mm;
 extern struct task_struct *task[NR_TASKS];
-extern struct task_struct *last_task_used_math;
 
 extern struct task_struct **tarray_freelist;
 extern spinlock_t taskslot_lock;
diff -u --recursive --new-file v2.1.102/linux/include/linux/umsdos_fs.h linux/include/linux/umsdos_fs.h
--- v2.1.102/linux/include/linux/umsdos_fs.h	Wed Apr  8 19:36:29 1998
+++ linux/include/linux/umsdos_fs.h	Wed May 20 16:24:36 1998
@@ -24,8 +24,8 @@
 
 
 struct umsdos_fake_info {
-  char fname[13];
-  int  len;
+	char fname[13];
+	int len;
 };
 
 #define UMSDOS_MAXNAME	220
@@ -33,99 +33,106 @@
 /* of it is written to disk */
 /* nice though it would be, I can't change this and preserve backward compatibility */
 struct umsdos_dirent {
-  unsigned char name_len;	/* if == 0, then this entry is not used */
-  unsigned char  flags;	/* UMSDOS_xxxx */
-  unsigned short nlink;	/* How many hard links point to this entry */
-  uid_t uid;		/* Owner user id */
-  gid_t	gid;		/* Group id */
-  time_t atime;		/* Access time */
-  time_t mtime;		/* Last modification time */
-  time_t ctime;		/* Creation time */
-  dev_t	rdev;		/* major and minor number of a device */
-  /* special file */
-  umode_t mode;		/* Standard UNIX permissions bits + type of */
-  char	spare[12];	/* unused bytes for future extensions */
-  /* file, see linux/stat.h */
-  char name[UMSDOS_MAXNAME];	/* Not '\0' terminated */
-  /* but '\0' padded, so it will allow */
-  /* for adding news fields in this record */
-  /* by reducing the size of name[] */
+	unsigned char name_len;	/* if == 0, then this entry is not used */
+	unsigned char flags;	/* UMSDOS_xxxx */
+	unsigned short nlink;	/* How many hard links point to this entry */
+	uid_t uid;		/* Owner user id */
+	gid_t gid;		/* Group id */
+	time_t atime;		/* Access time */
+	time_t mtime;		/* Last modification time */
+	time_t ctime;		/* Creation time */
+	dev_t rdev;		/* major and minor number of a device */
+				/* special file */
+	umode_t mode;		/* Standard UNIX permissions bits + type of */
+	char spare[12];		/* unused bytes for future extensions */
+				/* file, see linux/stat.h */
+	char name[UMSDOS_MAXNAME];	/* Not '\0' terminated */
+				/* but '\0' padded, so it will allow */
+				/* for adding news fields in this record */
+				/* by reducing the size of name[] */
 };
+
 #define UMSDOS_HIDDEN	1	/* Never show this entry in directory search */
 #define UMSDOS_HLINK	2	/* It is a (pseudo) hard link */
 
 /* #Specification: EMD file / record size
-	Entry are 64 bytes wide in the EMD file. It allows for a 30 characters
-	name. If a name is longer, contiguous entries are allocated. So a
-	umsdos_dirent may span multiple records.
-*/
+ * Entry are 64 bytes wide in the EMD file. It allows for a 30 characters
+ * name. If a name is longer, contiguous entries are allocated. So a
+ * umsdos_dirent may span multiple records.
+ */
+ 
 #define UMSDOS_REC_SIZE		64
 
 /* Translation between MSDOS name and UMSDOS name */
 
-struct umsdos_info{
-  int msdos_reject;	/* Tell if the file name is invalid for MSDOS */
-  /* See umsdos_parse */
-  struct umsdos_fake_info fake;  
-  struct umsdos_dirent entry;
-  off_t f_pos;		/* offset of the entry in the EMD file */
-  /* or offset where the entry may be store */
-  /* if it is a new entry */
-  int recsize;		/* Record size needed to store entry */
+struct umsdos_info {
+	int msdos_reject;	/* Tell if the file name is invalid for MSDOS */
+				/* See umsdos_parse */
+	struct umsdos_fake_info fake;
+	struct umsdos_dirent entry;
+	off_t f_pos;		/* offset of the entry in the EMD file
+				 * or offset where the entry may be store
+				 * if it is a new entry
+				 */
+	int recsize;		/* Record size needed to store entry */
 };
 
-/* Definitions for ioctl (number randomly chosen) */
-/* The next ioctl commands operate only on the DOS directory */
-/* The file umsdos_progs/umsdosio.c contain a string table */
-/* based on the order of those definition. Keep it in sync */
-#define UMSDOS_READDIR_DOS _IO(0x04,210) /* Do a readdir of the DOS directory */
-#define UMSDOS_UNLINK_DOS  _IO(0x04,211) /* Erase in the DOS directory only */
-#define UMSDOS_RMDIR_DOS   _IO(0x04,212) /* rmdir in the DOS directory only */
-#define UMSDOS_STAT_DOS    _IO(0x04,213) /* Get info about a file */
+/* Definitions for ioctl (number randomly chosen)
+ * The next ioctl commands operate only on the DOS directory
+ * The file umsdos_progs/umsdosio.c contain a string table
+ * based on the order of those definition. Keep it in sync
+ */
+#define UMSDOS_READDIR_DOS _IO(0x04,210)	/* Do a readdir of the DOS directory */
+#define UMSDOS_UNLINK_DOS  _IO(0x04,211)	/* Erase in the DOS directory only */
+#define UMSDOS_RMDIR_DOS   _IO(0x04,212)	/* rmdir in the DOS directory only */
+#define UMSDOS_STAT_DOS    _IO(0x04,213)	/* Get info about a file */
+
 /* The next ioctl commands operate only on the EMD file */
-#define UMSDOS_CREAT_EMD   _IO(0x04,214) /* Create a file */
-#define UMSDOS_UNLINK_EMD  _IO(0x04,215) /* unlink (rmdir) a file */
-#define UMSDOS_READDIR_EMD _IO(0x04,216) /* read the EMD file only. */
-#define UMSDOS_GETVERSION  _IO(0x04,217) /* Get the release number of UMSDOS */
-#define UMSDOS_INIT_EMD    _IO(0x04,218) /* Create the EMD file if not there */
-#define UMSDOS_DOS_SETUP   _IO(0x04,219) /* Set the defaults of the MsDOS driver */
-
-#define UMSDOS_RENAME_DOS  _IO(0x04,220) /* rename a file/directory in the DOS */
-									/* directory only */
-struct umsdos_ioctl{
-  struct dirent dos_dirent;
-  struct umsdos_dirent umsdos_dirent;
-  /* The following structure is used to exchange some data */
-  /* with utilities (umsdos_progs/util/umsdosio.c). The first */
-  /* releases were using struct stat from "sys/stat.h". This was */
-  /* causing some problem for cross compilation of the kernel */
-  /* Since I am not really using the structure stat, but only some field */
-  /* of it, I have decided to replicate the structure here */
-  /* for compatibility with the binaries out there */
-  /* FIXME PTW 1998, this has probably changed */
-  struct {
-    dev_t		st_dev;
-    unsigned short	__pad1;
-    ino_t		st_ino;
-    umode_t		st_mode;
-    nlink_t		st_nlink;
-    uid_t		st_uid;
-    gid_t		st_gid;
-    dev_t		st_rdev;
-    unsigned short	__pad2;
-    off_t		st_size;
-    unsigned long	st_blksize;
-    unsigned long	st_blocks;
-    time_t		st_atime;
-    unsigned long	__unused1;
-    time_t		st_mtime;
-    unsigned long	__unused2;
-    time_t		st_ctime;
-    unsigned long	__unused3;
-    unsigned long	__unused4;
-    unsigned long	__unused5;
-  }stat;
-  char version,release;
+#define UMSDOS_CREAT_EMD   _IO(0x04,214)	/* Create a file */
+#define UMSDOS_UNLINK_EMD  _IO(0x04,215)	/* unlink (rmdir) a file */
+#define UMSDOS_READDIR_EMD _IO(0x04,216)	/* read the EMD file only. */
+#define UMSDOS_GETVERSION  _IO(0x04,217)	/* Get the release number of UMSDOS */
+#define UMSDOS_INIT_EMD    _IO(0x04,218)	/* Create the EMD file if not there */
+#define UMSDOS_DOS_SETUP   _IO(0x04,219)	/* Set the defaults of the MsDOS driver */
+
+#define UMSDOS_RENAME_DOS  _IO(0x04,220)	/* rename a file/directory in the DOS
+						 * directory only */
+struct umsdos_ioctl {
+	struct dirent dos_dirent;
+	struct umsdos_dirent umsdos_dirent;
+	/* The following structure is used to exchange some data
+	 * with utilities (umsdos_progs/util/umsdosio.c). The first
+	 * releases were using struct stat from "sys/stat.h". This was
+	 * causing some problem for cross compilation of the kernel
+	 * Since I am not really using the structure stat, but only some field
+	 * of it, I have decided to replicate the structure here
+	 * for compatibility with the binaries out there
+	 * FIXME PTW 1998, this has probably changed
+	 */
+	
+	struct {
+		dev_t st_dev;
+		unsigned short __pad1;
+		ino_t st_ino;
+		umode_t st_mode;
+		nlink_t st_nlink;
+		uid_t st_uid;
+		gid_t st_gid;
+		dev_t st_rdev;
+		unsigned short __pad2;
+		off_t st_size;
+		unsigned long st_blksize;
+		unsigned long st_blocks;
+		time_t st_atime;
+		unsigned long __unused1;
+		time_t st_mtime;
+		unsigned long __unused2;
+		time_t st_ctime;
+		unsigned long __unused3;
+		unsigned long __unused4;
+		unsigned long __unused5;
+	} stat;
+	char version, release;
 };
 
 /* Different macros to access struct umsdos_dirent */
@@ -138,15 +145,15 @@
 #endif
 
 extern struct inode_operations umsdos_dir_inode_operations;
-extern struct file_operations  umsdos_file_operations;
+extern struct file_operations umsdos_file_operations;
 extern struct inode_operations umsdos_file_inode_operations;
 extern struct inode_operations umsdos_file_inode_operations_no_bmap;
 extern struct inode_operations umsdos_file_inode_operations_readpage;
 extern struct inode_operations umsdos_symlink_inode_operations;
-extern int init_umsdos_fs(void);
+extern int init_umsdos_fs (void);
 
 #include <linux/umsdos_fs.p>
 
-#endif /* __KERNEL__ */
+#endif				/* __KERNEL__ */
 
 #endif
diff -u --recursive --new-file v2.1.102/linux/include/linux/umsdos_fs.p linux/include/linux/umsdos_fs.p
--- v2.1.102/linux/include/linux/umsdos_fs.p	Wed Apr  8 19:36:29 1998
+++ linux/include/linux/umsdos_fs.p	Tue May 19 15:06:49 1998
@@ -27,12 +27,6 @@
 	 
 int umsdos_hlink2inode (struct inode *hlink, struct inode **result);
 /* emd.c 22/06/95 00.22.04 */
-void fill_new_filp (struct file *filp, struct dentry *dentry);
-void kill_dentry (struct dentry *dentry);
-struct dentry *creat_dentry (const char *name,
-			     const int len,
-			     struct inode *inode,
-			     struct dentry *parent);
 ssize_t umsdos_file_write_kmem_real (struct file *filp,
 				const char *buf,
 				size_t  count,
@@ -77,6 +71,16 @@
 	 int expect);
 /* file.c 25/01/95 02.25.38 */
 /* inode.c 12/06/95 09.49.40 */
+inline struct dentry *geti_dentry (struct inode *inode);
+inline void inc_count (struct inode *inode);
+void check_inode (struct inode *inode);
+void check_dentry (struct dentry *dentry);
+void fill_new_filp (struct file *filp, struct dentry *dentry);
+void kill_dentry (struct dentry *dentry);
+struct dentry *creat_dentry (const char *name,
+			     const int len,
+			     struct inode *inode,
+			     struct dentry *parent);
 void UMSDOS_put_inode (struct inode *inode);
 void UMSDOS_put_super (struct super_block *sb);
 int UMSDOS_statfs (struct super_block *sb,
diff -u --recursive --new-file v2.1.102/linux/include/linux/umsdos_fs_i.h linux/include/linux/umsdos_fs_i.h
--- v2.1.102/linux/include/linux/umsdos_fs_i.h	Fri Feb  6 15:32:54 1998
+++ linux/include/linux/umsdos_fs_i.h	Tue May 19 15:06:49 1998
@@ -4,65 +4,68 @@
 #ifndef _LINUX_TYPES_H
 #include <linux/types.h>
 #endif
+
 #include <linux/msdos_fs_i.h>
 #include <linux/pipe_fs_i.h>
 
 /* #Specification: strategy / in memory inode
-	Here is the information specific to the inode of the UMSDOS file
-	system. This information is added to the end of the standard struct
-	inode. Each file system has its own extension to struct inode,
-	so do the umsdos file system.
-
-	The strategy is to have the umsdos_inode_info as a superset of
-	the msdos_inode_info, since most of the time the job is done
-	by the msdos fs code.
-
-	So we duplicate the msdos_inode_info, and add our own info at the
-	end.
-
-	For all file type (and directory) the inode has a reference to:
-		the directory which hold this entry: i_dir_owner
-		The EMD file of i_dir_owner: i_emd_owner
-		The offset in this EMD file of the entry: pos
-
-	For directory, we also have a reference to the inode of its
-	own EMD file. Also, we have dir_locking_info to help synchronise
-	file creation and file lookup. This data is sharing space with
-	the pipe_inode_info not used by directory. See also msdos_fs_i.h
-	for more information about pipe_inode_info and msdos_inode_info.
+ * Here is the information specific to the inode of the UMSDOS file
+ * system. This information is added to the end of the standard struct
+ * inode. Each file system has its own extension to struct inode,
+ * so do the umsdos file system.
+ * 
+ * The strategy is to have the umsdos_inode_info as a superset of
+ * the msdos_inode_info, since most of the time the job is done
+ * by the msdos fs code.
+ * 
+ * So we duplicate the msdos_inode_info, and add our own info at the
+ * end.
+ * 
+ * For all file type (and directory) the inode has a reference to:
+ * the directory which hold this entry: i_dir_owner
+ * The EMD file of i_dir_owner: i_emd_owner
+ * The offset in this EMD file of the entry: pos
+ * 
+ * For directory, we also have a reference to the inode of its
+ * own EMD file. Also, we have dir_locking_info to help synchronise
+ * file creation and file lookup. This data is sharing space with
+ * the pipe_inode_info not used by directory. See also msdos_fs_i.h
+ * for more information about pipe_inode_info and msdos_inode_info.
+ * 
+ * Special file and fifo do have an inode which correspond to an
+ * empty MSDOS file.
+ * 
+ * symlink are processed mostly like regular file. The content is the
+ * link.
+ * 
+ * fifos add there own extension to the inode. I have reserved some
+ * space for fifos side by side with msdos_inode_info. This is just
+ * to for the show, because msdos_inode_info already include the
+ * pipe_inode_info.
+ * 
+ * The UMSDOS specific extension is placed after the union.
+ */
 
-	Special file and fifo do have an inode which correspond to an
-	empty MSDOS file.
-
-	symlink are processed mostly like regular file. The content is the
-	link.
-
-	fifos add there own extension to the inode. I have reserved some
-	space for fifos side by side with msdos_inode_info. This is just
-	to for the show, because msdos_inode_info already include the
-	pipe_inode_info.
-
-	The UMSDOS specific extension is placed after the union.
-*/
 struct dir_locking_info {
 	struct wait_queue *p;
-	short int looking;		/* How many process doing a lookup */
-	short int creating;		/* Is there any creation going on here */
-							/* Only one at a time, although one */
-							/* may recursively lock, so it is a counter */
-	long pid;				/* pid of the process owning the creation */
-							/* lock */
+	short int looking;	/* How many process doing a lookup */
+	short int creating;	/* Is there any creation going on here
+				 *  Only one at a time, although one
+				 *  may recursively lock, so it is a counter
+				 */
+	long pid;		/* pid of the process owning the creation */
+	/* lock */
 };
+
 struct umsdos_inode_info {
 	union {
 		struct msdos_inode_info msdos_info;
 		struct pipe_inode_info pipe_info;
 		struct dir_locking_info dir_info;
-	}u;	/* Simply a filler, never referenced by fs/umsdos/... */
-	unsigned long i_dir_owner;	/* Inode of the dir which hold this */
-								/* entry */
+	} u;				/* Simply a filler, never referenced by fs/umsdos/... */
+	unsigned long i_dir_owner;	/* Inode of the dir which hold this entry */
 	unsigned long i_emd_owner;	/* Inode of the EMD file of i_dir_owner */
-	off_t pos;					/* Entry offset in the emd_owner file */
+	off_t pos;			/* Entry offset in the emd_owner file */
 	/* The rest is used only if this inode describe a directory */
 	unsigned long i_emd_dir;	/* Inode of the EMD file of this inode */
 };
diff -u --recursive --new-file v2.1.102/linux/include/net/ip_masq.h linux/include/net/ip_masq.h
--- v2.1.102/linux/include/net/ip_masq.h	Sat May  2 14:19:54 1998
+++ linux/include/net/ip_masq.h	Wed May 20 16:25:05 1998
@@ -258,9 +258,10 @@
 extern int ip_masq_get_debug_level(void);
 
 #ifndef CONFIG_IP_MASQ_NDEBUG
-#define IP_MASQ_DEBUG(level, msg...) \
+#define IP_MASQ_DEBUG(level, msg...) do { \
 	if (level <= ip_masq_get_debug_level()) \
-		printk(KERN_DEBUG "IP_MASQ:" ## msg)
+		printk(KERN_DEBUG "IP_MASQ:" ## msg); \
+	} while (0)
 #else	/* NO DEBUGGING at ALL */
 #define IP_MASQ_DEBUG(level, msg...) do { } while (0)
 #endif
diff -u --recursive --new-file v2.1.102/linux/init/main.c linux/init/main.c
--- v2.1.102/linux/init/main.c	Fri May  8 23:14:57 1998
+++ linux/init/main.c	Thu May 14 19:11:48 1998
@@ -422,6 +422,18 @@
 #ifdef CONFIG_BLK_DEV_PS2
 	{ "eda",     0x2400 },
 #endif
+#ifdef CONFIG_PARIDE_PD
+	{ "pda",	0x2d00 },
+	{ "pdb",	0x2d10 },
+	{ "pdc",	0x2d20 },
+	{ "pdd",	0x2d30 },
+#endif
+#ifdef CONFIG_PARIDE_PCD
+	{ "pcd",	0x2e00 },
+#endif
+#ifdef CONFIG_PARIDE_PF
+	{ "pf",		0x2f00 },
+#endif
 #if CONFIG_APBLOCK
 	{ "apblock", APBLOCK_MAJOR << 8},
 #endif
diff -u --recursive --new-file v2.1.102/linux/kernel/sched.c linux/kernel/sched.c
--- v2.1.102/linux/kernel/sched.c	Fri May  8 23:14:57 1998
+++ linux/kernel/sched.c	Tue May 19 09:46:39 1998
@@ -98,8 +98,6 @@
  *	via the SMP irq return path.
  */
  
-struct task_struct *last_task_used_math = NULL;
-
 struct task_struct * task[NR_TASKS] = {&init_task, };
 
 struct kernel_stat kstat = { 0 };
diff -u --recursive --new-file v2.1.102/linux/kernel/sys.c linux/kernel/sys.c
--- v2.1.102/linux/kernel/sys.c	Thu May 14 19:47:44 1998
+++ linux/kernel/sys.c	Sun May 17 20:28:35 1998
@@ -822,37 +822,57 @@
 	return 1;
 }
 
+/*
+ * This should really be a blocking read-write lock
+ * rather than a semaphore. Anybody want to implement
+ * one?
+ */
+struct semaphore uts_sem = MUTEX;
+
 asmlinkage int sys_newuname(struct new_utsname * name)
 {
-	if (!name)
-		return -EFAULT;
+	int errno = 0;
+
+	down(&uts_sem);
 	if (copy_to_user(name,&system_utsname,sizeof *name))
-		return -EFAULT;
-	return 0;
+		errno = -EFAULT;
+	up(&uts_sem);
+	return errno;
 }
 
 asmlinkage int sys_sethostname(char *name, int len)
 {
+	int errno;
+
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 	if (len < 0 || len > __NEW_UTS_LEN)
 		return -EINVAL;
-	if(copy_from_user(system_utsname.nodename, name, len))
-		return -EFAULT;
-	system_utsname.nodename[len] = 0;
-	return 0;
+	down(&uts_sem);
+	errno = -EFAULT;
+	if (!copy_from_user(system_utsname.nodename, name, len)) {
+		system_utsname.nodename[len] = 0;
+		errno = 0;
+	}
+	up(&uts_sem);
+	return errno;
 }
 
 asmlinkage int sys_gethostname(char *name, int len)
 {
-	int i;
+	int i, errno;
 
 	if (len < 0)
 		return -EINVAL;
+	down(&uts_sem);
 	i = 1 + strlen(system_utsname.nodename);
 	if (i > len)
 		i = len;
-	return copy_to_user(name, system_utsname.nodename, i) ? -EFAULT : 0;
+	errno = 0;
+	if (copy_to_user(name, system_utsname.nodename, i))
+		errno = -EFAULT;
+	up(&uts_sem);
+	return errno;
 }
 
 /*
@@ -861,14 +881,21 @@
  */
 asmlinkage int sys_setdomainname(char *name, int len)
 {
+	int errno;
+
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 	if (len < 0 || len > __NEW_UTS_LEN)
 		return -EINVAL;
-	if(copy_from_user(system_utsname.domainname, name, len))
-		return -EFAULT;
-	system_utsname.domainname[len] = 0;
-	return 0;
+
+	down(&uts_sem);
+	errno = -EFAULT;
+	if (!copy_from_user(system_utsname.domainname, name, len)) {
+		errno = 0;
+		system_utsname.domainname[len] = 0;
+	}
+	up(&uts_sem);
+	return errno;
 }
 
 asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim)
diff -u --recursive --new-file v2.1.102/linux/kernel/time.c linux/kernel/time.c
--- v2.1.102/linux/kernel/time.c	Thu May  7 22:51:55 1998
+++ linux/kernel/time.c	Thu May 14 18:52:56 1998
@@ -262,7 +262,7 @@
 	    if (txc->modes & ADJ_TIMECONST)
 		time_constant = txc->constant;
 
-	    if (txc->modes & ADJ_OFFSET)
+	    if (txc->modes & ADJ_OFFSET) {
 	      if ((txc->modes == ADJ_OFFSET_SINGLESHOT)
 		  || !(time_status & STA_PLL))
 		{
@@ -327,6 +327,7 @@
 		  else if (time_freq < -time_tolerance)
 		    time_freq = -time_tolerance;
 		} /* STA_PLL || STA_PPSTIME */
+	    }
 	    if (txc->modes & ADJ_TICK)
 	      tick = txc->tick;
 
diff -u --recursive --new-file v2.1.102/linux/scripts/tkcond.c linux/scripts/tkcond.c
--- v2.1.102/linux/scripts/tkcond.c	Tue Dec 23 13:52:02 1997
+++ linux/scripts/tkcond.c	Thu May 14 18:55:46 1998
@@ -96,7 +96,7 @@
  * Walk all of the conditions, and look for choice values.  Convert
  * the tokens into something more digestible.
  */
-void fix_choice_cond()
+void fix_choice_cond(void)
 {
   struct condition * cond;
   struct condition * cond2;
