diff -u --recursive --new-file v1.1.61/linux/CREDITS linux/CREDITS
--- v1.1.61/linux/CREDITS	Thu Nov  3 17:53:27 1994
+++ linux/CREDITS	Sun Nov  6 15:02:33 1994
@@ -733,6 +733,15 @@
 S: Charlottesville, Virginia 22903
 S: USA
 
+N: Matthias Urlichs
+E: urlichs@noris.de
+E: urlichs@smurf.sub.org
+D: Consultant, developer, kernel hacker
+D: Playing with Streams, ISDN, and BSD networking code for Linux
+S: Schleiermacherstrasse 12
+S: 90491 Nuernberg
+S: Germany
+
 N: Patrick Volkerding
 E: volkerdi@ftp.cdrom.com
 D: Produced the Slackware distribution, updated the SVGAlib
@@ -809,6 +818,7 @@
 S: USA
 
 N: Eric Youngdale
+E: eric@aib.com
 E: ericy@cais.com
 D: General kernel hacker
 D: SCSI iso9660 and ELF
@@ -821,4 +831,11 @@
 D: XFree86 and kernel development
 S: 1507 145th Place SE #B5
 S: Bellevue, Washington 98007
+S: USA
+
+N: Leonard N. Zubkoff
+E: lnz@dandelion.com
+D: XFree86 and BusLogic driver additions
+S: 3078 Sulphur Spring Court
+S: San Jose, California 95148
 S: USA
diff -u --recursive --new-file v1.1.61/linux/Makefile linux/Makefile
--- v1.1.61/linux/Makefile	Thu Nov  3 17:53:27 1994
+++ linux/Makefile	Fri Nov  4 12:40:30 1994
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 61
+SUBLEVEL = 62
 
 ARCH = i386
 
diff -u --recursive --new-file v1.1.61/linux/README linux/README
--- v1.1.61/linux/README	Tue Aug  9 09:32:59 1994
+++ linux/README	Thu Nov  3 17:08:53 1994
@@ -1,10 +1,14 @@
 
-	Linux kernel release 1.0
+	Linux kernel release 1.1.xx
 
-These are the release notes for linux version 1.0.  Read them carefully,
+These are the release notes for linux version 1.1.  Read them carefully,
 as they tell you what this is all about, explain how to install the
 kernel, and what to do if something goes wrong. 
 
+Warning: This is a work in progress. If you are not reasonably at ease with
+the C programming language, GCC, installing Linux, and recovering from
+system crashes, please use the 1.0 version, or wait for 1.2.
+
 WHAT IS LINUX?
 
   Linux is a Unix clone for 386/486-based PCs written from scratch by
@@ -24,20 +28,24 @@
  - If you install the full sources, do a
 
 		cd /usr/src
-		tar xvf linux-1.0.tar
+		gzip -cd linux-1.1.XX.tar.gz | tar xfv -
 
-   to get it all put in place.
+   to get it all put in place. Replace "XX" with the version number of the
+   latest kernel.
 
- - if you install by patching, you need a *clean* 0.99.15 source tree,
-   which presumably exists in /usr/src/linux.  If so, to get the kernel
-   patched, just do a
+ - Installing by patching is not worth the effort because the full set of
+   patches is bigger than a new kernel distribution. Instead, get the
+   latest full source archive and install as above. Then, get all newer
+   patch files, and do
 
 		cd /usr/src
-		patch -p0 < linux-1.0.patch
+		gzip -cd patchXX.gz | patch -p0
 
-   and you should be ok.  You may want to remove the backup files (xxx~
-   or xxx.orig), and make sure that there are no failed patches (xxx# or
-   xxx.rej).
+   (repeat xx for all versions bigger than the version of your current
+   source tree, _in_order_) and you should be ok.  You may want to remove
+   the backup files (xxx~ or xxx.orig), and make sure that there are no
+   failed patches (xxx# or xxx.rej). If there are, either you or me has
+   made a mistake.
 
  - make sure your /usr/include/linux and /usr/include/asm directories
    are just symlinks to the kernel sources:
@@ -88,10 +96,11 @@
 
 COMPILING the kernel:
 
- - make sure you have gcc-2.4.5 or newer available.  It seems older gcc
+ - make sure you have gcc-2.5.8 or newer available.  It seems older gcc
    versions can have problems compiling newer versions of linux.  If you
    upgrade your compiler, remember to get the new binutils package too
-   (for as/ld/nm and company)
+   (for as/ld/nm and company). Do not use gcc-2.6.0; it has a few serious
+   bugs.
 
  - do a "make zImage" to create a compressed kernel image.  If you want
    to make a bootdisk (without root filesystem or lilo), insert a floppy
@@ -148,7 +157,7 @@
 
 	unable to handle kernel paging request at address C0000010
 	Oops: 0002
-	EIP:   0010:xxxxxxxx
+	EIP:   0010:XXXXXXXX
 	eax: xxxxxxxx   ebx: xxxxxxxx   ecx: xxxxxxxx   edx: xxxxxxxx
 	esi: xxxxxxxx   edi: xxxxxxxx   ebp: xxxxxxxx
 	ds: xxxx  es: xxxx  fs: xxxx  gs: xxxx
@@ -193,4 +202,17 @@
    If you for some reason cannot do the above (you have a pre-compiled
    kernel image or similar), telling me as much about your setup as
    possible will help. 
+
+ - alternately, you can use gdb on a running kernel. (read-only; i.e. you
+   cannot change values or set break points.) To do this, first compile the
+   kernel with -g; edit arch/i386/Makefile appropriately, then do a "make
+   clean". You'll also need to enable CONFIG_PROC_FS (via "make config").
+
+   After you've rebooted with the new kernel, do "gdb tools/zSystem
+   /proc/kcore". You can now use all the usual gdb commands. The command to
+   look up the point where your system crashed is "l *0xXXXXXXXX". (Replace
+   the XXXes with the EIP value.)
+
+   gdb'ing a non-running kernel currently fails because gdb (wrongly)
+   disregards the starting offset for which the kernel is compiled.
 
diff -u --recursive --new-file v1.1.61/linux/arch/i386/config.in linux/arch/i386/config.in
--- v1.1.61/linux/arch/i386/config.in	Wed Nov  2 12:03:44 1994
+++ linux/arch/i386/config.in	Thu Nov  3 16:21:53 1994
@@ -107,6 +107,7 @@
 	bool 'AT1500 and NE2100 (LANCE and PCnet-ISA) support' CONFIG_LANCE n
 	bool 'Cabletron E21xx support (not recommended)' CONFIG_E2100 n
 	bool 'DEPCA support' CONFIG_DEPCA n
+	bool 'EtherWorks 3 support' CONFIG_EWRK3 n
 	if [ "$CONFIG_NET_ALPHA" = "y" ]; then
 		bool 'EtherExpress support' CONFIG_EEXPRESS n
 		bool 'AT1700 support' CONFIG_AT1700 n
diff -u --recursive --new-file v1.1.61/linux/drivers/block/cdu31a.c linux/drivers/block/cdu31a.c
--- v1.1.61/linux/drivers/block/cdu31a.c	Thu Nov  3 17:53:27 1994
+++ linux/drivers/block/cdu31a.c	Sat Nov  5 13:32:14 1994
@@ -2787,6 +2787,9 @@
    }
    else if (sony_cd_base_io != 0)
    {
+      tmp_irq = irq_used; /* Need IRQ 0 because we can't sleep here. */
+      irq_used = 0;
+
       get_drive_configuration(sony_cd_base_io,
 			      drive_config.exec_status,
 			      &res_size);
@@ -2794,9 +2797,12 @@
       {
 	 drive_found = 1;
       }
+
+      irq_used = tmp_irq;
    }
    else
    {
+      irq_used = 0;
       i = 0;
       while (   (cdu31a_addresses[i].base != 0)
 	     && (!drive_found))
@@ -2844,12 +2850,18 @@
 	 tmp_irq = autoirq_report(10);
 	 disable_interrupts();
 	 
+         irq_used = 0;
 	 set_drive_params();
 	 irq_used = tmp_irq;
       }
       else
       {
+         tmp_irq = irq_used; /* Need IRQ 0 because we can't sleep here. */
+         irq_used = 0;
+
 	 set_drive_params();
+
+         irq_used = tmp_irq;
       }
       
       if (irq_used > 0)
diff -u --recursive --new-file v1.1.61/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v1.1.61/linux/drivers/block/floppy.c	Thu Nov  3 17:53:28 1994
+++ linux/drivers/block/floppy.c	Fri Nov  4 13:43:25 1994
@@ -2628,7 +2628,7 @@
 	case FDCLRPRM:
 		LOCK_FDC(drive,1);
 		current_type[drive] = NULL;
-		floppy_sizes[drive] = 2;
+		floppy_sizes[drive] = MAX_DISK_SIZE;
 		UDRS->keep_data = 0;
 		return invalidate_drive(device);
 	case FDFMTEND:
@@ -3159,7 +3159,6 @@
 
 static void floppy_release_irq_and_dma(void)
 {
-	int i;
 	cli();
 	if (--usage_count){
 		sti();
@@ -3170,7 +3169,9 @@
 	free_dma(FLOPPY_DMA);
 	disable_irq(FLOPPY_IRQ);
 	free_irq(FLOPPY_IRQ);
-	/* switch off dma gates */
-	for(i=0; i< N_FDC; i++)
-		set_dor(i, ~8, 0);
+	set_dor(0, ~0, 8);
+#if N_FDC > 1
+	if(fdc.address != -1)
+		set_dor(1, ~8, 0);
+#endif
 }
diff -u --recursive --new-file v1.1.61/linux/drivers/char/ChangeLog linux/drivers/char/ChangeLog
--- v1.1.61/linux/drivers/char/ChangeLog	Wed Nov  2 12:03:45 1994
+++ linux/drivers/char/ChangeLog	Fri Nov  4 12:38:55 1994
@@ -1,3 +1,10 @@
+Wed Nov  2 10:32:36 1994  Theodore Y. Ts'o  (tytso@rt-11)
+
+	* n_tty.c (n_tty_receive_room): Only allow excess characters
+		through if we are in ICANON mode *and* there are other no
+		pending lines in the buffer.  Otherwise cut and paste over
+		4k breaks.
+
 Sat Oct 29 18:17:34 1994  Theodore Y. Ts'o  (tytso@rt-11)
 
 	* serial.c (rs_ioctl, get_lsr_info): Added patch suggested by Arne
diff -u --recursive --new-file v1.1.61/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- v1.1.61/linux/drivers/char/n_tty.c	Tue Oct 25 18:10:13 1994
+++ linux/drivers/char/n_tty.c	Fri Nov  4 12:39:05 1994
@@ -585,11 +585,12 @@
 	int	left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
 
 	/*
-	 * If we are doing input canonicalization, let as many
-	 * characters through as possible, so that the excess
-	 * characters can be "beeped".
+	 * If we are doing input canonicalization, and there are no
+	 * pending newlines, let characters through without limit, so
+	 * that erase characters will be handled.  Other excess
+	 * characters will be beeped.
 	 */
-	if (L_ICANON(tty))
+	if (tty->icanon && !tty->canon_data)
 		return N_TTY_BUF_SIZE;
 
 	if (left > 0)
diff -u --recursive --new-file v1.1.61/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v1.1.61/linux/drivers/char/tty_io.c	Thu Oct 27 17:59:46 1994
+++ linux/drivers/char/tty_io.c	Sat Nov  5 19:46:24 1994
@@ -1009,6 +1009,12 @@
 		(tty->ldisc.close)(tty);
 	tty->ldisc = ldiscs[N_TTY];
 	tty->termios->c_line = N_TTY;
+	if (o_tty) {
+		if (o_tty->ldisc.close)
+			(o_tty->ldisc.close)(o_tty);
+		o_tty->ldisc = ldiscs[N_TTY];
+		o_tty->termios->c_line = N_TTY;
+	}
 	
 	tty->driver.table[idx] = NULL;
 	if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) {
diff -u --recursive --new-file v1.1.61/linux/drivers/scsi/README.st linux/drivers/scsi/README.st
--- v1.1.61/linux/drivers/scsi/README.st	Fri Aug 19 08:54:02 1994
+++ linux/drivers/scsi/README.st	Thu Nov  3 16:44:04 1994
@@ -1,5 +1,5 @@
 This file contains brief information about the SCSI tape driver.
-Last modified: Wed Jun 22 23:38:47 1994 by root@kai.home
+Last modified: Sun Oct 16 19:20:03 1994 by root@kai.home
 
 BASICS
 
@@ -78,7 +78,10 @@
 MTBSFM  As above but ape positioned after filemark.
 MTFSR   Space forward over count records.
 MTBSR   Space backward over count records.
+MTFSS   Space forward over count setmarks.
+MTBSS   Space backward over coutn setmarks.
 MTWEOF  Write count filemarks.
+MTWSM   Write count setmarks.
 MTREW   Rewind tape.
 MTOFFL  Set device off line (often rewind plus eject).
 MTNOP   Do nothing except flush the buffers.
@@ -125,9 +128,8 @@
         The current block size and the density code are stored in the field
         mt_dsreg (shifts for the subfields are MT_ST_BLKSIZE_SHIFT and
         MT_ST_DENSITY_SHIFT).
-	The write protect bit in mt_gstat is set if the tape is write
-	protected.
-        The other fields are empty.
+	The WR_PROT, BOT, EOF, EOT, EOD, and D_[800,1600,6250]_BPI
+	status bits reflect the tape status. The other bits are not used.
 
 
 MISCELLANEOUS COMPILE OPTIONS
diff -u --recursive --new-file v1.1.61/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c
--- v1.1.61/linux/drivers/scsi/fdomain.c	Fri Aug 19 08:54:04 1994
+++ linux/drivers/scsi/fdomain.c	Thu Nov  3 16:14:30 1994
@@ -1,10 +1,10 @@
 /* fdomain.c -- Future Domain TMC-16x0 SCSI driver
  * Created: Sun May  3 18:53:19 1992 by faith@cs.unc.edu
- * Revised: Sat Jul 30 22:06:37 1994 by faith@cs.unc.edu
+ * Revised: Wed Nov  2 16:37:58 1994 by faith@cs.unc.edu
  * Author: Rickard E. Faith, faith@cs.unc.edu
  * Copyright 1992, 1993, 1994 Rickard E. Faith
  *
- * $Id: fdomain.c,v 5.18 1994/07/31 03:09:15 faith Exp $
+ * $Id: fdomain.c,v 5.20 1994/11/02 21:38:33 root Exp $
 
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -38,10 +38,20 @@
  signature, then the driver may fail to function after the board is
  detected.
 
- The following BIOS versions are supported: 2.0, 3.0, 3.2, and 3.4.
+ The following BIOS versions are supported: 2.0, 3.0, 3.2, 3.4, and 3.5.
  The following chips are supported: TMC-1800, TMC-18C50, TMC-18C30.
  Reports suggest that the driver will also work with the 36C70 chip.
 
+ Please note that the drive ordering that Future Domain implemented in BIOS
+ versions 3.4 and 3.5 is the opposite of the order (currently) used by the
+ rest of the SCSI industry.  If you have BIOS version 3.4 or 3.5, and have
+ more then one drive, then the drive ordering will be the reverse of that
+ which you see under DOS.  For example, under DOS SCSI ID 0 will be D: and
+ SCSI ID 1 will be C: (the boot device).  Under Linux, SCSI ID 0 will be
+ /dev/sda and SCSI ID 1 will be /dev/sdb.  The Linux ordering is consistent
+ with that provided by all the other SCSI drivers for Linux.  If you want
+ this changed, send me patches that are protected by #ifdefs.
+
  If you have a TMC-8xx or TMC-9xx board, then this is not the driver for
  your board.  Please refer to the Seagate driver for more information and
  possible support.
@@ -119,7 +129,10 @@
  Thanks to James T. McKinley (mckinley@msupa.pa.msu.edu) for providing
  patches that support the TMC-3260, a PCI bus card with the 36C70 chip.
  The 36C70 chip appears to be "completely compatible" with the 18C30 chip.
- 
+
+ Thanks to Eric Kasten (tigger@petroglyph.cl.msu.edu) for providing the
+ patch for the version 3.5 BIOS.
+
  All of the alpha testers deserve much thanks.
 
 
@@ -133,14 +146,14 @@
  devices support parity, then you can probably get the driver to work by
  turning this option off.  I have no way of testing this, however.
 
- FIFO_COUNT: The host adapter has an 8K cache.  When this many 512 byte
- blocks are filled by the SCSI device, an interrupt will be raised.
- Therefore, this could be as low as 0, or as high as 16.  Note, however,
- that values which are too high or too low seem to prevent any interrupts
- from occuring, and thereby lock up the machine.  I have found that 2 is a
- good number, but throughput may be increased by changing this value to
- values which are close to 2.  Please let me know if you try any different
- values.
+ FIFO_COUNT: The host adapter has an 8K cache (host adapters based on the
+ 18C30 chip have a 2k cache).  When this many 512 byte blocks are filled by
+ the SCSI device, an interrupt will be raised.  Therefore, this could be as
+ low as 0, or as high as 16.  Note, however, that values which are too high
+ or too low seem to prevent any interrupts from occuring, and thereby lock
+ up the machine.  I have found that 2 is a good number, but throughput may
+ be increased by changing this value to values which are close to 2.
+ Please let me know if you try any different values.
 
  DO_DETECT: This activates some old scan code which was needed before the
  high level drivers got fixed.  If you are having trouble with the driver,
@@ -150,11 +163,11 @@
  RESELECTION: This is no longer an option, since I gave up trying to
  implement it in version 4.x of this driver.  It did not improve
  performance at all and made the driver unstable (because I never found one
- of the two race conditions which were introduced by multiple outstanding
- commands).  The instability seems a very high price to pay just so that
- you don't have to wait for the tape to rewind.  When I have time, I will
- work on this again.  In the interim, if anyone wants to work on the code,
- I can give them my latest version.
+ of the two race conditions which were introduced by the multiple
+ outstanding command code).  The instability seems a very high price to pay
+ just so that you don't have to wait for the tape to rewind.  If you want
+ this feature implemented, send me patches.  I'll be happy to send a copy
+ of my (broken) driver to anyone who would like to see a copy.
 
  **************************************************************************/
 
@@ -169,7 +182,7 @@
 #include <linux/string.h>
 #include <linux/ioport.h>
 
-#define VERSION          "$Revision: 5.18 $"
+#define VERSION          "$Revision: 5.20 $"
 
 /* START OF USER DEFINABLE OPTIONS */
 
@@ -292,7 +305,9 @@
    (void *)0xc8000,
    (void *)0xca000,
    (void *)0xce000,
-   (void *)0xde000 };
+   (void *)0xde000,
+   (void *)0xd0000,		/* Extra addresses for PCI boards */
+};
 #define ADDRESS_COUNT (sizeof( addresses ) / sizeof( unsigned ))
 		       
 static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 };
@@ -341,6 +356,7 @@
    { "FUTURE DOMAIN CORP. (C) 1992 V3.00.004/02/92",        5, 44,  3,  0, 0 },
    { "FUTURE DOMAIN TMC-18XX (C) 1993 V3.203/12/93",        5, 44,  3,  2, 0 },
    { "Future Domain Corp. V1.0008/18/93",                   5, 33,  3,  4, 0 },
+   { "FUTURE DOMAIN CORP.  V3.5008/18/93",                  5, 34,  3,  5, 0 },
    { "Future Domain Corp. V1.0008/18/93",                  26, 33,  3,  4, 1 },
    { "FUTURE DOMAIN TMC-18XX",                              5, 22, -1, -1, 0 },
 
@@ -459,11 +475,15 @@
 #endif
 
 				/* Check for board with lowest bios_base --
-				   this isn't valid for the 18c30, so just
-				   assume we have the right board. */
+				   this isn't valid for the 18c30 or for
+				   boards on the PCI bus, so just assume we
+				   have the right board. */
+
+   if (chip != tmc18c30
+       && !PCI_bus
+       && addresses[ (options & 0xc0) >> 6 ] != bios_base) return 0;
 
-   if (chip != tmc18c30 && addresses[ (options & 0xc0) >> 6 ] != bios_base)
-	 return 0;
+				/* Get the IRQ from the options. */
 
    interrupt_level = ints[ (options & 0x0e) >> 1 ];
 
@@ -587,18 +607,15 @@
 	 }
       } else {
 
-	 /* The proper way of doing this is to use the PCI BIOS call
-            (interrupt 0x1a) to determine the device IRQ and interrupt
-            level.  Then the port_base will be in configuration register
-            0x10 (and configuration register 0x30 will contain the value of
-            bios_base).
+	 /* The proper way of doing this is to use ask the PCI bus for the
+            device IRQ and interrupt level.
 
 	    Until the Linux kernel supports this sort of PCI bus query, we
-	    scan down a bunch of addresses (Future Domain folks say we
-	    should find the address before we get to 0xf800).  This works
-	    fine on some systems -- other systems may have to scan more
-	    addresses.  If you have to modify this section for your
-	    installation, please send mail to faith@cs.unc.edu. */
+	    scan down a bunch of addresses (Future Domain tech support says
+	    we will probably find the address before we get to 0xf800).
+	    This works fine on some systems -- other systems may have to
+	    scan more addresses.  If you have to modify this section for
+	    your installation, please send mail to faith@cs.unc.edu. */
 
 	 for (i = 0xff00; !flag && i > 0xf000; i -= 8) {
 	    port_base = i;
@@ -798,6 +815,7 @@
 {
    int           status;
    unsigned long timeout;
+   static int    flag = 0;
 
 
    outb( 0x82, SCSI_Cntl_port ); /* Bus Enable + Select */
@@ -806,11 +824,9 @@
    /* Stop arbitration and enable parity */
    outb( PARITY_MASK, TMC_Cntl_port ); 
 
-#if 0
-   timeout = jiffies + 25;	        /* 250mS */
-#else
-   timeout = jiffies + 35;	        /* 350mS -- because of timeouts */
-#endif
+   timeout = jiffies + 35;	        /* 350mS -- because of timeouts
+					   (was 250mS) */
+
    while (jiffies < timeout) {
       status = inb( SCSI_Status_port ); /* Read adapter status */
       if (status & 1) {		        /* Busy asserted */
@@ -825,7 +841,12 @@
    if (!target) printk( "Selection failed\n" );
 #endif
 #if ERRORS_ONLY
-   if (!target) printk( "Future Domain: Selection failed\n" );
+   if (!target) {
+      if (chip == tmc18c30 && !flag) /* Skip first failure for 18C30 chips. */
+	    ++flag;
+      else
+	    printk( "Future Domain: Selection failed\n" );
+   }
 #endif
    return 1;
 }
diff -u --recursive --new-file v1.1.61/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v1.1.61/linux/drivers/scsi/scsi.c	Fri Oct 14 10:44:52 1994
+++ linux/drivers/scsi/scsi.c	Sat Nov  5 19:28:48 1994
@@ -157,6 +157,7 @@
 				 * controller, which causes SCSI code to reset bus.*/
    {"QUANTUM","LPS525S","3110"},/* Locks sometimes if polled for lun != 0 */
    {"QUANTUM","PD1225S","3110"},/* Locks sometimes if polled for lun != 0 */
+   {"MEDIAVIS","CDR-H93MV","1.31"},  /* Locks up if polled for lun != 0 */
    {NULL, NULL, NULL}};	
 
 static int blacklisted(unsigned char * response_data){
diff -u --recursive --new-file v1.1.61/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v1.1.61/linux/drivers/scsi/st.c	Sat Aug  6 20:32:14 1994
+++ linux/drivers/scsi/st.c	Thu Nov  3 16:44:04 1994
@@ -11,7 +11,7 @@
   Copyright 1992, 1993, 1994 Kai Makisara
 		 email makisara@vtinsx.ins.vtt.fi or Kai.Makisara@vtt.fi
 
-  Last modified: Wed Jun 22 23:37:10 1994 by root@kai.home
+  Last modified: Tue Oct 25 19:37:33 1994 by root@kai.home
 */
 
 #include <linux/fs.h>
@@ -415,7 +415,8 @@
 
     STp->dirty = 0;
     STp->rw = ST_IDLE;
-    STp->eof = ST_NOEOF;
+    if (STp->eof != ST_EOD)  /* Save EOD across opens */
+      STp->eof = ST_NOEOF;
     STp->eof_hit = 0;
     STp->recover_count = 0;
 
@@ -450,6 +451,7 @@
 
       if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) );
       (STp->mt_status)->mt_fileno = STp->drv_block = 0;
+      STp->eof = ST_NOEOF;
     }
 
     if ((STp->buffer)->last_result_fatal != 0) {
@@ -601,7 +603,7 @@
 
 #ifdef DEBUG
       if (debugging)
-	printk("st%d: File length %ld bytes.\n", dev, filp->f_pos);
+	printk("st%d: File length %ld bytes.\n", dev, (long)(filp->f_pos));
 #endif
 
       if (result == 0 || result == (-ENOSPC)) {
@@ -1053,6 +1055,7 @@
 		  printk("st%d: Zero returned for first BLANK CHECK after EOF.\n",
 			 dev);
 #endif
+		STp->eof = ST_EOD;
 		return 0; /* First BLANK_CHECK after EOF */
 	      }
 	      else
@@ -1098,7 +1101,7 @@
 	STp->eof_hit = 1;
 	SCpnt->request.dev = -1;  /* Mark as not busy */
 	if (total == 0 && STp->eof == ST_FM) {
-	  STp->eof = 0;
+	  STp->eof = ST_NOEOF;
 	  STp->drv_block = 0;
 	  if (STp->moves_after_eof > 1)
 	    STp->moves_after_eof = 0;
@@ -1253,18 +1256,58 @@
        if (blkno >= 0)
 	 blkno -= arg;
        break; 
+      case MTFSS:
+       cmd[0] = SPACE;
+       cmd[1] = 0x04; /* Space Setmarks */
+       cmd[2] = (arg >> 16);
+       cmd[3] = (arg >> 8);
+       cmd[4] = arg;
+#ifdef DEBUG
+       if (debugging)
+	 printk("st%d: Spacing tape forward %d setmarks.\n", dev,
+		cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
+#endif
+       if (arg != 0)
+	 blkno = fileno = (-1);
+       break; 
+     case MTBSS:
+       cmd[0] = SPACE;
+       cmd[1] = 0x04; /* Space Setmarks */
+       ltmp = (-arg);
+       cmd[2] = (ltmp >> 16);
+       cmd[3] = (ltmp >> 8);
+       cmd[4] = ltmp;
+#ifdef DEBUG
+       if (debugging) {
+	 if (cmd[2] & 0x80)
+	   ltmp = 0xff000000;
+	 ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
+	 printk("st%d: Spacing tape backward %ld setmarks.\n", dev, (-ltmp));
+       }
+#endif
+       if (arg != 0)
+	 blkno = fileno = (-1);
+       break; 
      case MTWEOF:
+     case MTWSM:
        if (STp->write_prot)
 	 return (-EACCES);
        cmd[0] = WRITE_FILEMARKS;
+       if (cmd_in == MTWSM)
+	 cmd[1] = 2;
        cmd[2] = (arg >> 16);
        cmd[3] = (arg >> 8);
        cmd[4] = arg;
        timeout = ST_TIMEOUT;
 #ifdef DEBUG
-       if (debugging)
-	 printk("st%d: Writing %d filemarks.\n", dev,
-		cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
+       if (debugging) {
+	 if (cmd_in == MTWEOF)
+	   printk("st%d: Writing %d filemarks.\n", dev,
+		  cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
+	 else
+	   printk("st%d: Writing %d setmarks.\n", dev,
+		  cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
+       }
 #endif
        fileno += arg;
        blkno = 0;
@@ -1503,9 +1546,12 @@
        else
 	 STp->drv_block = (-1);
      }
+     if (STp->eof == ST_NOEOF &&
+	 (SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK)
+       STp->eof = ST_EOD;
    }
 
-   return ioctl_result ;
+   return ioctl_result;
 }
 
 
@@ -1576,9 +1622,26 @@
 	 (STp->mt_status)->mt_blkno -= ((STp->buffer)->buffer_bytes +
 	   STp->block_size - 1) / STp->block_size;
      }
+
      (STp->mt_status)->mt_gstat = 0;
      if (STp->drv_write_prot)
        (STp->mt_status)->mt_gstat |= GMT_WR_PROT(0xffffffff);
+     if ((STp->mt_status)->mt_blkno == 0) {
+       if ((STp->mt_status)->mt_fileno == 0)
+	 (STp->mt_status)->mt_gstat |= GMT_BOT(0xffffffff);
+       else
+	 (STp->mt_status)->mt_gstat |= GMT_EOF(0xffffffff);
+     }
+     if (STp->eof == ST_EOM_OK || STp->eof == ST_EOM_ERROR)
+       (STp->mt_status)->mt_gstat |= GMT_EOT(0xffffffff);
+     else if (STp->eof == ST_EOD)
+       (STp->mt_status)->mt_gstat |= GMT_EOD(0xffffffff);
+     if (STp->density == 1)
+       (STp->mt_status)->mt_gstat |= GMT_D_800(0xffffffff);
+     else if (STp->density == 2)
+       (STp->mt_status)->mt_gstat |= GMT_D_1600(0xffffffff);
+     else if (STp->density == 3)
+       (STp->mt_status)->mt_gstat |= GMT_D_6250(0xffffffff);
 
      memcpy_tofs((char *)arg, (char *)(STp->mt_status),
 		 sizeof(struct mtget));
diff -u --recursive --new-file v1.1.61/linux/drivers/scsi/st.h linux/drivers/scsi/st.h
--- v1.1.61/linux/drivers/scsi/st.h	Thu Jul  7 18:45:05 1994
+++ linux/drivers/scsi/st.h	Thu Nov  3 16:44:04 1994
@@ -55,6 +55,7 @@
 #define	ST_FM		1
 #define	ST_EOM_OK	2
 #define ST_EOM_ERROR	3
+#define ST_EOD		4
 
 /* Values of rw */
 #define	ST_IDLE		0
diff -u --recursive --new-file v1.1.61/linux/drivers/sound/configure.c linux/drivers/sound/configure.c
--- v1.1.61/linux/drivers/sound/configure.c	Fri Aug 19 08:54:08 1994
+++ linux/drivers/sound/configure.c	Sun Nov  6 13:43:22 1994
@@ -112,7 +112,7 @@
 
   {B (OPT_SB), B (OPT_PAS), "SBPRO", 1, 0, 1},
   {B (OPT_SB) | B (OPT_SBPRO), B (OPT_PAS), "SB16", 1, 0, 1},
-{B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_GUS), 0, "AUDIO", 1, 0, 1},
+{B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_GUS) | B (OPT_MSS), 0, "AUDIO", 1, 0, 1},
   {B (OPT_MPU401), 0, "MIDI_AUTO", 0, OPT_MIDI, 0},
   {B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_MPU401) | B (OPT_GUS), 0, "MIDI", 1, 0, 1},
   {B (OPT_ADLIB), 0, "YM3812_AUTO", 0, OPT_YM3812, 0},
diff -u --recursive --new-file v1.1.61/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- v1.1.61/linux/drivers/sound/soundcard.c	Thu Aug 11 17:35:35 1994
+++ linux/drivers/sound/soundcard.c	Sat Nov  5 20:03:11 1994
@@ -43,8 +43,14 @@
 int
 snd_ioctl_return (int *addr, int value)
 {
+  int error;
+
   if (value < 0)
     return value;
+
+  error = verify_area(VERIFY_WRITE, addr, sizeof(int));
+  if (error)
+    return error;
 
   PUT_WORD_TO_USER (addr, 0, value);
   return 0;
diff -u --recursive --new-file v1.1.61/linux/fs/block_dev.c linux/fs/block_dev.c
--- v1.1.61/linux/fs/block_dev.c	Thu Nov  3 17:53:29 1994
+++ linux/fs/block_dev.c	Sat Nov  5 16:14:07 1994
@@ -31,6 +31,7 @@
 	unsigned int dev;
 	struct buffer_head * bh, *bufferlist[NBUF];
 	register char * p;
+	int excess;
 
 	write_error = buffercount = 0;
 	dev = inode->i_rdev;
@@ -86,8 +87,9 @@
 		    blocks = read_ahead[MAJOR(dev)] / (blocksize >> 9) / 2;
 		    if (block + blocks > size) blocks = size - block;
 		    if (blocks > NBUF) blocks=NBUF;
-		    blocks -= (block % blocks_per_cluster);
-		    if(!blocks) blocks = 1;
+		    excess = (block + blocks) % blocks_per_cluster;
+		    if ( blocks > excess )
+			blocks -= excess;
 		    bhlist[0] = bh;
 		    for(i=1; i<blocks; i++){
 		      if(((i+block) % blocks_per_cluster) == 0) {
@@ -102,6 +104,7 @@
 		    };
 		    ll_rw_block(READ, blocks, bhlist);
 		    for(i=1; i<blocks; i++) brelse(bhlist[i]);
+		    wait_on_buffer(bh);
 		      
 		  };
 		};
@@ -168,6 +171,7 @@
 	loff_t size;
 	unsigned int dev;
 	int read;
+	int excess;
 
 	dev = inode->i_rdev;
 	blocksize = BLOCK_SIZE;
@@ -205,7 +209,9 @@
 	if (filp->f_reada) {
 	        if (blocks < read_ahead[MAJOR(dev)] / (blocksize >> 9))
 			blocks = read_ahead[MAJOR(dev)] / (blocksize >> 9);
-		blocks -= (block % blocks_per_cluster);
+		excess = (block + blocks) % blocks_per_cluster;
+		if ( blocks > excess )
+			blocks -= excess;		
 		if (rblocks > blocks)
 			blocks = rblocks;
 		
diff -u --recursive --new-file v1.1.61/linux/fs/exec.c linux/fs/exec.c
--- v1.1.61/linux/fs/exec.c	Fri Oct 21 09:54:09 1994
+++ linux/fs/exec.c	Sun Nov  6 13:43:54 1994
@@ -50,8 +50,6 @@
 asmlinkage int sys_exit(int exit_code);
 asmlinkage int sys_brk(unsigned long);
 
-extern void shm_exit (void);
-
 static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs);
 static int load_aout_library(int fd);
 static int aout_core_dump(long signr, struct pt_regs * regs);
@@ -197,6 +195,8 @@
 		goto end_coredump;
 	if (!inode->i_op || !inode->i_op->default_file_ops)
 		goto end_coredump;
+	if (get_write_access(inode))
+		goto end_coredump;
 	file.f_mode = 3;
 	file.f_flags = 0;
 	file.f_count = 1;
@@ -206,7 +206,7 @@
 	file.f_op = inode->i_op->default_file_ops;
 	if (file.f_op->open)
 		if (file.f_op->open(inode,&file))
-			goto end_coredump;
+			goto done_coredump;
 	if (!file.f_op->write)
 		goto close_coredump;
 	has_dumped = 1;
@@ -273,6 +273,8 @@
 close_coredump:
 	if (file.f_op->release)
 		file.f_op->release(inode,&file);
+done_coredump:
+	put_write_access(inode);
 end_coredump:
 	set_fs(fs);
 	iput(inode);
@@ -529,8 +531,6 @@
 				current->comm[i++] = ch;
 	}
 	current->comm[i] = '\0';
-	if (current->shm)
-		shm_exit();
 	/* Release all of the old mmap stuff. */
 
 	mpnt = current->mm->mmap;
@@ -636,6 +636,11 @@
 		retval = -EACCES;
 		goto exec_error2;
 	}
+	/* better not execute files which are being written to */
+	if (bprm.inode->i_wcount > 0) {
+		retval = -ETXTBSY;
+		goto exec_error2;
+	}
 	memset(bprm.buf,0,sizeof(bprm.buf));
 	old_fs = get_fs();
 	set_fs(get_ds());
@@ -844,17 +849,15 @@
 			goto beyond_if;
 		}
 
-		if (ex.a_text) {
-			error = do_mmap(file, N_TXTADDR(ex), ex.a_text,
-				PROT_READ | PROT_EXEC,
-				MAP_FIXED | MAP_SHARED | MAP_DENYWRITE | MAP_EXECUTABLE,
-				fd_offset);
-
-			if (error != N_TXTADDR(ex)) {
-				sys_close(fd);
-				send_sig(SIGSEGV, current, 0);
-				return -EINVAL;
-			}
+		error = do_mmap(file, N_TXTADDR(ex), ex.a_text,
+			PROT_READ | PROT_EXEC,
+			MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
+			fd_offset);
+
+		if (error != N_TXTADDR(ex)) {
+			sys_close(fd);
+			send_sig(SIGKILL, current, 0);
+			return error;
 		}
 		
  		error = do_mmap(file, N_TXTADDR(ex) + ex.a_text, ex.a_data,
@@ -863,8 +866,8 @@
 				fd_offset + ex.a_text);
 		sys_close(fd);
 		if (error != N_TXTADDR(ex) + ex.a_text) {
-			send_sig(SIGSEGV, current, 0);
-			return -EINVAL;
+			send_sig(SIGKILL, current, 0);
+			return error;
 		}
 	}
 beyond_if:
diff -u --recursive --new-file v1.1.61/linux/fs/ext2/CHANGES linux/fs/ext2/CHANGES
--- v1.1.61/linux/fs/ext2/CHANGES	Wed Oct 26 09:42:20 1994
+++ linux/fs/ext2/CHANGES	Fri Nov  4 12:38:44 1994
@@ -6,6 +6,12 @@
 	- The famous readdir() bug has been fixed by Stephen Tweedie.
 	- Added a revision level in the superblock.
 	- Full support for O_SYNC flag of the open system call.
+	- New mount options: `resuid=#uid' and `resgid=#gid'.  `resuid' causes
+	  ext2fs to consider user #uid like root for the reserved blocks.
+	  `resgid' acts the same way with group #gid.  New fields in the
+	  superblock contain default values for resuid and resgid and can
+	  be modified by tune2fs.
+	  Idea comes from Rene Cougnenc <cougnenc@renux.frmug.fr.net>.
 	- New mount options: `bsddf' and `minixdf'.  `bsddf' causes ext2fs
 	  to remove the blocks used for FS structures from the total block
 	  count in statfs.  With `minixdf', ext2fs mimics Minix behavior
diff -u --recursive --new-file v1.1.61/linux/fs/ext2/balloc.c linux/fs/ext2/balloc.c
--- v1.1.61/linux/fs/ext2/balloc.c	Wed Oct 26 09:42:21 1994
+++ linux/fs/ext2/balloc.c	Fri Nov  4 12:38:44 1994
@@ -270,7 +270,10 @@
 	}
 	lock_super (sb);
 	es = sb->u.ext2_sb.s_es;
-	if (es->s_free_blocks_count <= es->s_r_blocks_count && !fsuser()) {
+	if (es->s_free_blocks_count <= es->s_r_blocks_count &&
+	    (!fsuser() && (sb->u.ext2_sb.s_resuid != current->fsuid) &&
+	     (sb->u.ext2_sb.s_resgid == 0 ||
+	      !in_group_p (sb->u.ext2_sb.s_resgid)))) {
 		unlock_super (sb);
 		return 0;
 	}
diff -u --recursive --new-file v1.1.61/linux/fs/ext2/super.c linux/fs/ext2/super.c
--- v1.1.61/linux/fs/ext2/super.c	Wed Oct 26 09:42:21 1994
+++ linux/fs/ext2/super.c	Fri Nov  4 12:38:45 1994
@@ -173,6 +173,7 @@
  * This function has been shamelessly adapted from the msdos fs
  */
 static int parse_options (char * options, unsigned long * sb_block,
+			  unsigned short *resuid, unsigned short * resgid,
 			  unsigned long * mount_options)
 {
 	char * this_char;
@@ -247,6 +248,32 @@
 		else if (!strcmp (this_char, "nogrpid") ||
 			 !strcmp (this_char, "sysvgroups"))
 			clear_opt (*mount_options, GRPID);
+		else if (!strcmp (this_char, "resgid")) {
+			if (!value || !*value) {
+				printk ("EXT2-fs: the resgid option requires "
+					"an argument");
+				return 0;
+			}
+			*resgid = simple_strtoul (value, &value, 0);
+			if (*value) {
+				printk ("EXT2-fs: Invalid resgid option: %s\n",
+					value);
+				return 0;
+			}
+		}
+		else if (!strcmp (this_char, "resuid")) {
+			if (!value || !*value) {
+				printk ("EXT2-fs: the resuid option requires "
+					"an argument");
+				return 0;
+			}
+			*resuid = simple_strtoul (value, &value, 0);
+			if (*value) {
+				printk ("EXT2-fs: Invalid resuid option: %s\n",
+					value);
+				return 0;
+			}
+		}
 		else if (!strcmp (this_char, "sb")) {
 			if (!value || !*value) {
 				printk ("EXT2-fs: the sb option requires "
@@ -367,6 +394,8 @@
 	struct buffer_head * bh;
 	struct ext2_super_block * es;
 	unsigned long sb_block = 1;
+	unsigned short resuid = EXT2_DEF_RESUID;
+	unsigned short resgid = EXT2_DEF_RESGID;
 	unsigned long logic_sb_block = 1;
 	int dev = sb->s_dev;
 	int db_count;
@@ -376,7 +405,7 @@
 #endif
 
 	set_opt (sb->u.ext2_sb.s_mount_opt, CHECK_NORMAL);
-	if (!parse_options ((char *) data, &sb_block,
+	if (!parse_options ((char *) data, &sb_block, &resuid, &resgid,
 	    &sb->u.ext2_sb.s_mount_opt)) {
 		sb->s_dev = 0;
 		return NULL;
@@ -452,6 +481,14 @@
 					 sizeof (struct ext2_group_desc);
 	sb->u.ext2_sb.s_sbh = bh;
 	sb->u.ext2_sb.s_es = es;
+	if (resuid != EXT2_DEF_RESUID)
+		sb->u.ext2_sb.s_resuid = resuid;
+	else
+		sb->u.ext2_sb.s_resuid = es->s_def_resuid;
+	if (resgid != EXT2_DEF_RESGID)
+		sb->u.ext2_sb.s_resgid = resgid;
+	else
+		sb->u.ext2_sb.s_resgid = es->s_def_resgid;
 	sb->u.ext2_sb.s_mount_state = es->s_state;
 	sb->u.ext2_sb.s_rename_lock = 0;
 	sb->u.ext2_sb.s_rename_wait = NULL;
@@ -633,14 +670,22 @@
 int ext2_remount (struct super_block * sb, int * flags, char * data)
 {
 	struct ext2_super_block * es;
+	unsigned short resuid = sb->u.ext2_sb.s_resuid;
+	unsigned short resgid = sb->u.ext2_sb.s_resgid;
+	unsigned long new_mount_opt;
 	unsigned long tmp;
 
 	/*
 	 * Allow the "check" option to be passed as a remount option.
 	 */
 	set_opt (sb->u.ext2_sb.s_mount_opt, CHECK_NORMAL);
-	parse_options (data, &tmp, &sb->u.ext2_sb.s_mount_opt);
-
+	if (!parse_options (data, &tmp, &resuid, &resgid,
+			    &new_mount_opt))
+		return -EINVAL;
+
+	sb->u.ext2_sb.s_mount_opt = new_mount_opt;
+	sb->u.ext2_sb.s_resuid = resuid;
+	sb->u.ext2_sb.s_resgid = resgid;
 	es = sb->u.ext2_sb.s_es;
 	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
 		return 0;
diff -u --recursive --new-file v1.1.61/linux/fs/msdos/file.c linux/fs/msdos/file.c
--- v1.1.61/linux/fs/msdos/file.c	Thu Nov  3 17:53:29 1994
+++ linux/fs/msdos/file.c	Fri Nov  4 16:09:13 1994
@@ -22,6 +22,7 @@
 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
 
 #define PRINTK(x)
+#define Printk(x) printk x
 
 static struct file_operations msdos_file_operations = {
 	NULL,			/* lseek - default */
@@ -66,13 +67,14 @@
 {
 	char *start;
 	int left,offset,size,cnt;
+	#define MSDOS_PREFETCH	48
 	struct {
-		int   to_reada;		/* How many block to read all at once */
-		struct buffer_head *bhreq[64];	/* Buffers not already read */
-		int nbreq;			/* Number of buffers to read */
-		struct buffer_head *bhlist[64];	/* All buffers needed */
-		int nblist;			/* Number of buffers in bhlist */
-		int nolist;
+		int file_sector;/* Next sector to read in the prefetch table */
+				/* This is relative to the file, not the disk */
+		struct buffer_head *bhlist[MSDOS_PREFETCH];	/* All buffers needed */
+		int nblist;	/* Number of buffers in bhlist */
+		int nolist;	/* index in bhlist */
+		int fetched_max; /* End of pre fetch area */
 	}pre;
 	int i;
 		
@@ -89,59 +91,83 @@
 	if (filp->f_pos >= inode->i_size || count <= 0) return 0;
 	/*
 		Tell the buffer cache which block we expect to read in advance
-		Since we are limited with the stack, we preread only 64
+		Since we are limited with the stack, we preread only MSDOS_PREFETCH
 		because we have to keep the result into the local
-		arrays pre.bhlist and pre.bhreq.
+		arrays pre.bhlist and bhreq.
+		
+		Each time we process one block in bhlist, we replace
+		it by a new prefetch block if needed.
 	*/
+	PRINTK (("#### ino %ld pos %ld size %ld count %d\n",inode->i_ino,filp->f_pos,inode->i_size,count));
 	{
-		int file_sector = filp->f_pos >> SECTOR_BITS;
-		pre.to_reada = count / SECTOR_SIZE;
+		struct buffer_head *bhreq[MSDOS_PREFETCH];	/* Buffers not */
+													/* already read */
+		int nbreq;			/* Number of buffers in bhreq */
+		/*
+			We must prefetch complete block, so we must
+			take in account the offset in the first block.
+		*/
+		int count_max = (filp->f_pos & (SECTOR_SIZE-1)) + count;
+		int   to_reada;	/* How many block to read all at once */
+		pre.file_sector = filp->f_pos >> SECTOR_BITS;
+		to_reada = count_max / SECTOR_SIZE;
+		if (count_max & (SECTOR_SIZE-1)) to_reada++;
 		if (filp->f_reada){
 			int min_read = read_ahead[MAJOR(inode->i_dev)];
-			if (min_read > pre.to_reada) pre.to_reada = min_read;
+			if (min_read > to_reada) to_reada = min_read;
 		}
-		if (pre.to_reada > 64) pre.to_reada = 64;
-		pre.nbreq = pre.nblist = 0;
-		for (i=0; i<pre.to_reada; i++){
+		if (to_reada > MSDOS_PREFETCH) to_reada = MSDOS_PREFETCH;
+		nbreq = pre.nblist = 0;
+		for (i=0; i<to_reada; i++){
 			int sector;
 			struct buffer_head *bh;
-			if (!(sector = msdos_smap(inode,file_sector++))) break;
+			if (!(sector = msdos_smap(inode,pre.file_sector++))) break;
+			PRINTK (("fsector1 %d -> %d\n",pre.file_sector-1,sector));
 			bh = getblk(inode->i_dev,sector,SECTOR_SIZE);
 			if (bh == NULL)	break;
 			pre.bhlist[pre.nblist++] = bh;
 			if (!bh->b_uptodate){
-				pre.bhreq[pre.nbreq++] = bh;
+				bhreq[nbreq++] = bh;
 			}
 		}
-		if (pre.nbreq > 0) ll_rw_block (READ,pre.nbreq,pre.bhreq);
+		pre.fetched_max = pre.file_sector * SECTOR_SIZE;
+		if (nbreq > 0) ll_rw_block (READ,nbreq,bhreq);
 	}
 	start = buf;
 	pre.nolist = 0;
 	while ((left = MIN(inode->i_size-filp->f_pos,count-(buf-start))) > 0){
-		struct buffer_head *bh;
-		void *data;
-		PRINTK (("file_read pos %d\n",filp->f_pos));
-		if (pre.nolist >= pre.nblist){
-			/* This code is executed when more than 64 sectors */
-			/* are request at once */
+		struct buffer_head *bh = pre.bhlist[pre.nolist];
+		char *data;
+		if (bh == NULL) break;
+		PRINTK (("file_read pos %ld nblist %d %d %d\n",filp->f_pos,pre.nblist,pre.fetched,count));
+		pre.bhlist[pre.nolist] = NULL;
+		if (left + filp->f_pos > pre.fetched_max){
 			int sector;
-			if (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS)))
-				break;
-			if (!(bh = msdos_sread(inode->i_dev,sector)))
-				break;
-		}else{
-			bh = pre.bhlist[pre.nolist];
-			pre.bhlist[pre.nolist++] = NULL;
-			wait_on_buffer(bh);
-			if (!bh->b_uptodate){
-				/* read error  ? */
-				brelse (bh);
-				break;
+			if ((sector = msdos_smap(inode,pre.file_sector++))){
+				struct buffer_head *bhreq[1];
+				PRINTK (("fsector2 %d -> %d\n",pre.file_sector-1,sector));
+				bhreq[0] = getblk(inode->i_dev,sector,SECTOR_SIZE);
+				if (bhreq[0] == NULL)	break;
+				pre.bhlist[pre.nolist] = bhreq[0];
+				if (!bhreq[0]->b_uptodate)
+					ll_rw_block (READ,1,bhreq);
+				pre.fetched_max += SECTOR_SIZE;
+			}else{
+				/* Stop prefetching further, we have reached eof */
+				pre.fetched_max = 2000000000l;
 			}
+		} 
+		pre.nolist++;
+		if (pre.nolist >= pre.nblist) pre.nolist = 0;
+		wait_on_buffer(bh);
+		if (!bh->b_uptodate){
+			/* read error  ? */
+			brelse (bh);
+			break;
 		}
-		data = bh->b_data;
 		offset = filp->f_pos & (SECTOR_SIZE-1);
 		filp->f_pos += (size = MIN(SECTOR_SIZE-offset,left));
+		data = bh->b_data;
 		if (MSDOS_I(inode)->i_binary) {
 			memcpy_tofs(buf,data+offset,size);
 			buf += size;
@@ -161,6 +187,7 @@
 			}
 		brelse(bh);
 	}
+	PRINTK (("--- %d -> %d\n",count,(int)(buf-start)));
 	for (i=0; i<pre.nblist; i++) brelse (pre.bhlist[i]);
 	if (start == buf) return -EIO;
 	if (!IS_RDONLY(inode))
diff -u --recursive --new-file v1.1.61/linux/fs/namei.c linux/fs/namei.c
--- v1.1.61/linux/fs/namei.c	Sun Oct 23 20:55:40 1994
+++ linux/fs/namei.c	Sun Nov  6 13:43:54 1994
@@ -118,6 +118,38 @@
 }
 
 /*
+ * get_write_access() gets write permission for a file.
+ * put_write_access() releases this write permission.
+ * This is used for regular files.
+ * We cannot support write (and maybe mmap read-write shared) accesses and
+ * MAP_DENYWRITE mmapings simultaneously.
+ */
+int get_write_access(struct inode * inode)
+{
+	struct task_struct ** p;
+
+	if ((inode->i_count > 1) && S_ISREG(inode->i_mode)) /* shortcut */
+		for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
+		        struct vm_area_struct * mpnt;
+			if (!*p)
+				continue;
+			for(mpnt = (*p)->mm->mmap; mpnt; mpnt = mpnt->vm_next) {
+				if (inode != mpnt->vm_inode)
+					continue;
+				if (mpnt->vm_flags & VM_DENYWRITE)
+					return -ETXTBSY;
+			}
+		}
+	inode->i_wcount++;
+	return 0;
+}
+
+void put_write_access(struct inode * inode)
+{
+	inode->i_wcount--;
+}
+
+/*
  * lookup() looks up one part of a pathname, using the fs-dependent
  * routines (currently minix_lookup) for it. It also checks for
  * fathers (pseudo-roots, mount-points)
@@ -308,7 +340,6 @@
 	const char * basename;
 	int namelen,error;
 	struct inode * dir, *inode;
-	struct task_struct ** p;
 
 	mode &= S_IALLUGO & ~current->fs->umask;
 	mode |= S_IFREG;
@@ -380,23 +411,6 @@
 			return -EROFS;
 		}
 	}
- 	if ((inode->i_count > 1) && (flag & 2)) {
- 		for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
-		        struct vm_area_struct * mpnt;
- 			if (!*p)
- 				continue;
-			for(mpnt = (*p)->mm->mmap; mpnt; mpnt = mpnt->vm_next) {
-				if (inode != mpnt->vm_inode)
-					continue;
-				if (mpnt->vm_page_prot & PAGE_RW)
-					continue;
-				if (mpnt->vm_flags & VM_DENYWRITE) {
-					iput(inode);
-					return -ETXTBSY;
-				}
-			}
- 		}
- 	}
 	/*
 	 * An append-only file must be opened in append mode for writing
 	 */
@@ -407,9 +421,14 @@
 	if (flag & O_TRUNC) {
 		struct iattr newattrs;
 
+		if ((error = get_write_access(inode))) {
+			iput(inode);
+			return error;
+		}
 		newattrs.ia_size = 0;
 		newattrs.ia_valid = ATTR_SIZE;
 		if ((error = notify_change(inode, &newattrs))) {
+			put_write_access(inode);
 			iput(inode);
 			return error;
 		}
@@ -417,6 +436,7 @@
 		if (inode->i_op && inode->i_op->truncate)
 			inode->i_op->truncate(inode);
 		inode->i_dirt = 1;
+		put_write_access(inode);
 	}
 	*res_inode = inode;
 	return 0;
diff -u --recursive --new-file v1.1.61/linux/fs/nfs/proc.c linux/fs/nfs/proc.c
--- v1.1.61/linux/fs/nfs/proc.c	Wed Oct 12 16:00:57 1994
+++ linux/fs/nfs/proc.c	Fri Nov  4 16:18:50 1994
@@ -77,25 +77,12 @@
 
 static inline int *nfs_rpc_alloc(int size)
 {
-#if 0
-	/* Allow for the NFS crap as well as buffer */
-	return (int *)kmalloc(size+NFS_SLACK_SPACE,GFP_KERNEL);
-#else 
-	/* If kmalloc fails, then we will give an EIO to user level.
-	   (Please correct me, I am wron here... ??) This is not
-	   desirable, but it is also not desirable to execute the
-	   following code: Just loop until we get memory, call schedule(),
-	   so that other processes are run inbetween (and hopefully give
-	   some memory back).		Florian
-	*/
 	int *i;
 
-	while (!(i = (int *)kmalloc(size+NFS_SLACK_SPACE,GFP_KERNEL))) {
-		/* printk("NFS: call schedule\n"); */
+	while (!(i = (int *)kmalloc(size+NFS_SLACK_SPACE,GFP_NFS))) {
 		schedule();
 	}
 	return i;
-#endif
 }
 
 static inline void nfs_rpc_free(int *p)
diff -u --recursive --new-file v1.1.61/linux/fs/nfs/symlink.c linux/fs/nfs/symlink.c
--- v1.1.61/linux/fs/nfs/symlink.c	Wed Oct 12 16:00:57 1994
+++ linux/fs/nfs/symlink.c	Fri Nov  4 16:18:50 1994
@@ -71,16 +71,9 @@
 	}
 	error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), &mem,
 		&res, &len, NFS_MAXPATHLEN);
-#if 0
-	if ((res2 = (char *) kmalloc(NFS_MAXPATHLEN + 1, GFP_KERNEL)) == NULL) {
-		printk("NFS: no memory in nfs_follow_link\n");
-		error = -EIO;
-	}
-#else
-	while ((res2 = (char *) kmalloc(NFS_MAXPATHLEN + 1, GFP_KERNEL)) == NULL) {
+	while ((res2 = (char *) kmalloc(NFS_MAXPATHLEN + 1, GFP_NFS)) == NULL) {
 		schedule();
 	}
-#endif
 	if (error) {
 		iput(inode);
 		iput(dir);
diff -u --recursive --new-file v1.1.61/linux/fs/open.c linux/fs/open.c
--- v1.1.61/linux/fs/open.c	Thu Oct 27 17:15:24 1994
+++ linux/fs/open.c	Sun Nov  6 18:02:00 1994
@@ -86,6 +86,11 @@
 		iput(inode);
 		return -EPERM;
 	}
+	error = get_write_access(inode);
+	if (error) {
+		iput(inode);
+		return error;
+	}
 	inode->i_size = newattrs.ia_size = length;
 	if (inode->i_op && inode->i_op->truncate)
 		inode->i_op->truncate(inode);
@@ -93,6 +98,7 @@
 	newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME | ATTR_MTIME;
 	inode->i_dirt = 1;
 	error = notify_change(inode, &newattrs);
+	put_write_access(inode);
 	iput(inode);
 	return error;
 }
@@ -320,14 +326,14 @@
 	/*
 	 * If the owner has been changed, remove the setuid bit
 	 */
-	if (user != inode->i_uid && inode->i_mode & S_ISUID) {
+	if (user != inode->i_uid && (inode->i_mode & S_ISUID)) {
 		newattrs.ia_mode &= ~S_ISUID;
 		newattrs.ia_valid |= ATTR_MODE;
 	}
 	/*
 	 * If the group has been changed, remove the setgid bit
 	 */
-	if (group != inode->i_gid && inode->i_mode & S_ISGID) {
+	if (group != inode->i_gid && (inode->i_mode & S_ISGID)) {
 		newattrs.ia_mode &= ~S_ISGID;
 		newattrs.ia_valid |= ATTR_MODE;
 	}
@@ -352,6 +358,7 @@
 		user = inode->i_uid;
 	if (group == (gid_t) -1)
 		group = inode->i_gid;
+	newattrs.ia_mode = inode->i_mode;
 	newattrs.ia_uid = user;
 	newattrs.ia_gid = group;
 	newattrs.ia_ctime = CURRENT_TIME;
@@ -359,15 +366,15 @@
 	/*
 	 * If the owner has been changed, remove the setuid bit
 	 */
-	if (user != inode->i_uid && inode->i_mode & S_ISUID) {
-		newattrs.ia_mode = inode->i_mode & ~S_ISUID;
+	if (user != inode->i_uid && (inode->i_mode & S_ISUID)) {
+		newattrs.ia_mode &= ~S_ISUID;
 		newattrs.ia_valid |= ATTR_MODE;
 	}
 	/*
 	 * If the group has been changed, remove the setgid bit
 	 */
-	if (group != inode->i_gid && inode->i_mode & S_ISGID) {
-		newattrs.ia_mode = inode->i_mode & ~S_ISGID;
+	if (group != inode->i_gid && (inode->i_mode & S_ISGID)) {
+		newattrs.ia_mode &= ~S_ISGID;
 		newattrs.ia_valid |= ATTR_MODE;
 	}
 	inode->i_dirt = 1;
@@ -413,6 +420,8 @@
 	if (flag & (O_TRUNC | O_CREAT))
 		flag |= 2;
 	error = open_namei(filename,flag,mode,&inode,NULL);
+	if (!error && (f->f_mode & 2))
+		error = get_write_access(inode);
 	if (error) {
 		current->files->fd[fd]=NULL;
 		f->f_count--;
@@ -428,6 +437,7 @@
 	if (f->f_op && f->f_op->open) {
 		error = f->f_op->open(inode,f);
 		if (error) {
+			if (f->f_mode & 2) put_write_access(inode);
 			iput(inode);
 			f->f_count--;
 			current->files->fd[fd]=NULL;
@@ -475,6 +485,7 @@
 		filp->f_op->release(inode,filp);
 	filp->f_count--;
 	filp->f_inode = NULL;
+	if (filp->f_mode & 2) put_write_access(inode);
 	iput(inode);
 	return 0;
 }
diff -u --recursive --new-file v1.1.61/linux/fs/sysv/INTRO linux/fs/sysv/INTRO
--- v1.1.61/linux/fs/sysv/INTRO	Wed Jul 21 05:35:45 1993
+++ linux/fs/sysv/INTRO	Sat Nov  5 13:32:13 1994
@@ -178,12 +178,6 @@
 Notation: We often speak of a "block" but mean a zone (the allocation unit)
 and not the disk driver's notion of "block".
 
-Because the block size may be smaller than 1024 (which is the unit used by
-the disk drivers and the buffer code), many functions must return a pointer
-to the buffer data additionally to the buffer head pointer. One must not
-assume that the entire buffer is occupied by this single block. This makes
-the implementation of truncate() difficult.
-
 
 Bruno Haible  <haible@ma2s2.mathematik.uni-karlsruhe.de>
 
diff -u --recursive --new-file v1.1.61/linux/fs/sysv/Makefile linux/fs/sysv/Makefile
--- v1.1.61/linux/fs/sysv/Makefile	Tue Jul 26 21:34:03 1994
+++ linux/fs/sysv/Makefile	Sat Nov  5 13:32:13 1994
@@ -15,7 +15,7 @@
 	$(AS) -o $*.o $<
 
 OBJS=	ialloc.o balloc.o inode.o file.o dir.o symlink.o namei.o \
-	fsync.o truncate.o mmap.o
+	fsync.o truncate.o
 
 sysv.o: $(OBJS)
 	$(LD) -r -o sysv.o $(OBJS)
diff -u --recursive --new-file v1.1.61/linux/fs/sysv/README linux/fs/sysv/README
--- v1.1.61/linux/fs/sysv/README	Thu Oct  6 08:32:45 1994
+++ linux/fs/sysv/README	Sat Nov  5 13:32:13 1994
@@ -4,7 +4,7 @@
   - SystemV/386 FS,
   - Coherent FS.
 
-This is version beta 3.
+This is version beta 4.
 
 To install:
 * Answer the 'System V and Coherent filesystem support' question with 'y'
diff -u --recursive --new-file v1.1.61/linux/fs/sysv/balloc.c linux/fs/sysv/balloc.c
--- v1.1.61/linux/fs/sysv/balloc.c	Sat Oct 22 16:50:31 1994
+++ linux/fs/sysv/balloc.c	Sat Nov  5 13:32:14 1994
@@ -26,7 +26,7 @@
 #include <linux/locks.h>
 
 /* We don't trust the value of
-   sb->sv_sbd->s_tfree = *sb->sv_sb_total_free_blocks
+   sb->sv_sbd2->s_tfree = *sb->sv_sb_total_free_blocks
    but we nevertheless keep it up to date. */
 
 void sysv_free_block(struct super_block * sb, unsigned int block)
@@ -55,16 +55,13 @@
 		unsigned short * flc_count;
 		unsigned long * flc_blocks;
 
-		if (sb->sv_block_size_ratio_bits > 0) /* block_size < BLOCK_SIZE ? */
-			bh = bread(sb->s_dev, (block >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE);
-		else
-			bh = getblk(sb->s_dev, (block >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE);
+		bh = sv_getblk(sb, sb->s_dev, block);
 		if (!bh) {
-			printk("sysv_free_block: getblk() or bread() failed\n");
+			printk("sysv_free_block: getblk() failed\n");
 			unlock_super(sb);
 			return;
 		}
-		bh_data = bh->b_data + ((block & sb->sv_block_size_ratio_1) << sb->sv_block_size_bits);
+		bh_data = bh->b_data;
 		switch (sb->sv_type) {
 			case FSTYPE_XENIX:
 				flc_count = &((struct xenix_freelist_chunk *) bh_data)->fl_nfree;
@@ -95,30 +92,24 @@
 	 * in this block being freed:
 	 */
 	if (*sb->sv_sb_flc_count == 0) { /* Applies only to Coherent FS */
-		if (sb->sv_block_size_ratio_bits > 0) /* block_size < BLOCK_SIZE ? */
-			bh = bread(sb->s_dev, (block >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE);
-		else
-			bh = getblk(sb->s_dev, (block >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE);
+		bh = sv_getblk(sb, sb->s_dev, block);
 		if (!bh) {
-			printk("sysv_free_block: getblk() or bread() failed\n");
+			printk("sysv_free_block: getblk() failed\n");
 			unlock_super(sb);
 			return;
 		}
-		bh_data = bh->b_data + ((block & sb->sv_block_size_ratio_1) << sb->sv_block_size_bits);
-		memset(bh_data, 0, sb->sv_block_size);
-		/* this implies ((struct ..._freelist_chunk *) bh_data)->flc_count = 0; */
+		memset(bh->b_data, 0, sb->sv_block_size);
+		/* this implies ((struct ..._freelist_chunk *) bh->b_data)->flc_count = 0; */
 		mark_buffer_dirty(bh, 1);
 		bh->b_uptodate = 1;
 		brelse(bh);
 		/* still *sb->sv_sb_flc_count = 0 */
 	} else {
-		if (sb->sv_block_size_ratio_bits == 0) { /* block_size == BLOCK_SIZE ? */
-			/* Throw away block's contents */
-			bh = get_hash_table(sb->s_dev, (block >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE);
-			if (bh)
-				bh->b_dirt = 0;
-			brelse(bh);
-		}
+		/* Throw away block's contents */
+		bh = sv_get_hash_table(sb, sb->s_dev, block);
+		if (bh)
+			bh->b_dirt = 0;
+		brelse(bh);
 	}
 	if (sb->sv_convert)
 		block = to_coh_ulong(block);
@@ -128,7 +119,8 @@
 		  to_coh_ulong(from_coh_ulong(*sb->sv_sb_total_free_blocks) + 1);
 	else
 		*sb->sv_sb_total_free_blocks = *sb->sv_sb_total_free_blocks + 1;
-	mark_buffer_dirty(sb->sv_bh, 1); /* super-block has been modified */
+	mark_buffer_dirty(sb->sv_bh1, 1); /* super-block has been modified */
+	if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2, 1);
 	sb->s_dirt = 1; /* and needs time stamp */
 	unlock_super(sb);
 }
@@ -165,13 +157,14 @@
 		unsigned short * flc_count;
 		unsigned long * flc_blocks;
 
-		if (!(bh = sysv_bread(sb, sb->s_dev, block, &bh_data))) {
+		if (!(bh = sv_bread(sb, sb->s_dev, block))) {
 			printk("sysv_new_block: cannot read free-list block\n");
 			/* retry this same block next time */
 			(*sb->sv_sb_flc_count)++;
 			unlock_super(sb);
 			return 0;
 		}
+		bh_data = bh->b_data;
 		switch (sb->sv_type) {
 			case FSTYPE_XENIX:
 				flc_count = &((struct xenix_freelist_chunk *) bh_data)->fl_nfree;
@@ -202,23 +195,18 @@
 		brelse(bh);
 	}
 	/* Now the free list head in the superblock is valid again. */
-	if (sb->sv_block_size_ratio_bits > 0) /* block_size < BLOCK_SIZE ? */
-		bh = bread(sb->s_dev, (block >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE);
-	else
-		bh = getblk(sb->s_dev, (block >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE);
+	bh = sv_getblk(sb, sb->s_dev, block);
 	if (!bh) {
-		printk("sysv_new_block: getblk() or bread() failed\n");
+		printk("sysv_new_block: getblk() failed\n");
 		unlock_super(sb);
 		return 0;
 	}
-	bh_data = bh->b_data + ((block & sb->sv_block_size_ratio_1) << sb->sv_block_size_bits);
-	if (sb->sv_block_size_ratio_bits == 0) /* block_size == BLOCK_SIZE ? */
-		if (bh->b_count != 1) {
-			printk("sysv_new_block: block already in use\n");
-			unlock_super(sb);
-			return 0;
-		}
-	memset(bh_data, 0, sb->sv_block_size);
+	if (bh->b_count != 1) {
+		printk("sysv_new_block: block already in use\n");
+		unlock_super(sb);
+		return 0;
+	}
+	memset(bh->b_data, 0, sb->sv_block_size);
 	mark_buffer_dirty(bh, 1);
 	bh->b_uptodate = 1;
 	brelse(bh);
@@ -227,7 +215,8 @@
 		  to_coh_ulong(from_coh_ulong(*sb->sv_sb_total_free_blocks) - 1);
 	else
 		*sb->sv_sb_total_free_blocks = *sb->sv_sb_total_free_blocks - 1;
-	mark_buffer_dirty(sb->sv_bh, 1); /* super-block has been modified */
+	mark_buffer_dirty(sb->sv_bh1, 1); /* super-block has been modified */
+	if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2, 1);
 	sb->s_dirt = 1; /* and needs time stamp */
 	unlock_super(sb);
 	return block;
@@ -265,10 +254,11 @@
 				printk("sysv_count_free_blocks: new block %d is not in data zone\n",block);
 				break;
 			}
-			if (!(bh = sysv_bread(sb, sb->s_dev, block, &bh_data))) {
+			if (!(bh = sv_bread(sb, sb->s_dev, block))) {
 				printk("sysv_count_free_blocks: cannot read free-list block\n");
 				break;
 			}
+			bh_data = bh->b_data;
 			switch (sb->sv_type) {
 				case FSTYPE_XENIX:
 					flc_count = &((struct xenix_freelist_chunk *) bh_data)->fl_nfree;
@@ -321,7 +311,7 @@
 		printk("sysv_count_free_blocks: free block count was %d, correcting to %d\n",old_count,count);
 		if (!(sb->s_flags & MS_RDONLY)) {
 			*sb->sv_sb_total_free_blocks = (sb->sv_convert ? to_coh_ulong(count) : count);
-			mark_buffer_dirty(sb->sv_bh, 1); /* super-block has been modified */
+			mark_buffer_dirty(sb->sv_bh2, 1); /* super-block has been modified */
 			sb->s_dirt = 1; /* and needs time stamp */
 		}
 	}
diff -u --recursive --new-file v1.1.61/linux/fs/sysv/dir.c linux/fs/sysv/dir.c
--- v1.1.61/linux/fs/sysv/dir.c	Wed Nov  2 12:03:47 1994
+++ linux/fs/sysv/dir.c	Sat Nov  5 13:32:14 1994
@@ -80,11 +80,12 @@
 		return -EBADF;
 	while (filp->f_pos < inode->i_size) {
 		offset = filp->f_pos & sb->sv_block_size_1;
-		bh = sysv_file_bread(inode, filp->f_pos >> sb->sv_block_size_bits, 0, &bh_data);
+		bh = sysv_file_bread(inode, filp->f_pos >> sb->sv_block_size_bits, 0);
 		if (!bh) {
 			filp->f_pos += sb->sv_block_size - offset;
 			continue;
 		}
+		bh_data = bh->b_data;
 		while (offset < sb->sv_block_size && filp->f_pos < inode->i_size) {
 			de = (struct sysv_dir_entry *) (offset + bh_data);
 			offset += SYSV_DIRSIZE;
@@ -127,10 +128,6 @@
 	/* compatibility */
 	if (count==1)
 		return sysv_readdir1(inode,filp,dirent);
-
-	retval = verify_area(VERIFY_WRITE, dirent, count);
-	if (retval)
-		return retval;
 
 	stored = 0;
 	while (count >= sizeof(struct dirent)) {
diff -u --recursive --new-file v1.1.61/linux/fs/sysv/file.c linux/fs/sysv/file.c
--- v1.1.61/linux/fs/sysv/file.c	Tue Jul 26 21:34:03 1994
+++ linux/fs/sysv/file.c	Sat Nov  5 13:32:13 1994
@@ -45,19 +45,6 @@
 	NULL,			/* readdir - bad */
 	NULL,			/* select - default */
 	NULL,			/* ioctl - default */
-	sysv_mmap,		/* mmap */
-	NULL,			/* no special open is needed */
-	NULL,			/* release */
-	sysv_sync_file		/* fsync */
-};
-
-static struct file_operations sysv_file_operations_with_bmap = {
-	NULL,			/* lseek - default */
-	sysv_file_read,		/* read */
-	sysv_file_write,	/* write */
-	NULL,			/* readdir - bad */
-	NULL,			/* select - default */
-	NULL,			/* ioctl - default */
 	generic_mmap,		/* mmap */
 	NULL,			/* no special open is needed */
 	NULL,			/* release */
@@ -77,44 +64,21 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	NULL,			/* bmap */
-	sysv_truncate,		/* truncate */
-	NULL			/* permission */
-};
-
-struct inode_operations sysv_file_inode_operations_with_bmap = {
-	&sysv_file_operations_with_bmap, /* default file operations */
-	NULL,			/* create */
-	NULL,			/* lookup */
-	NULL,			/* link */
-	NULL,			/* unlink */
-	NULL,			/* symlink */
-	NULL,			/* mkdir */
-	NULL,			/* rmdir */
-	NULL,			/* mknod */
-	NULL,			/* rename */
-	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	sysv_bmap,		/* bmap */
 	sysv_truncate,		/* truncate */
 	NULL			/* permission */
 };
 
-struct sysv_buffer {
-	struct buffer_head * bh;
-	char * bh_data;
-};
-
 int sysv_file_read(struct inode * inode, struct file * filp, char * buf, int count)
 {
 	struct super_block * sb = inode->i_sb;
 	int read,left,chars;
 	unsigned int block;
 	int blocks, offset;
-	int bhrequest, bhreqi, uptodate;
-	struct sysv_buffer * bhb, * bhe;
+	int bhrequest, uptodate;
+	struct buffer_head ** bhb, ** bhe;
 	struct buffer_head * bhreq[NBUF];
-	struct sysv_buffer buflist[NBUF];
+	struct buffer_head * buflist[NBUF];
 	unsigned int size;
 
 	if (!inode) {
@@ -156,9 +120,6 @@
 
 	   This routine is optimized to make maximum use of the various
 	   buffers and caches.
-
-	   We must remove duplicates from the bhreq array as ll_rw_block
-	   doesn't like duplicate requests (it hangs in wait_on_buffer...).
 	 */
 
 	do {
@@ -166,15 +127,10 @@
 		uptodate = 1;
 		while (blocks) {
 			--blocks;
-			bhb->bh = sysv_getblk(inode, block++, 0, &bhb->bh_data);
-			if (bhb->bh && !bhb->bh->b_uptodate) {
+			*bhb = sysv_getblk(inode, block++, 0);
+			if (*bhb && !(*bhb)->b_uptodate) {
 				uptodate = 0;
-				if (sb->sv_block_size_ratio_bits > 0) /* block_size < BLOCK_SIZE ? */
-					for (bhreqi = 0; bhreqi < bhrequest; bhreqi++)
-						if (bhreq[bhreqi] == bhb->bh)
-							goto notreq;
-				bhreq[bhrequest++] = bhb->bh;
-				notreq: ;
+				bhreq[bhrequest++] = *bhb;
 			}
 
 			if (++bhb == &buflist[NBUF])
@@ -193,10 +149,10 @@
 			ll_rw_block(READ, bhrequest, bhreq);
 
 		do { /* Finish off all I/O that has actually completed */
-			if (bhe->bh) {
-				wait_on_buffer(bhe->bh);
-				if (!bhe->bh->b_uptodate) {	/* read error? */
-					brelse(bhe->bh);
+			if (*bhe) {
+				wait_on_buffer(*bhe);
+				if (!(*bhe)->b_uptodate) {	/* read error? */
+					brelse(*bhe);
 					if (++bhe == &buflist[NBUF])
 						bhe = buflist;
 					left = 0;
@@ -210,9 +166,9 @@
 			filp->f_pos += chars;
 			left -= chars;
 			read += chars;
-			if (bhe->bh) {
-				memcpy_tofs(buf,offset+bhe->bh_data,chars);
-				brelse(bhe->bh);
+			if (*bhe) {
+				memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
+				brelse(*bhe);
 				buf += chars;
 			} else {
 				while (chars-- > 0)
@@ -221,12 +177,12 @@
 			offset = 0;
 			if (++bhe == &buflist[NBUF])
 				bhe = buflist;
-		} while (left > 0 && bhe != bhb && (!bhe->bh || !bhe->bh->b_lock));
+		} while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
 	} while (left > 0);
 
 /* Release the read-ahead blocks */
 	while (bhe != bhb) {
-		brelse(bhe->bh);
+		brelse(*bhe);
 		if (++bhe == &buflist[NBUF])
 			bhe = buflist;
 	};
@@ -244,7 +200,6 @@
 	off_t pos;
 	int written,c;
 	struct buffer_head * bh;
-	char * bh_data;
 	char * p;
 
 	if (!inode) {
@@ -262,15 +217,13 @@
  * writing our data into blocks that have meanwhile been incorporated into
  * the freelist, thereby trashing the freelist.
  */
-	if (sb->sv_block_size_ratio_bits > 0) /* block_size < BLOCK_SIZE ? */
-		coh_lock_inode(inode);
 	if (filp->f_flags & O_APPEND)
 		pos = inode->i_size;
 	else
 		pos = filp->f_pos;
 	written = 0;
 	while (written<count) {
-		bh = sysv_getblk (inode, pos >> sb->sv_block_size_bits, 1, &bh_data);
+		bh = sysv_getblk (inode, pos >> sb->sv_block_size_bits, 1);
 		if (!bh) {
 			if (!written)
 				written = -ENOSPC;
@@ -279,7 +232,7 @@
 		c = sb->sv_block_size - (pos & sb->sv_block_size_1);
 		if (c > count-written)
 			c = count-written;
-		if (c != BLOCK_SIZE && !bh->b_uptodate) {
+		if (c != sb->sv_block_size && !bh->b_uptodate) {
 			ll_rw_block(READ, 1, &bh);
 			wait_on_buffer(bh);
 			if (!bh->b_uptodate) {
@@ -289,8 +242,8 @@
 				break;
 			}
 		}
-		/* now either c==BLOCK_SIZE or bh->b_uptodate */
-		p = (pos & sb->sv_block_size_1) + bh_data;
+		/* now either c==sb->sv_block_size or bh->b_uptodate */
+		p = (pos & sb->sv_block_size_1) + bh->b_data;
 		pos += c;
 		if (pos > inode->i_size) {
 			inode->i_size = pos;
@@ -306,7 +259,5 @@
 	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 	filp->f_pos = pos;
 	inode->i_dirt = 1;
-	if (sb->sv_block_size_ratio_bits > 0) /* block_size < BLOCK_SIZE ? */
-		coh_unlock_inode(inode);
 	return written;
 }
diff -u --recursive --new-file v1.1.61/linux/fs/sysv/fsync.c linux/fs/sysv/fsync.c
--- v1.1.61/linux/fs/sysv/fsync.c	Wed Jul 21 02:50:31 1993
+++ linux/fs/sysv/fsync.c	Sat Nov  5 13:32:13 1994
@@ -38,7 +38,7 @@
 	if (!block)
 		return 0;
 	sb = inode->i_sb;
-	bh = get_hash_table(inode->i_dev, (block >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE);
+	bh = sv_get_hash_table(sb, inode->i_dev, block);
 	if (!bh)
 		return 0;
 	if (*blockp != tmp) {
@@ -60,7 +60,7 @@
 
 /* Sync one block full of indirect pointers and read it because we'll need it. */
 static int sync_iblock (struct inode * inode, unsigned long * iblockp, int convert,
-			struct buffer_head * *bh, char * *bh_data, int wait)
+			struct buffer_head * *bh, int wait)
 {
 	int rc;
 	unsigned long tmp, block;
@@ -74,7 +74,7 @@
 	rc = sync_block (inode, iblockp, convert, wait);
 	if (rc)
 		return rc;
-	*bh = sysv_bread(inode->i_sb, inode->i_dev, block, bh_data);
+	*bh = sv_bread(inode->i_sb, inode->i_dev, block);
 	if (tmp != *iblockp) {
 		brelse(*bh);
 		*bh = NULL;
@@ -105,18 +105,17 @@
 {
 	int i;
 	struct buffer_head * ind_bh;
-	char * ind_bh_data;
 	int rc, err = 0;
 	struct super_block * sb;
 
-	rc = sync_iblock (inode, iblockp, convert, &ind_bh, &ind_bh_data, wait);
+	rc = sync_iblock (inode, iblockp, convert, &ind_bh, wait);
 	if (rc || !ind_bh)
 		return rc;
 
 	sb = inode->i_sb;
 	for (i = 0; i < sb->sv_ind_per_block; i++) {
 		rc = sync_block (inode,
-				 ((unsigned long *) ind_bh_data) + i, sb->sv_convert,
+				 ((unsigned long *) ind_bh->b_data) + i, sb->sv_convert,
 				 wait);
 		if (rc > 0)
 			break;
@@ -132,18 +131,17 @@
 {
 	int i;
 	struct buffer_head * dind_bh;
-	char * dind_bh_data;
 	int rc, err = 0;
 	struct super_block * sb;
 
-	rc = sync_iblock (inode, diblockp, convert, &dind_bh, &dind_bh_data, wait);
+	rc = sync_iblock (inode, diblockp, convert, &dind_bh, wait);
 	if (rc || !dind_bh)
 		return rc;
 
 	sb = inode->i_sb;
 	for (i = 0; i < sb->sv_ind_per_block; i++) {
 		rc = sync_indirect (inode,
-				    ((unsigned long *) dind_bh_data) + i, sb->sv_convert,
+				    ((unsigned long *) dind_bh->b_data) + i, sb->sv_convert,
 				    wait);
 		if (rc > 0)
 			break;
@@ -159,18 +157,17 @@
 {
 	int i;
 	struct buffer_head * tind_bh;
-	char * tind_bh_data;
 	int rc, err = 0;
 	struct super_block * sb;
 
-	rc = sync_iblock (inode, tiblockp, convert, &tind_bh, &tind_bh_data, wait);
+	rc = sync_iblock (inode, tiblockp, convert, &tind_bh, wait);
 	if (rc || !tind_bh)
 		return rc;
 
 	sb = inode->i_sb;
 	for (i = 0; i < sb->sv_ind_per_block; i++) {
 		rc = sync_dindirect (inode,
-				     ((unsigned long *) tind_bh_data) + i, sb->sv_convert,
+				     ((unsigned long *) tind_bh->b_data) + i, sb->sv_convert,
 				     wait);
 		if (rc > 0)
 			break;
diff -u --recursive --new-file v1.1.61/linux/fs/sysv/ialloc.c linux/fs/sysv/ialloc.c
--- v1.1.61/linux/fs/sysv/ialloc.c	Thu Aug 11 17:16:42 1994
+++ linux/fs/sysv/ialloc.c	Sat Nov  5 13:32:14 1994
@@ -23,22 +23,37 @@
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/sysv_fs.h>
+#include <linux/stddef.h>
 #include <linux/stat.h>
 #include <linux/string.h>
 #include <linux/locks.h>
 
 /* We don't trust the value of
-   sb->sv_sbd->s_tinode = *sb->sv_sb_total_free_inodes
+   sb->sv_sbd2->s_tinode = *sb->sv_sb_total_free_inodes
    but we nevertheless keep it up to date. */
 
 /* An inode on disk is considered free if both i_mode == 0 and i_nlink == 0. */
 
+/* return &sb->sv_sb_fic_inodes[i] = &sbd->s_inode[i]; */
+static inline sysv_ino_t * sv_sb_fic_inode (struct super_block * sb, unsigned int i)
+{
+	if (sb->sv_bh1 == sb->sv_bh2)
+		return &sb->sv_sb_fic_inodes[i];
+	else {
+		/* 512 byte Xenix FS */
+		unsigned int offset = offsetof(struct xenix_super_block, s_inode[i]);
+		if (offset < 512)
+			return (sysv_ino_t*)(sb->sv_sbd1 + offset);
+		else
+			return (sysv_ino_t*)(sb->sv_sbd2 + offset);
+	}
+}
+
 void sysv_free_inode(struct inode * inode)
 {
 	struct super_block * sb;
 	unsigned int ino;
 	struct buffer_head * bh;
-	char * bh_data;
 	struct sysv_inode * raw_inode;
 
 	if (!inode)
@@ -64,17 +79,18 @@
 		printk("sysv_free_inode: inode 0,1,2 or nonexistent inode\n");
 		return;
 	}
-	if (!(bh = sysv_bread(sb, inode->i_dev, sb->sv_firstinodezone + ((ino-1) >> sb->sv_inodes_per_block_bits), &bh_data))) {
+	if (!(bh = sv_bread(sb, inode->i_dev, sb->sv_firstinodezone + ((ino-1) >> sb->sv_inodes_per_block_bits)))) {
 		printk("sysv_free_inode: unable to read inode block on device %d/%d\n",MAJOR(inode->i_dev),MINOR(inode->i_dev));
 		clear_inode(inode);
 		return;
 	}
-	raw_inode = (struct sysv_inode *) bh_data + ((ino-1) & sb->sv_inodes_per_block_1);
+	raw_inode = (struct sysv_inode *) bh->b_data + ((ino-1) & sb->sv_inodes_per_block_1);
 	lock_super(sb);
 	if (*sb->sv_sb_fic_count < sb->sv_fic_size)
-		sb->sv_sb_fic_inodes[(*sb->sv_sb_fic_count)++] = ino;
+		*sv_sb_fic_inode(sb,(*sb->sv_sb_fic_count)++) = ino;
 	(*sb->sv_sb_total_free_inodes)++;
-	mark_buffer_dirty(sb->sv_bh, 1); /* super-block has been modified */
+	mark_buffer_dirty(sb->sv_bh1, 1); /* super-block has been modified */
+	if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2, 1);
 	sb->s_dirt = 1; /* and needs time stamp */
 	memset(raw_inode, 0, sizeof(struct sysv_inode));
 	mark_buffer_dirty(bh, 1);
@@ -88,7 +104,6 @@
 	struct inode * inode;
 	struct super_block * sb;
 	struct buffer_head * bh;
-	char * bh_data;
 	struct sysv_inode * raw_inode;
 	int i,j,ino,block;
 
@@ -99,7 +114,7 @@
 	inode->i_flags = inode->i_sb->s_flags;
 	lock_super(sb);		/* protect against task switches */
 	if ((*sb->sv_sb_fic_count == 0)
-	    || (sb->sv_sb_fic_inodes[(*sb->sv_sb_fic_count)-1] == 0) /* Applies only to SystemV2 FS */
+	    || (*sv_sb_fic_inode(sb,(*sb->sv_sb_fic_count)-1) == 0) /* Applies only to SystemV2 FS */
 	   ) {
 		/* Rebuild cache of free inodes: */
 		/* i : index into cache slot being filled	     */
@@ -109,15 +124,15 @@
 		/* bh : buffer for block			     */
 		/* raw_inode : pointer to inode ino in the block     */
 		for (i = 0, ino = SYSV_ROOT_INO+1, block = sb->sv_firstinodezone, j = SYSV_ROOT_INO ; i < sb->sv_fic_size && block < sb->sv_firstdatazone ; block++, j = 0) {
-			if (!(bh = sysv_bread(sb, sb->s_dev, block, &bh_data))) {
+			if (!(bh = sv_bread(sb, sb->s_dev, block))) {
 				printk("sysv_new_inode: unable to read inode table\n");
 				break;	/* go with what we've got */
 				/* FIXME: Perhaps try the next block? */
 			}
-			raw_inode = (struct sysv_inode *) bh_data + j;
+			raw_inode = (struct sysv_inode *) bh->b_data + j;
 			for (; j < sb->sv_inodes_per_block && i < sb->sv_fic_size; ino++, j++, raw_inode++) {
 				if (raw_inode->i_mode == 0 && raw_inode->i_nlink == 0)
-					sb->sv_sb_fic_inodes[i++] = ino;
+					*sv_sb_fic_inode(sb,i++) = ino;
 			}
 			brelse(bh);
 		}
@@ -129,8 +144,9 @@
 		*sb->sv_sb_fic_count = i;
 	}
 	/* Now *sb->sv_sb_fic_count > 0. */
-	ino = sb->sv_sb_fic_inodes[--(*sb->sv_sb_fic_count)];
-	mark_buffer_dirty(sb->sv_bh, 1); /* super-block has been modified */
+	ino = *sv_sb_fic_inode(sb,--(*sb->sv_sb_fic_count));
+	mark_buffer_dirty(sb->sv_bh1, 1); /* super-block has been modified */
+	if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2, 1);
 	sb->s_dirt = 1; /* and needs time stamp */
 	inode->i_count = 1;
 	inode->i_nlink = 1;
@@ -142,7 +158,6 @@
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	inode->i_op = NULL;
 	inode->i_blocks = inode->i_blksize = 0;
-	inode->u.sysv_i.i_lock = 0; inode->u.sysv_i.i_wait = NULL;
 	insert_inode_hash(inode);
 	/* Change directory entry: */
 	inode->i_mode = 0;		/* for sysv_write_inode() */
@@ -152,7 +167,7 @@
 	inode->i_dirt = 1;		/* cleared by sysv_write_inode() */
 	/* That's it. */
 	(*sb->sv_sb_total_free_inodes)--;
-	mark_buffer_dirty(sb->sv_bh, 1); /* super-block has been modified again */
+	mark_buffer_dirty(sb->sv_bh2, 1); /* super-block has been modified again */
 	sb->s_dirt = 1; /* and needs time stamp again */
 	unlock_super(sb);
 	return inode;
@@ -162,7 +177,6 @@
 {
 #if 1 /* test */
 	struct buffer_head * bh;
-	char * bh_data;
 	struct sysv_inode * raw_inode;
 	int j,block,count;
 
@@ -176,12 +190,12 @@
 	/* bh : buffer for block			     */
 	/* raw_inode : pointer to inode ino in the block     */
 	for (block = sb->sv_firstinodezone, j = SYSV_ROOT_INO ; block < sb->sv_firstdatazone ; block++, j = 0) {
-		if (!(bh = sysv_bread(sb, sb->s_dev, block, &bh_data))) {
+		if (!(bh = sv_bread(sb, sb->s_dev, block))) {
 			printk("sysv_count_free_inodes: unable to read inode table\n");
 			break;	/* go with what we've got */
 			/* FIXME: Perhaps try the next block? */
 		}
-		raw_inode = (struct sysv_inode *) bh_data + j;
+		raw_inode = (struct sysv_inode *) bh->b_data + j;
 		for (; j < sb->sv_inodes_per_block ; j++, raw_inode++)
 			if (raw_inode->i_mode == 0 && raw_inode->i_nlink == 0)
 				count++;
@@ -191,7 +205,7 @@
 		printk("sysv_count_free_inodes: free inode count was %d, correcting to %d\n",(short)(*sb->sv_sb_total_free_inodes),count);
 		if (!(sb->s_flags & MS_RDONLY)) {
 			*sb->sv_sb_total_free_inodes = count;
-			mark_buffer_dirty(sb->sv_bh, 1); /* super-block has been modified */
+			mark_buffer_dirty(sb->sv_bh2, 1); /* super-block has been modified */
 			sb->s_dirt = 1; /* and needs time stamp */
 		}
 	}
diff -u --recursive --new-file v1.1.61/linux/fs/sysv/inode.c linux/fs/sysv/inode.c
--- v1.1.61/linux/fs/sysv/inode.c	Wed Nov  2 12:03:47 1994
+++ linux/fs/sysv/inode.c	Sat Nov  5 13:32:14 1994
@@ -30,21 +30,6 @@
 
 #include <asm/segment.h>
 
-void _coh_wait_on_inode (struct inode * inode)
-{
-	struct wait_queue wait = { current, NULL };
-
-	add_wait_queue(&inode->u.sysv_i.i_wait, &wait);
-repeat:
-	current->state = TASK_UNINTERRUPTIBLE;
-	if (inode->u.sysv_i.i_lock) {
-		schedule();
-		goto repeat;
-	}
-	remove_wait_queue(&inode->u.sysv_i.i_wait, &wait);
-	current->state = TASK_RUNNING;
-}
-
 void sysv_put_inode(struct inode *inode)
 {
 	if (inode->i_nlink)
@@ -81,7 +66,6 @@
 	sb->sv_block_size_1 = 512-1;
 	sb->sv_block_size_bits = 9;
 	sb->sv_block_size_ratio = 2;
-	sb->sv_block_size_ratio_1 = 2-1;
 	sb->sv_block_size_ratio_bits = 1;
 	sb->sv_inodes_per_block = 512/64;
 	sb->sv_inodes_per_block_1 = 512/64-1;
@@ -94,6 +78,13 @@
 	sb->sv_ind_per_block_2_1 = (512/4)*(512/4)-1;
 	sb->sv_ind_per_block_2_bits = 2 *
 	  (sb->sv_ind_per_block_bits = 9-2);
+	sb->sv_ind_per_block_block_size_1 = (512/4)*512-1;
+	sb->sv_ind_per_block_block_size_bits = (9-2)+9;
+	sb->sv_ind_per_block_2_block_size_1 = (512/4)*(512/4)*512-1;
+	sb->sv_ind_per_block_2_block_size_bits = (9-2)+(9-2)+9;
+	sb->sv_ind0_size = 10 * 512;
+	sb->sv_ind1_size = (10 + (512/4))* 512;
+	sb->sv_ind2_size = (10 + (512/4) + (512/4)*(512/4)) * 512;
 }
 
 static void detected_bs1024 (struct super_block *sb)
@@ -102,7 +93,6 @@
 	sb->sv_block_size_1 = 1024-1;
 	sb->sv_block_size_bits = 10;
 	sb->sv_block_size_ratio = 1;
-	sb->sv_block_size_ratio_1 = 1-1;
 	sb->sv_block_size_ratio_bits = 0;
 	sb->sv_inodes_per_block = 1024/64;
 	sb->sv_inodes_per_block_1 = 1024/64-1;
@@ -115,6 +105,13 @@
 	sb->sv_ind_per_block_2_1 = (1024/4)*(1024/4)-1;
 	sb->sv_ind_per_block_2_bits = 2 *
 	  (sb->sv_ind_per_block_bits = 10-2);
+	sb->sv_ind_per_block_block_size_1 = (1024/4)*1024-1;
+	sb->sv_ind_per_block_block_size_bits = (10-2)+10;
+	sb->sv_ind_per_block_2_block_size_1 = (1024/4)*(1024/4)*1024-1;
+	sb->sv_ind_per_block_2_block_size_bits = (10-2)+(10-2)+10;
+	sb->sv_ind0_size = 10 * 1024;
+	sb->sv_ind1_size = (10 + (1024/4))* 1024;
+	sb->sv_ind2_size = (10 + (1024/4) + (1024/4)*(1024/4)) * 1024;
 }
 
 static const char* detect_xenix (struct super_block *sb, struct buffer_head *bh)
@@ -124,33 +121,54 @@
 	sbd = (struct xenix_super_block *) bh->b_data;
 	if (sbd->s_magic != 0x2b5544)
 		return NULL;
+	switch (sbd->s_type) {
+		case 1: detected_bs512(sb); break;
+		case 2: detected_bs1024(sb); break;
+		default: return NULL;
+	}
 	sb->sv_type = FSTYPE_XENIX;
+	return "Xenix";
+}
+static struct super_block * detected_xenix (struct super_block *sb, struct buffer_head *bh1, struct buffer_head *bh2)
+{
+	struct xenix_super_block * sbd1;
+	struct xenix_super_block * sbd2;
+
+	if (sb->sv_block_size == BLOCK_SIZE)
+		/* block size = 1024, so bh1 = bh2 */
+		sbd1 = sbd2 = (struct xenix_super_block *) bh1->b_data;
+	else {
+		/* block size = 512, so bh1 != bh2 */
+		sbd1 = (struct xenix_super_block *) bh1->b_data;
+		sbd2 = (struct xenix_super_block *) (bh2->b_data - BLOCK_SIZE/2);
+		/* sanity check */
+		if (sbd2->s_magic != 0x2b5544)
+			return NULL;
+	}
+
 	sb->sv_convert = 0;
 	sb->sv_kludge_symlinks = 1;
 	sb->sv_truncate = 1;
 	sb->sv_link_max = XENIX_LINK_MAX;
 	sb->sv_fic_size = XENIX_NICINOD;
 	sb->sv_flc_size = XENIX_NICFREE;
-	sb->sv_bh = bh;
-	sb->sv_sbd = (char *) sbd;
-	sb->sv_sb_fic_count = &sbd->s_ninode;
-	sb->sv_sb_fic_inodes = &sbd->s_inode[0];
-	sb->sv_sb_total_free_inodes = &sbd->s_tinode;
-	sb->sv_sb_flc_count = &sbd->s_nfree;
-	sb->sv_sb_flc_blocks = &sbd->s_free[0];
-	sb->sv_sb_total_free_blocks = &sbd->s_tfree;
-	sb->sv_sb_time = &sbd->s_time;
+	sb->sv_bh1 = bh1;
+	sb->sv_bh2 = bh2;
+	sb->sv_sbd1 = (char *) sbd1;
+	sb->sv_sbd2 = (char *) sbd2;
+	sb->sv_sb_fic_count = &sbd1->s_ninode;
+	sb->sv_sb_fic_inodes = &sbd1->s_inode[0];
+	sb->sv_sb_total_free_inodes = &sbd2->s_tinode;
+	sb->sv_sb_flc_count = &sbd1->s_nfree;
+	sb->sv_sb_flc_blocks = &sbd1->s_free[0];
+	sb->sv_sb_total_free_blocks = &sbd2->s_tfree;
+	sb->sv_sb_time = &sbd2->s_time;
 	sb->sv_block_base = 0;
 	sb->sv_firstinodezone = 2;
-	sb->sv_firstdatazone = sbd->s_isize;
-	sb->sv_nzones = sbd->s_fsize;
+	sb->sv_firstdatazone = sbd1->s_isize;
+	sb->sv_nzones = sbd1->s_fsize;
 	sb->sv_ndatazones = sb->sv_nzones - sb->sv_firstdatazone;
-	switch (sbd->s_type) {
-		case 1: detected_bs512(sb); break;
-		case 2: detected_bs1024(sb); break;
-		default: return NULL;
-	}
-	return "Xenix";
+	return sb;
 }
 
 static const char* detect_sysv4 (struct super_block *sb, struct buffer_head *bh)
@@ -162,15 +180,39 @@
 		return NULL;
 	if (sbd->s_time < 315532800) /* this is likely to happen on SystemV2 FS */
 		return NULL;
+	switch (sbd->s_type) {
+		case 1: detected_bs512(sb); break;
+		case 2: detected_bs1024(sb); break;
+		default: return NULL;
+	}
 	sb->sv_type = FSTYPE_SYSV4;
+	return "SystemV";
+}
+static struct super_block * detected_sysv4 (struct super_block *sb, struct buffer_head *bh)
+{
+	struct sysv4_super_block * sbd;
+
+	if (sb->sv_block_size == BLOCK_SIZE)
+		sbd = (struct sysv4_super_block *) (bh->b_data + BLOCK_SIZE/2);
+	else {
+		sbd = (struct sysv4_super_block *) bh->b_data;
+		/* sanity check */
+		if (sbd->s_magic != 0xfd187e20)
+			return NULL;
+		if (sbd->s_time < 315532800)
+			return NULL;
+	}
+
 	sb->sv_convert = 0;
 	sb->sv_kludge_symlinks = 0; /* ?? */
 	sb->sv_truncate = 1;
 	sb->sv_link_max = SYSV_LINK_MAX;
 	sb->sv_fic_size = SYSV_NICINOD;
 	sb->sv_flc_size = SYSV_NICFREE;
-	sb->sv_bh = bh;
-	sb->sv_sbd = (char *) sbd;
+	sb->sv_bh1 = bh;
+	sb->sv_bh2 = bh;
+	sb->sv_sbd1 = (char *) sbd;
+	sb->sv_sbd2 = (char *) sbd;
 	sb->sv_sb_fic_count = &sbd->s_ninode;
 	sb->sv_sb_fic_inodes = &sbd->s_inode[0];
 	sb->sv_sb_total_free_inodes = &sbd->s_tinode;
@@ -183,12 +225,7 @@
 	sb->sv_firstdatazone = sbd->s_isize;
 	sb->sv_nzones = sbd->s_fsize;
 	sb->sv_ndatazones = sb->sv_nzones - sb->sv_firstdatazone;
-	switch (sbd->s_type) {
-		case 1: detected_bs512(sb); break;
-		case 2: detected_bs1024(sb); break;
-		default: return NULL;
-	}
-	return "SystemV";
+	return sb;
 }
 
 static const char* detect_sysv2 (struct super_block *sb, struct buffer_head *bh)
@@ -200,15 +237,39 @@
 		return NULL;
 	if (sbd->s_time < 315532800) /* this is likely to happen on SystemV4 FS */
 		return NULL;
+	switch (sbd->s_type) {
+		case 1: detected_bs512(sb); break;
+		case 2: detected_bs1024(sb); break;
+		default: return NULL;
+	}
 	sb->sv_type = FSTYPE_SYSV2;
+	return "SystemV Release 2";
+}
+static struct super_block * detected_sysv2 (struct super_block *sb, struct buffer_head *bh)
+{
+	struct sysv2_super_block * sbd;
+
+	if (sb->sv_block_size == BLOCK_SIZE)
+		sbd = (struct sysv2_super_block *) (bh->b_data + BLOCK_SIZE/2);
+	else {
+		sbd = (struct sysv2_super_block *) bh->b_data;
+		/* sanity check */
+		if (sbd->s_magic != 0xfd187e20)
+			return NULL;
+		if (sbd->s_time < 315532800)
+			return NULL;
+	}
+
 	sb->sv_convert = 0;
 	sb->sv_kludge_symlinks = 0; /* ?? */
 	sb->sv_truncate = 1;
 	sb->sv_link_max = SYSV_LINK_MAX;
 	sb->sv_fic_size = SYSV_NICINOD;
 	sb->sv_flc_size = SYSV_NICFREE;
-	sb->sv_bh = bh;
-	sb->sv_sbd = (char *) sbd;
+	sb->sv_bh1 = bh;
+	sb->sv_bh2 = bh;
+	sb->sv_sbd1 = (char *) sbd;
+	sb->sv_sbd2 = (char *) sbd;
 	sb->sv_sb_fic_count = &sbd->s_ninode;
 	sb->sv_sb_fic_inodes = &sbd->s_inode[0];
 	sb->sv_sb_total_free_inodes = &sbd->s_tinode;
@@ -221,12 +282,7 @@
 	sb->sv_firstdatazone = sbd->s_isize;
 	sb->sv_nzones = sbd->s_fsize;
 	sb->sv_ndatazones = sb->sv_nzones - sb->sv_firstdatazone;
-	switch (sbd->s_type) {
-		case 1: detected_bs512(sb); break;
-		case 2: detected_bs1024(sb); break;
-		default: return NULL;
-	}
-	return "SystemV Release 2";
+	return sb;
 }
 
 static const char* detect_coherent (struct super_block *sb, struct buffer_head *bh)
@@ -237,15 +293,30 @@
 	if ((memcmp(sbd->s_fname,"noname",6) && memcmp(sbd->s_fname,"xxxxx ",6))
 	    || (memcmp(sbd->s_fpack,"nopack",6) && memcmp(sbd->s_fpack,"xxxxx\n",6)))
 		return NULL;
+	detected_bs512(sb);
 	sb->sv_type = FSTYPE_COH;
+	return "Coherent";
+}
+static struct super_block * detected_coherent (struct super_block *sb, struct buffer_head *bh)
+{
+	struct coh_super_block * sbd;
+
+	sbd = (struct coh_super_block *) bh->b_data;
+	/* sanity check */
+	if ((memcmp(sbd->s_fname,"noname",6) && memcmp(sbd->s_fname,"xxxxx ",6))
+	    || (memcmp(sbd->s_fpack,"nopack",6) && memcmp(sbd->s_fpack,"xxxxx\n",6)))
+		return NULL;
+
 	sb->sv_convert = 1;
 	sb->sv_kludge_symlinks = 1;
 	sb->sv_truncate = 1;
 	sb->sv_link_max = COH_LINK_MAX;
 	sb->sv_fic_size = COH_NICINOD;
 	sb->sv_flc_size = COH_NICFREE;
-	sb->sv_bh = bh;
-	sb->sv_sbd = (char *) sbd;
+	sb->sv_bh1 = bh;
+	sb->sv_bh2 = bh;
+	sb->sv_sbd1 = (char *) sbd;
+	sb->sv_sbd2 = (char *) sbd;
 	sb->sv_sb_fic_count = &sbd->s_ninode;
 	sb->sv_sb_fic_inodes = &sbd->s_inode[0];
 	sb->sv_sb_total_free_inodes = &sbd->s_tinode;
@@ -258,8 +329,7 @@
 	sb->sv_firstdatazone = sbd->s_isize;
 	sb->sv_nzones = from_coh_ulong(sbd->s_fsize);
 	sb->sv_ndatazones = sb->sv_nzones - sb->sv_firstdatazone;
-	detected_bs512(sb);
-	return "Coherent";
+	return sb;
 }
 
 struct super_block *sysv_read_super(struct super_block *sb,void *data, 
@@ -279,8 +349,7 @@
 	if (64 != sizeof (struct sysv_inode))
 		panic("sysv fs: bad i-node size");
 	lock_super(sb);
-	sb->s_blocksize = BLOCK_SIZE; /* anything else not supported by the block device drivers */
-	sb->s_blocksize_bits = BLOCK_SIZE_BITS;
+	set_blocksize(dev,BLOCK_SIZE);
 
 	/* Try to read Xenix superblock */
 	if ((bh = bread(dev, 1, BLOCK_SIZE)) != NULL) {
@@ -299,7 +368,7 @@
 			goto ok;
 		brelse(bh);
 	}
-	/* Try to recognize SystemV2 superblock */
+	/* Try to recognize SystemV superblock */
 	/* Offset by 1 track, i.e. most probably 9, 15, or 18 kilobytes. */
 	{	static int offsets[] = { 9, 15, 18, };
 		int i;
@@ -307,11 +376,11 @@
 			if ((bh = bread(dev, offsets[i], BLOCK_SIZE)) != NULL) {
 				/* Try to recognize SystemV superblock */
 				if ((found = detect_sysv4(sb,bh)) != NULL) {
-					sb->sv_block_base = offsets[i];
+					sb->sv_block_base = offsets[i] << sb->sv_block_size_ratio_bits;
 					goto ok;
 				}
 				if ((found = detect_sysv2(sb,bh)) != NULL) {
-					sb->sv_block_base = offsets[i];
+					sb->sv_block_base = offsets[i] << sb->sv_block_size_ratio_bits;
 					goto ok;
 				}
 				brelse(bh);
@@ -324,22 +393,95 @@
 	return NULL;
 
 	ok:
+	if (sb->sv_block_size == BLOCK_SIZE) {
+		switch (sb->sv_type) {
+			case FSTYPE_XENIX:
+				if (!detected_xenix(sb,bh,bh))
+					goto bad_superblock;
+				break;
+			case FSTYPE_SYSV4:
+				if (!detected_sysv4(sb,bh))
+					goto bad_superblock;
+				break;
+			case FSTYPE_SYSV2:
+				if (!detected_sysv2(sb,bh))
+					goto bad_superblock;
+				break;
+			default:
+			bad_superblock:
+				brelse(bh);
+				sb->s_dev = 0;
+				unlock_super(sb);
+				printk("SysV FS: cannot read superblock in 1024 byte mode\n");
+				return NULL;
+		}
+	} else {
+		/* Switch to another block size. Unfortunately, we have to
+		   release the 1 KB block bh and read it in two parts again. */
+		struct buffer_head *bh1, *bh2;
+		unsigned long blocknr = bh->b_blocknr << sb->sv_block_size_ratio_bits;
+
+		brelse(bh);
+		set_blocksize(dev,sb->sv_block_size);
+		bh1 = NULL; bh2 = NULL;
+		switch (sb->sv_type) {
+			case FSTYPE_XENIX:
+				if ((bh1 = bread(dev, blocknr, sb->sv_block_size)) == NULL)
+					goto bad_superblock2;
+				if ((bh2 = bread(dev, blocknr+1, sb->sv_block_size)) == NULL)
+					goto bad_superblock2;
+				if (!detected_xenix(sb,bh1,bh2))
+					goto bad_superblock2;
+				break;
+			case FSTYPE_SYSV4:
+				if ((bh2 = bread(dev, blocknr+1, sb->sv_block_size)) == NULL)
+					goto bad_superblock2;
+				if (!detected_sysv4(sb,bh2))
+					goto bad_superblock2;
+				break;
+			case FSTYPE_SYSV2:
+				if ((bh2 = bread(dev, blocknr+1, sb->sv_block_size)) == NULL)
+					goto bad_superblock2;
+				if (!detected_sysv2(sb,bh2))
+					goto bad_superblock2;
+				break;
+			case FSTYPE_COH:
+				if ((bh2 = bread(dev, blocknr+1, sb->sv_block_size)) == NULL)
+					goto bad_superblock2;
+				if (!detected_coherent(sb,bh2))
+					goto bad_superblock2;
+				break;
+			default:
+			bad_superblock2:
+				brelse(bh1);
+				brelse(bh2);
+				set_blocksize(sb->s_dev,BLOCK_SIZE);
+				sb->s_dev = 0;
+				unlock_super(sb);
+				printk("SysV FS: cannot read superblock in 512 byte mode\n");
+				return NULL;
+		}
+	}
 	sb->sv_ninodes = (sb->sv_firstdatazone - sb->sv_firstinodezone) << sb->sv_inodes_per_block_bits;
 	if (!silent)
 		printk("VFS: Found a %s FS (block size = %d) on device %d/%d\n",found,sb->sv_block_size,MAJOR(dev),MINOR(dev));
 	sb->s_magic = SYSV_MAGIC_BASE + sb->sv_type;
+	/* The buffer code now supports block size 512 as well as 1024. */
+	sb->s_blocksize = sb->sv_block_size;
+	sb->s_blocksize_bits = sb->sv_block_size_bits;
 	/* set up enough so that it can read an inode */
 	sb->s_dev = dev;
 	sb->s_op = &sysv_sops;
 	sb->s_mounted = iget(sb,SYSV_ROOT_INO);
 	unlock_super(sb);
 	if (!sb->s_mounted) {
-		brelse(bh);
-		sb->s_dev = 0;
+		sysv_put_super(sb);
 		printk("SysV FS: get root inode failed\n");
 		return NULL;
 	}
-	sb->s_dirt = 1; /* brelse(bh); occurs when the disk is unmounted. */
+	sb->s_dirt = 1;
+	/* brelse(bh);  resp.  brelse(bh1); brelse(bh2);
+	   occurs when the disk is unmounted. */
 	return sb;
 }
 
@@ -347,13 +489,14 @@
 void sysv_write_super (struct super_block *sb)
 {
 	lock_super(sb);
-	if (sb->sv_bh->b_dirt) {
+	if (sb->sv_bh1->b_dirt || sb->sv_bh2->b_dirt) {
 		/* If we are going to write out the super block,
 		   then attach current time stamp. */
 		unsigned long time = CURRENT_TIME;
 		if (sb->sv_convert)
 			time = to_coh_ulong(time);
 		*sb->sv_sb_time = time;
+		mark_buffer_dirty(sb->sv_bh2, 1);
 	}
 	sb->s_dirt = 0;
 	unlock_super(sb);
@@ -363,7 +506,11 @@
 {
 	/* we can assume sysv_write_super() has already been called */
 	lock_super(sb);
-	brelse(sb->sv_bh);
+	brelse(sb->sv_bh1);
+	if (sb->sv_bh1 != sb->sv_bh2) brelse(sb->sv_bh2);
+	/* switch back to default block size */
+	if (sb->s_blocksize != BLOCK_SIZE)
+		set_blocksize(sb->s_dev,BLOCK_SIZE);
 	sb->s_dev = 0;
 	unlock_super(sb);
 }
@@ -385,10 +532,7 @@
 }
 
 
-/* bmap support for running executables and shared libraries.
-   Used only if block_size = BLOCK_SIZE. */
-
-#define IND_PER_BLOCK	(BLOCK_SIZE / sizeof(sysv_zone_t))
+/* bmap support for running executables and shared libraries. */
 
 static inline int inode_bmap(struct super_block * sb, struct inode * inode, int nr)
 {
@@ -425,40 +569,40 @@
 		return inode_bmap(sb,inode,block);
 	block -= 10;
 	convert = sb->sv_convert;
-	if (block < IND_PER_BLOCK) {
+	if (block < sb->sv_ind_per_block) {
 		i = inode_bmap(sb,inode,10);
 		if (!i)
 			return 0;
-		bh = bread(inode->i_dev,i,BLOCK_SIZE);
-		return block_bmap(sb,bh,block,convert);
+		bh = bread(inode->i_dev,i,sb->sv_block_size);
+		return block_bmap(sb, bh, block, convert);
 	}
-	block -= IND_PER_BLOCK;
-	if (block < IND_PER_BLOCK*IND_PER_BLOCK) {
+	block -= sb->sv_ind_per_block;
+	if (block < sb->sv_ind_per_block_2) {
 		i = inode_bmap(sb,inode,11);
 		if (!i)
 			return 0;
-		bh = bread(inode->i_dev,i,BLOCK_SIZE);
-		i = block_bmap(sb,bh,block/IND_PER_BLOCK,convert);
+		bh = bread(inode->i_dev,i,sb->sv_block_size);
+		i = block_bmap(sb, bh, block >> sb->sv_ind_per_block_bits, convert);
 		if (!i)
 			return 0;
-		bh = bread(inode->i_dev,i,BLOCK_SIZE);
-		return block_bmap(sb,bh,block%IND_PER_BLOCK,convert);
+		bh = bread(inode->i_dev,i,sb->sv_block_size);
+		return block_bmap(sb, bh, block & sb->sv_ind_per_block_1, convert);
 	}
-	block -= IND_PER_BLOCK*IND_PER_BLOCK;
-	if (block < IND_PER_BLOCK*IND_PER_BLOCK*IND_PER_BLOCK) {
+	block -= sb->sv_ind_per_block_2;
+	if (block < sb->sv_ind_per_block_3) {
 		i = inode_bmap(sb,inode,12);
 		if (!i)
 			return 0;
-		bh = bread(inode->i_dev,i,BLOCK_SIZE);
-		i = block_bmap(sb,bh,block/(IND_PER_BLOCK*IND_PER_BLOCK),convert);
+		bh = bread(inode->i_dev,i,sb->sv_block_size);
+		i = block_bmap(sb, bh, block >> sb->sv_ind_per_block_2_bits, convert);
 		if (!i)
 			return 0;
-		bh = bread(inode->i_dev,i,BLOCK_SIZE);
-		i = block_bmap(sb,bh,(block/IND_PER_BLOCK)%IND_PER_BLOCK,convert);
+		bh = bread(inode->i_dev,i,sb->sv_block_size);
+		i = block_bmap(sb, bh, (block >> sb->sv_ind_per_block_bits) & sb->sv_ind_per_block_1,convert);
 		if (!i)
 			return 0;
-		bh = bread(inode->i_dev,i,BLOCK_SIZE);
-		return block_bmap(sb,bh,block%IND_PER_BLOCK,convert);
+		bh = bread(inode->i_dev,i,sb->sv_block_size);
+		return block_bmap(sb, bh, block & sb->sv_ind_per_block_1, convert);
 	}
 	if ((int)block<0) {
 		printk("sysv_bmap: block<0");
@@ -473,7 +617,7 @@
 
 /* Access selected blocks of regular files (or directories) */
 
-static struct buffer_head * inode_getblk(struct inode * inode, int nr, int create, char * *start)
+static struct buffer_head * inode_getblk(struct inode * inode, int nr, int create)
 {
 	struct super_block *sb;
 	unsigned long tmp;
@@ -485,11 +629,9 @@
 repeat:
 	tmp = *p;
 	if (tmp) {
-		result = getblk(inode->i_dev, (tmp >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE);
-		if (tmp == *p) {
-			*start = result->b_data + ((tmp & sb->sv_block_size_ratio_1) << sb->sv_block_size_bits);
+		result = sv_getblk(sb, inode->i_dev, tmp);
+		if (tmp == *p)
 			return result;
-		}
 		brelse(result);
 		goto repeat;
 	}
@@ -498,7 +640,7 @@
 	tmp = sysv_new_block(sb);
 	if (!tmp)
 		return NULL;
-	result = getblk(inode->i_dev, (tmp >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE);
+	result = sv_getblk(sb, inode->i_dev, tmp);
 	if (*p) {
 		sysv_free_block(sb,tmp);
 		brelse(result);
@@ -507,12 +649,11 @@
 	*p = tmp;
 	inode->i_ctime = CURRENT_TIME;
 	inode->i_dirt = 1;
-	*start = result->b_data + ((tmp & sb->sv_block_size_ratio_1) << sb->sv_block_size_bits);
 	return result;
 }
 
 static struct buffer_head * block_getblk(struct inode * inode, 
-	struct buffer_head * bh, int nr, int create, char * *start)
+	struct buffer_head * bh, int nr, int create)
 {
 	struct super_block *sb;
 	unsigned long tmp, block;
@@ -530,16 +671,15 @@
 		}
 	}
 	sb = inode->i_sb;
-	p = nr + (sysv_zone_t *) *start;
+	p = nr + (sysv_zone_t *) bh->b_data;
 repeat:
 	block = tmp = *p;
 	if (sb->sv_convert)
 		block = from_coh_ulong(block);
 	if (tmp) {
-		result = getblk(bh->b_dev, (block >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE);
+		result = sv_getblk(sb, bh->b_dev, block);
 		if (tmp == *p) {
 			brelse(bh);
-			*start = result->b_data + ((block & sb->sv_block_size_ratio_1) << sb->sv_block_size_bits);
 			return result;
 		}
 		brelse(result);
@@ -554,7 +694,7 @@
 		brelse(bh);
 		return NULL;
 	}
-	result = getblk(bh->b_dev, (block >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE);
+	result = sv_getblk(sb, bh->b_dev, block);
 	if (*p) {
 		sysv_free_block(sb,block);
 		brelse(result);
@@ -563,35 +703,33 @@
 	*p = (sb->sv_convert ? to_coh_ulong(block) : block);
 	mark_buffer_dirty(bh, 1);
 	brelse(bh);
-	*start = result->b_data + ((block & sb->sv_block_size_ratio_1) << sb->sv_block_size_bits);
 	return result;
 }
 
-struct buffer_head * sysv_getblk(struct inode * inode, unsigned int block,
-	int create, char * *start)
+struct buffer_head * sysv_getblk(struct inode * inode, unsigned int block, int create)
 {
 	struct super_block * sb = inode->i_sb;
 	struct buffer_head * bh;
 
 	if (block < 10)
-		return inode_getblk(inode,block,create,start);
+		return inode_getblk(inode,block,create);
 	block -= 10;
 	if (block < sb->sv_ind_per_block) {
-		bh = inode_getblk(inode,10,create,start);
-		return block_getblk(inode, bh, block, create, start);
+		bh = inode_getblk(inode,10,create);
+		return block_getblk(inode, bh, block, create);
 	}
 	block -= sb->sv_ind_per_block;
 	if (block < sb->sv_ind_per_block_2) {
-		bh = inode_getblk(inode,11,create,start);
-		bh = block_getblk(inode, bh, block >> sb->sv_ind_per_block_bits, create, start);
-		return block_getblk(inode, bh, block & sb->sv_ind_per_block_1, create, start);
+		bh = inode_getblk(inode,11,create);
+		bh = block_getblk(inode, bh, block >> sb->sv_ind_per_block_bits, create);
+		return block_getblk(inode, bh, block & sb->sv_ind_per_block_1, create);
 	}
 	block -= sb->sv_ind_per_block_2;
 	if (block < sb->sv_ind_per_block_3) {
-		bh = inode_getblk(inode,12,create,start);
-		bh = block_getblk(inode, bh, block >> sb->sv_ind_per_block_2_bits, create, start);
-		bh = block_getblk(inode, bh, (block >> sb->sv_ind_per_block_bits) & sb->sv_ind_per_block_1, create, start);
-		return block_getblk(inode, bh, block & sb->sv_ind_per_block_1, create, start);
+		bh = inode_getblk(inode,12,create);
+		bh = block_getblk(inode, bh, block >> sb->sv_ind_per_block_2_bits, create);
+		bh = block_getblk(inode, bh, (block >> sb->sv_ind_per_block_bits) & sb->sv_ind_per_block_1, create);
+		return block_getblk(inode, bh, block & sb->sv_ind_per_block_1, create);
 	}
 	if ((int)block<0) {
 		printk("sysv_getblk: block<0");
@@ -601,11 +739,11 @@
 	return NULL;
 }
 
-struct buffer_head * sysv_file_bread(struct inode * inode, int block, int create, char * *start)
+struct buffer_head * sysv_file_bread(struct inode * inode, int block, int create)
 {
 	struct buffer_head * bh;
 
-	bh = sysv_getblk(inode,block,create,start);
+	bh = sysv_getblk(inode,block,create);
 	if (!bh || bh->b_uptodate)
 		return bh;
 	ll_rw_block(READ, 1, &bh);
@@ -645,7 +783,6 @@
 {
 	struct super_block * sb = inode->i_sb;
 	struct buffer_head * bh;
-	char * bh_data;
 	struct sysv_inode * raw_inode;
 	unsigned int block, ino;
 	umode_t mode;
@@ -659,12 +796,12 @@
 		return;
 	}
 	block = sb->sv_firstinodezone + ((ino-1) >> sb->sv_inodes_per_block_bits);
-	if (!(bh=sysv_bread(sb,inode->i_dev,block,&bh_data))) {
+	if (!(bh = sv_bread(sb,inode->i_dev,block))) {
 		printk("Major problem: unable to read inode from dev 0x%04x\n",
 			inode->i_dev);
 		return;
 	}
-	raw_inode = (struct sysv_inode *) bh_data + ((ino-1) & sb->sv_inodes_per_block_1);
+	raw_inode = (struct sysv_inode *) bh->b_data + ((ino-1) & sb->sv_inodes_per_block_1);
 	mode = raw_inode->i_mode;
 	if (sb->sv_kludge_symlinks)
 		mode = from_coh_imode(mode);
@@ -698,10 +835,7 @@
 				read3byte(&raw_inode->i_a.i_addb[3*block]);
 	brelse(bh);
 	if (S_ISREG(inode->i_mode))
-		if (sb->sv_block_size_ratio_bits == 0) /* block_size == BLOCK_SIZE ? */
-			inode->i_op = &sysv_file_inode_operations_with_bmap;
-		else
-			inode->i_op = &sysv_file_inode_operations;
+		inode->i_op = &sysv_file_inode_operations;
 	else if (S_ISDIR(inode->i_mode))
 		inode->i_op = &sysv_dir_inode_operations;
 	else if (S_ISLNK(inode->i_mode))
@@ -736,7 +870,6 @@
 {
 	struct super_block * sb = inode->i_sb;
 	struct buffer_head * bh;
-	char * bh_data;
 	struct sysv_inode * raw_inode;
 	unsigned int ino, block;
 	umode_t mode;
@@ -749,12 +882,12 @@
 		return 0;
 	}
 	block = sb->sv_firstinodezone + ((ino-1) >> sb->sv_inodes_per_block_bits);
-	if (!(bh = sysv_bread(sb,inode->i_dev,block,&bh_data))) {
+	if (!(bh = sv_bread(sb,inode->i_dev,block))) {
 		printk("unable to read i-node block\n");
 		inode->i_dirt = 0;
 		return 0;
 	}
-	raw_inode = (struct sysv_inode *) bh_data + ((ino-1) & sb->sv_inodes_per_block_1);
+	raw_inode = (struct sysv_inode *) bh->b_data + ((ino-1) & sb->sv_inodes_per_block_1);
 	mode = inode->i_mode;
 	if (sb->sv_kludge_symlinks)
 		mode = to_coh_imode(mode);
diff -u --recursive --new-file v1.1.61/linux/fs/sysv/namei.c linux/fs/sysv/namei.c
--- v1.1.61/linux/fs/sysv/namei.c	Sat Oct 22 16:49:27 1994
+++ linux/fs/sysv/namei.c	Sat Nov  5 13:32:13 1994
@@ -63,7 +63,6 @@
 	struct super_block * sb;
 	unsigned long pos, block, offset; /* pos = block * block_size + offset */
 	struct buffer_head * bh;
-	char * bh_data;
 
 	*res_dir = NULL;
 	if (!dir)
@@ -78,7 +77,7 @@
 	pos = block = offset = 0;
 	while (pos < dir->i_size) {
 		if (!bh) {
-			bh = sysv_file_bread(dir,block,0,&bh_data);
+			bh = sysv_file_bread(dir,block,0);
 			if (!bh) {
 				/* offset = 0; */ block++;
 				pos += sb->sv_block_size;
@@ -86,7 +85,7 @@
 			}
 		}
 		if (sysv_match(namelen, name,
-			       *res_dir = (struct sysv_dir_entry *) (bh_data + offset) ))
+			       *res_dir = (struct sysv_dir_entry *) (bh->b_data + offset) ))
 			return bh;
 		pos += SYSV_DIRSIZE;
 		offset += SYSV_DIRSIZE;
@@ -148,7 +147,6 @@
 	int i;
 	unsigned long pos, block, offset; /* pos = block * block_size + offset */
 	struct buffer_head * bh;
-	char * bh_data;
 	struct sysv_dir_entry * de;
 
 	*res_buf = NULL;
@@ -167,11 +165,11 @@
 	pos = block = offset = 0;
 	while (1) {
 		if (!bh) {
-			bh = sysv_file_bread(dir,block,1,&bh_data);
+			bh = sysv_file_bread(dir,block,1);
 			if (!bh)
 				return -ENOSPC;
 		}
-		de = (struct sysv_dir_entry *) (bh_data + offset);
+		de = (struct sysv_dir_entry *) (bh->b_data + offset);
 		pos += SYSV_DIRSIZE;
 		offset += SYSV_DIRSIZE;
 		if (pos > dir->i_size) {
@@ -218,10 +216,7 @@
 		iput(dir);
 		return -ENOSPC;
 	}
-	if (inode->i_sb->sv_block_size_ratio_bits == 0) /* block_size == BLOCK_SIZE ? */
-		inode->i_op = &sysv_file_inode_operations_with_bmap;
-	else
-		inode->i_op = &sysv_file_inode_operations;
+	inode->i_op = &sysv_file_inode_operations;
 	inode->i_mode = mode;
 	inode->i_dirt = 1;
 	error = sysv_add_entry(dir,name,len, &bh ,&de);
@@ -264,10 +259,7 @@
 	inode->i_mode = mode;
 	inode->i_op = NULL;
 	if (S_ISREG(inode->i_mode))
-		if (inode->i_sb->sv_block_size_ratio_bits == 0) /* block_size == BLOCK_SIZE ? */
-			inode->i_op = &sysv_file_inode_operations_with_bmap;
-		else
-			inode->i_op = &sysv_file_inode_operations;
+		inode->i_op = &sysv_file_inode_operations;
 	else if (S_ISDIR(inode->i_mode)) {
 		inode->i_op = &sysv_dir_inode_operations;
 		if (dir->i_mode & S_ISGID)
@@ -305,7 +297,6 @@
 	int error;
 	struct inode * inode;
 	struct buffer_head * bh, *dir_block;
-	char * bh_data;
 	struct sysv_dir_entry * de;
 
 	if (!dir) {
@@ -329,7 +320,7 @@
 	}
 	inode->i_op = &sysv_dir_inode_operations;
 	inode->i_size = 2 * SYSV_DIRSIZE;
-	dir_block = sysv_file_bread(inode,0,1,&bh_data);
+	dir_block = sysv_file_bread(inode,0,1);
 	if (!dir_block) {
 		iput(dir);
 		inode->i_nlink--;
@@ -337,10 +328,10 @@
 		iput(inode);
 		return -ENOSPC;
 	}
-	de = (struct sysv_dir_entry *) (bh_data + 0*SYSV_DIRSIZE);
+	de = (struct sysv_dir_entry *) (dir_block->b_data + 0*SYSV_DIRSIZE);
 	de->inode = inode->i_ino;
 	strcpy(de->name,"."); /* rest of de->name is zero, see sysv_new_block */
-	de = (struct sysv_dir_entry *) (bh_data + 1*SYSV_DIRSIZE);
+	de = (struct sysv_dir_entry *) (dir_block->b_data + 1*SYSV_DIRSIZE);
 	de->inode = dir->i_ino;
 	strcpy(de->name,".."); /* rest of de->name is zero, see sysv_new_block */
 	inode->i_nlink = 2;
@@ -375,7 +366,6 @@
 	struct super_block * sb;
 	unsigned long pos, block, offset; /* pos = block * block_size + offset */
 	struct buffer_head * bh;
-	char * bh_data;
 	struct sysv_dir_entry * de;
 
 	if (!inode)
@@ -387,26 +377,26 @@
 		goto bad_dir;
 	if (inode->i_size < pos)
 		goto bad_dir;
-	bh = sysv_file_bread(inode,0,0,&bh_data);
+	bh = sysv_file_bread(inode,0,0);
 	if (!bh)
 		goto bad_dir;
-	de = (struct sysv_dir_entry *) (bh_data + 0*SYSV_DIRSIZE);
+	de = (struct sysv_dir_entry *) (bh->b_data + 0*SYSV_DIRSIZE);
 	if (!de->inode || strcmp(de->name,"."))
 		goto bad_dir;
-	de = (struct sysv_dir_entry *) (bh_data + 1*SYSV_DIRSIZE);
+	de = (struct sysv_dir_entry *) (bh->b_data + 1*SYSV_DIRSIZE);
 	if (!de->inode || strcmp(de->name,".."))
 		goto bad_dir;
 	sb = inode->i_sb;
 	while (pos < inode->i_size) {
 		if (!bh) {
-			bh = sysv_file_bread(inode,block,0,&bh_data);
+			bh = sysv_file_bread(inode,block,0);
 			if (!bh) {
 				/* offset = 0; */ block++;
 				pos += sb->sv_block_size;
 				continue;
 			}
 		}
-		de = (struct sysv_dir_entry *) (bh_data + offset);
+		de = (struct sysv_dir_entry *) (bh->b_data + offset);
 		pos += SYSV_DIRSIZE;
 		offset += SYSV_DIRSIZE;
 		if (de->inode) {
@@ -553,7 +543,7 @@
 	}
 	inode->i_mode = S_IFLNK | 0777;
 	inode->i_op = &sysv_symlink_inode_operations;
-	name_block = sysv_file_bread(inode,0,1,&name_block_data);
+	name_block = sysv_file_bread(inode,0,1);
 	if (!name_block) {
 		iput(dir);
 		inode->i_nlink--;
@@ -562,6 +552,7 @@
 		return -ENOSPC;
 	}
 	sb = inode->i_sb;
+	name_block_data = name_block->b_data;
 	i = 0;
 	while (i < sb->sv_block_size_1 && (c = *(symname++)))
 		name_block_data[i++] = c;
@@ -678,7 +669,6 @@
 {
 	struct inode * old_inode, * new_inode;
 	struct buffer_head * old_bh, * new_bh, * dir_bh;
-	char * dir_bh_data;
 	struct sysv_dir_entry * old_de, * new_de;
 	int retval;
 
@@ -745,10 +735,10 @@
 		if (subdir(new_dir, old_inode))
 			goto end_rename;
 		retval = -EIO;
-		dir_bh = sysv_file_bread(old_inode,0,0,&dir_bh_data);
+		dir_bh = sysv_file_bread(old_inode,0,0);
 		if (!dir_bh)
 			goto end_rename;
-		if (PARENT_INO(dir_bh_data) != old_dir->i_ino)
+		if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
 			goto end_rename;
 		retval = -EMLINK;
 		if (!new_inode && new_dir->i_nlink >= new_dir->i_sb->sv_link_max)
@@ -781,7 +771,7 @@
 	mark_buffer_dirty(old_bh, 1);
 	mark_buffer_dirty(new_bh, 1);
 	if (dir_bh) {
-		PARENT_INO(dir_bh_data) = new_dir->i_ino;
+		PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
 		mark_buffer_dirty(dir_bh, 1);
 		old_dir->i_nlink--;
 		old_dir->i_dirt = 1;
diff -u --recursive --new-file v1.1.61/linux/fs/sysv/symlink.c linux/fs/sysv/symlink.c
--- v1.1.61/linux/fs/sysv/symlink.c	Mon May  2 18:34:30 1994
+++ linux/fs/sysv/symlink.c	Sat Nov  5 13:32:13 1994
@@ -49,7 +49,6 @@
 {
 	int error;
 	struct buffer_head * bh;
-	char * bh_data;
 
 	*res_inode = NULL;
 	if (!dir) {
@@ -70,14 +69,14 @@
 		iput(dir);
 		return -ELOOP;
 	}
-	if (!(bh = sysv_file_bread(inode, 0, 0, &bh_data))) { /* is reading 1 block enough ?? */
+	if (!(bh = sysv_file_bread(inode, 0, 0))) { /* is reading 1 block enough ?? */
 		iput(inode);
 		iput(dir);
 		return -EIO;
 	}
 	iput(inode);
 	current->link_count++;
-	error = open_namei(bh_data,flag,mode,res_inode,dir);
+	error = open_namei(bh->b_data,flag,mode,res_inode,dir);
 	current->link_count--;
 	brelse(bh);
 	return error;
@@ -96,10 +95,11 @@
 	}
 	if (buflen > inode->i_sb->sv_block_size_1)
 		buflen = inode->i_sb->sv_block_size_1;
-	bh = sysv_file_bread(inode, 0, 0, &bh_data);
+	bh = sysv_file_bread(inode, 0, 0);
 	iput(inode);
 	if (!bh)
 		return 0;
+	bh_data = bh->b_data;
 	i = 0;
 	while (i<buflen && (c = bh_data[i])) {
 		i++;
diff -u --recursive --new-file v1.1.61/linux/fs/sysv/truncate.c linux/fs/sysv/truncate.c
--- v1.1.61/linux/fs/sysv/truncate.c	Wed Aug 10 19:26:28 1994
+++ linux/fs/sysv/truncate.c	Sat Nov  5 13:32:13 1994
@@ -17,226 +17,11 @@
 #include <linux/stat.h>
 
 
-/* There are two different implementations of truncate() here.
- * One (by Bruno) needs to do locking to ensure that no one is writing
- * to a block being truncated away and incorporated into the free list.
- * The better one (by Linus) doesn't need locking because it can tell from
- * looking at bh->b_count whether a given block is in use elsewhere.
- * Alas, this doesn't work if block_size < BLOCK_SIZE.
+/* Linus' implementation of truncate.
+ * It doesn't need locking because it can tell from looking at bh->b_count
+ * whether a given block is in use elsewhere.
  */
 
-
-/* Bruno's implementation of truncate. */
-
-/* Leave at most `blocks' direct blocks. */
-static int coh_trunc_direct (struct inode * inode, unsigned long blocks)
-{
-	unsigned int i;
-	unsigned long * p;
-	unsigned long block;
-
-	for (i = blocks; i < 10 ; i++) {
-		p = &inode->u.sysv_i.i_data[i];
-		block = *p;
-		if (!block)
-			continue;
-		*p = 0;
-		inode->i_dirt = 1;
-		sysv_free_block(inode->i_sb,block);
-	}
-	return 0;
-}
-
-/* Leave at most `blocks' blocks out of an indirect block whose number is
- * from_coh_ulong(*p) if convert=1, *p if convert=0.
- */
-static int coh_trunc_indirect (struct inode * inode, unsigned long blocks, unsigned long * p, int convert, unsigned char * dirt)
-{
-	struct super_block * sb = inode->i_sb;
-	unsigned long tmp, block, indblock;
-	struct buffer_head * bh;
-	char * bh_data;
-	unsigned long i;
-	sysv_zone_t * ind;
-
-	if (blocks >= sb->sv_ind_per_block)
-		return 0;
-	block = tmp = *p;
-	if (convert)
-		block = from_coh_ulong(block);
-	if (!block)
-		return 0;
-	bh = sysv_bread(sb,inode->i_dev,block,&bh_data);
-	if (tmp != *p) {
-		brelse(bh);
-		return 1;
-	}
-	if (!bh) {
-		*p = 0;
-		*dirt = 1;
-		return 0;
-	}
-	for (i = blocks; i < sb->sv_ind_per_block; i++) {
-		ind = &((sysv_zone_t *) bh_data)[i];
-		indblock = *ind;
-		if (sb->sv_convert)
-			indblock = from_coh_ulong(indblock);
-		if (!indblock)
-			continue;
-		*ind = 0;
-		mark_buffer_dirty(bh, 1);
-		sysv_free_block(sb,indblock);
-	}
-	for (i = 0; i < sb->sv_ind_per_block; i++)
-		if (((sysv_zone_t *) bh_data)[i])
-			goto done;
-	if (tmp != *p) {
-		brelse(bh);
-		return 1;
-	}
-	*p = 0;
-	*dirt = 1;
-	sysv_free_block(sb,block);
-done:
-	brelse(bh);
-	return 0;
-}
-
-/* Leave at most `blocks' blocks out of an double indirect block whose number is
- * from_coh_ulong(*p) if convert=1, *p if convert=0.
- */
-static int coh_trunc_dindirect (struct inode * inode, unsigned long blocks, unsigned long * p, int convert, unsigned char * dirt)
-{
-	struct super_block * sb = inode->i_sb;
-	unsigned long tmp, block, dindblock;
-	struct buffer_head * bh;
-	char * bh_data;
-	unsigned long i, j;
-	sysv_zone_t * dind;
-	int retry = 0;
-
-	if (blocks >= sb->sv_ind_per_block_2)
-		return 0;
-	block = tmp = *p;
-	if (convert)
-		block = from_coh_ulong(block);
-	if (!block)
-		return 0;
-	bh = sysv_bread(sb,inode->i_dev,block,&bh_data);
-	if (tmp != *p) {
-		brelse(bh);
-		return 1;
-	}
-	if (!bh) {
-		*p = 0;
-		*dirt = 1;
-		return 0;
-	}
-	for (i = blocks >> sb->sv_ind_per_block_bits, j = blocks & sb->sv_ind_per_block_1;
-	     i < sb->sv_ind_per_block;
-	     i++, j = 0) {
-		/* j = max(blocks-i*ind_per_block,0) */
-		dind = &((sysv_zone_t *) bh_data)[i];
-		dindblock = *dind;
-		if (sb->sv_convert)
-			dindblock = from_coh_ulong(dindblock);
-		if (!dindblock)
-			continue;
-		retry |= coh_trunc_indirect(inode,j,dind,sb->sv_convert,&bh->b_dirt);
-	}
-	for (i = 0; i < sb->sv_ind_per_block; i++)
-		if (((sysv_zone_t *) bh_data)[i])
-			goto done;
-	if (tmp != *p) {
-		brelse(bh);
-		return 1;
-	}
-	*p = 0;
-	*dirt = 1;
-	sysv_free_block(sb,block);
-done:
-	brelse(bh);
-	return retry;
-}
-
-/* Leave at most `blocks' blocks out of an triple indirect block whose number is
- * from_coh_ulong(*p) if convert=1, *p if convert=0.
- */
-static int coh_trunc_tindirect (struct inode * inode, unsigned long blocks, unsigned long * p)
-{
-	struct super_block * sb = inode->i_sb;
-	unsigned long block, tindblock;
-	struct buffer_head * bh;
-	char * bh_data;
-	unsigned long i, j;
-	sysv_zone_t * tind;
-	int retry = 0;
-
-	if (blocks >= sb->sv_ind_per_block_3)
-		return 0;
-	block = *p;
-	if (!block)
-		return 0;
-	bh = sysv_bread(sb,inode->i_dev,block,&bh_data);
-	if (block != *p) {
-		brelse(bh);
-		return 1;
-	}
-	if (!bh) {
-		*p = 0;
-		inode->i_dirt = 1;
-		return 0;
-	}
-	for (i = blocks >> sb->sv_ind_per_block_2_bits, j = blocks & sb->sv_ind_per_block_2_1;
-	     i < sb->sv_ind_per_block;
-	     i++, j = 0) {
-		/* j = max(blocks-i*ind_per_block^2,0) */
-		tind = &((sysv_zone_t *) bh_data)[i];
-		tindblock = *tind;
-		if (sb->sv_convert)
-			tindblock = from_coh_ulong(tindblock);
-		if (!tindblock)
-			continue;
-		retry |= coh_trunc_dindirect(inode,j,tind,sb->sv_convert,&bh->b_dirt);
-	}
-	for (i = 0; i < sb->sv_ind_per_block; i++)
-		if (((sysv_zone_t *) bh_data)[i])
-			goto done;
-	if (block != *p) {
-		brelse(bh);
-		return 1;
-	}
-	*p = 0;
-	inode->i_dirt = 1;
-	sysv_free_block(sb,block);
-done:
-	brelse(bh);
-	return retry;
-}
-
-static int coh_trunc_all(struct inode * inode)
-{
-	struct super_block * sb = inode->i_sb;
-	long blocks;
-	int retry;
-
-	blocks = (inode->i_size + sb->sv_block_size_1) >> sb->sv_block_size_bits;
-	retry = coh_trunc_direct(inode,blocks);
-	blocks -= 10;
-	if (blocks < 0) blocks = 0;
-	retry |= coh_trunc_indirect(inode,blocks,&inode->u.sysv_i.i_data[10],0,&inode->i_dirt);
-	blocks -= sb->sv_ind_per_block;
-	if (blocks < 0) blocks = 0;
-	retry |= coh_trunc_dindirect(inode,blocks,&inode->u.sysv_i.i_data[11],0,&inode->i_dirt);
-	blocks -= sb->sv_ind_per_block_2;
-	if (blocks < 0) blocks = 0;
-	retry |= coh_trunc_tindirect(inode,blocks,&inode->u.sysv_i.i_data[12]);
-	return retry;
-}
-
-
-/* Linus' implementation of truncate. Used only if block_size = BLOCK_SIZE. */
-
 /*
  * Truncate has the most races in the whole filesystem: coding it is
  * a pain in the a**. Especially as I don't do any locking...
@@ -263,13 +48,13 @@
 
 	sb = inode->i_sb;
 repeat:
-	for (i = ((unsigned long) inode->i_size + BLOCK_SIZE-1) / BLOCK_SIZE; i < 10; i++) {
+	for (i = ((unsigned long) inode->i_size + sb->sv_block_size_1) >> sb->sv_block_size_bits; i < 10; i++) {
 		p = inode->u.sysv_i.i_data + i;
 		block = *p;
 		if (!block)
 			continue;
-		bh = get_hash_table(inode->i_dev,block+sb->sv_block_base,BLOCK_SIZE);
-		if (i*BLOCK_SIZE < inode->i_size) {
+		bh = sv_get_hash_table(sb, inode->i_dev, block);
+		if ((i << sb->sv_block_size_bits) < inode->i_size) {
 			brelse(bh);
 			goto repeat;
 		}
@@ -286,8 +71,6 @@
 	return retry;
 }
 
-#define IND_PER_BLOCK   (BLOCK_SIZE / sizeof(sysv_zone_t))
-
 static int trunc_indirect(struct inode * inode, unsigned long offset, unsigned long * p, int convert, unsigned char * dirt)
 {
 	unsigned long indtmp, indblock;
@@ -305,7 +88,7 @@
 	if (!indblock)
 		return 0;
 	sb = inode->i_sb;
-	indbh = bread(inode->i_dev,indblock+sb->sv_block_base,BLOCK_SIZE);
+	indbh = sv_bread(sb, inode->i_dev, indblock);
 	if (indtmp != *p) {
 		brelse(indbh);
 		return 1;
@@ -319,16 +102,16 @@
 	if (inode->i_size < offset)
 		i = 0;
 	else
-		i = (inode->i_size - offset + BLOCK_SIZE-1) / BLOCK_SIZE;
-	for (; i < IND_PER_BLOCK; i++) {
+		i = (inode->i_size - offset + sb->sv_block_size_1) >> sb->sv_block_size_bits;
+	for (; i < sb->sv_ind_per_block; i++) {
 		ind = ((sysv_zone_t *) indbh->b_data) + i;
 		block = tmp = *ind;
 		if (sb->sv_convert)
 			block = from_coh_ulong(block);
 		if (!block)
 			continue;
-		bh = get_hash_table(inode->i_dev,block+sb->sv_block_base,BLOCK_SIZE);
-		if (i*BLOCK_SIZE + offset < inode->i_size) {
+		bh = sv_get_hash_table(sb, inode->i_dev, block);
+		if ((i << sb->sv_block_size_bits) + offset < inode->i_size) {
 			brelse(bh);
 			goto repeat;
 		}
@@ -342,7 +125,7 @@
 		brelse(bh);
 		sysv_free_block(sb,block);
 	}
-	for (i = 0; i < IND_PER_BLOCK; i++)
+	for (i = 0; i < sb->sv_ind_per_block; i++)
 		if (((sysv_zone_t *) indbh->b_data)[i])
 			goto done;
 	if ((indbh->b_count != 1) || (indtmp != *p)) {
@@ -373,7 +156,7 @@
 	if (!indblock)
 		return 0;
 	sb = inode->i_sb;
-	indbh = bread(inode->i_dev,indblock+sb->sv_block_base,BLOCK_SIZE);
+	indbh = sv_bread(sb, inode->i_dev, indblock);
 	if (indtmp != *p) {
 		brelse(indbh);
 		return 1;
@@ -386,17 +169,17 @@
 	if (inode->i_size < offset)
 		i = 0;
 	else
-		i = (inode->i_size - offset + IND_PER_BLOCK*BLOCK_SIZE-1) / (IND_PER_BLOCK*BLOCK_SIZE);
-	for (; i < IND_PER_BLOCK; i++) {
+		i = (inode->i_size - offset + sb->sv_ind_per_block_block_size_1) >> sb->sv_ind_per_block_block_size_bits;
+	for (; i < sb->sv_ind_per_block; i++) {
 		ind = ((sysv_zone_t *) indbh->b_data) + i;
 		block = tmp = *ind;
 		if (sb->sv_convert)
 			block = from_coh_ulong(block);
 		if (!block)
 			continue;
-		retry |= trunc_indirect(inode,offset+i*IND_PER_BLOCK,ind,sb->sv_convert,&indbh->b_dirt);
+		retry |= trunc_indirect(inode,offset+(i<<sb->sv_ind_per_block_bits),ind,sb->sv_convert,&indbh->b_dirt);
 	}
-	for (i = 0; i < IND_PER_BLOCK; i++)
+	for (i = 0; i < sb->sv_ind_per_block; i++)
 		if (((sysv_zone_t *) indbh->b_data)[i])
 			goto done;
 	if ((indbh->b_count != 1) || (indtmp != *p)) {
@@ -427,7 +210,7 @@
 	if (!indblock)
 		return 0;
 	sb = inode->i_sb;
-	indbh = bread(inode->i_dev,indblock+sb->sv_block_base,BLOCK_SIZE);
+	indbh = sv_bread(sb, inode->i_dev, indblock);
 	if (indtmp != *p) {
 		brelse(indbh);
 		return 1;
@@ -440,17 +223,17 @@
 	if (inode->i_size < offset)
 		i = 0;
 	else
-		i = (inode->i_size - offset + IND_PER_BLOCK*IND_PER_BLOCK*BLOCK_SIZE-1) / (IND_PER_BLOCK*IND_PER_BLOCK*BLOCK_SIZE);
-	for (; i < IND_PER_BLOCK; i++) {
+		i = (inode->i_size - offset + sb->sv_ind_per_block_2_block_size_1) >> sb->sv_ind_per_block_2_block_size_bits;
+	for (; i < sb->sv_ind_per_block; i++) {
 		ind = ((sysv_zone_t *) indbh->b_data) + i;
 		block = tmp = *ind;
 		if (sb->sv_convert)
 			block = from_coh_ulong(block);
 		if (!block)
 			continue;
-		retry |= trunc_dindirect(inode,offset+i*IND_PER_BLOCK*IND_PER_BLOCK,ind,sb->sv_convert,&indbh->b_dirt);
+		retry |= trunc_dindirect(inode,offset+(i<<sb->sv_ind_per_block_2_bits),ind,sb->sv_convert,&indbh->b_dirt);
 	}
-	for (i = 0; i < IND_PER_BLOCK; i++)
+	for (i = 0; i < sb->sv_ind_per_block; i++)
 		if (((sysv_zone_t *) indbh->b_data)[i])
 			goto done;
 	if ((indbh->b_count != 1) || (indtmp != *p)) {
@@ -467,10 +250,13 @@
 
 static int trunc_all(struct inode * inode)
 {
+	struct super_block * sb;
+
+	sb = inode->i_sb;
 	return trunc_direct(inode)
-	     | trunc_indirect(inode,10*BLOCK_SIZE,&inode->u.sysv_i.i_data[10],0,&inode->i_dirt)
-	     | trunc_dindirect(inode,(10+IND_PER_BLOCK)*BLOCK_SIZE,&inode->u.sysv_i.i_data[11],0,&inode->i_dirt)
-	     | trunc_tindirect(inode,(10+IND_PER_BLOCK+IND_PER_BLOCK*IND_PER_BLOCK)*BLOCK_SIZE,&inode->u.sysv_i.i_data[12],0,&inode->i_dirt);
+	     | trunc_indirect(inode,sb->sv_ind0_size,&inode->u.sysv_i.i_data[10],0,&inode->i_dirt)
+	     | trunc_dindirect(inode,sb->sv_ind1_size,&inode->u.sysv_i.i_data[11],0,&inode->i_dirt)
+	     | trunc_tindirect(inode,sb->sv_ind2_size,&inode->u.sysv_i.i_data[12],0,&inode->i_dirt);
 }
 
 
@@ -488,21 +274,10 @@
 		printk("sysv_truncate: truncating symbolic link\n");
 	else if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)))
 		return;
-	if (inode->i_sb->sv_block_size_ratio_bits > 0) { /* block_size < BLOCK_SIZE ? */
-		coh_lock_inode(inode); /* do not write to the inode while we truncate */
-		while (coh_trunc_all(inode)) {
-			current->counter = 0;
-			schedule();
-		}
-		inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-		inode->i_dirt = 1;
-		coh_unlock_inode(inode);
-	} else {
-		while (trunc_all(inode)) {
-			current->counter = 0;
-			schedule();
-		}
-		inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-		inode->i_dirt = 1;
+	while (trunc_all(inode)) {
+		current->counter = 0;
+		schedule();
 	}
+	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	inode->i_dirt = 1;
 }
diff -u --recursive --new-file v1.1.61/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h
--- v1.1.61/linux/include/linux/ext2_fs.h	Wed Oct 26 09:42:22 1994
+++ linux/include/linux/ext2_fs.h	Fri Nov  4 12:38:45 1994
@@ -349,7 +349,9 @@
 	unsigned long  s_checkinterval;	/* max. time between checks */
 	unsigned long  s_creator_os;	/* OS */
 	unsigned long  s_rev_level;	/* Revision level */
-	unsigned long  s_reserved[236];	/* Padding to the end of the block */
+	unsigned short s_def_resuid;	/* Default uid for reserved blocks */
+	unsigned short s_def_resgid;	/* Default gid for reserved blocks */
+	unsigned long  s_reserved[235];	/* Padding to the end of the block */
 };
 
 #define EXT2_OS_LINUX		0
@@ -357,6 +359,9 @@
 #define EXT2_OS_MASIX		2
 
 #define EXT2_CURRENT_REV	0
+
+#define	EXT2_DEF_RESUID		0
+#define	EXT2_DEF_RESGID		0
 
 /*
  * Structure of a directory entry
diff -u --recursive --new-file v1.1.61/linux/include/linux/ext2_fs_sb.h linux/include/linux/ext2_fs_sb.h
--- v1.1.61/linux/include/linux/ext2_fs_sb.h	Mon Aug 15 15:53:50 1994
+++ linux/include/linux/ext2_fs_sb.h	Fri Nov  4 12:38:45 1994
@@ -49,6 +49,8 @@
 	int s_rename_lock;
 	struct wait_queue * s_rename_wait;
 	unsigned long  s_mount_opt;
+	unsigned short s_resuid;
+	unsigned short s_resgid;
 	unsigned short s_mount_state;
 };
 
diff -u --recursive --new-file v1.1.61/linux/include/linux/fs.h linux/include/linux/fs.h
--- v1.1.61/linux/include/linux/fs.h	Sun Oct 23 19:02:13 1994
+++ linux/include/linux/fs.h	Sun Nov  6 13:43:54 1994
@@ -226,6 +226,7 @@
 	struct inode * i_mount;
 	struct socket * i_socket;
 	unsigned short i_count;
+	unsigned short i_wcount;
 	unsigned short i_flags;
 	unsigned char i_lock;
 	unsigned char i_dirt;
@@ -464,6 +465,8 @@
 extern int namei(const char * pathname, struct inode ** res_inode);
 extern int lnamei(const char * pathname, struct inode ** res_inode);
 extern int permission(struct inode * inode,int mask);
+extern int get_write_access(struct inode * inode);
+extern void put_write_access(struct inode * inode);
 extern int open_namei(const char * pathname, int flag, int mode,
 	struct inode ** res_inode, struct inode * base);
 extern int do_mknod(const char * filename, int mode, dev_t dev);
diff -u --recursive --new-file v1.1.61/linux/include/linux/interrupt.h linux/include/linux/interrupt.h
--- v1.1.61/linux/include/linux/interrupt.h	Mon May 23 08:17:43 1994
+++ linux/include/linux/interrupt.h	Sun Nov  6 13:43:38 1994
@@ -20,6 +20,7 @@
 	TQUEUE_BH,
 	SERIAL_BH,
 	NET_BH,
+	IMMEDIATE_BH,
 	KEYBOARD_BH
 };
 
diff -u --recursive --new-file v1.1.61/linux/include/linux/mm.h linux/include/linux/mm.h
--- v1.1.61/linux/include/linux/mm.h	Wed Nov  2 12:03:47 1994
+++ linux/include/linux/mm.h	Sat Nov  5 14:50:03 1994
@@ -196,6 +196,7 @@
 extern void merge_segments(struct vm_area_struct *);
 extern void insert_vm_struct(struct task_struct *, struct vm_area_struct *);
 extern int do_munmap(unsigned long, size_t);
+extern unsigned long get_unmapped_area(unsigned long);
 
 #define read_swap_page(nr,buf) \
 	rw_swap_page(READ,(nr),(buf))
@@ -232,7 +233,7 @@
 #define GFP_USER	0x02
 #define GFP_KERNEL	0x03
 #define GFP_NOBUFFER	0x04
-
+#define GFP_NFS		0x05
 
 /*
  * vm_ops not present page codes for shared memory.
diff -u --recursive --new-file v1.1.61/linux/include/linux/mtio.h linux/include/linux/mtio.h
--- v1.1.61/linux/include/linux/mtio.h	Sat Jul 23 12:58:37 1994
+++ linux/include/linux/mtio.h	Thu Nov  3 16:44:04 1994
@@ -50,7 +50,9 @@
 #define MTTELL	23	/* tell block (Tandberg, etc.) */
 #define MTSETDRVBUFFER 24 /* set the drive buffering according to SCSI-2 */
 			/* ordinary buffered operation with code 1 */
-
+#define MTFSS	25	/* space forward over setmarks */
+#define MTBSS	26	/* space backward over setmarks */
+#define MTWSM	27	/* write setmarks */
 
 /* structure for MTIOCGET - mag tape get status command */
 
diff -u --recursive --new-file v1.1.61/linux/include/linux/sched.h linux/include/linux/sched.h
--- v1.1.61/linux/include/linux/sched.h	Thu Nov  3 17:53:30 1994
+++ linux/include/linux/sched.h	Sat Nov  5 14:50:03 1994
@@ -288,8 +288,7 @@
 /* file system info */
 	int link_count;
 	struct tty_struct *tty; /* NULL if no tty */
-/* shm stuff */
-	struct shm_desc *shm;
+/* ipc stuff */
 	struct sem_undo *semundo;
 /* ldt for this task - used by Wine.  If NULL, default_ldt is used */
 	struct desc_struct *ldt;
@@ -343,7 +342,7 @@
 /* comm */	"swapper", \
 /* vm86_info */	NULL, 0, 0, 0, 0, \
 /* fs info */	0,NULL, \
-/* ipc */	NULL, NULL, \
+/* ipc */	NULL, \
 /* ldt */	NULL, \
 /* tss */	INIT_TSS, \
 /* fs */	{ INIT_FS }, \
diff -u --recursive --new-file v1.1.61/linux/include/linux/shm.h linux/include/linux/shm.h
--- v1.1.61/linux/include/linux/shm.h	Thu Nov  3 17:53:30 1994
+++ linux/include/linux/shm.h	Sat Nov  5 14:50:03 1994
@@ -14,9 +14,13 @@
 	/* the following are private */
 	unsigned short   shm_npages;	/* size of segment (pages) */
 	unsigned long   *shm_pages;	/* array of ptrs to frames -> SHMMAX */ 
-	struct shm_desc *attaches;	/* descriptors for attaches */
+	struct vm_area_struct *attaches; /* descriptors for attaches */
 };
 
+/* permission flag for shmget */
+#define SHM_R		0400	/* or S_IRUGO from <linux/stat.h> */
+#define SHM_W		0200	/* or S_IWUGO from <linux/stat.h> */
+
 /* mode for attach */
 #define	SHM_RDONLY	010000	/* read-only access */
 #define	SHM_RND		020000	/* round attach address to SHMLBA boundary */
@@ -35,7 +39,7 @@
 };
 
 /* address range for shared memory attaches if no address passed to shmat() */
-#define SHM_RANGE_START	0x40000000
+#define SHM_RANGE_START	0x50000000
 #define SHM_RANGE_END	0x60000000
 
 /* format of page table entries that correspond to shared memory pages
@@ -87,20 +91,6 @@
 	ulong shm_swp; /* total swapped shm */
 	ulong swap_attempts;
 	ulong swap_successes;
-};
-
-
-/*
- * Per process internal structure for managing segments.
- * A shmat will add to and shmdt will remove from the list.
- */
-struct	shm_desc {
-	struct task_struct *task;     /* attacher */
-	unsigned long shm_sgn;        /* signature for this attach */
-	unsigned long start;   /* virt addr of attach, multiple of SHMLBA */
-	unsigned long end;            /* multiple of SHMLBA */
-	struct shm_desc *task_next;   /* next attach for task */
-	struct shm_desc *seg_next;    /* next attach for segment */
 };
 
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v1.1.61/linux/include/linux/sysv_fs.h linux/include/linux/sysv_fs.h
--- v1.1.61/linux/include/linux/sysv_fs.h	Sun Oct 23 19:41:19 1994
+++ linux/include/linux/sysv_fs.h	Sat Nov  5 13:32:13 1994
@@ -335,54 +335,25 @@
 #define SYSV2_SUPER_MAGIC	(SYSV_MAGIC_BASE+FSTYPE_SYSV2)
 #define COH_SUPER_MAGIC		(SYSV_MAGIC_BASE+FSTYPE_COH)
 
-/* Because the block size may be smaller than 1024 (which is the unit used by
-   the disk drivers and the buffer code), many functions must return a pointer
-   to the buffer data additionally to the buffer head pointer.
-*/
-#if 0
-struct bh_data {
-	struct buffer_head * bh;
-	char * bh_data;
-};
-#endif
-
-/* sysv_bread(sb,dev,block,...) would be equivalent to
-   bread(dev,block,BLOCK_SIZE)
-   if the block size were always 1024, which is the only one bread() supports.
-*/
+/* sv_get_hash_table(sb,dev,block) is equivalent to  get_hash_table(dev,block,block_size)  */
 static inline struct buffer_head *
-sysv_bread (struct super_block *sb, int dev, unsigned int block, char* * data)
+sv_get_hash_table (struct super_block *sb, int dev, unsigned int block)
 {
-	struct buffer_head *bh;
-
-	if (!(bh = bread (dev, (block >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE)))
-		return NULL;
-	*data = bh->b_data + ((block & sb->sv_block_size_ratio_1) << sb->sv_block_size_bits);
-	return bh;
+	return get_hash_table (dev, block + sb->sv_block_base, sb->sv_block_size);
 }
 
-
-/* locks - protect against simultaneous write and truncate */
-
-extern void _coh_wait_on_inode (struct inode * inode);
-
-extern inline void coh_wait_on_inode (struct inode * inode)
-{
-	if (inode->u.sysv_i.i_lock)
-		_coh_wait_on_inode(inode);
-}
-
-extern inline void coh_lock_inode (struct inode * inode)
+/* sv_getblk(sb,dev,block) is equivalent to  getblk(dev,block,block_size)  */
+static inline struct buffer_head *
+sv_getblk (struct super_block *sb, int dev, unsigned int block)
 {
-	if (inode->u.sysv_i.i_lock)
-		_coh_wait_on_inode(inode);
-	inode->u.sysv_i.i_lock = 1;
+	return getblk (dev, block + sb->sv_block_base, sb->sv_block_size);
 }
 
-extern inline void coh_unlock_inode (struct inode * inode)
+/* sv_bread(sb,dev,block) is equivalent to  bread(dev,block,block_size)  */
+static inline struct buffer_head *
+sv_bread (struct super_block *sb, int dev, unsigned int block)
 {
-	inode->u.sysv_i.i_lock = 0;
-	wake_up(&inode->u.sysv_i.i_wait);
+	return bread (dev, block + sb->sv_block_base, sb->sv_block_size);
 }
 
 
@@ -412,8 +383,8 @@
 
 extern int sysv_bmap(struct inode *,int);
 
-extern struct buffer_head * sysv_getblk(struct inode *, unsigned int, int, char* *);
-extern struct buffer_head * sysv_file_bread(struct inode *, int, int, char* *);
+extern struct buffer_head * sysv_getblk(struct inode *, unsigned int, int);
+extern struct buffer_head * sysv_file_bread(struct inode *, int, int);
 extern int sysv_file_read(struct inode *, struct file *, char *, int);
 
 extern void sysv_truncate(struct inode *);
diff -u --recursive --new-file v1.1.61/linux/include/linux/sysv_fs_i.h linux/include/linux/sysv_fs_i.h
--- v1.1.61/linux/include/linux/sysv_fs_i.h	Wed Jul 21 22:41:16 1993
+++ linux/include/linux/sysv_fs_i.h	Sat Nov  5 13:32:13 1994
@@ -10,10 +10,6 @@
 					 * then 1 double indirection block,
 					 * then 1 triple indirection block.
 					 */
-	/* the following are only used if  block_size < BLOCK_SIZE  */
-	int i_lock;			/* lock to protect against simultaneous	*/
-	struct wait_queue * i_wait;	/* write and truncate			*/
-					/*					*/
 };
 
 #endif
diff -u --recursive --new-file v1.1.61/linux/include/linux/sysv_fs_sb.h linux/include/linux/sysv_fs_sb.h
--- v1.1.61/linux/include/linux/sysv_fs_sb.h	Wed Jul 21 02:29:00 1993
+++ linux/include/linux/sysv_fs_sb.h	Sat Nov  5 13:32:13 1994
@@ -16,7 +16,6 @@
 	unsigned int   s_block_size_1;	/* block_size - 1 */
 	unsigned int   s_block_size_bits;	/* log2(block_size) */
 	unsigned int   s_block_size_ratio;	/* BLOCK_SIZE / block_size */
-	unsigned int   s_block_size_ratio_1;	/* block_size_ratio - 1 */
 	unsigned int   s_block_size_ratio_bits;	/* log2(block_size_ratio) */
 	char	       s_convert;	/* flag whether byte ordering requires conversion */
 	char	       s_kludge_symlinks; /* flag whether symlinks have a kludgey mode */
@@ -33,15 +32,24 @@
 	unsigned int   s_ind_per_block_2_1;	/* ind_per_block ^ 2 - 1 */
 	unsigned int   s_ind_per_block_2_bits;	/* log2(ind_per_block^2) */
 	unsigned int   s_ind_per_block_3;	/* ind_per_block ^ 3 */
+	unsigned int   s_ind_per_block_block_size_1;	/* ind_per_block*block_size - 1 */
+	unsigned int   s_ind_per_block_block_size_bits;	/* log2(ind_per_block*block_size) */
+	unsigned int   s_ind_per_block_2_block_size_1;	/* ind_per_block^2 * block_size - 1 */
+	unsigned int   s_ind_per_block_2_block_size_bits; /* log2(ind_per_block^2 * block_size) */
+	unsigned int   s_ind0_size;		/* 10 * block_size */
+	unsigned int   s_ind1_size;		/* (10 + ipb) * block_size */
+	unsigned int   s_ind2_size;		/* (10 + ipb + ipb^2) * block_size */
 	unsigned int   s_toobig_block;		/* 10 + ipb + ipb^2 + ipb^3 */
 	unsigned int   s_block_base;	/* physical block number of block 0 */
 	unsigned short s_fic_size;	/* free inode cache size, NICINOD */
 	unsigned short s_flc_size;	/* free block list chunk size, NICFREE */
-	/* The superblock is kept in a disk buffer: */
-	struct buffer_head *s_bh;
+	/* The superblock is kept in one or two disk buffers: */
+	struct buffer_head *s_bh1;
+	struct buffer_head *s_bh2;
 	/* These are pointers into the disk buffer, to compensate for
 	   different superblock layout. */
-	char *         s_sbd;		/* entire superblock data */
+	char *         s_sbd1;		/* entire superblock data, for part 1 */
+	char *         s_sbd2;		/* entire superblock data, for part 2 */
 	unsigned short *s_sb_fic_count;	/* pointer to s_sbd->s_ninode */
         unsigned short *s_sb_fic_inodes; /* pointer to s_sbd->s_inode */
 	unsigned short *s_sb_total_free_inodes; /* pointer to s_sbd->s_tinode */
@@ -57,48 +65,56 @@
 	unsigned long  s_ndatazones;	/* total number of data zones */
 	unsigned long  s_nzones;	/* same as s_sbd->s_fsize */
 };
-/* The fields s_block_size_ratio, s_toobig_block, s_sbd are currently unused. */
+/* The fields s_block_size_ratio, s_ind_per_block_2_1, s_toobig_block are currently unused. */
 
 /* sv_ == u.sysv_sb.s_ */
-#define sv_type				u.sysv_sb.s_type
-#define sv_block_size			u.sysv_sb.s_block_size
-#define sv_block_size_1			u.sysv_sb.s_block_size_1
-#define sv_block_size_bits		u.sysv_sb.s_block_size_bits
-#define sv_block_size_ratio		u.sysv_sb.s_block_size_ratio
-#define sv_block_size_ratio_1		u.sysv_sb.s_block_size_ratio_1
-#define sv_block_size_ratio_bits	u.sysv_sb.s_block_size_ratio_bits
-#define sv_convert			u.sysv_sb.s_convert
-#define sv_kludge_symlinks		u.sysv_sb.s_kludge_symlinks
-#define sv_truncate			u.sysv_sb.s_truncate
-#define sv_link_max			u.sysv_sb.s_link_max
-#define sv_inodes_per_block		u.sysv_sb.s_inodes_per_block
-#define sv_inodes_per_block_1		u.sysv_sb.s_inodes_per_block_1
-#define sv_inodes_per_block_bits	u.sysv_sb.s_inodes_per_block_bits
-#define sv_ind_per_block		u.sysv_sb.s_ind_per_block
-#define sv_ind_per_block_1		u.sysv_sb.s_ind_per_block_1
-#define sv_ind_per_block_bits		u.sysv_sb.s_ind_per_block_bits
-#define sv_ind_per_block_2		u.sysv_sb.s_ind_per_block_2
-#define sv_ind_per_block_2_1		u.sysv_sb.s_ind_per_block_2_1
-#define sv_ind_per_block_2_bits		u.sysv_sb.s_ind_per_block_2_bits
-#define sv_ind_per_block_3		u.sysv_sb.s_ind_per_block_3
-#define sv_toobig_block			u.sysv_sb.s_toobig_block
-#define sv_block_base			u.sysv_sb.s_block_base
-#define sv_fic_size			u.sysv_sb.s_fic_size
-#define sv_flc_size			u.sysv_sb.s_flc_size
-#define sv_bh				u.sysv_sb.s_bh
-#define sv_sbd				u.sysv_sb.s_sbd
-#define sv_sb_fic_count			u.sysv_sb.s_sb_fic_count
-#define sv_sb_fic_inodes		u.sysv_sb.s_sb_fic_inodes
-#define sv_sb_total_free_inodes		u.sysv_sb.s_sb_total_free_inodes
-#define sv_sb_flc_count			u.sysv_sb.s_sb_flc_count
-#define sv_sb_flc_blocks		u.sysv_sb.s_sb_flc_blocks
-#define sv_sb_total_free_blocks		u.sysv_sb.s_sb_total_free_blocks
-#define sv_sb_time			u.sysv_sb.s_sb_time
-#define sv_firstinodezone		u.sysv_sb.s_firstinodezone
-#define sv_firstdatazone		u.sysv_sb.s_firstdatazone
-#define sv_ninodes			u.sysv_sb.s_ninodes
-#define sv_ndatazones			u.sysv_sb.s_ndatazones
-#define sv_nzones			u.sysv_sb.s_nzones
+#define sv_type					u.sysv_sb.s_type
+#define sv_block_size				u.sysv_sb.s_block_size
+#define sv_block_size_1				u.sysv_sb.s_block_size_1
+#define sv_block_size_bits			u.sysv_sb.s_block_size_bits
+#define sv_block_size_ratio			u.sysv_sb.s_block_size_ratio
+#define sv_block_size_ratio_bits		u.sysv_sb.s_block_size_ratio_bits
+#define sv_convert				u.sysv_sb.s_convert
+#define sv_kludge_symlinks			u.sysv_sb.s_kludge_symlinks
+#define sv_truncate				u.sysv_sb.s_truncate
+#define sv_link_max				u.sysv_sb.s_link_max
+#define sv_inodes_per_block			u.sysv_sb.s_inodes_per_block
+#define sv_inodes_per_block_1			u.sysv_sb.s_inodes_per_block_1
+#define sv_inodes_per_block_bits		u.sysv_sb.s_inodes_per_block_bits
+#define sv_ind_per_block			u.sysv_sb.s_ind_per_block
+#define sv_ind_per_block_1			u.sysv_sb.s_ind_per_block_1
+#define sv_ind_per_block_bits			u.sysv_sb.s_ind_per_block_bits
+#define sv_ind_per_block_2			u.sysv_sb.s_ind_per_block_2
+#define sv_ind_per_block_2_1			u.sysv_sb.s_ind_per_block_2_1
+#define sv_ind_per_block_2_bits			u.sysv_sb.s_ind_per_block_2_bits
+#define sv_ind_per_block_3			u.sysv_sb.s_ind_per_block_3
+#define sv_ind_per_block_block_size_1		u.sysv_sb.s_ind_per_block_block_size_1
+#define sv_ind_per_block_block_size_bits	u.sysv_sb.s_ind_per_block_block_size_bits
+#define sv_ind_per_block_2_block_size_1		u.sysv_sb.s_ind_per_block_2_block_size_1
+#define sv_ind_per_block_2_block_size_bits	u.sysv_sb.s_ind_per_block_2_block_size_bits
+#define sv_ind0_size				u.sysv_sb.s_ind0_size
+#define sv_ind1_size				u.sysv_sb.s_ind1_size
+#define sv_ind2_size				u.sysv_sb.s_ind2_size
+#define sv_toobig_block				u.sysv_sb.s_toobig_block
+#define sv_block_base				u.sysv_sb.s_block_base
+#define sv_fic_size				u.sysv_sb.s_fic_size
+#define sv_flc_size				u.sysv_sb.s_flc_size
+#define sv_bh1					u.sysv_sb.s_bh1
+#define sv_bh2					u.sysv_sb.s_bh2
+#define sv_sbd1					u.sysv_sb.s_sbd1
+#define sv_sbd2					u.sysv_sb.s_sbd2
+#define sv_sb_fic_count				u.sysv_sb.s_sb_fic_count
+#define sv_sb_fic_inodes			u.sysv_sb.s_sb_fic_inodes
+#define sv_sb_total_free_inodes			u.sysv_sb.s_sb_total_free_inodes
+#define sv_sb_flc_count				u.sysv_sb.s_sb_flc_count
+#define sv_sb_flc_blocks			u.sysv_sb.s_sb_flc_blocks
+#define sv_sb_total_free_blocks			u.sysv_sb.s_sb_total_free_blocks
+#define sv_sb_time				u.sysv_sb.s_sb_time
+#define sv_firstinodezone			u.sysv_sb.s_firstinodezone
+#define sv_firstdatazone			u.sysv_sb.s_firstdatazone
+#define sv_ninodes				u.sysv_sb.s_ninodes
+#define sv_ndatazones				u.sysv_sb.s_ndatazones
+#define sv_nzones				u.sysv_sb.s_nzones
 
 #endif
 
diff -u --recursive --new-file v1.1.61/linux/include/linux/tqueue.h linux/include/linux/tqueue.h
--- v1.1.61/linux/include/linux/tqueue.h	Fri Aug 19 10:33:57 1994
+++ linux/include/linux/tqueue.h	Sun Nov  6 13:43:46 1994
@@ -57,7 +57,7 @@
 #define DECLARE_TASK_QUEUE(q)  task_queue q = &tq_last
 
 extern struct tq_struct tq_last;
-extern task_queue tq_timer;
+extern task_queue tq_timer, tq_immediate;
 
 #ifdef INCLUDE_INLINE_FUNCS
 struct tq_struct tq_last = {
diff -u --recursive --new-file v1.1.61/linux/ipc/shm.c linux/ipc/shm.c
--- v1.1.61/linux/ipc/shm.c	Thu Nov  3 17:53:30 1994
+++ linux/ipc/shm.c	Sat Nov  5 14:50:04 1994
@@ -2,11 +2,13 @@
  * linux/ipc/shm.c
  * Copyright (C) 1992, 1993 Krishna Balasubramanian
  *         Many improvements/fixes by Bruno Haible.
+ * Replaced `struct shm_desc' by `struct vm_area_struct', July 1994.
  */
 
 #include <linux/errno.h>
 #include <asm/segment.h>
 #include <linux/sched.h>
+#include <linux/mm.h>
 #include <linux/ipc.h>
 #include <linux/shm.h>
 #include <linux/stat.h>
@@ -16,8 +18,10 @@
 extern unsigned int get_swap_page (void);
 static int findkey (key_t key);
 static int newseg (key_t key, int shmflg, int size);
-static int shm_map (struct shm_desc *shmd, int remap);
+static int shm_map (struct vm_area_struct *shmd, int remap);
 static void killseg (int id);
+static void shm_open (struct vm_area_struct *shmd);
+static void shm_close (struct vm_area_struct *shmd);
 static unsigned long shm_swap_in (struct vm_area_struct *, unsigned long);
 
 static int shm_tot = 0; /* total number of shared memory pages */
@@ -340,99 +344,95 @@
 }
 
 /*
+ * The per process internal structure for managing segments is
+ * `struct vm_area_struct'.
+ * A shmat will add to and shmdt will remove from the list.
+ * shmd->vm_task	the attacher
+ * shmd->vm_start	virt addr of attach, multiple of SHMLBA
+ * shmd->vm_end		multiple of SHMLBA
+ * shmd->vm_next	next attach for task
+ * shmd->vm_share	next attach for segment
+ * shmd->vm_offset	offset into segment
+ * shmd->vm_pte		signature for this attach
+ */
+
+static struct vm_operations_struct shm_vm_ops = {
+	shm_open,		/* open */
+	shm_close,		/* close */
+	NULL,			/* nopage (done with swapin) */
+	NULL,			/* wppage */
+	NULL,			/* share */
+	NULL,			/* unmap */
+	NULL,			/* swapout (hardcoded right now) */
+	shm_swap_in		/* swapin */
+};
+
+/*
  * check range is unmapped, ensure page tables exist
  * mark page table entries with shm_sgn.
  * if remap != 0 the range is remapped.
  */
-static int shm_map (struct shm_desc *shmd, int remap)
+static int shm_map (struct vm_area_struct *shmd, int remap)
 {
-	unsigned long invalid = 0;
 	unsigned long *page_table;
 	unsigned long tmp, shm_sgn;
-	unsigned long page_dir = shmd->task->tss.cr3;
+	unsigned long page_dir = shmd->vm_task->tss.cr3;
 
-	/* check that the range is unmapped and has page_tables */
-	for (tmp = shmd->start; tmp < shmd->end; tmp += PAGE_SIZE) {
+	/* check that the range is unmapped */
+	if (!remap)
+		for (tmp = shmd->vm_start; tmp < shmd->vm_end; tmp += PAGE_SIZE) {
+			page_table = PAGE_DIR_OFFSET(page_dir,tmp);
+			if (*page_table & PAGE_PRESENT) {
+				page_table = (ulong *) (PAGE_MASK & *page_table);
+				page_table += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1));
+				if (*page_table) {
+					/* printk("shmat() -> EINVAL because address 0x%lx is already mapped.\n",tmp); */
+					return -EINVAL;
+				}
+			}
+		}
+
+	/* clear old mappings */
+	do_munmap(shmd->vm_start, shmd->vm_end - shmd->vm_start);
+
+	/* add new mapping */
+	insert_vm_struct(current, shmd);
+	merge_segments(current->mm->mmap);
+
+	/* check that the range has page_tables */
+	for (tmp = shmd->vm_start; tmp < shmd->vm_end; tmp += PAGE_SIZE) {
 		page_table = PAGE_DIR_OFFSET(page_dir,tmp);
 		if (*page_table & PAGE_PRESENT) {
 			page_table = (ulong *) (PAGE_MASK & *page_table);
 			page_table += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1));
 			if (*page_table) {
-				if (!remap)
-					return -EINVAL;
 				if (*page_table & PAGE_PRESENT) {
 					--current->mm->rss;
 					free_page (*page_table & PAGE_MASK);
 				}
 				else
 					swap_free (*page_table);
-				invalid++;
+				*page_table = 0;
 			}
-			continue;
+		} else {
+			unsigned long new_pt;
+			if (!(new_pt = get_free_page(GFP_KERNEL)))
+				return -ENOMEM;
+			*page_table = new_pt | PAGE_TABLE;
+			tmp |= ((PAGE_SIZE << 10) - PAGE_SIZE);
 		}
-	      {
-		unsigned long new_pt;
-		if (!(new_pt = get_free_page(GFP_KERNEL)))
-			return -ENOMEM;
-		*page_table = new_pt | PAGE_TABLE;
-		tmp |= ((PAGE_SIZE << 10) - PAGE_SIZE);
-	}}
-	if (invalid)
-		invalidate();
+	}
 
 	/* map page range */
-	shm_sgn = shmd->shm_sgn;
-	for (tmp = shmd->start; tmp < shmd->end; tmp += PAGE_SIZE,
+	shm_sgn = shmd->vm_pte + ((shmd->vm_offset >> PAGE_SHIFT) << SHM_IDX_SHIFT);
+	for (tmp = shmd->vm_start; tmp < shmd->vm_end; tmp += PAGE_SIZE,
 	     shm_sgn += (1 << SHM_IDX_SHIFT)) {
 		page_table = PAGE_DIR_OFFSET(page_dir,tmp);
 		page_table = (ulong *) (PAGE_MASK & *page_table);
 		page_table += (tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
 		*page_table = shm_sgn;
 	}
-	return 0;
-}
-
-static struct vm_operations_struct shm_vm_ops = {
-	NULL,			/* open */
-	NULL,			/* close */
-	NULL,			/* nopage (done with swapin) */
-	NULL,			/* wppage */
-	NULL,			/* share */
-	NULL,			/* unmap */
-	NULL,			/* swapout (hardcoded right now) */
-	shm_swap_in		/* swapin */
-};
-
-/*
- * This is really minimal support to make the shared mem stuff
- * be known by the general VM manager. It should add the vm_ops
- * field so that 'munmap()' and friends work correctly on shared
- * memory areas..
- */
-static int add_vm_area(unsigned long addr, unsigned long len, int readonly)
-{
-	struct vm_area_struct * vma;
-
-	vma = (struct vm_area_struct * ) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
-	if (!vma)
-		return -ENOMEM;
-	do_munmap(addr, len);
-	vma->vm_task = current;
-	vma->vm_start = addr;
-	vma->vm_end = addr + len;
-	vma->vm_flags = VM_SHM | VM_SHARED | VM_MAYREAD | VM_MAYEXEC | VM_READ | VM_EXEC;
-	if (readonly)
-		vma->vm_page_prot = PAGE_READONLY;
-	else {
-		vma->vm_flags |= VM_MAYWRITE | VM_WRITE;
-		vma->vm_page_prot = PAGE_SHARED;
-	}
-	vma->vm_share = NULL;
-	vma->vm_inode = NULL;
-	vma->vm_offset = 0;
-	vma->vm_ops = &shm_vm_ops;
-	insert_vm_struct(current, vma);
-	merge_segments(current->mm->mmap);
+	invalidate();
 	return 0;
 }
 
@@ -443,13 +443,15 @@
 int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
 {
 	struct shmid_ds *shp;
-	struct shm_desc *shmd;
+	struct vm_area_struct *shmd;
 	int err;
 	unsigned int id;
 	unsigned long addr;
 
-	if (shmid < 0)
+	if (shmid < 0) {
+		/* printk("shmat() -> EINVAL because shmid = %d < 0\n",shmid); */
 		return -EINVAL;
+	}
 
 	if (raddr) {
 		err = verify_area(VERIFY_WRITE, raddr, sizeof(ulong));
@@ -458,63 +460,62 @@
 	}
 
 	shp = shm_segs[id = (unsigned int) shmid % SHMMNI];
-	if (shp == IPC_UNUSED || shp == IPC_NOID)
+	if (shp == IPC_UNUSED || shp == IPC_NOID) {
+		/* printk("shmat() -> EINVAL because shmid = %d is invalid\n",shmid); */
 		return -EINVAL;
+	}
 
 	if (!(addr = (ulong) shmaddr)) {
 		if (shmflg & SHM_REMAP)
 			return -EINVAL;
-		/* set addr below  all current unspecified attaches */
-		addr = SHM_RANGE_END;
-		for (shmd = current->shm; shmd; shmd = shmd->task_next) {
-			if (shmd->start < SHM_RANGE_START)
-				continue;
-			if (addr >= shmd->start)
-				addr = shmd->start;
-		}
-		addr = (addr - shp->shm_segsz) & PAGE_MASK;
+		if (!(addr = get_unmapped_area(shp->shm_segsz)))
+			return -ENOMEM;
 	} else if (addr & (SHMLBA-1)) {
 		if (shmflg & SHM_RND)
 			addr &= ~(SHMLBA-1);       /* round down */
 		else
 			return -EINVAL;
 	}
-	if ((addr > current->mm->start_stack - 16384 - PAGE_SIZE*shp->shm_npages))
+	if ((addr > current->mm->start_stack - 16384 - PAGE_SIZE*shp->shm_npages)) {
+		/* printk("shmat() -> EINVAL because segment intersects stack\n"); */
 		return -EINVAL;
-	if (shmflg & SHM_REMAP)
-		for (shmd = current->shm; shmd; shmd = shmd->task_next) {
-			if (addr >= shmd->start && addr < shmd->end)
-				return -EINVAL;
-			if (addr + shp->shm_segsz >= shmd->start &&
-			    addr + shp->shm_segsz < shmd->end)
+	}
+	if (!(shmflg & SHM_REMAP))
+		for (shmd = current->mm->mmap; shmd; shmd = shmd->vm_next)
+			if (!(addr >= shmd->vm_end || addr + shp->shm_segsz <= shmd->vm_start)) {
+				/* printk("shmat() -> EINVAL because the interval [0x%lx,0x%lx) intersects an already mapped interval [0x%lx,0x%lx).\n",
+					addr, addr + shp->shm_segsz, shmd->vm_start, shmd->vm_end); */
 				return -EINVAL;
-		}
+			}
 
 	if (ipcperms(&shp->shm_perm, shmflg & SHM_RDONLY ? S_IRUGO : S_IRUGO|S_IWUGO))
 		return -EACCES;
 	if (shp->shm_perm.seq != (unsigned int) shmid / SHMMNI)
 		return -EIDRM;
 
-	shmd = (struct shm_desc *) kmalloc (sizeof(*shmd), GFP_KERNEL);
+	shmd = (struct vm_area_struct *) kmalloc (sizeof(*shmd), GFP_KERNEL);
 	if (!shmd)
 		return -ENOMEM;
 	if ((shp != shm_segs[id]) || (shp->shm_perm.seq != (unsigned int) shmid / SHMMNI)) {
 		kfree(shmd);
 		return -EIDRM;
 	}
-	shmd->shm_sgn = (SHM_SWP_TYPE << 1) | (id << SHM_ID_SHIFT) |
-		(shmflg & SHM_RDONLY ? SHM_READ_ONLY : 0);
-	shmd->start = addr;
-	shmd->end = addr + shp->shm_npages * PAGE_SIZE;
-	shmd->task = current;
 
-	if ((err = add_vm_area(shmd->start, shmd->end - shmd->start, shmflg & SHM_RDONLY))) {
-		kfree(shmd);
-		return err;
-	}
+	shmd->vm_pte = (SHM_SWP_TYPE << 1) | (id << SHM_ID_SHIFT) |
+		(shmflg & SHM_RDONLY ? SHM_READ_ONLY : 0);
+	shmd->vm_start = addr;
+	shmd->vm_end = addr + shp->shm_npages * PAGE_SIZE;
+	shmd->vm_task = current;
+	shmd->vm_page_prot = (shmflg & SHM_RDONLY) ? PAGE_READONLY : PAGE_SHARED;
+	shmd->vm_flags = VM_SHM | VM_MAYSHARE | VM_SHARED
+			 | VM_MAYREAD | VM_MAYEXEC | VM_READ | VM_EXEC
+			 | ((shmflg & SHM_RDONLY) ? 0 : VM_MAYWRITE | VM_WRITE);
+	shmd->vm_share = NULL;
+	shmd->vm_inode = NULL;
+	shmd->vm_offset = 0;
+	shmd->vm_ops = &shm_vm_ops;
 
 	shp->shm_nattch++;            /* prevent destruction */
-
 	if ((err = shm_map (shmd, shmflg & SHM_REMAP))) {
 		if (--shp->shm_nattch <= 0 && shp->shm_perm.mode & SHM_DEST)
 			killseg(id);
@@ -522,120 +523,87 @@
 		return err;
 	}
 
-	shmd->task_next = current->shm;
-	current->shm = shmd;
-	shmd->seg_next = shp->attaches;
+	shmd->vm_share = shp->attaches;
 	shp->attaches = shmd;
 	shp->shm_lpid = current->pid;
 	shp->shm_atime = CURRENT_TIME;
+
 	if (!raddr)
 		return addr;
 	put_fs_long (addr, raddr);
 	return 0;
 }
 
+/* This is called by fork, once for every shm attach. */
+static void shm_open (struct vm_area_struct *shmd)
+{
+	unsigned int id;
+	struct shmid_ds *shp;
+
+	id = (shmd->vm_pte >> SHM_ID_SHIFT) & SHM_ID_MASK;
+	shp = shm_segs[id];
+	if (shp == IPC_UNUSED) {
+		printk("shm_open: unused id=%d PANIC\n", id);
+		return;
+	}
+	shmd->vm_share = shp->attaches;
+	shp->attaches = shmd;
+	shp->shm_nattch++;
+	shp->shm_atime = CURRENT_TIME;
+	shp->shm_lpid = current->pid;
+}
+
 /*
- * remove the first attach descriptor from the list *shmdp.
+ * remove the attach descriptor shmd.
  * free memory for segment if it is marked destroyed.
- * The descriptor is detached before the sleep in unmap_page_range.
+ * The descriptor has already been removed from the current->mm->mmap list
+ * and will later be kfree()d.
  */
-static void detach (struct shm_desc **shmdp)
+static void shm_close (struct vm_area_struct *shmd)
 {
-	struct shm_desc *shmd = *shmdp;
+	struct vm_area_struct **shmdp;
 	struct shmid_ds *shp;
 	int id;
 
-	id = (shmd->shm_sgn >> SHM_ID_SHIFT) & SHM_ID_MASK;
+	unmap_page_range (shmd->vm_start, shmd->vm_end - shmd->vm_start);
+
+	/* remove from the list of attaches of the shm segment */
+	id = (shmd->vm_pte >> SHM_ID_SHIFT) & SHM_ID_MASK;
 	shp = shm_segs[id];
-	*shmdp = shmd->task_next;
-	for (shmdp = &shp->attaches; *shmdp; shmdp = &(*shmdp)->seg_next)
+	for (shmdp = &shp->attaches; *shmdp; shmdp = &(*shmdp)->vm_share)
 		if (*shmdp == shmd) {
-			*shmdp = shmd->seg_next;
+			*shmdp = shmd->vm_share;
 			goto found;
 		}
-	printk("detach: shm segment (id=%d) attach list inconsistent\n",id);
+	printk("shm_close: shm segment (id=%d) attach list inconsistent\n",id);
+	printk("shm_close: %d %08lx-%08lx %c%c%c%c %08lx %08lx\n",
+		shmd->vm_task->pid, shmd->vm_start, shmd->vm_end,
+		shmd->vm_flags & VM_READ ? 'r' : '-',
+		shmd->vm_flags & VM_WRITE ? 'w' : '-',
+		shmd->vm_flags & VM_EXEC ? 'x' : '-',
+		shmd->vm_flags & VM_SHARED ? 's' : 'p',
+		shmd->vm_offset, shmd->vm_pte);
 
  found:
-	do_munmap(shmd->start, shp->shm_segsz);
-	kfree(shmd);
-	shp->shm_lpid = current->pid;
+  	shp->shm_lpid = current->pid;
 	shp->shm_dtime = CURRENT_TIME;
 	if (--shp->shm_nattch <= 0 && shp->shm_perm.mode & SHM_DEST)
-		killseg (id); /* sleeps */
-	return;
+		killseg (id);
 }
 
 /*
  * detach and kill segment if marked destroyed.
- * The work is done in detach.
+ * The work is done in shm_close.
  */
 int sys_shmdt (char *shmaddr)
 {
-	struct shm_desc *shmd, **shmdp;
-
-	for (shmdp = &current->shm; (shmd = *shmdp); shmdp=&shmd->task_next) {
-		if (shmd->start == (ulong) shmaddr) {
-			detach (shmdp);
-			return 0;
-		}
-	}
-	return -EINVAL;
-}
-
-/*
- * detach all attached segments.
- */
-void shm_exit (void)
-{
-	while (current->shm)
-		detach(&current->shm);
-	return;
-}
-
-/*
- * copy the parent shm descriptors and update nattch
- * parent is stuck in fork so an attach on each segment is assured.
- * copy_page_tables does the mapping.
- */
-int shm_fork (struct task_struct *p1, struct task_struct *p2)
-{
-	struct shm_desc *shmd, *new_desc = NULL, *tmp;
-	struct shmid_ds *shp;
-	int id;
+	struct vm_area_struct *shmd, *shmdnext;
 
-	p2->semundo = NULL;
-	p2->shm = NULL;
-        if (!p1->shm)
-		return 0;
-	for (shmd = p1->shm; shmd; shmd = shmd->task_next) {
-		tmp = (struct shm_desc *) kmalloc(sizeof(*tmp), GFP_KERNEL);
-		if (!tmp) {
-			while (new_desc) {
-				tmp = new_desc->task_next;
-				kfree(new_desc);
-				new_desc = tmp;
-			}
-			free_page_tables (p2);
-			return -ENOMEM;
-		}
-		*tmp = *shmd;
-		tmp->task = p2;
-		tmp->task_next = new_desc;
-		new_desc = tmp;
-	}
-	p2->shm = new_desc;
-	for (shmd = new_desc; shmd; shmd = shmd->task_next) {
-		id = (shmd->shm_sgn >> SHM_ID_SHIFT) & SHM_ID_MASK;
-		shp = shm_segs[id];
-		if (shp == IPC_UNUSED) {
-			printk("shm_fork: unused id=%d PANIC\n", id);
-			return -ENOMEM;
-		}
-		shmd->seg_next = shp->attaches;
-		shp->attaches = shmd;
-		shp->shm_nattch++;
-		shp->shm_atime = CURRENT_TIME;
-		shp->shm_lpid = current->pid;
+	for (shmd = current->mm->mmap; shmd; shmd = shmdnext) {
+		shmdnext = shmd->vm_next;
+		if (shmd->vm_ops == &shm_vm_ops
+		    && shmd->vm_start - shmd->vm_offset == (ulong) shmaddr)
+			do_munmap(shmd->vm_start, shmd->vm_end - shmd->vm_start);
 	}
 	return 0;
 }
@@ -707,7 +675,7 @@
 {
 	unsigned long page;
 	struct shmid_ds *shp;
-	struct shm_desc *shmd;
+	struct vm_area_struct *shmd;
 	unsigned int swap_nr;
 	unsigned long id, idx, invalid = 0;
 	int counter;
@@ -746,21 +714,19 @@
 		swap_free (swap_nr);
 		return 0;
 	}
-	for (shmd = shp->attaches; shmd; shmd = shmd->seg_next) {
+	for (shmd = shp->attaches; shmd; shmd = shmd->vm_share) {
 		unsigned long tmp, *pte;
-		if ((shmd->shm_sgn >> SHM_ID_SHIFT & SHM_ID_MASK) != id) {
-			printk ("shm_swap: id=%ld does not match shmd\n", id);
+		if ((shmd->vm_pte >> SHM_ID_SHIFT & SHM_ID_MASK) != id) {
+			printk ("shm_swap: id=%ld does not match shmd->vm_pte.id=%ld\n", id, shmd->vm_pte >> SHM_ID_SHIFT & SHM_ID_MASK);
 			continue;
 		}
-		tmp = shmd->start + (idx << PAGE_SHIFT);
-		if (tmp >= shmd->end) {
-			printk ("shm_swap: too large idx=%ld id=%ld PANIC\n",idx, id);
+		tmp = shmd->vm_start + (idx << PAGE_SHIFT) - shmd->vm_offset;
+		if (!(tmp >= shmd->vm_start && tmp < shmd->vm_end))
 			continue;
-		}
-		pte = PAGE_DIR_OFFSET(shmd->task->tss.cr3,tmp);
+		pte = PAGE_DIR_OFFSET(shmd->vm_task->tss.cr3,tmp);
 		if (!(*pte & PAGE_PRESENT)) {
 			printk("shm_swap: bad pgtbl! id=%ld start=%lx idx=%ld\n",
-					id, shmd->start, idx);
+					id, shmd->vm_start, idx);
 			*pte = 0;
 			continue;
 		}
@@ -773,10 +739,10 @@
 			*pte &= ~PAGE_ACCESSED;
 			continue;
 		}
-		tmp = shmd->shm_sgn | idx << SHM_IDX_SHIFT;
+		tmp = shmd->vm_pte | idx << SHM_IDX_SHIFT;
 		*pte = tmp;
 		mem_map[MAP_NR(page)]--;
-		shmd->task->mm->rss--;
+		shmd->vm_task->mm->rss--;
 		invalid++;
 	}
 
diff -u --recursive --new-file v1.1.61/linux/ipc/util.c linux/ipc/util.c
--- v1.1.61/linux/ipc/util.c	Thu Nov  3 17:53:30 1994
+++ linux/ipc/util.c	Sat Nov  5 14:50:04 1994
@@ -132,17 +132,7 @@
     return -ENOSYS;
 }
 
-int shm_fork (struct task_struct *p1, struct task_struct *p2)
-{
-    return 0;
-}
-
 void sem_exit (void)
-{
-    return;
-}
-
-void shm_exit (void)
 {
     return;
 }
diff -u --recursive --new-file v1.1.61/linux/kernel/exit.c linux/kernel/exit.c
--- v1.1.61/linux/kernel/exit.c	Thu Nov  3 17:53:30 1994
+++ linux/kernel/exit.c	Sat Nov  5 14:50:03 1994
@@ -17,7 +17,6 @@
 #include <linux/malloc.h>
 
 #include <asm/segment.h>
-extern void shm_exit (void);
 extern void sem_exit (void);
 
 int getrusage(struct task_struct *, int, struct rusage *);
@@ -413,8 +412,6 @@
 fake_volatile:
 	if (current->semundo)
 		sem_exit();
-	if (current->shm)
-		shm_exit();
 	exit_mm();
 	exit_files();
 	exit_fs();
diff -u --recursive --new-file v1.1.61/linux/kernel/fork.c linux/kernel/fork.c
--- v1.1.61/linux/kernel/fork.c	Tue Jul 26 11:25:11 1994
+++ linux/kernel/fork.c	Sat Nov  5 14:50:03 1994
@@ -32,7 +32,6 @@
 #define MAX_TASKS_PER_USER (NR_TASKS/2)
 #define MIN_TASKS_LEFT_FOR_ROOT 4
 
-extern int shm_fork(struct task_struct *, struct task_struct *);
 long last_pid=0;
 
 static int find_empty_process(void)
@@ -104,6 +103,8 @@
 		tmp->vm_next = NULL;
 		if (tmp->vm_inode)
 			tmp->vm_inode->i_count++;
+		if (tmp->vm_ops && tmp->vm_ops->open)
+			tmp->vm_ops->open(tmp);
 		*p = tmp;
 		p = &tmp->vm_next;
 	}
@@ -141,13 +142,12 @@
 		p->mm->cmin_flt = p->mm->cmaj_flt = 0;
 		if (copy_page_tables(p))
 			return 1;
-		dup_mmap(p);
+		return dup_mmap(p);
 	} else {
 		if (clone_page_tables(p))
 			return 1;
-		dup_mmap(p);		/* wrong.. */
+		return dup_mmap(p);		/* wrong.. */
 	}
-	return shm_fork(current, p);
 }
 
 static void copy_fs(unsigned long clone_flags, struct task_struct * p)
@@ -243,6 +243,7 @@
 		__asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387));
 	if (copy_mm(clone_flags, p))
 		goto bad_fork_cleanup;
+	p->semundo = NULL;
 	copy_files(clone_flags, p);
 	copy_fs(clone_flags, p);
 	set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
diff -u --recursive --new-file v1.1.61/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v1.1.61/linux/kernel/ksyms.c	Thu Nov  3 17:53:30 1994
+++ linux/kernel/ksyms.c	Sun Nov  6 13:46:23 1994
@@ -29,6 +29,7 @@
 #include <linux/serial.h>
 #include <linux/locks.h>
 #include <linux/string.h>
+#include <linux/delay.h>
 #ifdef CONFIG_INET
 #include <linux/net.h>
 #include <linux/netdevice.h>
@@ -143,6 +144,7 @@
 	X(bh_mask),
 	X(add_timer),
 	X(del_timer),
+	X(tq_immediate),
 
 	/* dma handling */
 	X(request_dma),
@@ -157,6 +159,10 @@
 	X(current),
 	X(jiffies),
 	X(xtime),
+	X(loops_per_sec),
+	X(kill_proc),
+	X(kill_pg),
+	X(kill_sl),
 
 	/* misc */
 	X(panic),
diff -u --recursive --new-file v1.1.61/linux/kernel/sched.c linux/kernel/sched.c
--- v1.1.61/linux/kernel/sched.c	Sun Oct  9 11:50:06 1994
+++ linux/kernel/sched.c	Sun Nov  6 13:43:29 1994
@@ -43,6 +43,7 @@
 int tickadj = 500/HZ;			/* microsecs */
 
 DECLARE_TASK_QUEUE(tq_timer);
+DECLARE_TASK_QUEUE(tq_immediate);
 
 /*
  * phase-lock loop variables
@@ -589,6 +590,11 @@
 	run_task_queue(&tq_timer);
 }
 
+void immediate_bh(void * unused)
+{
+	run_task_queue(&tq_immediate);
+}
+
 /*
  * The int argument is really a (struct pt_regs *), in case the
  * interrupt wants to know from where it was called. The timer
@@ -830,6 +836,7 @@
 
 	bh_base[TIMER_BH].routine = timer_bh;
 	bh_base[TQUEUE_BH].routine = tqueue_bh;
+	bh_base[IMMEDIATE_BH].routine = immediate_bh;
 	if (sizeof(struct sigaction) != 16)
 		panic("Struct sigaction MUST be 16 bytes");
 	set_tss_desc(gdt+FIRST_TSS_ENTRY,&init_task.tss);
diff -u --recursive --new-file v1.1.61/linux/mm/mmap.c linux/mm/mmap.c
--- v1.1.61/linux/mm/mmap.c	Tue Sep 13 03:54:09 1994
+++ linux/mm/mmap.c	Sun Nov  6 13:43:54 1994
@@ -71,6 +71,8 @@
 		default:
 			return -EINVAL;
 		}
+		if ((flags & MAP_DENYWRITE) && (file->f_inode->i_wcount > 0))
+			return -ETXTBSY;
 	} else if ((flags & MAP_TYPE) == MAP_SHARED)
 		return -EINVAL;
 
@@ -85,23 +87,8 @@
 		if (len > TASK_SIZE || addr > TASK_SIZE - len)
 			return -EINVAL;
 	} else {
-		struct vm_area_struct * vmm;
-
-		/* Maybe this works.. Ugly it is. */
-		addr = SHM_RANGE_START;
-		while (addr+len < SHM_RANGE_END) {
-			for (vmm = current->mm->mmap ; vmm ; vmm = vmm->vm_next) {
-				if (addr >= vmm->vm_end)
-					continue;
-				if (addr + len <= vmm->vm_start)
-					continue;
-				addr = PAGE_ALIGN(vmm->vm_end);
-				break;
-			}
-			if (!vmm)
-				break;
-		}
-		if (addr+len >= SHM_RANGE_END)
+		addr = get_unmapped_area(len);
+		if (!addr)
 			return -ENOMEM;
 	}
 
@@ -157,22 +144,45 @@
 	
 	if (error) {
 		kfree(vma);
-		if (!current->errno)
-			current->errno = -error;
-		return -1;
+		return error;
 	}
 	insert_vm_struct(current, vma);
 	merge_segments(current->mm->mmap);
 	return addr;
 }
 
+/*
+ * Get an address range which is currently unmapped.
+ * For mmap() without MAP_FIXED and shmat() with addr=0.
+ * Return value 0 means ENOMEM.
+ */
+unsigned long get_unmapped_area(unsigned long len)
+{
+	struct vm_area_struct * vmm;
+	unsigned long gap_start = 0, gap_end;
+
+	for (vmm = current->mm->mmap; ; vmm = vmm->vm_next) {
+		if (gap_start < SHM_RANGE_START)
+			gap_start = SHM_RANGE_START;
+		if (!vmm || ((gap_end = vmm->vm_start) > SHM_RANGE_END))
+			gap_end = SHM_RANGE_END;
+		gap_start = PAGE_ALIGN(gap_start);
+		gap_end &= PAGE_MASK;
+		if ((gap_start <= gap_end) && (gap_end - gap_start >= len))
+			return gap_start;
+		if (!vmm)
+			return 0;
+		gap_start = vmm->vm_end;
+	}
+}
+
 asmlinkage int sys_mmap(unsigned long *buffer)
 {
 	int error;
 	unsigned long flags;
 	struct file * file = NULL;
 
-	error = verify_area(VERIFY_READ, buffer, 6*4);
+	error = verify_area(VERIFY_READ, buffer, 6*sizeof(long));
 	if (error)
 		return error;
 	flags = get_fs_long(buffer+3);
@@ -252,6 +262,8 @@
 		mpnt->vm_start = end;
 		if (mpnt->vm_inode)
 			mpnt->vm_inode->i_count++;
+		if (mpnt->vm_ops && mpnt->vm_ops->open)
+			mpnt->vm_ops->open(mpnt);
 		area->vm_end = addr;	/* Truncate area */
 		insert_vm_struct(current, mpnt);
 	}
@@ -261,6 +273,12 @@
 	if (!mpnt)
 		return;
 	*mpnt = *area;
+	if (mpnt->vm_ops && mpnt->vm_ops->open)
+		mpnt->vm_ops->open(mpnt);
+	if (area->vm_ops && area->vm_ops->close) {
+		area->vm_end = area->vm_start;
+		area->vm_ops->close(area);
+	}
 	insert_vm_struct(current, mpnt);
 }
 
@@ -416,7 +434,7 @@
 		/*
 		 * and if we have an inode, the offsets must be contiguous..
 		 */
-		if (mpnt->vm_inode != NULL) {
+		if ((mpnt->vm_inode != NULL) || (mpnt->vm_flags & VM_SHM)) {
 			if (prev->vm_offset + prev->vm_end - prev->vm_start != mpnt->vm_offset)
 				continue;
 		}
diff -u --recursive --new-file v1.1.61/linux/mm/mprotect.c linux/mm/mprotect.c
--- v1.1.61/linux/mm/mprotect.c	Tue Sep 13 06:51:52 1994
+++ linux/mm/mprotect.c	Sat Nov  5 14:50:03 1994
@@ -76,6 +76,8 @@
 	n->vm_page_prot = prot;
 	if (n->vm_inode)
 		n->vm_inode->i_count++;
+	if (n->vm_ops && n->vm_ops->open)
+		n->vm_ops->open(n);
 	insert_vm_struct(current, n);
 	merge_segments(current->mm->mmap);
 	return 0;
@@ -98,6 +100,8 @@
 	n->vm_page_prot = prot;
 	if (n->vm_inode)
 		n->vm_inode->i_count++;
+	if (n->vm_ops && n->vm_ops->open)
+		n->vm_ops->open(n);
 	insert_vm_struct(current, n);
 	merge_segments(current->mm->mmap);
 	return 0;
@@ -129,6 +133,10 @@
 	vma->vm_page_prot = prot;
 	if (vma->vm_inode)
 		vma->vm_inode->i_count += 2;
+	if (vma->vm_ops && vma->vm_ops->open) {
+		vma->vm_ops->open(left);
+		vma->vm_ops->open(right);
+	}
 	insert_vm_struct(current, left);
 	insert_vm_struct(current, right);
 	merge_segments(current->mm->mmap);
@@ -210,6 +218,8 @@
 		start = tmp;
 		if (vma->vm_end <= start) {
 			vma = vma->vm_next;
+			if (vma && vma->vm_start < start)
+				vma = vma->vm_next;
 			if (!vma || vma->vm_start != start)
 				return -EFAULT;
 		}
diff -u --recursive --new-file v1.1.61/linux/mm/swap.c linux/mm/swap.c
--- v1.1.61/linux/mm/swap.c	Wed Nov  2 12:03:47 1994
+++ linux/mm/swap.c	Thu Nov  3 17:53:04 1994
@@ -616,6 +616,7 @@
 unsigned long __get_free_pages(int priority, unsigned long order)
 {
 	unsigned long flags;
+	int reserved_pages;
 
 	if (intr_count && priority != GFP_ATOMIC) {
 		static int count = 0;
@@ -625,10 +626,13 @@
 			priority = GFP_ATOMIC;
 		}
 	}
+	reserved_pages = 5;
+	if (priority != GFP_NFS)
+		reserved_pages = min_free_pages;
 	save_flags(flags);
 repeat:
 	cli();
-	if ((priority==GFP_ATOMIC) || nr_free_pages > min_free_pages) {
+	if ((priority==GFP_ATOMIC) || nr_free_pages > reserved_pages) {
 		RMQUEUE(order);
 		restore_flags(flags);
 		return 0;
diff -u --recursive --new-file v1.1.61/linux/net/inet/devinet.c linux/net/inet/devinet.c
--- v1.1.61/linux/net/inet/devinet.c	Tue Aug 16 17:32:33 1994
+++ linux/net/inet/devinet.c	Fri Nov  4 12:15:59 1994
@@ -67,42 +67,6 @@
   	return(0);
 }
 
-/*
- *	Perform an IP address matching operation
- */
-
-int ip_addr_match(unsigned long me, unsigned long him)
-{
-	int i;
-	unsigned long mask=0xFFFFFFFF;
-
-	/*
-	 *	Simple case
-	 */
-	if (me == him) 
-  		return(1);
-  		
-  	/*
-  	 *	Look for a match ending in all 1's 
-  	 */
-  	 
-	for (i = 0; i < 4; i++, me >>= 8, him >>= 8, mask >>= 8) 
-	{
-		if ((me & 0xFF) != (him & 0xFF)) 
-		{
-		/*
-		 * The only way this could be a match is for
-		 * the rest of addr1 to be 0 or 255.
-		 */
-			if (me != 0 && me != mask) 
-				return(0);
-			return(1);
-		}
-	}
-  	return(1);
-}
-
-
 /* 
  *	Check the address for our address, broadcasts, etc. 
  *
diff -u --recursive --new-file v1.1.61/linux/net/inet/icmp.c linux/net/inet/icmp.c
--- v1.1.61/linux/net/inet/icmp.c	Mon Oct 10 12:05:29 1994
+++ linux/net/inet/icmp.c	Fri Nov  4 13:10:05 1994
@@ -176,8 +176,13 @@
 	 *	Build Layer 2-3 headers for message back to source. 
 	 */
 
-	offset = ip_build_header(skb, dev->pa_addr, iph->saddr,
-			   &ndev, IPPROTO_ICMP, NULL, len, skb_in->ip_hdr->tos,255);
+	{ unsigned long our_addr = dev->pa_addr;
+	if (iph->daddr != our_addr && ip_chk_addr(iph->daddr) == IS_MYADDR)
+		our_addr = iph->daddr;
+	offset = ip_build_header(skb, our_addr, iph->saddr,
+			   &ndev, IPPROTO_ICMP, NULL, len,
+			   skb_in->ip_hdr->tos,255);
+	}
 
 	if (offset < 0) 
 	{
diff -u --recursive --new-file v1.1.61/linux/net/inet/udp.c linux/net/inet/udp.c
--- v1.1.61/linux/net/inet/udp.c	Wed Aug 10 19:26:51 1994
+++ linux/net/inet/udp.c	Fri Nov  4 11:48:37 1994
@@ -276,7 +276,7 @@
 	 */
 	 
 	buff = skb->data;
-	saddr = 0;
+	saddr = sk->saddr;
 	dev = NULL;
 	tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr,
 			&dev, IPPROTO_UDP, sk->opt, skb->mem_len,sk->ip_tos,sk->ip_ttl);
