linux-cvs-patches
[Top] [All Lists]

CVS Update@linux-mips.org: linux

To: linux-cvs-patches@linux-mips.org
Subject: CVS Update@linux-mips.org: linux
From: ralf@linux-mips.org
Date: Mon, 27 Dec 2004 04:14:04 +0000
Reply-to: linux-mips@linux-mips.org
Sender: linux-cvs-patches-bounce@linux-mips.org
CVSROOT:        /home/cvs
Module name:    linux
Changes by:     ralf@ftp.linux-mips.org 04/12/27 04:13:57

Modified files:
        .              : Tag: linux_2_4 MAINTAINERS Makefile 
        Documentation  : Tag: linux_2_4 Configure.help parport.txt 
        Documentation/DocBook: Tag: linux_2_4 libata.tmpl 
        Documentation/sysctl: Tag: linux_2_4 vm.txt 
        arch/cris/drivers: Tag: linux_2_4 serial.c 
        arch/ia64/ia32 : Tag: linux_2_4 binfmt_elf32.c sys_ia32.c 
        arch/ia64/mm   : Tag: linux_2_4 init.c 
        arch/m68k/kernel: Tag: linux_2_4 setup.c 
        arch/mips64/kernel: Tag: linux_2_4 linux32.c 
        arch/parisc/kernel: Tag: linux_2_4 sys_parisc32.c 
        arch/ppc/8xx_io: Tag: linux_2_4 uart.c 
        arch/ppc/cpm2_io: Tag: linux_2_4 uart.c 
        arch/ppc/kernel: Tag: linux_2_4 traps.c 
        arch/ppc64/kernel: Tag: linux_2_4 sys_ppc32.c 
        arch/s390x/kernel: Tag: linux_2_4 exec32.c linux32.c 
        arch/sparc64   : Tag: linux_2_4 defconfig 
        arch/sparc64/kernel: Tag: linux_2_4 binfmt_elf32.c ioctl32.c 
                             smp.c sys_sparc32.c trampoline.S 
        arch/x86_64/ia32: Tag: linux_2_4 ia32_binfmt.c ia32entry.S 
                          socket32.c 
        arch/x86_64/kernel: Tag: linux_2_4 setup.c signal.c 
        drivers/acpi   : Tag: linux_2_4 bus.c 
        drivers/block  : Tag: linux_2_4 floppy.c sx8.c 
        drivers/bluetooth: Tag: linux_2_4 hci_ldisc.c 
        drivers/char   : Tag: linux_2_4 amiserial.c au1x00-serial.c 
                         console.c cyclades.c dz.c epca.c esp.c 
                         generic_serial.c hvc_console.c ip2main.c 
                         isicom.c istallion.c lp.c moxa.c mux.c mxser.c 
                         n_hdlc.c n_r3964.c n_tty.c pcxx.c pdc_console.c 
                         pty.c riscom8.c rocket.c selection.c 
                         ser_a2232.c serial.c serial167.c serial_amba.c 
                         serial_tx3912.c serial_txx927.c sgiserial.c 
                         sh-sci.c specialix.c stallion.c sx.c synclink.c 
                         synclinkmp.c tty_io.c tty_ioctl.c vac-serial.c 
                         vme_scc.c vt.c 
        drivers/char/ip2: Tag: linux_2_4 i2lib.c 
        drivers/char/pcmcia: Tag: linux_2_4 synclink_cs.c 
        drivers/char/rio: Tag: linux_2_4 riointr.c 
        drivers/isdn   : Tag: linux_2_4 isdn_tty.c 
        drivers/macintosh: Tag: linux_2_4 macserial.c 
        drivers/net    : Tag: linux_2_4 3c505.c eexpress.c forcedeth.c 
                         ppp_async.c ppp_synctty.c slip.c strip.c 
        drivers/net/hamradio: Tag: linux_2_4 6pack.c mkiss.c 
        drivers/net/irda: Tag: linux_2_4 irtty.c 
        drivers/net/wan: Tag: linux_2_4 pc300_tty.c sdla_chdlc.c 
                         x25_asy.c 
        drivers/net/wan/8253x: Tag: linux_2_4 8253xsyn.c 8253xtty.c 
                               8253xutl.c 
        drivers/parport: Tag: linux_2_4 ieee1284.c parport_arc.c 
                         parport_gsc.c parport_pc.c parport_sunbpp.c 
                         probe.c 
        drivers/s390/char: Tag: linux_2_4 con3215.c tubtty.c 
        drivers/s390/net: Tag: linux_2_4 ctctty.c 
        drivers/sbus/char: Tag: linux_2_4 aurora.c sab82532.c su.c zs.c 
        drivers/scsi   : Tag: linux_2_4 Config.in advansys.c ahci.c 
                         dpt_i2o.c dpti.h libata-core.c libata-scsi.c 
        drivers/scsi/aacraid: Tag: linux_2_4 README 
        drivers/scsi/dpt: Tag: linux_2_4 dpti_ioctl.h 
        drivers/tc     : Tag: linux_2_4 zs.c 
        drivers/usb    : Tag: linux_2_4 acm.c bluetooth.c 
        drivers/usb/gadget: Tag: linux_2_4 Config.in epautoconf.c 
                            ether.c gadget_chips.h rndis.c zero.c 
        drivers/usb/serial: Tag: linux_2_4 digi_acceleport.c 
                            io_edgeport.c io_ti.c keyspan_pda.c 
                            mct_u232.c usbserial.c 
        drivers/video  : Tag: linux_2_4 fbmem.c radeonfb.c vga16fb.c 
        fs             : Tag: linux_2_4 binfmt_aout.c binfmt_elf.c 
                         exec.c namei.c 
        fs/nfs         : Tag: linux_2_4 dir.c unlink.c 
        fs/proc        : Tag: linux_2_4 base.c proc_tty.c 
        fs/xfs         : Tag: linux_2_4 Makefile xfs_acl.h xfs_alloc.c 
                         xfs_attr.c xfs_attr_leaf.h xfs_bmap_btree.h 
                         xfs_dinode.h xfs_fs.h xfs_iget.c xfs_inode.c 
                         xfs_inode.h xfs_itable.c xfs_log.c 
                         xfs_log_priv.h xfs_log_recover.c xfs_mount.c 
                         xfs_mount.h xfs_rtalloc.c xfs_trans.h 
                         xfs_trans_inode.c xfs_utils.c xfs_vfsops.c 
                         xfs_vnodeops.c 
        fs/xfs/linux-2.4: Tag: linux_2_4 xfs_aops.c xfs_buf.c xfs_buf.h 
                          xfs_file.c xfs_fs_subr.h xfs_globals.c 
                          xfs_ioctl.c xfs_iops.c xfs_linux.h xfs_lrw.c 
                          xfs_super.c xfs_sysctl.c xfs_sysctl.h 
                          xfs_vfs.c xfs_vfs.h xfs_vnode.c xfs_vnode.h 
        fs/xfs/quota   : Tag: linux_2_4 xfs_qm.c xfs_qm.h xfs_qm_bhv.c 
                         xfs_qm_syscalls.c 
        include/asm-sparc: Tag: linux_2_4 elf.h 
        include/asm-x86_64: Tag: linux_2_4 socket32.h 
        include/linux  : Tag: linux_2_4 delay.h dqblk_xfs.h fb.h 
                         libata-compat.h libata.h mm.h pci_ids.h 
                         proc_fs.h socket.h tty.h tty_ldisc.h usb_ch9.h 
                         usb_gadget.h 
        include/net    : Tag: linux_2_4 ip_vs.h udp.h 
        init           : Tag: linux_2_4 do_mounts.c 
        kernel         : Tag: linux_2_4 fork.c sysctl.c 
        mm             : Tag: linux_2_4 mmap.c mremap.c 
        net            : Tag: linux_2_4 netsyms.c 
        net/802        : Tag: linux_2_4 p8022.c psnap.c 
        net/bluetooth/rfcomm: Tag: linux_2_4 tty.c 
        net/core       : Tag: linux_2_4 scm.c 
        net/ipv4       : Tag: linux_2_4 af_inet.c igmp.c ip_options.c 
                         ip_sockglue.c tcp_input.c udp.c 
        net/ipv4/ipvs  : Tag: linux_2_4 ip_vs_conn.c ip_vs_ctl.c 
        net/ipv6       : Tag: linux_2_4 af_inet6.c datagram.c mcast.c 
        net/irda/ircomm: Tag: linux_2_4 ircomm_tty.c 
        net/sched      : Tag: linux_2_4 cls_tcindex.c sch_netem.c 
        net/sctp       : Tag: linux_2_4 socket.c 
Removed files:
        fs/xfs         : Tag: linux_2_4 xfs_cap.c xfs_mac.c 

Log message:
        Merge with Linux 2.4.29-pre3.

diff -urN linux/MAINTAINERS linux/MAINTAINERS
--- linux/MAINTAINERS   2004/11/29 17:47:14     1.76.2.29
+++ linux/MAINTAINERS   2004/12/27 04:13:37     1.76.2.30
@@ -80,7 +80,7 @@
 
 3C505 NETWORK DRIVER
 P:     Philip Blundell
-M:     Philip.Blundell@pobox.com
+M:     philb@gnu.org
 L:     linux-net@vger.kernel.org
 S:     Maintained
 
@@ -699,7 +699,7 @@
 
 ETHEREXPRESS-16 NETWORK DRIVER
 P:     Philip Blundell
-M:     Philip.Blundell@pobox.com
+M:     philb@gnu.org
 L:     linux-net@vger.kernel.org
 S:     Maintained
 
@@ -1421,13 +1421,13 @@
 
 PARALLEL PORT SUPPORT
 P:     Phil Blundell
-M:     Philip.Blundell@pobox.com
+M:     philb@gnu.org
 P:     Tim Waugh
 M:     tim@cyberelk.net
 P:     David Campbell
 M:     campbell@torque.net
 P:     Andrea Arcangeli
-M:     andrea@e-mind.com
+M:     andrea@suse.de
 L:     linux-parport@torque.net
 W:     http://people.redhat.com/twaugh/parport/
 S:     Maintained
diff -urN linux/Makefile linux/Makefile
--- linux/Makefile      2004/11/29 17:47:14     1.119.2.29
+++ linux/Makefile      2004/12/27 04:13:37     1.119.2.30
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 29
-EXTRAVERSION = -pre1
+EXTRAVERSION = -pre3
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux/Documentation/Configure.help linux/Documentation/Configure.help
--- linux/Documentation/Attic/Configure.help    2004/11/29 17:47:14     
1.109.2.53
+++ linux/Documentation/Attic/Configure.help    2004/12/27 04:13:37     
1.109.2.54
@@ -617,6 +617,8 @@
 
   This is required for the full functionality of sar(8) and interesting
   if you want to do performance tuning, by tweaking the elevator, e.g.
+  On the other hand, it will cause random and mysterious failures for
+  fdisk, mount and other programs reading /proc/partitions.
 
   If unsure, say N.
 
@@ -1317,21 +1319,6 @@
 
   Please read the comments at the top of <file:drivers/ide/pci/piix.c>.
 
-  If you say Y here, you should also say Y to "PIIXn Tuning support",
-  below.
-
-  If unsure, say N.
-
-PIIXn Tuning support
-CONFIG_PIIX_TUNING
-  This driver extension adds DMA mode setting and tuning for all PIIX
-  IDE controllers by Intel. Since the BIOS can sometimes improperly
-  set up the device/adapter combination and speed limits, it has
-  become a necessity to back/forward speed devices as needed.
-
-  Case 430HX/440FX PIIX3 need speed limits to reduce UDMA to DMA mode
-  2 if the BIOS can not perform this task at initialization.
-
   If unsure, say N.
 
 Promise PDC202{46|62|65|67} support
@@ -7759,7 +7746,7 @@
   of MPT adapters via system ioctl calls.  Use of ioctl calls to
   the MPT driver requires that you create and use a misc device
   node ala:
-    mknod /dev/mptctl c 10 240
+    mknod /dev/mptctl c 10 220
 
   One use of this ioctl interface is to perform an upgrade (reflash)
   of the MPT adapter firmware.  Refer to readme file(s) distributed
@@ -9345,6 +9332,11 @@
 
   If unsure, say N.
 
+CONFIG_SCSI_SATA_AHCI
+  This option enables support for AHCI Serial ATA.
+
+  If unsure, say N.
+
 CONFIG_SCSI_SATA_SVW
   This option enables support for Broadcom/Serverworks/Apple K2
   SATA support.
diff -urN linux/Documentation/parport.txt linux/Documentation/parport.txt
--- linux/Documentation/parport.txt     2001/12/02 11:34:34     1.18
+++ linux/Documentation/parport.txt     2004/12/27 04:13:38     1.18.2.1
@@ -264,5 +264,5 @@
     io=0x378 irq=7 dma=none (for PIO)
     io=0x378 irq=7 dma=3 (for DMA)
 --
-Philip.Blundell@pobox.com
+philb@gnu.org
 tim@cyberelk.net
diff -urN linux/Documentation/DocBook/libata.tmpl 
linux/Documentation/DocBook/libata.tmpl
--- linux/Documentation/DocBook/libata.tmpl     2004/08/14 18:38:44     1.2.2.1
+++ linux/Documentation/DocBook/libata.tmpl     2004/12/27 04:13:38     1.2.2.2
@@ -61,6 +61,196 @@
   </para>
   </chapter>
 
+  <chapter id="libataDriverApi">
+     <title>libata Driver API</title>
+     <sect1>
+        <title>struct ata_port_operations</title>
+
+       <programlisting>
+void (*port_disable) (struct ata_port *);
+       </programlisting>
+
+       <para>
+       Called from ata_bus_probe() and ata_bus_reset() error paths,
+       as well as when unregistering from the SCSI module (rmmod, hot
+       unplug).
+       </para>
+
+       <programlisting>
+void (*dev_config) (struct ata_port *, struct ata_device *);
+       </programlisting>
+
+       <para>
+       Called after IDENTIFY [PACKET] DEVICE is issued to each device
+       found.  Typically used to apply device-specific fixups prior to
+       issue of SET FEATURES - XFER MODE, and prior to operation.
+       </para>
+
+       <programlisting>
+void (*set_piomode) (struct ata_port *, struct ata_device *);
+void (*set_dmamode) (struct ata_port *, struct ata_device *);
+void (*post_set_mode) (struct ata_port *ap);
+       </programlisting>
+
+       <para>
+       Hooks called prior to the issue of SET FEATURES - XFER MODE
+       command.  dev->pio_mode is guaranteed to be valid when
+       ->set_piomode() is called, and dev->dma_mode is guaranteed to be
+       valid when ->set_dmamode() is called.  ->post_set_mode() is
+       called unconditionally, after the SET FEATURES - XFER MODE
+       command completes successfully.
+       </para>
+
+       <para>
+       ->set_piomode() is always called (if present), but
+       ->set_dma_mode() is only called if DMA is possible.
+       </para>
+
+       <programlisting>
+void (*tf_load) (struct ata_port *ap, struct ata_taskfile *tf);
+void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf);
+       </programlisting>
+
+       <para>
+       ->tf_load() is called to load the given taskfile into hardware
+       registers / DMA buffers.  ->tf_read() is called to read the
+       hardware registers / DMA buffers, to obtain the current set of
+       taskfile register values.
+       </para>
+
+       <programlisting>
+void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf);
+       </programlisting>
+
+       <para>
+       causes an ATA command, previously loaded with
+       ->tf_load(), to be initiated in hardware.
+       </para>
+
+       <programlisting>
+u8   (*check_status)(struct ata_port *ap);
+void (*dev_select)(struct ata_port *ap, unsigned int device);
+       </programlisting>
+
+       <para>
+       Reads the Status ATA shadow register from hardware.  On some
+       hardware, this has the side effect of clearing the interrupt
+       condition.
+       </para>
+
+       <programlisting>
+void (*dev_select)(struct ata_port *ap, unsigned int device);
+       </programlisting>
+
+       <para>
+       Issues the low-level hardware command(s) that causes one of N
+       hardware devices to be considered 'selected' (active and
+       available for use) on the ATA bus.
+       </para>
+
+       <programlisting>
+void (*phy_reset) (struct ata_port *ap);
+       </programlisting>
+
+       <para>
+       The very first step in the probe phase.  Actions vary depending
+       on the bus type, typically.  After waking up the device and probing
+       for device presence (PATA and SATA), typically a soft reset
+       (SRST) will be performed.  Drivers typically use the helper
+       functions ata_bus_reset() or sata_phy_reset() for this hook.
+       </para>
+
+       <programlisting>
+void (*bmdma_setup) (struct ata_queued_cmd *qc);
+void (*bmdma_start) (struct ata_queued_cmd *qc);
+       </programlisting>
+
+       <para>
+       When setting up an IDE BMDMA transaction, these hooks arm
+       (->bmdma_setup) and fire (->bmdma_start) the hardware's DMA
+       engine.
+       </para>
+
+       <programlisting>
+void (*qc_prep) (struct ata_queued_cmd *qc);
+int (*qc_issue) (struct ata_queued_cmd *qc);
+       </programlisting>
+
+       <para>
+       Higher-level hooks, these two hooks can potentially supercede
+       several of the above taskfile/DMA engine hooks.  ->qc_prep is
+       called after the buffers have been DMA-mapped, and is typically
+       used to populate the hardware's DMA scatter-gather table.
+       Most drivers use the standard ata_qc_prep() helper function, but
+       more advanced drivers roll their own.
+       </para>
+       <para>
+       ->qc_issue is used to make a command active, once the hardware
+       and S/G tables have been prepared.  IDE BMDMA drivers use the
+       helper function ata_qc_issue_prot() for taskfile protocol-based
+       dispatch.  More advanced drivers roll their own ->qc_issue
+       implementation, using this as the "issue new ATA command to
+       hardware" hook.
+       </para>
+
+       <programlisting>
+void (*eng_timeout) (struct ata_port *ap);
+       </programlisting>
+
+       <para>
+       This is a high level error handling function, called from the
+       error handling thread, when a command times out.
+       </para>
+
+       <programlisting>
+irqreturn_t (*irq_handler)(int, void *, struct pt_regs *);
+void (*irq_clear) (struct ata_port *);
+       </programlisting>
+
+       <para>
+       ->irq_handler is the interrupt handling routine registered with
+       the system, by libata.  ->irq_clear is called during probe just
+       before the interrupt handler is registered, to be sure hardware
+       is quiet.
+       </para>
+
+       <programlisting>
+u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg);
+void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
+                   u32 val);
+       </programlisting>
+
+       <para>
+       Read and write standard SATA phy registers.  Currently only used
+       if ->phy_reset hook called the sata_phy_reset() helper function.
+       </para>
+
+       <programlisting>
+int (*port_start) (struct ata_port *ap);
+void (*port_stop) (struct ata_port *ap);
+void (*host_stop) (struct ata_host_set *host_set);
+       </programlisting>
+
+       <para>
+       ->port_start() is called just after the data structures for each
+       port are initialized.  Typically this is used to alloc per-port
+       DMA buffers / tables / rings, enable DMA engines, and similar
+       tasks.  
+       </para>
+       <para>
+       ->host_stop() is called when the rmmod or hot unplug process
+       begins.  The hook must stop all hardware interrupts, DMA
+       engines, etc.
+       </para>
+       <para>
+       ->port_stop() is called after ->host_stop().  It's sole function
+       is to release DMA/memory resources, now that they are no longer
+       actively being used.
+       </para>
+
+     </sect1>
+  </chapter>
+
   <chapter id="libataExt">
      <title>libata Library</title>
 !Edrivers/scsi/libata-core.c
@@ -78,7 +268,7 @@
   </chapter>
 
   <chapter id="SILInt">
-     <title>ata_sil Internals</title>
+     <title>sata_sil Internals</title>
 !Idrivers/scsi/sata_sil.c
   </chapter>
 
diff -urN linux/Documentation/sysctl/vm.txt linux/Documentation/sysctl/vm.txt
--- linux/Documentation/sysctl/vm.txt   2004/11/29 17:47:15     1.13.2.3
+++ linux/Documentation/sysctl/vm.txt   2004/12/27 04:13:39     1.13.2.4
@@ -307,7 +307,7 @@
 Low ram machines that swaps all the time want to turn
 this on (i.e. set to 1).
 
-The default value is 1.
+The default value is 0.
 =============================================================
 
 
diff -urN linux/arch/cris/drivers/serial.c linux/arch/cris/drivers/serial.c
--- linux/arch/cris/drivers/Attic/serial.c      2003/12/15 18:19:48     1.7.2.6
+++ linux/arch/cris/drivers/Attic/serial.c      2004/12/27 04:13:39     1.7.2.7
@@ -3324,10 +3324,7 @@
                return;
        
        if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup)(tty);
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
        }
 }
 
@@ -3952,11 +3949,7 @@
        info->xmit.head = info->xmit.tail = 0;
        restore_flags(flags);
 
-       wake_up_interruptible(&tty->write_wait);
-
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
 }
 
 /*
@@ -4578,8 +4571,7 @@
        shutdown(info);
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
        tty->closing = 0;
        info->event = 0;
        info->tty = 0;
diff -urN linux/arch/ia64/ia32/binfmt_elf32.c 
linux/arch/ia64/ia32/binfmt_elf32.c
--- linux/arch/ia64/ia32/binfmt_elf32.c 2004/08/14 18:38:45     1.13.2.5
+++ linux/arch/ia64/ia32/binfmt_elf32.c 2004/12/27 04:13:39     1.13.2.6
@@ -95,7 +95,11 @@
                vma->vm_private_data = NULL;
                down_write(&current->mm->mmap_sem);
                {
-                       insert_vm_struct(current->mm, vma);
+                       if (insert_vm_struct(current->mm, vma)) {
+                               kmem_cache_free(vm_area_cachep, vma);
+                               up_write(&current->mm->mmap_sem);
+                               return;
+                       }
                }
                up_write(&current->mm->mmap_sem);
        }
@@ -117,7 +121,11 @@
                vma->vm_private_data = NULL;
                down_write(&current->mm->mmap_sem);
                {
-                       insert_vm_struct(current->mm, vma);
+                       if (insert_vm_struct(current->mm, vma)) {
+                               kmem_cache_free(vm_area_cachep, vma);
+                               up_write(&current->mm->mmap_sem);
+                               return;
+                       }
                }
                up_write(&current->mm->mmap_sem);
        }
@@ -164,7 +172,7 @@
 {
        unsigned long stack_base;
        struct vm_area_struct *mpnt;
-       int i;
+       int i, ret;
 
        stack_base = IA32_STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
 
@@ -188,7 +196,11 @@
                mpnt->vm_pgoff = 0;
                mpnt->vm_file = NULL;
                mpnt->vm_private_data = 0;
-               insert_vm_struct(current->mm, mpnt);
+               if ((ret = insert_vm_struct(current->mm, mpnt))) {
+                       up_write(&current->mm->mmap_sem);
+                       kmem_cache_free(vm_area_cachep, mpnt);
+                       return ret;
+               }
                current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> 
PAGE_SHIFT;
        }
 
diff -urN linux/arch/ia64/ia32/sys_ia32.c linux/arch/ia64/ia32/sys_ia32.c
--- linux/arch/ia64/ia32/sys_ia32.c     2004/11/29 17:47:15     1.22.2.9
+++ linux/arch/ia64/ia32/sys_ia32.c     2004/12/27 04:13:39     1.22.2.10
@@ -1369,6 +1369,11 @@
 #define __CMSG32_FIRSTHDR(ctl,len) \
        ((len) >= sizeof(struct cmsghdr32) ? (struct cmsghdr32 *)(ctl) : 
(struct cmsghdr32 *)NULL)
 #define CMSG32_FIRSTHDR(msg)   __CMSG32_FIRSTHDR((msg)->msg_control, 
(msg)->msg_controllen)
+#define CMSG32_OK(ucmlen, ucmsg, mhdr) \
+       ((ucmlen) >= sizeof(struct cmsghdr) && \
+        (ucmlen) <= (unsigned long) \
+        ((mhdr)->msg_controllen - \
+         ((char *)(ucmsg) - (char *)(mhdr)->msg_control)))
 
 static inline struct cmsghdr32 *
 __cmsg32_nxthdr (void *ctl, __kernel_size_t size, struct cmsghdr32 *cmsg, int 
cmsg_len)
@@ -1429,10 +1434,7 @@
                        return -EFAULT;
 
                /* Catch bogons. */
-               if (CMSG32_ALIGN(ucmlen) < CMSG32_ALIGN(sizeof(struct 
cmsghdr32)))
-                       return -EINVAL;
-               if ((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control) 
+ ucmlen)
-                   > kmsg->msg_controllen)
+               if (!CMSG32_OK(ucmlen, ucmsg, kmsg))
                        return -EINVAL;
 
                tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
diff -urN linux/arch/ia64/mm/init.c linux/arch/ia64/mm/init.c
--- linux/arch/ia64/mm/init.c   2004/02/20 01:22:12     1.14.2.7
+++ linux/arch/ia64/mm/init.c   2004/12/27 04:13:39     1.14.2.8
@@ -105,7 +105,13 @@
                vma->vm_pgoff = 0;
                vma->vm_file = NULL;
                vma->vm_private_data = NULL;
-               insert_vm_struct(current->mm, vma);
+               down_write(&current->mm->mmap_sem);
+               if (insert_vm_struct(current->mm, vma)) {
+                       up_write(&current->mm->mmap_sem);
+                       kmem_cache_free(vm_area_cachep, vma);
+                       return;
+               }
+               up_write(&current->mm->mmap_sem);
        }
 
        /* map NaT-page at address zero to speed up speculative dereferencing 
of NULL: */
@@ -117,7 +123,13 @@
                        vma->vm_end = PAGE_SIZE;
                        vma->vm_page_prot = __pgprot(pgprot_val(PAGE_READONLY) 
| _PAGE_MA_NAT);
                        vma->vm_flags = VM_READ | VM_MAYREAD | VM_IO | 
VM_RESERVED;
-                       insert_vm_struct(current->mm, vma);
+                       down_write(&current->mm->mmap_sem);
+                       if (insert_vm_struct(current->mm, vma)) {
+                               up_write(&current->mm->mmap_sem);
+                               kmem_cache_free(vm_area_cachep, vma);
+                               return;
+                       }
+                       up_write(&current->mm->mmap_sem);
                }
        }
 }
diff -urN linux/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c
--- linux/arch/m68k/kernel/setup.c      2004/11/19 00:28:32     1.16.2.5
+++ linux/arch/m68k/kernel/setup.c      2004/12/27 04:13:39     1.16.2.6
@@ -597,7 +597,5 @@
                printk( KERN_EMERG "(see http://no-fpu.linux-m68k.org)\n" );
                panic( "no FPU" );
        }
-
-#endif /* CONFIG_SUN3 */
-
+#endif /* !CONFIG_M68KFPU_EMU */
 }
diff -urN linux/arch/mips64/kernel/linux32.c linux/arch/mips64/kernel/linux32.c
--- linux/arch/mips64/kernel/Attic/linux32.c    2004/11/29 17:47:15     
1.42.2.42
+++ linux/arch/mips64/kernel/Attic/linux32.c    2004/12/27 04:13:39     
1.42.2.43
@@ -2483,6 +2483,12 @@
                                    (struct cmsghdr32 *)(ctl) : \
                                    (struct cmsghdr32 *)NULL)
 #define CMSG32_FIRSTHDR(msg)   __CMSG32_FIRSTHDR((msg)->msg_control, 
(msg)->msg_controllen)
+#define CMSG32_OK(ucmlen, ucmsg, mhdr) \
+       ((ucmlen) >= sizeof(struct cmsghdr) && \
+        (ucmlen) <= (unsigned long) \
+        ((mhdr)->msg_controllen - \
+         ((char *)(ucmsg) - (char *)(mhdr)->msg_control)))
+
 
 __inline__ struct cmsghdr32 *__cmsg32_nxthdr(void *__ctl, __kernel_size_t 
__size,
                                              struct cmsghdr32 *__cmsg, int 
__cmsg_len)
@@ -2623,11 +2629,7 @@
                        return -EFAULT;
 
                /* Catch bogons. */
-               if(CMSG32_ALIGN(ucmlen) <
-                  CMSG32_ALIGN(sizeof(struct cmsghdr32)))
-                       return -ENOBUFS;
-               if((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control)
-                                  + ucmlen) > kmsg->msg_controllen)
+               if (!CMSG32_OK(ucmlen, ucmsg, kmsg))
                        return -EINVAL;
 
                tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
diff -urN linux/arch/parisc/kernel/sys_parisc32.c 
linux/arch/parisc/kernel/sys_parisc32.c
--- linux/arch/parisc/kernel/sys_parisc32.c     2003/07/05 03:23:32     1.1.2.2
+++ linux/arch/parisc/kernel/sys_parisc32.c     2004/12/27 04:13:39     1.1.2.3
@@ -1814,6 +1814,11 @@
                                    (struct cmsghdr32 *)(ctl) : \
                                    (struct cmsghdr32 *)NULL)
 #define CMSG32_FIRSTHDR(msg)   __CMSG32_FIRSTHDR((msg)->msg_control, 
(msg)->msg_controllen)
+#define CMSG32_OK(ucmlen, ucmsg, mhdr) \
+       ((ucmlen) >= sizeof(struct cmsghdr) && \
+        (ucmlen) <= (unsigned long) \
+        ((mhdr)->msg_controllen - \
+         ((char *)(ucmsg) - (char *)(mhdr)->msg_control)))
 
 __inline__ struct cmsghdr32 *__cmsg32_nxthdr(void *__ctl, __kernel_size_t 
__size,
                                              struct cmsghdr32 *__cmsg, int 
__cmsg_len)
@@ -1940,11 +1945,7 @@
                        return -EFAULT;
 
                /* Catch bogons. */
-               if(CMSG32_ALIGN(ucmlen) <
-                  CMSG32_ALIGN(sizeof(struct cmsghdr32)))
-                       return -EINVAL;
-               if((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control)
-                                  + ucmlen) > kmsg->msg_controllen)
+               if (!CMSG32_OK(ucmlen, ucmsg, kmsg))
                        return -EINVAL;
 
                tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
diff -urN linux/arch/ppc/8xx_io/uart.c linux/arch/ppc/8xx_io/uart.c
--- linux/arch/ppc/8xx_io/Attic/uart.c  2003/11/17 01:07:33     1.21.2.5
+++ linux/arch/ppc/8xx_io/Attic/uart.c  2004/12/27 04:13:39     1.21.2.6
@@ -738,10 +738,7 @@
                return;
 
        if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup)(tty);
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
        }
 }
 
@@ -1209,10 +1206,7 @@
        /* There is nothing to "flush", whatever we gave the CPM
         * is on its way out.
         */
-       wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
        info->flags &= ~TX_WAKEUP;
 }
 
@@ -1760,8 +1754,8 @@
         * the line discipline to only process XON/XOFF characters.
         */
        tty->closing = 1;
-       if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, info->closing_wait);
+       if (state->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, state->closing_wait);
        /*
         * At this point we stop accepting input.  To do this, we
         * disable the receive line status interrupts, and tell the
@@ -1791,15 +1785,14 @@
        shutdown(info);
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
        tty->closing = 0;
        info->event = 0;
        info->tty = 0;
        if (info->blocked_open) {
-               if (info->close_delay) {
+               if (state->close_delay) {
                        current->state = TASK_INTERRUPTIBLE;
-                       schedule_timeout(info->close_delay);
+                       schedule_timeout(state->close_delay);
                }
                wake_up_interruptible(&info->open_wait);
        }
diff -urN linux/arch/ppc/cpm2_io/uart.c linux/arch/ppc/cpm2_io/uart.c
--- linux/arch/ppc/cpm2_io/Attic/uart.c 2004/04/16 03:14:12     1.1.2.1
+++ linux/arch/ppc/cpm2_io/Attic/uart.c 2004/12/27 04:13:39     1.1.2.2
@@ -1754,8 +1754,8 @@
         * the line discipline to only process XON/XOFF characters.
         */
        tty->closing = 1;
-       if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, info->closing_wait);
+       if (state->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, state->closing_wait);
        /*
         * At this point we stop accepting input.  To do this, we
         * disable the receive line status interrupts, and tell the
@@ -1790,9 +1790,9 @@
        info->event = 0;
        info->tty = 0;
        if (info->blocked_open) {
-               if (info->close_delay) {
+               if (state->close_delay) {
                        current->state = TASK_INTERRUPTIBLE;
-                       schedule_timeout(info->close_delay);
+                       schedule_timeout(state->close_delay);
                }
                wake_up_interruptible(&info->open_wait);
        }
diff -urN linux/arch/ppc/kernel/traps.c linux/arch/ppc/kernel/traps.c
--- linux/arch/ppc/kernel/traps.c       2004/04/16 03:14:12     1.29.2.4
+++ linux/arch/ppc/kernel/traps.c       2004/12/27 04:13:40     1.29.2.5
@@ -88,8 +88,10 @@
        console_verbose();
        spin_lock_irq(&die_lock);
 #ifdef CONFIG_PMAC_BACKLIGHT
-       set_backlight_enable(1);
-       set_backlight_level(BACKLIGHT_MAX);
+       if (_machine == _MACH_Pmac) {
+               set_backlight_enable(1);
+               set_backlight_level(BACKLIGHT_MAX);
+       }
 #endif
        printk("Oops: %s, sig: %ld\n", str, err);
        show_regs(fp);
diff -urN linux/arch/ppc64/kernel/sys_ppc32.c 
linux/arch/ppc64/kernel/sys_ppc32.c
--- linux/arch/ppc64/kernel/sys_ppc32.c 2004/11/19 00:28:33     1.1.2.7
+++ linux/arch/ppc64/kernel/sys_ppc32.c 2004/12/27 04:13:40     1.1.2.8
@@ -3273,6 +3273,11 @@
                                    (struct cmsghdr32 *)(ctl) : \
                                    (struct cmsghdr32 *)NULL)
 #define CMSG32_FIRSTHDR(msg)   __CMSG32_FIRSTHDR((msg)->msg_control, 
(msg)->msg_controllen)
+#define CMSG32_OK(ucmlen, ucmsg, mhdr) \
+       ((ucmlen) >= sizeof(struct cmsghdr) && \
+        (ucmlen) <= (unsigned long) \
+        ((mhdr)->msg_controllen - \
+         ((char *)(ucmsg) - (char *)(mhdr)->msg_control)))
 
 struct msghdr32
 {
@@ -3448,11 +3453,7 @@
                        return -EFAULT;
 
                /* Catch bogons. */
-               if(CMSG32_ALIGN(ucmlen) <
-                  CMSG32_ALIGN(sizeof(struct cmsghdr32)))
-                       return -EINVAL;
-               if((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control)
-                                  + ucmlen) > kmsg->msg_controllen)
+               if (!CMSG32_OK(ucmlen, ucmsg, kmsg))
                        return -EINVAL;
 
                tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
diff -urN linux/arch/s390x/kernel/exec32.c linux/arch/s390x/kernel/exec32.c
--- linux/arch/s390x/kernel/Attic/exec32.c      2001/06/13 17:27:44     1.3
+++ linux/arch/s390x/kernel/Attic/exec32.c      2004/12/27 04:13:40     1.3.2.1
@@ -41,7 +41,7 @@
 {
        unsigned long stack_base;
        struct vm_area_struct *mpnt;
-       int i;
+       int i, ret;
 
        stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
 
@@ -65,7 +65,11 @@
                mpnt->vm_pgoff = 0;
                mpnt->vm_file = NULL;
                mpnt->vm_private_data = (void *) 0;
-               insert_vm_struct(current->mm, mpnt);
+               if ((ret = insert_vm_struct(current->mm, mpnt))) {
+                       up_write(&current->mm->mmap_sem);
+                       kmem_cache_free(vm_area_cachep, mpnt);
+                       return ret;
+               }
                current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> 
PAGE_SHIFT;
        } 
 
diff -urN linux/arch/s390x/kernel/linux32.c linux/arch/s390x/kernel/linux32.c
--- linux/arch/s390x/kernel/Attic/linux32.c     2004/11/19 00:28:34     1.7.2.5
+++ linux/arch/s390x/kernel/Attic/linux32.c     2004/12/27 04:13:40     1.7.2.6
@@ -2306,6 +2306,11 @@
                                    (struct cmsghdr32 *)(ctl) : \
                                    (struct cmsghdr32 *)NULL)
 #define CMSG32_FIRSTHDR(msg)   __CMSG32_FIRSTHDR((msg)->msg_control, 
(msg)->msg_controllen)
+#define CMSG32_OK(ucmlen, ucmsg, mhdr) \
+       ((ucmlen) >= sizeof(struct cmsghdr) && \
+        (ucmlen) <= (unsigned long) \
+        ((mhdr)->msg_controllen - \
+         ((char *)(ucmsg) - (char *)(mhdr)->msg_control)))
 
 __inline__ struct cmsghdr32 *__cmsg32_nxthdr(void *__ctl, __kernel_size_t 
__size,
                                              struct cmsghdr32 *__cmsg, int 
__cmsg_len)
@@ -2432,11 +2437,7 @@
                        return -EFAULT;
 
                /* Catch bogons. */
-               if(CMSG32_ALIGN(ucmlen) <
-                  CMSG32_ALIGN(sizeof(struct cmsghdr32)))
-                       return -EINVAL;
-               if((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control)
-                                  + ucmlen) > kmsg->msg_controllen)
+               if (!CMSG32_OK(ucmlen, ucmsg, kmsg))
                        return -EINVAL;
 
                tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
diff -urN linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- linux/arch/sparc64/defconfig        2004/11/19 00:28:35     1.60.2.15
+++ linux/arch/sparc64/defconfig        2004/12/27 04:13:40     1.60.2.16
@@ -415,6 +415,7 @@
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # CONFIG_IDEDISK_STROKE is not set
 # CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_DELKIN is not set
 CONFIG_BLK_DEV_IDECD=y
 CONFIG_BLK_DEV_IDETAPE=m
 CONFIG_BLK_DEV_IDEFLOPPY=m
@@ -1128,6 +1129,7 @@
 CONFIG_CRYPTO_SHA1=y
 CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_WP512=m
 CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_TWOFISH=m
@@ -1137,6 +1139,7 @@
 CONFIG_CRYPTO_CAST6=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
 CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_DEFLATE=y
 CONFIG_CRYPTO_MICHAEL_MIC=m
diff -urN linux/arch/sparc64/kernel/binfmt_elf32.c 
linux/arch/sparc64/kernel/binfmt_elf32.c
--- linux/arch/sparc64/kernel/binfmt_elf32.c    2003/07/05 03:23:34     1.8.4.2
+++ linux/arch/sparc64/kernel/binfmt_elf32.c    2004/12/27 04:13:40     1.8.4.3
@@ -81,7 +81,7 @@
 
 #define elf_check_arch(x)      (((x)->e_machine == EM_SPARC) || 
((x)->e_machine == EM_SPARC32PLUS))
 
-#define ELF_ET_DYN_BASE         0x08000000
+#define ELF_ET_DYN_BASE         0x70000000
 
 
 #include <asm/processor.h>
diff -urN linux/arch/sparc64/kernel/ioctl32.c 
linux/arch/sparc64/kernel/ioctl32.c
--- linux/arch/sparc64/kernel/ioctl32.c 2004/11/19 00:28:35     1.47.2.13
+++ linux/arch/sparc64/kernel/ioctl32.c 2004/12/27 04:13:40     1.47.2.14
@@ -4928,6 +4928,7 @@
 COMPATIBLE_IOCTL(RAW_GETBIND)
 /* SMB ioctls which do not need any translations */
 COMPATIBLE_IOCTL(SMB_IOC_NEWCONN)
+COMPATIBLE_IOCTL(SMB_IOC_GETMOUNTUID32)
 /* NCP ioctls which do not need any translations */
 COMPATIBLE_IOCTL(NCP_IOC_CONN_LOGGED_IN)
 COMPATIBLE_IOCTL(NCP_IOC_SIGN_INIT)
diff -urN linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
--- linux/arch/sparc64/kernel/smp.c     2003/11/17 01:07:34     1.36.2.6
+++ linux/arch/sparc64/kernel/smp.c     2004/12/27 04:13:40     1.36.2.7
@@ -137,15 +137,6 @@
 void __init smp_callin(void)
 {
        int cpuid = hard_smp_processor_id();
-       extern int bigkernel;
-       extern unsigned long kern_locked_tte_data;
-
-       if (bigkernel) {
-               prom_dtlb_load(sparc64_highest_locked_tlbent()-1, 
-                       kern_locked_tte_data + 0x400000, KERNBASE + 0x400000);
-               prom_itlb_load(sparc64_highest_locked_tlbent()-1, 
-                       kern_locked_tte_data + 0x400000, KERNBASE + 0x400000);
-       }
 
        inherit_locked_prom_mappings(0);
 
diff -urN linux/arch/sparc64/kernel/sys_sparc32.c 
linux/arch/sparc64/kernel/sys_sparc32.c
--- linux/arch/sparc64/kernel/sys_sparc32.c     2004/11/19 00:28:35     
1.60.2.12
+++ linux/arch/sparc64/kernel/sys_sparc32.c     2004/12/27 04:13:40     
1.60.2.13
@@ -2354,6 +2354,11 @@
                                    (struct cmsghdr32 *)(ctl) : \
                                    (struct cmsghdr32 *)NULL)
 #define CMSG32_FIRSTHDR(msg)   __CMSG32_FIRSTHDR((msg)->msg_control, 
(msg)->msg_controllen)
+#define CMSG32_OK(ucmlen, ucmsg, mhdr) \
+       ((ucmlen) >= sizeof(struct cmsghdr) && \
+        (ucmlen) <= (unsigned long) \
+        ((mhdr)->msg_controllen - \
+         ((char *)(ucmsg) - (char *)(mhdr)->msg_control)))
 
 __inline__ struct cmsghdr32 *__cmsg32_nxthdr(void *__ctl, __kernel_size_t 
__size,
                                              struct cmsghdr32 *__cmsg, int 
__cmsg_len)
@@ -2480,11 +2485,7 @@
                        return -EFAULT;
 
                /* Catch bogons. */
-               if(CMSG32_ALIGN(ucmlen) <
-                  CMSG32_ALIGN(sizeof(struct cmsghdr32)))
-                       return -EINVAL;
-               if((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control)
-                                  + ucmlen) > kmsg->msg_controllen)
+               if (!CMSG32_OK(ucmlen, ucmsg, kmsg))
                        return -EINVAL;
 
                tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
diff -urN linux/arch/sparc64/kernel/trampoline.S 
linux/arch/sparc64/kernel/trampoline.S
--- linux/arch/sparc64/kernel/trampoline.S      2003/07/05 03:23:35     1.13.2.4
+++ linux/arch/sparc64/kernel/trampoline.S      2004/12/27 04:13:40     1.13.2.5
@@ -90,7 +90,9 @@
        sllx            %g2, 32, %g2
        wr              %g2, 0, %tick_cmpr
 
-       /* Call OBP by hand to lock KERNBASE into i/d tlbs. */
+       /* Call OBP by hand to lock KERNBASE into i/d tlbs.
+        * We lock 2 consequetive entries if we are 'bigkernel'.
+        */
        mov             %o0, %l0
 
        sethi           %hi(prom_entry_lock), %g2
@@ -136,6 +138,46 @@
        call            %o1
         add            %sp, (2047 + 128), %o0
 
+       sethi           %hi(bigkernel), %g2
+       lduw            [%g2 + %lo(bigkernel)], %g2
+       cmp             %g2, 0
+       be,pt           %icc, do_dtlb
+        nop
+
+       sethi           %hi(call_method), %g2
+       or              %g2, %lo(call_method), %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x00]
+       mov             5, %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x08]
+       mov             1, %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x10]
+       sethi           %hi(itlb_load), %g2
+       or              %g2, %lo(itlb_load), %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x18]
+       sethi           %hi(mmu_ihandle_cache), %g2
+       lduw            [%g2 + %lo(mmu_ihandle_cache)], %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x20]
+       sethi           %hi(KERNBASE + 0x400000), %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x28]
+       sethi           %hi(kern_locked_tte_data), %g2
+       ldx             [%g2 + %lo(kern_locked_tte_data)], %g2
+       sethi           %hi(0x400000), %g1
+       add             %g2, %g1, %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x30]
+
+       mov             14, %g2
+       BRANCH_IF_ANY_CHEETAH(g1,g5,1f)
+
+       mov             62, %g2
+1:
+       stx             %g2, [%sp + 2047 + 128 + 0x38]
+       sethi           %hi(p1275buf), %g2
+       or              %g2, %lo(p1275buf), %g2
+       ldx             [%g2 + 0x08], %o1
+       call            %o1
+        add            %sp, (2047 + 128), %o0
+
+do_dtlb:
        sethi           %hi(call_method), %g2
        or              %g2, %lo(call_method), %g2
        stx             %g2, [%sp + 2047 + 128 + 0x00]
@@ -168,6 +210,47 @@
        call            %o1
         add            %sp, (2047 + 128), %o0
 
+       sethi           %hi(bigkernel), %g2
+       lduw            [%g2 + %lo(bigkernel)], %g2
+       cmp             %g2, 0
+       be,pt           %icc, do_unlock
+        nop
+
+       sethi           %hi(call_method), %g2
+       or              %g2, %lo(call_method), %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x00]
+       mov             5, %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x08]
+       mov             1, %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x10]
+       sethi           %hi(dtlb_load), %g2
+       or              %g2, %lo(dtlb_load), %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x18]
+       sethi           %hi(mmu_ihandle_cache), %g2
+       lduw            [%g2 + %lo(mmu_ihandle_cache)], %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x20]
+       sethi           %hi(KERNBASE + 0x400000), %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x28]
+       sethi           %hi(kern_locked_tte_data), %g2
+       ldx             [%g2 + %lo(kern_locked_tte_data)], %g2
+       sethi           %hi(0x400000), %g1
+       add             %g2, %g1, %g2
+       stx             %g2, [%sp + 2047 + 128 + 0x30]
+
+       mov             14, %g2
+       BRANCH_IF_ANY_CHEETAH(g1,g5,1f)
+
+       mov             62, %g2
+1:
+
+       stx             %g2, [%sp + 2047 + 128 + 0x38]
+       sethi           %hi(p1275buf), %g2
+       or              %g2, %lo(p1275buf), %g2
+       ldx             [%g2 + 0x08], %o1
+       call            %o1
+        add            %sp, (2047 + 128), %o0
+
+do_unlock:
        sethi           %hi(prom_entry_lock), %g2
        stb             %g0, [%g2 + %lo(prom_entry_lock)]
        membar          #StoreStore | #StoreLoad
diff -urN linux/arch/x86_64/ia32/ia32_binfmt.c 
linux/arch/x86_64/ia32/ia32_binfmt.c
--- linux/arch/x86_64/ia32/ia32_binfmt.c        2003/11/17 01:07:34     1.3.2.4
+++ linux/arch/x86_64/ia32/ia32_binfmt.c        2004/12/27 04:13:40     1.3.2.5
@@ -225,7 +225,7 @@
 {
        unsigned long stack_base;
        struct vm_area_struct *mpnt;
-       int i;
+       int i, ret;
 
        stack_base = IA32_STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
 
@@ -250,7 +250,11 @@
                mpnt->vm_pgoff = 0;
                mpnt->vm_file = NULL;
                mpnt->vm_private_data = (void *) 0;
-               insert_vm_struct(current->mm, mpnt);
+               if ((ret = insert_vm_struct(current->mm, mpnt))) {
+                       up_write(&current->mm->mmap_sem);
+                       kmem_cache_free(vm_area_cachep, mpnt);
+                       return ret;
+               }
                current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> 
PAGE_SHIFT;
        } 
 
diff -urN linux/arch/x86_64/ia32/ia32entry.S linux/arch/x86_64/ia32/ia32entry.S
--- linux/arch/x86_64/ia32/ia32entry.S  2004/08/14 18:38:48     1.2.2.8
+++ linux/arch/x86_64/ia32/ia32entry.S  2004/12/27 04:13:40     1.2.2.9
@@ -52,6 +52,7 @@
 ENTRY(ia32_syscall)
        swapgs  
        sti
+       movl %eax,%eax  
        pushq %rax
        cld
        SAVE_ARGS
diff -urN linux/arch/x86_64/ia32/socket32.c linux/arch/x86_64/ia32/socket32.c
--- linux/arch/x86_64/ia32/Attic/socket32.c     2004/11/19 00:28:35     1.1.2.5
+++ linux/arch/x86_64/ia32/Attic/socket32.c     2004/12/27 04:13:40     1.1.2.6
@@ -136,12 +136,9 @@
                        return -EFAULT;
 
                /* Catch bogons. */
-               if(CMSG32_ALIGN(ucmlen) <
-                  CMSG32_ALIGN(sizeof(struct cmsghdr32)))
-                       return -EINVAL;
-               if((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control)
-                                  + ucmlen) > kmsg->msg_controllen)
+               if (!CMSG32_OK(ucmlen, ucmsg, kmsg))
                        return -EINVAL;
+
                if (kmsg->msg_controllen > 65536) 
                        return -EINVAL;
 
diff -urN linux/arch/x86_64/kernel/setup.c linux/arch/x86_64/kernel/setup.c
--- linux/arch/x86_64/kernel/setup.c    2004/08/14 18:38:48     1.2.2.9
+++ linux/arch/x86_64/kernel/setup.c    2004/12/27 04:13:41     1.2.2.10
@@ -52,6 +52,7 @@
 EXPORT_SYMBOL(acpi_disabled);
 
 int swiotlb;
+EXPORT_SYMBOL(swiotlb);
 
 extern int phys_proc_id[NR_CPUS];
 
diff -urN linux/arch/x86_64/kernel/signal.c linux/arch/x86_64/kernel/signal.c
--- linux/arch/x86_64/kernel/signal.c   2003/11/17 01:07:34     1.3.2.4
+++ linux/arch/x86_64/kernel/signal.c   2004/12/27 04:13:41     1.3.2.5
@@ -561,7 +561,7 @@
        }
 
        /* Did we come from a system call? */
-       if (regs->orig_rax >= 0) {
+       if ((long)regs->orig_rax >= 0) {
                /* Restart the system call - no handlers present */
                if (regs->rax == -ERESTARTNOHAND ||
                    regs->rax == -ERESTARTSYS ||
diff -urN linux/drivers/acpi/bus.c linux/drivers/acpi/bus.c
--- linux/drivers/acpi/bus.c    2004/11/19 00:28:36     1.14.2.8
+++ linux/drivers/acpi/bus.c    2004/12/27 04:13:41     1.14.2.9
@@ -1850,7 +1850,10 @@
        acpi_status             status = AE_OK;
        struct acpi_buffer      buffer = {sizeof(acpi_fadt), &acpi_fadt};
 
-       ACPI_FUNCTION_TRACE("acpi_bus_init");
+       ACPI_FUNCTION_TRACE("acpi_early_init");
+
+       if (acpi_disabled)
+               return_VOID;
 
        status = acpi_initialize_subsystem();
        if (ACPI_FAILURE(status)) {
@@ -1899,11 +1902,11 @@
                goto error0;
        }
 
-       return;
+       return_VOID;
 
 error0:
        disable_acpi();
-       return;
+       return_VOID;
 }
 
 static int __init
diff -urN linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- linux/drivers/block/floppy.c        2003/08/13 17:19:16     1.42.2.4
+++ linux/drivers/block/floppy.c        2004/12/27 04:13:41     1.42.2.5
@@ -4255,6 +4255,14 @@
                max_buffer_sectors = 0;
        }
 
+       /*
+        * Small 10 msec delay to let through any interrupt that
+        * initialization might have triggered, to not
+        * confuse detection:
+        */
+       current->state = TASK_UNINTERRUPTIBLE;
+       schedule_timeout(HZ/100 + 1);
+
        for (i = 0; i < N_FDC; i++) {
                fdc = i;
                FDCS->driver_version = FD_DRIVER_VERSION;
diff -urN linux/drivers/block/sx8.c linux/drivers/block/sx8.c
--- linux/drivers/block/sx8.c   2004/08/14 18:38:49     1.1.2.1
+++ linux/drivers/block/sx8.c   2004/12/27 04:13:41     1.1.2.2
@@ -548,17 +548,6 @@
        return -EOPNOTSUPP;
 }
 
-static inline unsigned long msecs_to_jiffies(unsigned long msecs)
-{
-       return ((HZ * msecs + 999) / 1000);
-}
-
-static void msleep(unsigned long msecs)
-{
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       schedule_timeout(msecs_to_jiffies(msecs) + 1);
-}
-
 static const u32 msg_sizes[] = { 32, 64, 128, CARM_MSG_SIZE };
 
 static inline int carm_lookup_bucket(u32 msg_size)
diff -urN linux/drivers/bluetooth/hci_ldisc.c 
linux/drivers/bluetooth/hci_ldisc.c
--- linux/drivers/bluetooth/hci_ldisc.c 2004/08/14 18:38:49     1.1.2.4
+++ linux/drivers/bluetooth/hci_ldisc.c 2004/12/27 04:13:41     1.1.2.5
@@ -188,9 +188,7 @@
                kfree_skb(hu->tx_skb); hu->tx_skb = NULL;
        }
 
-       /* Flush any pending characters in the driver and discipline. */
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
 
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
@@ -283,9 +281,10 @@
 
        spin_lock_init(&hu->rx_lock);
 
-       /* Flush any pending characters in the driver and line discipline */
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       /* Flush any pending characters in the driver and line discipline. */
+       /* FIXME: why is this needed. Note don't use ldisc_ref here as the
+          open path is before the ldisc is referencable */
+       tty_ldisc_flush(tty);
 
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
diff -urN linux/drivers/char/amiserial.c linux/drivers/char/amiserial.c
--- linux/drivers/char/amiserial.c      2002/09/11 12:44:46     1.10.2.2
+++ linux/drivers/char/amiserial.c      2004/12/27 04:13:41     1.10.2.3
@@ -575,10 +575,7 @@
                return;
 
        if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup)(tty);
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
        }
 }
 
@@ -1040,10 +1037,7 @@
        save_flags(flags); cli();
        info->xmit.head = info->xmit.tail = 0;
        restore_flags(flags);
-       wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
 }
 
 /*
@@ -1581,8 +1575,8 @@
         * the line discipline to only process XON/XOFF characters.
         */
        tty->closing = 1;
-       if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, info->closing_wait);
+       if (state->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, state->closing_wait);
        /*
         * At this point we stop accepting input.  To do this, we
         * disable the receive line status interrupts, and tell the
@@ -1608,15 +1602,14 @@
        shutdown(info);
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
        tty->closing = 0;
        info->event = 0;
        info->tty = 0;
        if (info->blocked_open) {
-               if (info->close_delay) {
+               if (state->close_delay) {
                        current->state = TASK_INTERRUPTIBLE;
-                       schedule_timeout(info->close_delay);
+                       schedule_timeout(state->close_delay);
                }
                wake_up_interruptible(&info->open_wait);
        }
diff -urN linux/drivers/char/au1x00-serial.c linux/drivers/char/au1x00-serial.c
--- linux/drivers/char/Attic/au1x00-serial.c    2003/06/24 22:19:58     1.1.2.2
+++ linux/drivers/char/Attic/au1x00-serial.c    2004/12/27 04:13:41     1.1.2.3
@@ -1948,8 +1948,8 @@
         * the line discipline to only process XON/XOFF characters.
         */
        tty->closing = 1;
-       if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, info->closing_wait);
+       if (state->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, state->closing_wait);
        /*
         * At this point we stop accepting input.  To do this, we
         * disable the receive line status interrupts, and tell the
@@ -1976,9 +1976,9 @@
        info->event = 0;
        info->tty = 0;
        if (info->blocked_open) {
-               if (info->close_delay) {
+               if (state->close_delay) {
                        set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(info->close_delay);
+                       schedule_timeout(state->close_delay);
                }
                wake_up_interruptible(&info->open_wait);
        }
diff -urN linux/drivers/char/console.c linux/drivers/char/console.c
--- linux/drivers/char/Attic/console.c  2003/11/17 01:07:36     1.37.2.4
+++ linux/drivers/char/Attic/console.c  2004/12/27 04:13:42     1.37.2.5
@@ -705,6 +705,9 @@
        return 0;
 }
 
+#define VC_RESIZE_MAXCOL (32767)
+#define VC_RESIZE_MAXROW (32767)
+
 /*
  * Change # of rows and columns (0 means unchanged/the size of fg_console)
  * [this is to be used together with some user program
@@ -717,6 +720,9 @@
        unsigned int currcons = fg_console, i;
        unsigned short *newscreens[MAX_NR_CONSOLES];
 
+       if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW)
+               return -EINVAL;
+
        cc = (cols ? cols : video_num_columns);
        ll = (lines ? lines : video_num_lines);
        sr = cc << 1;
diff -urN linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- linux/drivers/char/cyclades.c       2003/02/25 22:03:05     1.27.2.3
+++ linux/drivers/char/cyclades.c       2004/12/27 04:13:42     1.27.2.4
@@ -1000,11 +1000,7 @@
        wake_up_interruptible(&info->delta_msr_wait);
     }
     if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) {
-        if((tty->flags & (1<< TTY_DO_WRITE_WAKEUP))
-        && tty->ldisc.write_wakeup){
-            (tty->ldisc.write_wakeup)(tty);
-        }
-        wake_up_interruptible(&tty->write_wait);
+       tty_wakeup(tty);
     }
 #ifdef Z_WAKE
     if (test_and_clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP, &info->event)) {
@@ -2918,8 +2914,7 @@
     shutdown(info);
     if (tty->driver.flush_buffer)
         tty->driver.flush_buffer(tty);
-    if (tty->ldisc.flush_buffer)
-        tty->ldisc.flush_buffer(tty);
+    tty_ldisc_flush(tty);
     CY_LOCK(info, flags);
 
     tty->closing = 0;
@@ -4689,10 +4684,7 @@
        }
        CY_UNLOCK(info, flags);
     }
-    wake_up_interruptible(&tty->write_wait);
-    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
-       && tty->ldisc.write_wakeup)
-           (tty->ldisc.write_wakeup)(tty);
+    tty_wakeup(tty);
 } /* cy_flush_buffer */
 
 
diff -urN linux/drivers/char/dz.c linux/drivers/char/dz.c
--- linux/drivers/char/Attic/dz.c       2004/09/28 00:53:01     1.23.2.11
+++ linux/drivers/char/Attic/dz.c       2004/12/27 04:13:42     1.23.2.12
@@ -437,9 +437,7 @@
                return;
 
        if (test_and_clear_bit(DZ_EVENT_WRITE_WAKEUP, &info->event)) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && 
tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup) (tty);
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
        }
 }
 
@@ -851,10 +849,7 @@
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
        sti();
 
-       wake_up_interruptible(&tty->write_wait);
-
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && 
tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup) (tty);
+       tty_wakeup(tty);
 }
 
 /*
@@ -1156,16 +1151,15 @@
 
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
        tty->closing = 0;
        info->event = 0;
        info->tty = 0;
 
-       if (tty->ldisc.num != ldiscs[N_TTY].num) {
+       if (tty->ldisc.num != N_TTY) {
                if (tty->ldisc.close)
                        (tty->ldisc.close) (tty);
-               tty->ldisc = ldiscs[N_TTY];
+               tty->ldisc = *(tty_ldisc_get(N_TTY));
                tty->termios->c_line = N_TTY;
                if (tty->ldisc.open)
                        (tty->ldisc.open) (tty);
diff -urN linux/drivers/char/epca.c linux/drivers/char/epca.c
--- linux/drivers/char/epca.c   2003/07/05 03:23:35     1.26.2.3
+++ linux/drivers/char/epca.c   2004/12/27 04:13:42     1.26.2.4
@@ -585,9 +585,7 @@
                if (tty->driver.flush_buffer)
                        tty->driver.flush_buffer(tty);
 
-               if (tty->ldisc.flush_buffer)
-                       tty->ldisc.flush_buffer(tty);
-
+               tty_ldisc_flush(tty);
                shutdown(ch);
                tty->closing = 0;
                ch->event = 0;
@@ -692,15 +690,13 @@
                cli();
                if (tty->driver.flush_buffer)
                        tty->driver.flush_buffer(tty);
-
-               if (tty->ldisc.flush_buffer)
-                       tty->ldisc.flush_buffer(tty);
-
+               
+               tty_ldisc_flush(tty);
+               
                shutdown(ch);
 
                if (ch->count)
                        MOD_DEC_USE_COUNT;
-               
 
                ch->tty   = NULL;
                ch->event = 0;
@@ -1175,9 +1171,7 @@
        memoff(ch);
        restore_flags(flags);
 
-       wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && 
tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
 
 } /* End pc_flush_buffer */
 
@@ -2383,10 +2377,7 @@
                                { /* Begin if LOWWAIT */
 
                                        ch->statusflags &= ~LOWWAIT;
-                                       if ((tty->flags & (1 << 
TTY_DO_WRITE_WAKEUP)) &&
-                                                 tty->ldisc.write_wakeup)
-                                               (tty->ldisc.write_wakeup)(tty);
-                                       wake_up_interruptible(&tty->write_wait);
+                                       tty_wakeup(tty);
 
                                } /* End if LOWWAIT */
 
@@ -2402,11 +2393,7 @@
                                { /* Begin if EMPTYWAIT */
 
                                        ch->statusflags &= ~EMPTYWAIT;
-                                       if ((tty->flags & (1 << 
TTY_DO_WRITE_WAKEUP)) &&
-                                                 tty->ldisc.write_wakeup)
-                                               (tty->ldisc.write_wakeup)(tty);
-
-                                       wake_up_interruptible(&tty->write_wait);
+                                       tty_wakeup(tty);
 
                                } /* End if EMPTYWAIT */
 
@@ -3255,8 +3242,8 @@
                        }
                        else 
                        {
-                               if (tty->ldisc.flush_buffer)
-                                       tty->ldisc.flush_buffer(tty);
+                               /* ldisc lock already held in ioctl */
+                               tty_ldisc_flush(tty);
                        }
 
                        /* Fall Thru */
diff -urN linux/drivers/char/esp.c linux/drivers/char/esp.c
--- linux/drivers/char/esp.c    2002/06/26 22:35:32     1.21.2.1
+++ linux/drivers/char/esp.c    2004/12/27 04:13:42     1.21.2.2
@@ -786,10 +786,7 @@
                return;
 
        if (test_and_clear_bit(ESP_EVENT_WRITE_WAKEUP, &info->event)) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup)(tty);
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
        }
 }
 
@@ -1395,10 +1392,7 @@
        cli();
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
        sti();
-       wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
 }
 
 /*
@@ -2115,8 +2109,7 @@
        shutdown(info);
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
        tty->closing = 0;
        info->event = 0;
        info->tty = 0;
diff -urN linux/drivers/char/generic_serial.c 
linux/drivers/char/generic_serial.c
--- linux/drivers/char/generic_serial.c 2002/09/11 12:44:46     1.12.2.2
+++ linux/drivers/char/generic_serial.c 2004/12/27 04:13:42     1.12.2.3
@@ -439,10 +439,7 @@
        port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
        restore_flags(flags);
 
-       wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
        func_exit ();
 }
 
@@ -582,10 +579,7 @@
        if (!tty) return;
 
        if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup)(tty);
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
        }
        func_exit ();
 }
@@ -729,8 +723,8 @@
 {
        unsigned long flags;
        struct gs_port *port;
-
-       func_enter ();
+       
+       func_enter();
 
        if (!tty) return;
 
@@ -803,8 +797,7 @@
 
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
        tty->closing = 0;
 
        port->event = 0;
diff -urN linux/drivers/char/hvc_console.c linux/drivers/char/hvc_console.c
--- linux/drivers/char/hvc_console.c    2004/02/20 01:22:16     1.6.2.2
+++ linux/drivers/char/hvc_console.c    2004/12/27 04:13:42     1.6.2.3
@@ -217,10 +217,7 @@
 
                if (hp->do_wakeup) {
                        hp->do_wakeup = 0;
-                       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
-                           && tty->ldisc.write_wakeup)
-                               (tty->ldisc.write_wakeup)(tty);
-                       wake_up_interruptible(&tty->write_wait);
+                       tty_wakeup(tty);
                }
        }
 
diff -urN linux/drivers/char/ip2main.c linux/drivers/char/ip2main.c
--- linux/drivers/char/ip2main.c        2004/11/19 00:28:36     1.16.2.3
+++ linux/drivers/char/ip2main.c        2004/12/27 04:13:42     1.16.2.4
@@ -1462,8 +1462,7 @@
        if (tty->pgrp > 0)
                kill_pg(tty->pgrp, sig, 1);
        if (flush || !L_NOFLSH(tty)) {
-               if ( tty->ldisc.flush_buffer )  
-                       tty->ldisc.flush_buffer(tty);
+               tty_ldisc_flush(tty);
                i2InputFlush( tty->driver_data );
        }
 }
@@ -1853,8 +1852,7 @@
 
        if ( tty->driver.flush_buffer ) 
                tty->driver.flush_buffer(tty);
-       if ( tty->ldisc.flush_buffer )  
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
        tty->closing = 0;
        
        pCh->pTTY = NULL;
diff -urN linux/drivers/char/isicom.c linux/drivers/char/isicom.c
--- linux/drivers/char/isicom.c 2003/02/25 22:03:05     1.14.2.2
+++ linux/drivers/char/isicom.c 2004/12/27 04:13:42     1.14.2.3
@@ -502,11 +502,8 @@
        
        if (!tty)
                return;
-       
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
-       wake_up_interruptible(&tty->write_wait);
+
+       tty_wakeup(tty);        
 }              
                
 /* main interrupt handler routine */           
@@ -1199,8 +1196,8 @@
        isicom_shutdown_port(port);
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       
+       tty_ldisc_flush(tty);
        tty->closing = 0;
        port->tty = 0;
        if (port->blocked_open) {
@@ -1670,10 +1667,7 @@
        port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
        restore_flags(flags);
        
-       wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
 }
 
 
diff -urN linux/drivers/char/istallion.c linux/drivers/char/istallion.c
--- linux/drivers/char/istallion.c      2004/11/29 17:47:16     1.29.2.4
+++ linux/drivers/char/istallion.c      2004/12/27 04:13:42     1.29.2.5
@@ -1214,8 +1214,7 @@
        clear_bit(ST_TXBUSY, &portp->state);
        clear_bit(ST_RXSTOP, &portp->state);
        set_bit(TTY_IO_ERROR, &tty->flags);
-       if (tty->ldisc.flush_buffer)
-               (tty->ldisc.flush_buffer)(tty);
+       tty_ldisc_flush(tty);
        set_bit(ST_DOFLUSHRX, &portp->state);
        stli_flushbuffer(tty);
 
@@ -2477,10 +2476,7 @@
        }
        restore_flags(flags);
 
-       wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
 }
 
 /*****************************************************************************/
@@ -2915,6 +2911,7 @@
        asynotify_t             nt;
        unsigned long           oldsigs;
        int                     rc, donerx;
+       struct tty_ldisc        *ld;
 
 #if DEBUG
        printk(KERN_DEBUG "stli_hostcmd(brdp=%x,channr=%d)\n",
@@ -3014,10 +3011,15 @@
                        clear_bit(ST_TXBUSY, &portp->state);
                if (nt.data & (DT_TXEMPTY | DT_TXLOW)) {
                        if (tty != (struct tty_struct *) NULL) {
-                               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                                   tty->ldisc.write_wakeup) {
-                                       (tty->ldisc.write_wakeup)(tty);
-                                       EBRDENABLE(brdp);
+                               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))) {
+                                       ld = tty_ldisc_ref(tty);
+                                       if(ld) {
+                                               if(ld->write_wakeup) {
+                                                       ld->write_wakeup(tty);
+                                                       EBRDENABLE(brdp);
+                                               }
+                                               tty_ldisc_deref(ld);
+                                       }
                                }
                                wake_up_interruptible(&tty->write_wait);
                        }
diff -urN linux/drivers/char/lp.c linux/drivers/char/lp.c
--- linux/drivers/char/lp.c     2002/06/26 22:35:33     1.38.2.2
+++ linux/drivers/char/lp.c     2004/12/27 04:13:42     1.38.2.3
@@ -12,7 +12,7 @@
  * "lp=" command line parameters added by Grant Guenther, grant@torque.net
  * lp_read (Status readback) support added by Carsten Gross,
  *                                             carsten@sol.wohnheim.uni-ulm.de
- * Support for parport by Philip Blundell <Philip.Blundell@pobox.com>
+ * Support for parport by Philip Blundell <philb@gnu.org>
  * Parport sharing hacking by Andrea Arcangeli
  * Fixed kernel_(to/from)_user memory copy to check for errors
  *                             by Riccardo Facchetti <fizban@tin.it>
diff -urN linux/drivers/char/moxa.c linux/drivers/char/moxa.c
--- linux/drivers/char/moxa.c   2001/11/06 07:55:58     1.9
+++ linux/drivers/char/moxa.c   2004/12/27 04:13:42     1.9.2.1
@@ -677,8 +677,8 @@
 
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
+
        tty->closing = 0;
        ch->event = 0;
        ch->tty = 0;
@@ -754,10 +754,7 @@
        if (ch == NULL)
                return;
        MoxaPortFlushData(ch->port, 1);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup) (tty);
-       wake_up_interruptible(&tty->write_wait);
+       tty_wakeup(tty);
 }
 
 static int moxa_chars_in_buffer(struct tty_struct *tty)
@@ -1011,10 +1008,7 @@
                                if (MoxaPortTxQueue(ch->port) <= WAKEUP_CHARS) {
                                        if (!tp->stopped) {
                                                ch->statusflags &= ~LOWWAIT;
-                                               if ((tp->flags & (1 << 
TTY_DO_WRITE_WAKEUP)) &&
-                                                 tp->ldisc.write_wakeup)
-                                                       
(tp->ldisc.write_wakeup) (tp);
-                                               
wake_up_interruptible(&tp->write_wait);
+                                               tty_wakeup(tp);
                                        }
                                }
                        }
@@ -1203,10 +1197,7 @@
        if (ch->tty && (ch->statusflags & EMPTYWAIT)) {
                if (MoxaPortTxQueue(ch->port) == 0) {
                        ch->statusflags &= ~EMPTYWAIT;
-                       if ((ch->tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                           ch->tty->ldisc.write_wakeup)
-                               (ch->tty->ldisc.write_wakeup) (ch->tty);
-                       wake_up_interruptible(&ch->tty->write_wait);
+                       tty_wakeup(ch->tty);
                        return;
                }
                moxaEmptyTimer[ch->port].expires = jiffies + HZ;
diff -urN linux/drivers/char/mux.c linux/drivers/char/mux.c
--- linux/drivers/char/Attic/mux.c      2003/02/26 00:53:49     1.1.2.1
+++ linux/drivers/char/Attic/mux.c      2004/12/27 04:13:42     1.1.2.2
@@ -429,8 +429,7 @@
 
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
        tty->closing = 0;
        info->event = 0;
        info->tty = 0;
diff -urN linux/drivers/char/mxser.c linux/drivers/char/mxser.c
--- linux/drivers/char/mxser.c  2004/11/19 00:28:37     1.11.2.4
+++ linux/drivers/char/mxser.c  2004/12/27 04:13:43     1.11.2.5
@@ -725,10 +725,7 @@
        tty = info->tty;
        if (tty) {
                if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event)) {
-                       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                           tty->ldisc.write_wakeup)
-                               (tty->ldisc.write_wakeup) (tty);
-                       wake_up_interruptible(&tty->write_wait);
+                       tty_wakeup(tty);
                }
                if (test_and_clear_bit(MXSER_EVENT_HANGUP, &info->event)) {
                        tty_hangup(tty);        /* FIXME: module removal race 
here - AKPM */
@@ -890,8 +887,8 @@
        mxser_shutdown(info);
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
+
        tty->closing = 0;
        info->event = 0;
        info->tty = 0;
@@ -1050,10 +1047,7 @@
        cli();
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
        restore_flags(flags);
-       wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup) (tty);
+       tty_wakeup(tty);
 }
 
 static int mxser_ioctl(struct tty_struct *tty, struct file *file,
diff -urN linux/drivers/char/n_hdlc.c linux/drivers/char/n_hdlc.c
--- linux/drivers/char/n_hdlc.c 2003/11/17 01:07:36     1.13.2.2
+++ linux/drivers/char/n_hdlc.c 2004/12/27 04:13:43     1.13.2.3
@@ -351,9 +351,8 @@
 #endif
        
        /* Flush any pending characters in the driver and discipline. */
-       
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer (tty);
+
+       tty_ldisc_flush(tty);   
 
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer (tty);
diff -urN linux/drivers/char/n_r3964.c linux/drivers/char/n_r3964.c
--- linux/drivers/char/n_r3964.c        2003/02/25 22:03:05     1.10.2.1
+++ linux/drivers/char/n_r3964.c        2004/12/27 04:13:43     1.10.2.2
@@ -158,7 +158,8 @@
         r3964_write,           /* write */
         r3964_ioctl,           /* ioctl */
         r3964_set_termios,     /* set_termios */
-        r3964_poll,            /* poll */            
+        r3964_poll,            /* poll */
+        NULL,                  /* hangup */
         r3964_receive_buf,     /* receive_buf */
         r3964_receive_room,    /* receive_room */
         0                      /* write_wakeup */
diff -urN linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- linux/drivers/char/n_tty.c  2003/08/13 17:19:16     1.23.2.2
+++ linux/drivers/char/n_tty.c  2004/12/27 04:13:43     1.23.2.3
@@ -112,11 +112,18 @@
        spin_unlock_irqrestore(&tty->read_lock, flags);
 }
 
-/* 
- * Check whether to call the driver.unthrottle function.
- * We test the TTY_THROTTLED bit first so that it always
- * indicates the current state.
+/**
+ *     check_unthrottle        -       allow new receive data
+ *     @tty; tty device
+ *
+ *     Check whether to call the driver.unthrottle function.
+ *     We test the TTY_THROTTLED bit first so that it always
+ *     indicates the current state. The decision about whether
+ *     it is worth allowing more input has been taken by the caller.
+ *     Can sleep, may be called under the atomic_read semaphore but
+ *     this is not guaranteed.
  */
+ 
 static void check_unthrottle(struct tty_struct * tty)
 {
        if (tty->count &&
@@ -125,10 +132,13 @@
                tty->driver.unthrottle(tty);
 }
 
-/*
- * Reset the read buffer counters, clear the flags, 
- * and make sure the driver is unthrottled. Called
- * from n_tty_open() and n_tty_flush_buffer().
+/**
+ *     reset_buffer_flags      -       reset buffer state
+ *     @tty: terminal to reset
+ *
+ *     Reset the read buffer counters, clear the flags, 
+ *     and make sure the driver is unthrottled. Called
+ *     from n_tty_open() and n_tty_flush_buffer().
  */
 static void reset_buffer_flags(struct tty_struct *tty)
 {
@@ -142,9 +152,19 @@
        check_unthrottle(tty);
 }
 
-/*
- * Flush the input buffer
+/**
+ *     n_tty_flush_buffer      -       clean input queue
+ *     @tty:   terminal device
+ *
+ *     Flush the input buffer. Called when the line discipline is
+ *     being closed, when the tty layer wants the buffer flushed (eg
+ *     at hangup) or when the N_TTY line discipline internally has to
+ *     clean the pending queue (for example some signals).
+ *
+ *     FIXME: tty->ctrl_status is not spinlocked and relies on
+ *     lock_kernel() still.
  */
+ 
 void n_tty_flush_buffer(struct tty_struct * tty)
 {
        /* clear everything and unthrottle the driver */
@@ -159,9 +179,14 @@
        }
 }
 
-/*
- * Return number of characters buffered to be delivered to user
+/**
+ *     n_tty_chars_in_buffer   -       report available bytes
+ *     @tty: tty device
+ *
+ *     Report the number of characters buffered to be delivered to user
+ *     at this instant in time. 
  */
+ 
 ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
 {
        unsigned long flags;
@@ -242,10 +267,20 @@
        return 0;
 }
 
-/*
- * opost_block --- to speed up block console writes, among other
- * things.
+/**
+ *     opost_block             -       block postprocess
+ *     @tty: terminal device
+ *     @inbuf: user buffer
+ *     @nr: number of bytes
+ *
+ *     This path is used to speed up block console writes, among other
+ *     things when processing blocks of output data. It handles only
+ *     the simple cases normally found and helps to generate blocks of
+ *     symbols for the console driver and thus improve performance.
+ *
+ *     Called from write_chan under the tty layer write lock.
  */
+ 
 static ssize_t opost_block(struct tty_struct * tty,
                       const unsigned char * inbuf, unsigned int nr)
 {
@@ -334,6 +369,16 @@
        }
 }
 
+/**
+ *     eraser          -       handle erase function
+ *     @c: character input
+ *     @tty: terminal device
+ *
+ *     Perform erase and neccessary output when an erase character is
+ *     present in the stream from the driver layer. Handles the complexities
+ *     of UTF-8 multibyte symbols.
+ */
+ 
 static void eraser(unsigned char c, struct tty_struct *tty)
 {
        enum { ERASE, WERASE, KILL } kill_type;
@@ -450,6 +495,18 @@
                finish_erasing(tty);
 }
 
+/**
+ *     isig            -       handle the ISIG optio
+ *     @sig: signal
+ *     @tty: terminal
+ *     @flush: force flush
+ *
+ *     Called when a signal is being sent due to terminal input. This
+ *     may caus terminal flushing to take place according to the termios
+ *     settings and character used. Called from the driver receive_buf
+ *     path so serialized.
+ */
+ 
 static inline void isig(int sig, struct tty_struct *tty, int flush)
 {
        if (tty->pgrp > 0)
@@ -461,6 +518,16 @@
        }
 }
 
+/**
+ *     n_tty_receive_break     -       handle break
+ *     @tty: terminal
+ *
+ *     An RS232 break event has been hit in the incoming bitstream. This
+ *     can cause a variety of events depending upon the termios settings.
+ *
+ *     Called from the receive_buf path so single threaded.
+ */
+ 
 static inline void n_tty_receive_break(struct tty_struct *tty)
 {
        if (I_IGNBRK(tty))
@@ -477,19 +544,40 @@
        wake_up_interruptible(&tty->read_wait);
 }
 
+/**
+ *     n_tty_receive_overrun   -       handle overrun reporting
+ *     @tty: terminal
+ *
+ *     Data arrived faster than we could process it. While the tty
+ *     driver has flagged this the bits that were missed are gone
+ *     forever.
+ *
+ *     Called from the receive_buf path so single threaded. Does not
+ *     need locking as num_overrun and overrun_time are function
+ *     private.
+ */
+ 
 static inline void n_tty_receive_overrun(struct tty_struct *tty)
 {
        char buf[64];
 
        tty->num_overrun++;
        if (time_before(tty->overrun_time, jiffies - HZ)) {
-               printk("%s: %d input overrun(s)\n", tty_name(tty, buf),
+               printk(KERN_WARNING "%s: %d input overrun(s)\n", tty_name(tty, 
buf),
                       tty->num_overrun);
                tty->overrun_time = jiffies;
                tty->num_overrun = 0;
        }
 }
 
+/**
+ *     n_tty_receive_parity_error      -       error notifier
+ *     @tty: terminal device
+ *     @c: character
+ *
+ *     Process a parity error and queue the right data to indicate
+ *     the error case if neccessary. Locking as per n_tty_receive_buf.
+ */
 static inline void n_tty_receive_parity_error(struct tty_struct *tty,
                                              unsigned char c)
 {
@@ -507,6 +595,16 @@
        wake_up_interruptible(&tty->read_wait);
 }
 
+/**
+ *     n_tty_receive_char      -       perform processing
+ *     @tty: terminal device
+ *     @c: character
+ *
+ *     Process an individual character of input received from the driver.
+ *     This is serialized with respect to itself by the rules for the 
+ *     driver above.
+ */
+
 static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
 {
        unsigned long flags;
@@ -698,6 +796,16 @@
        put_tty_queue(c, tty);
 }      
 
+/**
+ *     n_tty_receive_room      -       receive space
+ *     @tty: terminal
+ *
+ *     Called by the driver to find out how much data it is
+ *     permitted to feed to the line discipline without any being lost
+ *     and thus to manage flow control. Not serialized. Answers for the
+ *     "instant".
+ */
+ 
 static int n_tty_receive_room(struct tty_struct *tty)
 {
        int     left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
@@ -716,10 +824,13 @@
        return 0;
 }
 
-/*
- * Required for the ptys, serial driver etc. since processes
- * that attach themselves to the master and rely on ASYNC
- * IO must be woken up
+/**
+ *     n_tty_write_wakeup      -       asynchronous I/O notifier
+ *     @tty: tty device
+ *
+ *     Required for the ptys, serial driver etc. since processes
+ *     that attach themselves to the master and rely on ASYNC
+ *     IO must be woken up
  */
 
 static void n_tty_write_wakeup(struct tty_struct *tty)
@@ -732,6 +843,19 @@
        return;
 }
 
+/**
+ *     n_tty_receive_buf       -       data receive
+ *     @tty: terminal device
+ *     @cp: buffer
+ *     @fp: flag buffer
+ *     @count: characters
+ *
+ *     Called by the terminal driver when a block of characters has
+ *     been received. This function must be called from soft contexts
+ *     not from interrupt context. The driver is responsible for making
+ *     calls one at a time and in order (or using queue_ldisc)
+ */
+ 
 static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
                              char *fp, int count)
 {
@@ -813,6 +937,18 @@
                current->sig->action[sig-1].sa.sa_handler == SIG_IGN);
 }
 
+/**
+ *     n_tty_set_termios       -       termios data changed
+ *     @tty: terminal
+ *     @old: previous data
+ *
+ *     Called by the tty layer when the user changes termios flags so
+ *     that the line discipline can plan ahead. This function cannot sleep
+ *     and is protected from re-entry by the tty layer. The user is 
+ *     guaranteed that this function will not be re-entered or in progress
+ *     when the ldisc is closed.
+ */
+ 
 static void n_tty_set_termios(struct tty_struct *tty, struct termios * old)
 {
        if (!tty)
@@ -828,7 +964,6 @@
            I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
            I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
            I_PARMRK(tty)) {
-               cli();
                memset(tty->process_char_map, 0, 256/8);
 
                if (I_IGNCR(tty) || I_ICRNL(tty))
@@ -864,7 +999,6 @@
                        set_bit(SUSP_CHAR(tty), &tty->process_char_map);
                }
                clear_bit(__DISABLED_CHAR, &tty->process_char_map);
-               sti();
                tty->raw = 0;
                tty->real_raw = 0;
        } else {
@@ -878,6 +1012,16 @@
        }
 }
 
+/**
+ *     n_tty_close             -       close the ldisc for this tty
+ *     @tty: device
+ *
+ *     Called from the terminal layer when this line discipline is 
+ *     being shut down, either because of a close or becsuse of a 
+ *     discipline change. The function will not be called while other
+ *     ldisc methods are in progress.
+ */
+ 
 static void n_tty_close(struct tty_struct *tty)
 {
        n_tty_flush_buffer(tty);
@@ -887,11 +1031,22 @@
        }
 }
 
+/**
+ *     n_tty_open              -       open an ldisc
+ *     @tty: terminal to open
+ *
+ *     Called when this line discipline is being attached to the 
+ *     terminal device. Can sleep. Called serialized so that no
+ *     other events will occur in parallel. No further open will occur
+ *     until a close.
+ */
+
 static int n_tty_open(struct tty_struct *tty)
 {
        if (!tty)
                return -EINVAL;
 
+       /* This one is ugly. Currently a malloc failure here can panic */
        if (!tty->read_buf) {
                tty->read_buf = alloc_buf();
                if (!tty->read_buf)
@@ -917,14 +1072,23 @@
        return 0;
 }
 
-/*
- * Helper function to speed up read_chan.  It is only called when
- * ICANON is off; it copies characters straight from the tty queue to
- * user space directly.  It can be profitably called twice; once to
- * drain the space from the tail pointer to the (physical) end of the
- * buffer, and once to drain the space from the (physical) beginning of
- * the buffer to head pointer.
+/**
+ *     copy_from_read_buf      -       copy read data directly
+ *     @tty: terminal device
+ *     @b: user data
+ *     @nr: size of data
+ *
+ *     Helper function to speed up read_chan.  It is only called when
+ *     ICANON is off; it copies characters straight from the tty queue to
+ *     user space directly.  It can be profitably called twice; once to
+ *     drain the space from the tail pointer to the (physical) end of the
+ *     buffer, and once to drain the space from the (physical) beginning of
+ *     the buffer to head pointer.
+ *
+ *     Called under the tty->atomic_read sem and with TTY_DONT_FLIP set
+ *
  */
+ 
 static inline int copy_from_read_buf(struct tty_struct *tty,
                                      unsigned char **b,
                                      size_t *nr)
@@ -952,25 +1116,18 @@
        return retval;
 }
 
-static ssize_t read_chan(struct tty_struct *tty, struct file *file,
-                        unsigned char *buf, size_t nr)
-{
-       unsigned char *b = buf;
-       DECLARE_WAITQUEUE(wait, current);
-       int c;
-       int minimum, time;
-       ssize_t retval = 0;
-       ssize_t size;
-       long timeout;
-       unsigned long flags;
-
-do_it_again:
-
-       if (!tty->read_buf) {
-               printk("n_tty_read_chan: called with read_buf == NULL?!?\n");
-               return -EIO;

[%d lines skipped]
132diff -urN linux/drivers/char/pcxx.c linux/drivers/char/pcxx.c
--- linux/drivers/char/pcxx.c   2002/09/11 12:44:47     1.18.2.1
+++ linux/drivers/char/pcxx.c   2004/12/27 04:13:43     1.18.2.2
@@ -619,28 +619,11 @@
        
                if(tty->driver.flush_buffer)
                        tty->driver.flush_buffer(tty);
-               if(tty->ldisc.flush_buffer)
-                       tty->ldisc.flush_buffer(tty);
+               tty_ldisc_flush(tty);
                shutdown(info);
                tty->closing = 0;
                info->event = 0;
                info->tty = NULL;
-#ifndef MODULE
-/* ldiscs[] is not available in a MODULE
-** worth noting that while I'm not sure what this hunk of code is supposed
-** to do, it is not present in the serial.c driver.  Hmmm.  If you know,
-** please send me a note.  brian@ilinx.com
-** Don't know either what this is supposed to do christoph@lameter.com.
-*/
-               if(tty->ldisc.num != ldiscs[N_TTY].num) {
-                       if(tty->ldisc.close)
-                               (tty->ldisc.close)(tty);
-                       tty->ldisc = ldiscs[N_TTY];
-                       tty->termios->c_line = N_TTY;
-                       if(tty->ldisc.open)
-                               (tty->ldisc.open)(tty);
-               }
-#endif
                if(info->blocked_open) {
                        if(info->close_delay) {
                                current->state = TASK_INTERRUPTIBLE;
@@ -883,9 +866,7 @@
        memoff(ch);
        restore_flags(flags);
 
-       wake_up_interruptible(&tty->write_wait);
-       if((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
 }
 
 static void pcxe_flush_chars(struct tty_struct *tty)
@@ -1793,10 +1774,7 @@
                        if (event & LOWTX_IND) {
                                if (ch->statusflags & LOWWAIT) {
                                        ch->statusflags &= ~LOWWAIT;
-                                       if ((tty->flags & (1 << 
TTY_DO_WRITE_WAKEUP)) &&
-                                               tty->ldisc.write_wakeup)
-                                               (tty->ldisc.write_wakeup)(tty);
-                                       wake_up_interruptible(&tty->write_wait);
+                                       tty_wakeup(tty);
                                }
                        }
 
@@ -1804,10 +1782,7 @@
                                ch->statusflags &= ~TXBUSY;
                                if (ch->statusflags & EMPTYWAIT) {
                                        ch->statusflags &= ~EMPTYWAIT;
-                                       if ((tty->flags & (1 << 
TTY_DO_WRITE_WAKEUP)) &&
-                                               tty->ldisc.write_wakeup)
-                                               (tty->ldisc.write_wakeup)(tty);
-                                       wake_up_interruptible(&tty->write_wait);
+                                       tty_wakeup(tty);
                                }
                        }
                }
@@ -2254,8 +2229,7 @@
                                tty_wait_until_sent(tty, 0);
                        }
                        else {
-                               if(tty->ldisc.flush_buffer)
-                                       tty->ldisc.flush_buffer(tty);
+                               tty_ldisc_flush(tty);
                        }
 
                        /* Fall Thru */
diff -urN linux/drivers/char/pdc_console.c linux/drivers/char/pdc_console.c
--- linux/drivers/char/Attic/pdc_console.c      2003/02/25 22:03:05     1.1.2.2
+++ linux/drivers/char/Attic/pdc_console.c      2004/12/27 04:13:43     1.1.2.3
@@ -463,8 +463,7 @@
 
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
        tty->closing = 0;
        info->event = 0;
        info->tty = 0;
diff -urN linux/drivers/char/pty.c linux/drivers/char/pty.c
--- linux/drivers/char/pty.c    2002/06/26 22:35:33     1.16.2.2
+++ linux/drivers/char/pty.c    2004/12/27 04:13:43     1.16.2.3
@@ -85,9 +85,9 @@
        if (!tty->link)
                return;
        tty->link->packet = 0;
+       set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
        wake_up_interruptible(&tty->link->read_wait);
        wake_up_interruptible(&tty->link->write_wait);
-       set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
        if (tty->driver.subtype == PTY_TYPE_MASTER) {
                set_bit(TTY_OTHER_CLOSED, &tty->flags);
 #ifdef CONFIG_UNIX98_PTYS
@@ -121,10 +121,7 @@
        if (!o_tty)
                return;
 
-       if ((o_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           o_tty->ldisc.write_wakeup)
-               (o_tty->ldisc.write_wakeup)(o_tty);
-       wake_up_interruptible(&o_tty->write_wait);
+       tty_wakeup(o_tty);
        set_bit(TTY_THROTTLED, &tty->flags);
 }
 
@@ -137,6 +134,10 @@
  *   (2) avoid redundant copying for cases where count >> receive_room
  * N.B. Calls from user space may now return an error code instead of
  * a count.
+ *
+ * FIXME: Our pty_write method is called with our ldisc lock held but
+ * not our partners. We can't just take the other one blindly without
+ * risking deadlocks.  There is also the small matter of TTY_DONT_FLIP
  */
 static int pty_write(struct tty_struct * tty, int from_user,
                       const unsigned char *buf, int count)
@@ -299,9 +300,8 @@
        
        if (!to)
                return;
-       
-       if (to->ldisc.flush_buffer)
-               to->ldisc.flush_buffer(to);
+
+       tty_ldisc_flush(to);    
        
        if (to->packet) {
                tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
diff -urN linux/drivers/char/riscom8.c linux/drivers/char/riscom8.c
--- linux/drivers/char/riscom8.c        2001/10/19 01:24:15     1.16
+++ linux/drivers/char/riscom8.c        2004/12/27 04:13:43     1.16.2.1
@@ -1200,8 +1200,7 @@
        rc_shutdown_port(bp, port);
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
        tty->closing = 0;
        port->event = 0;
        port->tty = 0;
@@ -1375,9 +1374,7 @@
        restore_flags(flags);
        
        wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
 }
 
 static int rc_get_modem_info(struct riscom_port * port, unsigned int *value)
@@ -1734,10 +1731,7 @@
                return;
 
        if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup)(tty);
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
        }
 }
 
diff -urN linux/drivers/char/rocket.c linux/drivers/char/rocket.c
--- linux/drivers/char/rocket.c 2003/11/17 01:07:36     1.22.2.1
+++ linux/drivers/char/rocket.c 2004/12/27 04:13:43     1.22.2.2
@@ -241,9 +241,12 @@
                                   CHANNEL_t *cp, unsigned int ChanStatus)
 {
        unsigned int CharNStat;
-       int ToRecv, wRecv, space, count;
+       int ToRecv, wRecv, space = 0, count;
        unsigned char   *cbuf;
        char            *fbuf;
+       struct tty_ldisc *ld;
+
+       ld = tty_ldisc_ref(tty);
        
        ToRecv= sGetRxCnt(cp);
        space = 2*TTY_FLIPBUF_SIZE;
@@ -348,8 +351,8 @@
                fbuf += ToRecv;
                count += ToRecv;
        }
-       tty->ldisc.receive_buf(tty, tty->flip.char_buf,
-                              tty->flip.flag_buf, count);
+       ld->receive_buf(tty, tty->flip.char_buf, tty->flip.flag_buf, count);
+       tty_ldisc_deref(ld);
 }
 
 /*
@@ -400,10 +403,7 @@
        if (info->xmit_cnt == 0)
                xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f));
        if (info->xmit_cnt < WAKEUP_CHARS) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup)(tty);
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
        }
 #ifdef ROCKET_DEBUG_INTR
        printk("(%d,%d,%d,%d)...", info->xmit_cnt, info->xmit_head,
@@ -1128,8 +1128,7 @@
        }
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
 
        xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f));
        if (info->blocked_open) {
@@ -1806,10 +1805,7 @@
        restore_flags(flags);
 end:
        if (info->xmit_cnt < WAKEUP_CHARS) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup)(tty);
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
        }
        return retval;
 }
@@ -1868,9 +1864,7 @@
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
        sti();
        wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
        
        cp = &info->channel;
        
diff -urN linux/drivers/char/selection.c linux/drivers/char/selection.c
--- linux/drivers/char/selection.c      2001/10/19 01:24:15     1.11
+++ linux/drivers/char/selection.c      2004/12/27 04:13:43     1.11.2.1
@@ -290,9 +290,11 @@
 {
        struct vt_struct *vt = (struct vt_struct *) tty->driver_data;
        int     pasted = 0, count;
+       struct  tty_ldisc *ld;
        DECLARE_WAITQUEUE(wait, current);
 
        poke_blanked_console();
+       ld = tty_ldisc_ref_wait(tty);
        add_wait_queue(&vt->paste_wait, &wait);
        while (sel_buffer && sel_buffer_lth > pasted) {
                set_current_state(TASK_INTERRUPTIBLE);
@@ -301,12 +303,14 @@
                        continue;
                }
                count = sel_buffer_lth - pasted;
-               count = MIN(count, tty->ldisc.receive_room(tty));
-               tty->ldisc.receive_buf(tty, sel_buffer + pasted, 0, count);
+               count = MIN(count, ld->receive_room(tty));
+               ld->receive_buf(tty, sel_buffer + pasted, 0, count);
                pasted += count;
        }
        remove_wait_queue(&vt->paste_wait, &wait);
        current->state = TASK_RUNNING;
+
+       tty_ldisc_deref(ld);
        return 0;
 }
 
diff -urN linux/drivers/char/ser_a2232.c linux/drivers/char/ser_a2232.c
--- linux/drivers/char/ser_a2232.c      2003/11/17 01:07:36     1.2.2.1
+++ linux/drivers/char/ser_a2232.c      2004/12/27 04:13:43     1.2.2.2
@@ -633,10 +633,7 @@
                                        
                                /* WakeUp if output buffer runs low */
                                if ((port->gs.xmit_cnt <= 
port->gs.wakeup_chars) && port->gs.tty) {
-                                       if ((port->gs.tty->flags & (1 << 
TTY_DO_WRITE_WAKEUP)) && port->gs.tty->ldisc.write_wakeup){
-                                               
(port->gs.tty->ldisc.write_wakeup)(port->gs.tty);
-                                       }
-                                       
wake_up_interruptible(&port->gs.tty->write_wait);
+                                       tty_wakeup(port->gs.tty);
                                }
                        } // if the port is used
                } // for every port on the board
diff -urN linux/drivers/char/serial.c linux/drivers/char/serial.c
--- linux/drivers/char/Attic/serial.c   2004/11/19 00:28:37     1.62.2.11
+++ linux/drivers/char/Attic/serial.c   2004/12/27 04:13:43     1.62.2.12
@@ -1092,17 +1092,15 @@
 static void do_softint(void *private_)
 {
        struct async_struct     *info = (struct async_struct *) private_;
-       struct tty_struct       *tty;
-       
+       struct tty_struct       *tty;
+
        tty = info->tty;
        if (!tty)
                return;
 
        if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup)(tty);
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
+               
 #ifdef SERIAL_HAVE_POLL_WAIT
                wake_up_interruptible(&tty->poll_wait);
 #endif
@@ -2000,13 +1998,10 @@
        save_flags(flags); cli();
        info->xmit.head = info->xmit.tail = 0;
        restore_flags(flags);
-       wake_up_interruptible(&tty->write_wait);
 #ifdef SERIAL_HAVE_POLL_WAIT
        wake_up_interruptible(&tty->poll_wait);
 #endif
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
 }
 
 /*
@@ -2869,8 +2864,8 @@
         * the line discipline to only process XON/XOFF characters.
         */
        tty->closing = 1;
-       if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, info->closing_wait);
+       if (state->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, state->closing_wait);
        /*
         * At this point we stop accepting input.  To do this, we
         * disable the receive line status interrupts, and tell the
@@ -2891,15 +2886,14 @@
        shutdown(info);
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
        tty->closing = 0;
        info->event = 0;
        info->tty = 0;
        if (info->blocked_open) {
-               if (info->close_delay) {
+               if (state->close_delay) {
                        set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(info->close_delay);
+                       schedule_timeout(state->close_delay);
                }
                wake_up_interruptible(&info->open_wait);
        }
diff -urN linux/drivers/char/serial167.c linux/drivers/char/serial167.c
--- linux/drivers/char/serial167.c      2002/09/11 12:44:47     1.9.2.2
+++ linux/drivers/char/serial167.c      2004/12/27 04:13:43     1.9.2.3
@@ -773,11 +773,7 @@
        wake_up_interruptible(&info->open_wait);
     }
     if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) {
-       if((tty->flags & (1<< TTY_DO_WRITE_WAKEUP))
-       && tty->ldisc.write_wakeup){
-           (tty->ldisc.write_wakeup)(tty);
-       }
-       wake_up_interruptible(&tty->write_wait);
+       tty_wakeup(tty);
     }
 } /* do_softint */
 
@@ -1357,9 +1353,7 @@
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
     restore_flags(flags);
     wake_up_interruptible(&tty->write_wait);
-    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
-    && tty->ldisc.write_wakeup)
-       (tty->ldisc.write_wakeup)(tty);
+    tty_wakeup(tty);
 } /* cy_flush_buffer */
 
 
@@ -1916,18 +1910,9 @@
     shutdown(info);
     if (tty->driver.flush_buffer)
        tty->driver.flush_buffer(tty);
-    if (tty->ldisc.flush_buffer)
-       tty->ldisc.flush_buffer(tty);
+    tty_ldisc_flush(tty);
     info->event = 0;
     info->tty = 0;
-    if (tty->ldisc.num != ldiscs[N_TTY].num) {
-       if (tty->ldisc.close)
-           (tty->ldisc.close)(tty);
-       tty->ldisc = ldiscs[N_TTY];
-       tty->termios->c_line = N_TTY;
-       if (tty->ldisc.open)
-           (tty->ldisc.open)(tty);
-    }
     if (info->blocked_open) {
        if (info->close_delay) {
            current->state = TASK_INTERRUPTIBLE;
diff -urN linux/drivers/char/serial_amba.c linux/drivers/char/serial_amba.c
--- linux/drivers/char/Attic/serial_amba.c      2002/06/26 22:35:33     1.4.2.1
+++ linux/drivers/char/Attic/serial_amba.c      2004/12/27 04:13:43     1.4.2.2
@@ -569,10 +569,7 @@
        if (!tty || !test_and_clear_bit(EVT_WRITE_WAKEUP, &info->event))
                return;
 
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
-       wake_up_interruptible(&tty->write_wait);
+       tty_wakeup(tty);
 }
 
 static int ambauart_startup(struct amba_info *info)
@@ -958,10 +955,7 @@
        save_flags(flags); cli();
        info->xmit.head = info->xmit.tail = 0;
        restore_flags(flags);
-       wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
 }
 
 /*
@@ -1459,8 +1453,7 @@
        ambauart_shutdown(info);
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
        tty->closing = 0;
        info->event = 0;
        info->tty = NULL;
diff -urN linux/drivers/char/serial_tx3912.c linux/drivers/char/serial_tx3912.c
--- linux/drivers/char/serial_tx3912.c  2002/06/26 22:35:33     1.6.2.2
+++ linux/drivers/char/serial_tx3912.c  2004/12/27 04:13:43     1.6.2.3
@@ -127,12 +127,9 @@
        }
        
         if (port->gs.xmit_cnt <= port->gs.wakeup_chars) {
-                if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                    port->gs.tty->ldisc.write_wakeup)
-                        (port->gs.tty->ldisc.write_wakeup)(port->gs.tty);
+               tty_wakeup(port->gs.tty);
                 rs_dprintk(TX3912_UART_DEBUG_TRANSMIT, "Waking up.... ldisc 
(%d)....\n",
                             port->gs.wakeup_chars); 
-                wake_up_interruptible(&port->gs.tty->write_wait);
                }       
 }
 
diff -urN linux/drivers/char/serial_txx927.c linux/drivers/char/serial_txx927.c
--- linux/drivers/char/serial_txx927.c  2002/12/01 19:02:27     1.1.2.3
+++ linux/drivers/char/serial_txx927.c  2004/12/27 04:13:43     1.1.2.4
@@ -535,10 +535,7 @@
                return;
 
        if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup)(tty);
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
 #ifdef SERIAL_HAVE_POLL_WAIT
                wake_up_interruptible(&tty->poll_wait);
 #endif                                                    
@@ -1104,13 +1101,10 @@
        save_flags(flags); cli();
        info->xmit.head = info->xmit.tail = 0;
        restore_flags(flags);
-       wake_up_interruptible(&tty->write_wait);
 #ifdef SERIAL_HAVE_POLL_WAIT
        wake_up_interruptible(&tty->poll_wait);
 #endif
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
 }
 
 /*
@@ -1442,8 +1436,8 @@
         * the line discipline to only process XON/XOFF characters.
         */
        tty->closing = 1;
-       if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, info->closing_wait);
+       if (state->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, state->closing_wait);
        /*
         * At this point we stop accepting input.  To do this, we
         * disable the receive line status interrupts, and tell the
@@ -1465,15 +1459,14 @@
        shutdown(info);
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
        tty->closing = 0;
        info->event = 0;
        info->tty = 0;
        if (info->blocked_open) {
-               if (info->close_delay) {
+               if (state->close_delay) {
                        current->state = TASK_INTERRUPTIBLE;
-                       schedule_timeout(info->close_delay);
+                       schedule_timeout(state->close_delay);
                }
                wake_up_interruptible(&info->open_wait);
        }
diff -urN linux/drivers/char/sgiserial.c linux/drivers/char/sgiserial.c
--- linux/drivers/char/Attic/sgiserial.c        2003/11/06 12:30:34     1.1.2.3
+++ linux/drivers/char/Attic/sgiserial.c        2004/12/27 04:13:43     1.1.2.4
@@ -1498,10 +1498,10 @@
        tty->closing = 0;
        info->event = 0;
        info->tty = 0;
-       if (tty->ldisc.num != ldiscs[N_TTY].num) {
+       if (tty->ldisc.num != N_TTY) {
                if (tty->ldisc.close)
                        (tty->ldisc.close)(tty);
-               tty->ldisc = ldiscs[N_TTY];
+               tty->ldisc = *(tty_ldisc_get(N_TTY));
                tty->termios->c_line = N_TTY;
                if (tty->ldisc.open)
                        (tty->ldisc.open)(tty);
diff -urN linux/drivers/char/sh-sci.c linux/drivers/char/sh-sci.c
--- linux/drivers/char/Attic/sh-sci.c   2003/11/17 01:07:36     1.15.2.4
+++ linux/drivers/char/Attic/sh-sci.c   2004/12/27 04:13:43     1.15.2.5
@@ -1021,10 +1021,7 @@
                return;
 
        if (test_and_clear_bit(SCI_EVENT_WRITE_WAKEUP, &port->event)) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup)(tty);
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
        }
 }
 
diff -urN linux/drivers/char/specialix.c linux/drivers/char/specialix.c
--- linux/drivers/char/specialix.c      2002/06/26 22:35:33     1.17.2.1
+++ linux/drivers/char/specialix.c      2004/12/27 04:13:43     1.17.2.2
@@ -1579,8 +1579,7 @@
        sx_shutdown_port(bp, port);
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
        tty->closing = 0;
        port->event = 0;
        port->tty = 0;
@@ -1758,10 +1757,7 @@
        port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
        restore_flags(flags);
        
-       wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
 }
 
 
@@ -2211,12 +2207,8 @@
        if(!(tty = port->tty)) 
                return;
 
-       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup)(tty);
-               wake_up_interruptible(&tty->write_wait);
-       }
+       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) 
+               tty_wakeup(tty);
 }
 
 
diff -urN linux/drivers/char/stallion.c linux/drivers/char/stallion.c
--- linux/drivers/char/stallion.c       2004/11/29 17:47:16     1.33.2.3
+++ linux/drivers/char/stallion.c       2004/12/27 04:13:43     1.33.2.4
@@ -1238,8 +1238,7 @@
                portp->tx.tail = (char *) NULL;
        }
        set_bit(TTY_IO_ERROR, &tty->flags);
-       if (tty->ldisc.flush_buffer)
-               (tty->ldisc.flush_buffer)(tty);
+       tty_ldisc_flush(tty);
 
        tty->closing = 0;
        portp->tty = (struct tty_struct *) NULL;
@@ -1850,10 +1849,7 @@
                return;
 
        stl_flush(portp);
-       wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
 }
 
 /*****************************************************************************/
@@ -2224,10 +2220,7 @@
 
        lock_kernel();
        if (test_bit(ASYI_TXLOW, &portp->istate)) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup)(tty);
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
        }
        if (test_bit(ASYI_DCDCHANGE, &portp->istate)) {
                clear_bit(ASYI_DCDCHANGE, &portp->istate);
diff -urN linux/drivers/char/sx.c linux/drivers/char/sx.c
--- linux/drivers/char/sx.c     2003/07/05 03:23:35     1.22.2.5
+++ linux/drivers/char/sx.c     2004/12/27 04:13:43     1.22.2.6
@@ -1057,9 +1057,7 @@
        }
 
        if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.tty) {
-               if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   port->gs.tty->ldisc.write_wakeup)
-                       (port->gs.tty->ldisc.write_wakeup)(port->gs.tty);
+               tty_wakeup(port->gs.tty);
                sx_dprintk (SX_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n",
                            port->gs.wakeup_chars); 
                wake_up_interruptible(&port->gs.tty->write_wait);
diff -urN linux/drivers/char/synclink.c linux/drivers/char/synclink.c
--- linux/drivers/char/synclink.c       2003/11/19 18:49:50     1.20.2.6
+++ linux/drivers/char/synclink.c       2004/12/27 04:13:43     1.20.2.7
@@ -1011,6 +1011,29 @@
        return 0;
 }
 
+/**
+ * line discipline callback wrappers
+ *
+ * The wrappers maintain line discipline references
+ * while calling into the line discipline.
+ *
+ * ldisc_receive_buf  - pass receive data to line discipline
+ */
+
+static void ldisc_receive_buf(struct tty_struct *tty,
+                             const __u8 *data, char *flags, int count)
+{
+       struct tty_ldisc *ld;
+       if (!tty)
+               return;
+       ld = tty_ldisc_ref(tty);
+       if (ld) {
+               if (ld->receive_buf)
+                       ld->receive_buf(tty, data, flags, count);
+               tty_ldisc_deref(ld);
+       }
+}
+
 /* mgsl_stop()         throttle (stop) transmitter
  *     
  * Arguments:          tty     pointer to tty info structure
@@ -1170,14 +1193,7 @@
                        __FILE__,__LINE__,info->device_name);
 
        if (tty) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup) {
-                       if ( debug_level >= DEBUG_LEVEL_BH )
-                               printk( "%s(%d):calling ldisc.write_wakeup on 
%s\n",
-                                       __FILE__,__LINE__,info->device_name);
-                       (tty->ldisc.write_wakeup)(tty);
-               }
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
        }
 
        /* if transmitter idle and loopmode_send_done_requested
@@ -2433,12 +2449,8 @@
        del_timer(&info->tx_timer);     
        spin_unlock_irqrestore(&info->irq_spinlock,flags);
        
-       wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
-               
-}      /* end of mgsl_flush_buffer() */
+       tty_wakeup(tty);
+}
 
 /* mgsl_send_xchar()
  *
@@ -3342,9 +3354,8 @@
 
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-               
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       
+       tty_ldisc_flush(tty);
                
        shutdown(info);
        
@@ -7007,11 +7018,7 @@
                        } 
                        else
 #endif
-                       {
-                               /* Call the line discipline receive callback 
directly. */
-                               if ( tty && tty->ldisc.receive_buf )
-                               tty->ldisc.receive_buf(tty, 
info->intermediate_rxbuffer, info->flag_buf, framesize);
-                       }
+                               ldisc_receive_buf(tty, 
info->intermediate_rxbuffer, info->flag_buf, framesize);
                }
        }
        /* Free the buffers used by this frame. */
@@ -7183,9 +7190,7 @@
                        memcpy( info->intermediate_rxbuffer, 
pBufEntry->virt_addr, framesize);
                        info->icount.rxok++;
 
-                       /* Call the line discipline receive callback directly. 
*/
-                       if ( tty && tty->ldisc.receive_buf )
-                               tty->ldisc.receive_buf(tty, 
info->intermediate_rxbuffer, info->flag_buf, framesize);
+                       ldisc_receive_buf(tty, info->intermediate_rxbuffer, 
info->flag_buf, framesize);
                }
 
                /* Free the buffers used by this frame. */
diff -urN linux/drivers/char/synclinkmp.c linux/drivers/char/synclinkmp.c
--- linux/drivers/char/synclinkmp.c     2004/11/19 00:28:37     1.2.2.3
+++ linux/drivers/char/synclinkmp.c     2004/12/27 04:13:43     1.2.2.4
@@ -735,6 +735,29 @@
        return 0;
 }
 
+/**
+ * line discipline callback wrappers
+ *
+ * The wrappers maintain line discipline references
+ * while calling into the line discipline.
+ *
+ * ldisc_receive_buf  - pass receive data to line discipline
+ */
+
+static void ldisc_receive_buf(struct tty_struct *tty,
+                             const __u8 *data, char *flags, int count)
+{
+       struct tty_ldisc *ld;
+       if (!tty)
+               return;
+       ld = tty_ldisc_ref(tty);
+       if (ld) {
+               if (ld->receive_buf)
+                       ld->receive_buf(tty, data, flags, count);
+               tty_ldisc_deref(ld);
+       }
+}
+
 /* tty callbacks */
 
 /* Called when a port is opened.  Init and enable port.
@@ -906,8 +929,7 @@
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
 
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
 
        shutdown(info);
 
@@ -1315,9 +1337,7 @@
        spin_unlock_irqrestore(&info->lock,flags);
 
        wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
 }
 
 /* throttle (stop) transmitter
@@ -1983,13 +2003,7 @@
                        __FILE__,__LINE__,info->device_name);
 
        if (tty) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup) {
-                       if ( debug_level >= DEBUG_LEVEL_BH )
-                               printk( "%s(%d):%s calling 
ldisc.write_wakeup\n",
-                                       __FILE__,__LINE__,info->device_name);
-                       (tty->ldisc.write_wakeup)(tty);
-               }
+               tty_wakeup(tty);
                wake_up_interruptible(&tty->write_wait);
        }
 }
@@ -4989,15 +5003,8 @@
                        }
                        else
 #endif
-                       {
-                               if ( tty && tty->ldisc.receive_buf ) {
-                                       /* Call the line discipline receive 
callback directly. */
-                                       tty->ldisc.receive_buf(tty,
-                                               info->tmp_rx_buf,
-                                               info->flag_buf,
-                                               framesize);
-                               }
-                       }
+                               ldisc_receive_buf(tty,info->tmp_rx_buf,
+                                                 info->flag_buf, framesize);
                }
        }
        /* Free the buffers used by this frame. */
diff -urN linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- linux/drivers/char/tty_io.c 2004/11/19 00:28:37     1.62.2.15
+++ linux/drivers/char/tty_io.c 2004/12/27 04:13:43     1.62.2.16
@@ -120,7 +120,6 @@
 
 struct termios tty_std_termios;                /* for the benefit of tty 
drivers  */
 struct tty_driver *tty_drivers;                /* linked list of tty drivers */
-struct tty_ldisc ldiscs[NR_LDISCS];    /* line disc dispatch table     */
 
 #ifdef CONFIG_UNIX98_PTYS
 extern struct tty_driver ptm_driver[]; /* Unix98 pty masters; for /dev/ptmx */
@@ -260,63 +259,315 @@
        return 0;
 }
 
+/*
+ *     This is probably overkill for real world processors but
+ *     they are not on hot paths so a little discipline won't do
+ *     any harm.
+ */    
+
+static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
+{
+       down(&tty->termios_sem);
+       tty->termios->c_line = num;
+       up(&tty->termios_sem);
+}
+
+/*
+ *     This guards the refcounted line discipline lists. The lock
+ *     must be taken with irqs off because there are hangup path
+ *     callers who will do ldisc lookups and cannot sleep.
+ */
+
+spinlock_t tty_ldisc_lock = SPIN_LOCK_UNLOCKED;
+DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
+struct tty_ldisc tty_ldiscs[NR_LDISCS]; /* line disc dispatch table     */
+
 int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
 {
+
+       unsigned long flags;
+       int ret = 0;
+
        if (disc < N_TTY || disc >= NR_LDISCS)
                return -EINVAL;
-       
+
+       spin_lock_irqsave(&tty_ldisc_lock, flags);
        if (new_ldisc) {
-               ldiscs[disc] = *new_ldisc;
-               ldiscs[disc].flags |= LDISC_FLAG_DEFINED;
-               ldiscs[disc].num = disc;
-       } else
-               memset(&ldiscs[disc], 0, sizeof(struct tty_ldisc));
+               tty_ldiscs[disc] = *new_ldisc;
+               tty_ldiscs[disc].num = disc;
+               tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED;
+               tty_ldiscs[disc].refcount = 0;
+       } else {
+               if(tty_ldiscs[disc].refcount)
+                       ret = -EBUSY;
+               else
+                       tty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED;
+        }
+       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
        
-       return 0;
+       return ret;
+
 }
 
+
 EXPORT_SYMBOL(tty_register_ldisc);
 
-/* Set the discipline of a tty line. */
+struct tty_ldisc *tty_ldisc_get(int disc)
+{
+       unsigned long flags;
+       struct tty_ldisc *ld;
+
+       if (disc < N_TTY || disc >= NR_LDISCS)
+               return NULL;
+
+       spin_lock_irqsave(&tty_ldisc_lock, flags);
+
+       ld = &tty_ldiscs[disc];
+       /* Check the entry is defined */
+       if(ld->flags & LDISC_FLAG_DEFINED)
+               ld->refcount++;
+       else
+               ld = NULL;
+       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+       return ld;
+}
+
+EXPORT_SYMBOL_GPL(tty_ldisc_get);
+
+void tty_ldisc_put(int disc)
+{
+       struct tty_ldisc *ld;
+       unsigned long flags;
+
+       if (disc < N_TTY || disc >= NR_LDISCS)
+               BUG();
+
+       spin_lock_irqsave(&tty_ldisc_lock, flags);
+       ld = &tty_ldiscs[disc];
+       if(ld->refcount <= 0)
+               BUG();
+       ld->refcount--;
+       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+}
+      
+EXPORT_SYMBOL_GPL(tty_ldisc_put);
+
+void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
+{
+       tty->ldisc = *ld;
+       tty->ldisc.refcount = 0;
+}
+
+/**
+ *     tty_ldisc_try           -       internal helper
+ *     @tty: the tty
+ *
+ *     Make a single attempt to grab and bump the refcount on
+ *     the tty ldisc. Return 0 on failure or 1 on success. This is
+ *     used to implement both the waiting and non waiting versions
+ *     of tty_ldisc_ref
+ */
+
+static int tty_ldisc_try(struct tty_struct *tty)
+{
+       unsigned long flags;
+       struct tty_ldisc *ld;
+       int ret = 0;
+
+       spin_lock_irqsave(&tty_ldisc_lock, flags);
+       ld = &tty->ldisc;
+       if(test_bit(TTY_LDISC, &tty->flags))
+       {
+               ld->refcount++;
+               ret = 1;
+       }
+       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+       return ret;
+}
+
+/**
+ *     tty_ldisc_ref_wait      -       wait for the tty ldisc
+ *     @tty: tty device
+ *
+ *     Dereference the line discipline for the terminal and take a
+ *     reference to it. If the line discipline is in flux then
+ *     wait patiently until it changes.
+ *
+ *     Note: Must not be called from an IRQ/timer context. The caller
+ *     must also be careful not to hold other locks that will deadlock
+ *     against a discipline change, such as an existing ldisc reference
+ *     (which we check for)
+ */
+
+struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
+{
+       /* wait_event is a macro */
+       wait_event(tty_ldisc_wait, tty_ldisc_try(tty));
+       return &tty->ldisc;
+}
+
+EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
+
+/**
+ *     tty_ldisc_ref           -       get the tty ldisc
+ *     @tty: tty device
+ *
+ *     Dereference the line discipline for the terminal and take a
+ *     reference to it. If the line discipline is in flux then
+ *     return NULL. Can be called from IRQ and timer functions.
+ */
+
+struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
+{
+       if(tty_ldisc_try(tty))
+               return &tty->ldisc;
+       return NULL;
+}
+
+EXPORT_SYMBOL_GPL(tty_ldisc_ref);
+
+
+void tty_ldisc_deref(struct tty_ldisc *ld)
+{
+
+       unsigned long flags;
+
+       if(ld == NULL)
+               BUG();
+
+       spin_lock_irqsave(&tty_ldisc_lock, flags);
+       if(ld->refcount == 0)
+               printk(KERN_EMERG "tty_ldisc_deref: no references.\n");
+       else
+               ld->refcount--;
+       if(ld->refcount == 0)
+               wake_up(&tty_ldisc_wait);
+       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+}
+
+EXPORT_SYMBOL_GPL(tty_ldisc_deref);
+
+/**
+  *     tty_ldisc_enable        -       allow ldisc use
+  *     @tty: terminal to activate ldisc on
+  *
+  *     Set the TTY_LDISC flag when the line discipline can be called
+  *     again. Do neccessary wakeups for existing sleepers.
+  *
+  *     Note: nobody should set this bit except via this function. Clearing
+  *     directly is allowed.
+  */
+
+static void tty_ldisc_enable(struct tty_struct *tty)
+{
+       set_bit(TTY_LDISC, &tty->flags);
+       wake_up(&tty_ldisc_wait);
+}
+
+/**
+ *     tty_set_ldisc           -       set line discipline
+ *     @tty: the terminal to set
+ *     @ldisc: the line discipline
+ *
+ *     Set the discipline of a tty line. Must be called from a process
+ *     context.
+ */
+
 static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 {
        int     retval = 0;
        struct  tty_ldisc o_ldisc;
        char buf[64];
+       int work;
+       unsigned long flags;
+       struct tty_ldisc *ld;
 
        if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS))
                return -EINVAL;
+
+restart:
+
+       if (tty->ldisc.num == ldisc)
+               return 0; /* We are already in the desired discipline */
+
+       ld = tty_ldisc_get(ldisc);
        /* Eduardo Blanco <ejbs@cs.cs.com.uy> */
        /* Cyrus Durgin <cider@speakeasy.org> */
-       if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) {
+       if (ld == NULL)
+       {
                char modname [20];
-               sprintf(modname, "tty-ldisc-%d", ldisc);
-               request_module (modname);
+                sprintf(modname, "tty-ldisc-%d", ldisc);
+                request_module (modname);
+               ld = tty_ldisc_get(ldisc);
        }
-       if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED))
+       
+       if (ld == NULL)
                return -EINVAL;
 
-       if (tty->ldisc.num == ldisc)
-               return 0;       /* We are already in the desired discipline */
+       
        o_ldisc = tty->ldisc;
-
        tty_wait_until_sent(tty, 0);
+
+       /*
+        *      Make sure we don't change while someone holds a
+        *      reference to the line discipline. The TTY_LDISC bit
+        *      prevents anyone taking a reference once it is clear.
+        *      We need the lock to avoid racing reference takers.
+        */
+
+       spin_lock_irqsave(&tty_ldisc_lock, flags);
+       if(tty->ldisc.refcount)
+       {
+               /* Free the new ldisc we grabbed. Must drop the lock
+                  first. */
+               spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+               tty_ldisc_put(ldisc);
+               /*
+                * There are several reasons we may be busy, including
+                * random momentary I/O traffic. We must therefore
+                * retry. We could distinguish between blocking ops
+                * and retries if we made tty_ldisc_wait() smarter. That
+                * is up for discussion.
+                */
+               if(wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount 
== 0) < 0)
+                       return -ERESTARTSYS;
+               goto restart;
+       }
+       clear_bit(TTY_LDISC, &tty->flags);
+       clear_bit(TTY_DONT_FLIP, &tty->flags);
+       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+
+       /*
+        *      From this point on we know nobody has an ldisc
+        *      usage reference, nor can they obtain one until
+        *      we say so later on.
+        */
+
+       /*
+        * Wait for ->hangup_work and ->flip.work handlers to terminate
+        */
+       run_task_queue(&tq_timer);
+       flush_scheduled_tasks();
        
        /* Shutdown the current discipline. */
        if (tty->ldisc.close)
                (tty->ldisc.close)(tty);
 
        /* Now set up the new line discipline. */
-       tty->ldisc = ldiscs[ldisc];
-       tty->termios->c_line = ldisc;
+       tty_ldisc_assign(tty, ld);
+       tty_set_termios_ldisc(tty, ldisc);
        if (tty->ldisc.open)
                retval = (tty->ldisc.open)(tty);
        if (retval < 0) {
-               tty->ldisc = o_ldisc;
-               tty->termios->c_line = tty->ldisc.num;
+               tty_ldisc_put(ldisc);
+               /* There is an outstanding reference here so this is safe */
+               tty_ldisc_assign(tty, tty_ldisc_get(o_ldisc.num));
+               tty_set_termios_ldisc(tty, tty->ldisc.num);
                if (tty->ldisc.open && (tty->ldisc.open(tty) < 0)) {
-                       tty->ldisc = ldiscs[N_TTY];
-                       tty->termios->c_line = N_TTY;
+                       tty_ldisc_put(o_ldisc.num);
+                       /* This driver is always present */
+                       tty_ldisc_assign(tty, tty_ldisc_get(N_TTY));
+                       tty_set_termios_ldisc(tty, N_TTY);
                        if (tty->ldisc.open) {
                                int r = tty->ldisc.open(tty);
 
@@ -327,8 +578,21 @@
                        }
                }
        }
+       /* At this point we hold a reference to the new ldisc and a
+           reference to the old ldisc. If we ended up flipping back
+           to the existing ldisc we have two references to it */
+
        if (tty->ldisc.num != o_ldisc.num && tty->driver.set_ldisc)
                tty->driver.set_ldisc(tty);
+
+       tty_ldisc_put(o_ldisc.num);
+
+       /*
+        *      Allow ldisc referencing to occur as soon as the driver
+        *      ldisc callback completes.
+        */
+       tty_ldisc_enable(tty);
+
        return retval;
 }
 
@@ -430,11 +694,45 @@
 
 static spinlock_t redirect_lock = SPIN_LOCK_UNLOCKED;
 static struct file *redirect;
-/*
- * This can be called by the "eventd" kernel thread.  That is process 
synchronous,
- * but doesn't hold any locks, so we need to make sure we have the appropriate
- * locks for what we're doing..
- */
+
+/**
+  *     tty_wakeup      -       request more data
+  *     @tty: terminal
+  *
+  *     Internal and external helper for wakeups of tty. This function
+  *     informs the line discipline if present that the driver is ready\
+  *     to receive more output data.
+  */
+
+void tty_wakeup(struct tty_struct *tty)
+{
+       struct tty_ldisc *ld;
+
+       if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) {
+               ld = tty_ldisc_ref(tty);
+               if(ld) {
+                       if(ld->write_wakeup)
+                               ld->write_wakeup(tty);
+                       tty_ldisc_deref(ld);
+               }
+       }

[%d lines skipped]
464diff -urN linux/drivers/char/tty_ioctl.c linux/drivers/char/tty_ioctl.c
--- linux/drivers/char/tty_ioctl.c      2002/09/11 12:44:47     1.10.2.1
+++ linux/drivers/char/tty_ioctl.c      2004/12/27 04:13:43     1.10.2.2
@@ -96,8 +96,16 @@
 {
        int canon_change;
        struct termios old_termios = *tty->termios;
+       struct tty_ldisc *ld;
+
+       /*
+        *      Perform the actual termios internal changes under lock.
+        */
+
+       /* FIXME: we need to decide on some locking/ordering semantics
+          for the set_termios notification eventually */
+       down(&tty->termios_sem);
 
-       cli();
        *tty->termios = *new_termios;
        unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
        canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
@@ -107,7 +115,6 @@
                tty->canon_data = 0;
                tty->erasing = 0;
        }
-       sti();
        if (canon_change && !L_ICANON(tty) && tty->read_cnt)
                /* Get characters left over from canonical mode. */
                wake_up_interruptible(&tty->read_wait);
@@ -134,13 +141,19 @@
        if (tty->driver.set_termios)
                (*tty->driver.set_termios)(tty, &old_termios);
 
-       if (tty->ldisc.set_termios)
-               (*tty->ldisc.set_termios)(tty, &old_termios);
+       ld = tty_ldisc_ref(tty);
+       if (ld != NULL) {
+               if (ld->set_termios)
+                       (ld->set_termios)(tty, &old_termios);
+               tty_ldisc_deref(ld);
+       }
+       up(&tty->termios_sem);
 }
 
 static int set_termios(struct tty_struct * tty, unsigned long arg, int opt)
 {
        struct termios tmp_termios;
+       struct tty_ldisc *ld;
        int retval = tty_check_change(tty);
 
        if (retval)
@@ -157,8 +170,13 @@
                        return -EFAULT;
        }
 
-       if ((opt & TERMIOS_FLUSH) && tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       ld = tty_ldisc_ref(tty);
+
+       if (ld != NULL) {
+               if ((opt & TERMIOS_FLUSH) && ld->flush_buffer)
+                       ld->flush_buffer(tty);
+               tty_ldisc_deref(ld);
+       }
 
        if (opt & TERMIOS_WAIT) {
                tty_wait_until_sent(tty, 0);
@@ -223,12 +241,16 @@
 static int get_sgttyb(struct tty_struct * tty, struct sgttyb * sgttyb)
 {
        struct sgttyb tmp;
+       unsigned long flags;
 
+       down(&tty->termios_sem);
        tmp.sg_ispeed = 0;
        tmp.sg_ospeed = 0;
        tmp.sg_erase = tty->termios->c_cc[VERASE];
        tmp.sg_kill = tty->termios->c_cc[VKILL];
        tmp.sg_flags = get_sgflags(tty);
+       up(&tty->termios_sem);
+
        return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
 }
 
@@ -267,12 +289,14 @@
        retval = tty_check_change(tty);
        if (retval)
                return retval;
-       termios =  *tty->termios;
        if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
                return -EFAULT;
+       down(&tty->termios_sem);
+       termios =  *tty->termios;
        termios.c_cc[VERASE] = tmp.sg_erase;
        termios.c_cc[VKILL] = tmp.sg_kill;
        set_sgflags(&termios, tmp.sg_flags);
+       up(&tty->termios_sem);
        change_termios(tty, &termios);
        return 0;
 }
@@ -362,6 +386,8 @@
 {
        struct tty_struct * real_tty;
        int retval;
+       struct tty_ldisc *ld;
+       unsigned long flags;
 
        if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
            tty->driver.subtype == PTY_TYPE_MASTER)
@@ -440,22 +466,26 @@
                        retval = tty_check_change(tty);
                        if (retval)
                                return retval;
+
+                       ld = tty_ldisc_ref(tty);
                        switch (arg) {
                        case TCIFLUSH:
-                               if (tty->ldisc.flush_buffer)
-                                       tty->ldisc.flush_buffer(tty);
+                               if (ld->flush_buffer)
+                                       ld->flush_buffer(tty);
                                break;
                        case TCIOFLUSH:
-                               if (tty->ldisc.flush_buffer)
-                                       tty->ldisc.flush_buffer(tty);
+                               if (ld->flush_buffer)
+                                       ld->flush_buffer(tty);
                                /* fall through */
                        case TCOFLUSH:
                                if (tty->driver.flush_buffer)
                                        tty->driver.flush_buffer(tty);
                                break;
                        default:
+                               tty_ldisc_deref(ld);
                                return -EINVAL;
                        }
+                       tty_ldisc_deref(ld);
                        return 0;
                case TIOCOUTQ:
                        return put_user(tty->driver.chars_in_buffer ?
@@ -501,9 +531,11 @@
                case TIOCSSOFTCAR:
                        if (get_user(arg, (unsigned int *) arg))
                                return -EFAULT;
+                       down(&tty->termios_sem);
                        tty->termios->c_cflag =
                                ((tty->termios->c_cflag & ~CLOCAL) |
                                 (arg ? CLOCAL : 0));
+                       up(&tty->termios_sem);
                        return 0;
                default:
                        return -ENOIOCTLCMD;
diff -urN linux/drivers/char/vac-serial.c linux/drivers/char/vac-serial.c
--- linux/drivers/char/Attic/vac-serial.c       2004/02/20 01:22:16     1.1.2.2
+++ linux/drivers/char/Attic/vac-serial.c       2004/12/27 04:13:43     1.1.2.3
@@ -1699,8 +1699,8 @@
         * the line discipline to only process XON/XOFF characters.
         */
        tty->closing = 1;
-       if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, info->closing_wait);
+       if (state->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, state->closing_wait);
        /*
         * At this point we stop accepting input.  To do this, we
         * disable the receive line status interrupts, and tell the
@@ -1727,9 +1727,9 @@
        info->event = 0;
        info->tty = 0;
        if (info->blocked_open) {
-               if (info->close_delay) {
+               if (state->close_delay) {
                        current->state = TASK_INTERRUPTIBLE;
-                       schedule_timeout(info->close_delay);
+                       schedule_timeout(state->close_delay);
                }
                wake_up_interruptible(&info->open_wait);
        }
diff -urN linux/drivers/char/vme_scc.c linux/drivers/char/vme_scc.c
--- linux/drivers/char/vme_scc.c        2002/06/26 22:35:34     1.6.2.1
+++ linux/drivers/char/vme_scc.c        2004/12/27 04:13:43     1.6.2.2
@@ -569,12 +569,8 @@
                SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET);   /* disable tx_int 
on next tx underrun? */
                port->gs.flags &= ~GS_TX_INTEN;
        }
-       if (port->gs.tty && port->gs.xmit_cnt <= port->gs.wakeup_chars) {
-               if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                               port->gs.tty->ldisc.write_wakeup)
-                       (port->gs.tty->ldisc.write_wakeup)(port->gs.tty);
-               wake_up_interruptible(&port->gs.tty->write_wait);
-       }
+       if (port->gs.tty && port->gs.xmit_cnt <= port->gs.wakeup_chars) 
+               tty_wakeup(port->gs.tty);
 
        SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
 }
diff -urN linux/drivers/char/vt.c linux/drivers/char/vt.c
--- linux/drivers/char/vt.c     2003/01/11 17:53:12     1.34.2.2
+++ linux/drivers/char/vt.c     2004/12/27 04:13:43     1.34.2.3
@@ -588,8 +588,7 @@
                  default:
                        return -EINVAL;
                }
-               if (tty->ldisc.flush_buffer)
-                       tty->ldisc.flush_buffer(tty);
+               tty_ldisc_flush(tty);
                return 0;
 
        case KDGKBMODE:
diff -urN linux/drivers/char/ip2/i2lib.c linux/drivers/char/ip2/i2lib.c
--- linux/drivers/char/ip2/i2lib.c      2002/06/26 22:35:37     1.5.2.1
+++ linux/drivers/char/ip2/i2lib.c      2004/12/27 04:13:45     1.5.2.2
@@ -1385,15 +1385,9 @@
        ip2trace (CHANN, ITRC_SICMD, 10, 2, tp->flags,
                        (1 << TTY_DO_WRITE_WAKEUP) );
 
-       wake_up_interruptible ( &tp->write_wait );
-       if ( ( tp->flags & (1 << TTY_DO_WRITE_WAKEUP) ) 
-         && tp->ldisc.write_wakeup )
-       {
-               (tp->ldisc.write_wakeup) ( tp );
+       tty_wakeup(tp);
+       ip2trace (CHANN, ITRC_SICMD, 11, 0 );
 
-               ip2trace (CHANN, ITRC_SICMD, 11, 0 );
-
-       }
 }
 
 static inline void
diff -urN linux/drivers/char/pcmcia/synclink_cs.c 
linux/drivers/char/pcmcia/synclink_cs.c
--- linux/drivers/char/pcmcia/synclink_cs.c     2003/11/17 01:07:37     1.2.2.2
+++ linux/drivers/char/pcmcia/synclink_cs.c     2004/12/27 04:13:45     1.2.2.3
@@ -553,6 +553,29 @@
 static void* mgslpc_get_text_ptr(void);
 static void* mgslpc_get_text_ptr() {return mgslpc_get_text_ptr;}
 
+/**
+ * line discipline callback wrappers
+ *
+ * The wrappers maintain line discipline references
+ * while calling into the line discipline.
+ *
+ * ldisc_receive_buf  - pass receive data to line discipline
+ */
+
+static void ldisc_receive_buf(struct tty_struct *tty,
+                             const __u8 *data, char *flags, int count)
+{
+       struct tty_ldisc *ld;
+       if (!tty)
+               return;
+       ld = tty_ldisc_ref(tty);
+       if (ld) {
+               if (ld->receive_buf)
+                       ld->receive_buf(tty, data, flags, count);
+               tty_ldisc_deref(ld);
+       }
+}
+
 static dev_link_t *mgslpc_attach(void)
 {
     MGSLPC_INFO *info;
@@ -1027,13 +1050,7 @@
                printk("bh_transmit() entry on %s\n", info->device_name);
 
        if (tty) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup) {
-                       if ( debug_level >= DEBUG_LEVEL_BH )
-                               printk( "%s(%d):calling ldisc.write_wakeup on 
%s\n",
-                                       __FILE__,__LINE__,info->device_name);
-                       (tty->ldisc.write_wakeup)(tty);
-               }
+               tty_wakeup(tty);
                wake_up_interruptible(&tty->write_wait);
        }
 }
@@ -1917,11 +1934,9 @@
        info->tx_count = info->tx_put = info->tx_get = 0;
        del_timer(&info->tx_timer);     
        spin_unlock_irqrestore(&info->lock,flags);
-       
+
        wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
 }
 
 /* Send a high-priority XON/XOFF character
@@ -2685,9 +2700,8 @@
 
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-               
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       
+       tty_ldisc_flush(tty);
                
        shutdown(info);
        
@@ -4199,11 +4213,7 @@
                        } 
                        else
 #endif
-                       {
-                               /* Call the line discipline receive callback 
directly. */
-                               if (tty && tty->ldisc.receive_buf)
-                                       tty->ldisc.receive_buf(tty, buf->data, 
info->flag_buf, framesize);
-                       }
+                               ldisc_receive_buf(tty, buf->data, 
info->flag_buf, framesize);
                }
        }
 
diff -urN linux/drivers/char/rio/riointr.c linux/drivers/char/rio/riointr.c
--- linux/drivers/char/rio/riointr.c    2001/10/19 01:24:22     1.5
+++ linux/drivers/char/rio/riointr.c    2004/12/27 04:13:45     1.5.2.1
@@ -248,12 +248,9 @@
     rio_dprintk (RIO_DEBUG_INTR, "Waking up.... ldisc:%d (%d/%d)....",
                 (int)(PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)),
                 PortP->gs.wakeup_chars, PortP->gs.xmit_cnt); 
-    if ((PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-       PortP->gs.tty->ldisc.write_wakeup)
-      (PortP->gs.tty->ldisc.write_wakeup)(PortP->gs.tty);
+    tty_wakeup(PortP->gs.tty);
     rio_dprintk (RIO_DEBUG_INTR, "(%d/%d)\n",
                PortP->gs.wakeup_chars, PortP->gs.xmit_cnt); 
-    wake_up_interruptible(&PortP->gs.tty->write_wait);
   }
 
 }
diff -urN linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c
--- linux/drivers/isdn/Attic/isdn_tty.c 2001/12/29 05:37:55     1.24.2.1
+++ linux/drivers/isdn/Attic/isdn_tty.c 2004/12/27 04:13:45     1.24.2.2
@@ -321,10 +321,7 @@
                info->send_outstanding++;
                info->msr &= ~UART_MSR_CTS;
                info->lsr &= ~UART_LSR_TEMT;
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup) (tty);
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
                return;
        }
        if (slen < 0) {
@@ -1214,10 +1211,7 @@
                                                /* If DLE decoding results in 
zero-transmit, but
                                                 * c originally was non-zero, 
do a wakeup.
                                                 */
-                                               if ((tty->flags & (1 << 
TTY_DO_WRITE_WAKEUP)) &&
-                                                tty->ldisc.write_wakeup)
-                                                       
(tty->ldisc.write_wakeup) (tty);
-                                               
wake_up_interruptible(&tty->write_wait);
+                                               tty_wakeup(tty);
                                                info->msr |= UART_MSR_CTS;
                                                info->lsr |= UART_LSR_TEMT;
                                        }
@@ -1335,10 +1329,7 @@
        isdn_tty_cleanup_xmit(info);
        info->xmit_count = 0;
        restore_flags(flags);
-       wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup) (tty);
+       tty_wakeup(tty);
 }
 
 static void
@@ -1867,8 +1858,7 @@
        isdn_tty_shutdown(info);
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
        info->tty = 0;
        info->ncarrier = 0;
        tty->closing = 0;
@@ -2791,8 +2781,7 @@
                        restore_flags(flags);
                        return;
                }
-               if (info->tty->ldisc.flush_buffer)
-                       info->tty->ldisc.flush_buffer(info->tty);
+               tty_ldisc_flush(info->tty);
                if ((info->flags & ISDN_ASYNC_CHECK_CD) &&
                    (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
                       (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) {
diff -urN linux/drivers/macintosh/macserial.c 
linux/drivers/macintosh/macserial.c
--- linux/drivers/macintosh/macserial.c 2002/06/26 22:35:47     1.24.2.2
+++ linux/drivers/macintosh/macserial.c 2004/12/27 04:13:45     1.24.2.3
@@ -735,12 +735,8 @@
        if (!tty)
                return;
 
-       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup)(tty);
-               wake_up_interruptible(&tty->write_wait);
-       }
+       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) 
+               tty_wakeup(tty);
 }
 
 static int startup(struct mac_serial * info)
@@ -1595,10 +1591,7 @@
        save_flags(flags); cli();
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
        restore_flags(flags);
-       wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
 }
 
 /*
@@ -2029,8 +2022,7 @@
 
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
        tty->closing = 0;
        info->event = 0;
        info->tty = 0;
diff -urN linux/drivers/net/3c505.c linux/drivers/net/3c505.c
--- linux/drivers/net/3c505.c   2003/11/17 01:07:38     1.25.2.4
+++ linux/drivers/net/3c505.c   2004/12/27 04:13:45     1.25.2.5
@@ -32,7 +32,7 @@
  *              Linux 1.3.0 changes by
  *                      Alan Cox <Alan.Cox@linux.org>
  *              More debugging, DMA support, currently maintained by
- *                      Philip Blundell <Philip.Blundell@pobox.com>
+ *                      Philip Blundell <philb@gnu.org>
  *              Multicard/soft configurable dma channel/rev 2 hardware support
  *                      by Christopher Collins <ccollins@pcug.org.au>
  *             Ethtool support (jgarzik), 11/17/2001
diff -urN linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c
--- linux/drivers/net/eexpress.c        2003/08/13 17:19:18     1.22.2.4
+++ linux/drivers/net/eexpress.c        2004/12/27 04:13:45     1.22.2.5
@@ -7,7 +7,7 @@
  * Support for 8-bit mode by Zoltan Szilagyi <zoltans@cs.arizona.edu>
  *
  * Many modifications, and currently maintained, by
- *  Philip Blundell <Philip.Blundell@pobox.com>
+ *  Philip Blundell <philb@gnu.org>
  * Added the Compaq LTE  Alan Cox <alan@redhat.com>
  * Added MCA support Adam Fritzler <mid@auk.cx>
  *
diff -urN linux/drivers/net/forcedeth.c linux/drivers/net/forcedeth.c
--- linux/drivers/net/forcedeth.c       2004/11/29 17:47:16     1.3.2.2
+++ linux/drivers/net/forcedeth.c       2004/12/27 04:13:45     1.3.2.3
@@ -575,12 +575,6 @@
        return retval;
 }
 
-static void msleep(unsigned long msecs)
-{
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       schedule_timeout((HZ * msecs + 999) / 1000);
-}
-
 static int phy_reset(struct net_device *dev)
 {
        struct fe_priv *np = get_nvpriv(dev);
diff -urN linux/drivers/net/ppp_async.c linux/drivers/net/ppp_async.c
--- linux/drivers/net/ppp_async.c       2002/06/26 22:35:52     1.12.2.1
+++ linux/drivers/net/ppp_async.c       2004/12/27 04:13:45     1.12.2.2
@@ -117,6 +117,9 @@
  * frees the memory that ppp_asynctty_receive is using.  The best
  * way to fix this is to use a rwlock in the tty struct, but for now
  * we use a single global rwlock for all ttys in ppp line discipline.
+ *
+ * FIXME: this is no longer true. The _close path for the ldisc is 
+ * now guaranteed to be sane. 
  */
 static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED;
 
@@ -139,7 +142,8 @@
 }
 
 /*
- * Called when a tty is put into PPP line discipline.
+ * Called when a tty is put into PPP line discipline. Called in process
+ * context.
  */
 static int
 ppp_asynctty_open(struct tty_struct *tty)
@@ -227,6 +231,18 @@
 }
 
 /*
+ * Called on tty hangup in process context.
+ *
+ * Wait for I/O to driver to complete and unregister PPP channel.
+ * This is already done by the close routine, so just call that.
+ */
+static int ppp_asynctty_hangup(struct tty_struct *tty)
+{
+       ppp_asynctty_close(tty);
+       return 0;
+}
+
+/*
  * Read does nothing - no data is ever available this way.
  * Pppd reads and writes packets via /dev/ppp instead.
  */
@@ -248,6 +264,11 @@
        return -EAGAIN;
 }
 
+/*
+ * Called in process context only. May be re-entered by multiple
+ * ioctl calling threads.
+ */
+ 
 static int
 ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,
                   unsigned int cmd, unsigned long arg)
@@ -359,6 +380,7 @@
        write:  ppp_asynctty_write,
        ioctl:  ppp_asynctty_ioctl,
        poll:   ppp_asynctty_poll,
+       hangup: ppp_asynctty_hangup,
        receive_room: ppp_asynctty_room,
        receive_buf: ppp_asynctty_receive,
        write_wakeup: ppp_asynctty_wakeup,
@@ -714,7 +736,8 @@
 
 /*
  * Flush output from our internal buffers.
- * Called for the TCFLSH ioctl.
+ * Called for the TCFLSH ioctl. Can be entered in parallel
+ * but this is covered by the xmit_lock.
  */
 static void
 ppp_async_flush_output(struct asyncppp *ap)
@@ -819,7 +842,9 @@
        ppp_input_error(&ap->chan, code);
 }
 
-/* called when the tty driver has data for us. */
+/* Called when the tty driver has data for us. Runs parallel with the
+   other ldisc functions but will not be re-entered */
+
 static void
 ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
                char *flags, int count)
diff -urN linux/drivers/net/ppp_synctty.c linux/drivers/net/ppp_synctty.c
--- linux/drivers/net/ppp_synctty.c     2002/06/26 22:35:53     1.10.2.1
+++ linux/drivers/net/ppp_synctty.c     2004/12/27 04:13:45     1.10.2.2
@@ -172,6 +172,8 @@
  * frees the memory that ppp_synctty_receive is using.  The best
  * way to fix this is to use a rwlock in the tty struct, but for now
  * we use a single global rwlock for all ttys in ppp line discipline.
+ *
+ * FIXME: Fixed in tty_io nowdays.
  */
 static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED;
 
@@ -280,6 +282,18 @@
 }
 
 /*
+ * Called on tty hangup in process context.
+ *
+ * Wait for I/O to driver to complete and unregister PPP channel.
+ * This is already done by the close routine, so just call that.
+ */
+static int ppp_sync_hangup(struct tty_struct *tty)
+{
+       ppp_sync_close(tty);
+       return 0;
+}
+
+/*
  * Read does nothing - no data is ever available this way.
  * Pppd reads and writes packets via /dev/ppp instead.
  */
@@ -412,6 +426,7 @@
        write:  ppp_sync_write,
        ioctl:  ppp_synctty_ioctl,
        poll:   ppp_sync_poll,
+       hangup: ppp_sync_hangup,
        receive_room: ppp_sync_room,
        receive_buf: ppp_sync_receive,
        write_wakeup: ppp_sync_wakeup,
diff -urN linux/drivers/net/slip.c linux/drivers/net/slip.c
--- linux/drivers/net/slip.c    2002/09/11 12:45:06     1.19.2.2
+++ linux/drivers/net/slip.c    2004/12/27 04:13:45     1.19.2.3
@@ -670,7 +670,9 @@
  * Handle the 'receiver data ready' interrupt.
  * This function is called by the 'tty_io' module in the kernel when
  * a block of SLIP data has been received, which can now be decapsulated
- * and sent on to some IP layer for further processing.
+ * and sent on to some IP layer for further processing. This will not
+ * be re-entered while running but other ldisc functions may be called
+ * in parallel
  */
  
 static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, 
char *fp, int count)
@@ -826,9 +828,11 @@
  * SLIP line discipline is called for.  Because we are
  * sure the tty line exists, we only have to link it to
  * a free SLIP channel...
+ *
+ * Called in process context serialized from other ldisc calls.
  */
-static int
-slip_open(struct tty_struct *tty)
+
+static int slip_open(struct tty_struct *tty)
 {
        struct slip *sl;
        int err;
@@ -865,8 +869,6 @@
        sl->pid = current->pid;
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
 
        if (!test_bit(SLF_INUSE, &sl->flags)) {
                /* Perform the low-level SLIP initialization. */
@@ -910,6 +912,9 @@
 }
 
 /*
+
+  FIXME: 1,2 are fixed 3 was never true anyway.
+  
    Let me to blame a bit.
    1. TTY module calls this funstion on soft interrupt.
    2. TTY module calls this function WITH MASKED INTERRUPTS!
@@ -928,9 +933,8 @@
 
 /*
  * Close down a SLIP channel.
- * This means flushing out any pending queues, and then restoring the
- * TTY line discipline to what it was before it got hooked to SLIP
- * (which usually is TTY again).
+ * This means flushing out any pending queues, and then returning. This
+ * call is serialized against other ldisc functions.
  */
 static void
 slip_close(struct tty_struct *tty)
diff -urN linux/drivers/net/strip.c linux/drivers/net/strip.c
--- linux/drivers/net/Attic/strip.c     2001/12/02 11:34:43     1.21
+++ linux/drivers/net/Attic/strip.c     2004/12/27 04:13:45     1.21.2.1
@@ -2706,8 +2706,7 @@
     tty->disc_data = strip_info;
     if (tty->driver.flush_buffer)
         tty->driver.flush_buffer(tty);
-    if (tty->ldisc.flush_buffer)
-        tty->ldisc.flush_buffer(tty);
+    tty_ldisc_flush(tty);
 
     /*
      * Restore default settings
diff -urN linux/drivers/net/hamradio/6pack.c linux/drivers/net/hamradio/6pack.c
--- linux/drivers/net/hamradio/6pack.c  2004/08/14 18:38:53     1.11.2.2
+++ linux/drivers/net/hamradio/6pack.c  2004/12/27 04:13:46     1.11.2.3
@@ -571,8 +571,7 @@
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
 
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
 
        /* Restore default settings */
        sp->dev->type = ARPHRD_AX25;
diff -urN linux/drivers/net/hamradio/mkiss.c linux/drivers/net/hamradio/mkiss.c
--- linux/drivers/net/hamradio/mkiss.c  2003/08/13 17:19:19     1.14.2.3
+++ linux/drivers/net/hamradio/mkiss.c  2004/12/27 04:13:46     1.14.2.4
@@ -654,8 +654,7 @@
 
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
 
        /* Restore default settings */
        ax->dev->type = ARPHRD_AX25;
diff -urN linux/drivers/net/irda/irtty.c linux/drivers/net/irda/irtty.c
--- linux/drivers/net/irda/Attic/irtty.c        2003/02/25 22:03:08     1.22.2.2
+++ linux/drivers/net/irda/Attic/irtty.c        2004/12/27 04:13:46     1.22.2.3
@@ -179,9 +179,8 @@
 
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+
+       tty_ldisc_flush(tty);   
        
        self->magic = IRTTY_MAGIC;
        self->mode = IRDA_IRLAP;
diff -urN linux/drivers/net/wan/pc300_tty.c linux/drivers/net/wan/pc300_tty.c
--- linux/drivers/net/wan/pc300_tty.c   2004/11/19 00:28:41     1.10.2.2
+++ linux/drivers/net/wan/pc300_tty.c   2004/12/27 04:13:46     1.10.2.3
@@ -627,14 +627,8 @@
        }
 
        CPC_TTY_DBG("%s: call wake_up_interruptible\n",cpc_tty->name);
-       
-       wake_up_interruptible(&tty->write_wait); 
-
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && 
tty->ldisc.write_wakeup){
-               CPC_TTY_DBG("%s: call line disc. wake up\n",cpc_tty->name);
-               tty->ldisc.write_wakeup(tty); 
-       } 
 
+       tty_wakeup(tty);        
        return; 
 } 
 
@@ -699,12 +693,19 @@
                        cpc_tty = &cpc_tty_area[port];
                
                        if ((buf=cpc_tty->buf_rx.first) != 0) {
-                                                                               
                                        
-                               if (cpc_tty->tty && 
(cpc_tty->tty->ldisc.receive_buf)) { 
-                                       CPC_TTY_DBG("%s: call line disc. 
receive_buf\n",cpc_tty->name);
-                                       
cpc_tty->tty->ldisc.receive_buf(cpc_tty->tty, (const unsigned char *)buf->data, 
-                                                                               
                        &flags, buf->size);
-                               }       
+                               
+                               if(cpc_tty->tty) 
+                               {
+                                       struct tty_ldisc *ld = 
tty_ldisc_ref(cpc_tty->tty);
+                                       if(ld)
+                                       {
+                                               if (ld->receive_buf) {
+                                                       CPC_TTY_DBG("%s: call 
line disc. receive_buf\n",cpc_tty->name);
+                                                       
ld->receive_buf(cpc_tty->tty, (char *)(buf->data), &flags, buf->size);
+                                               }
+                                               tty_ldisc_deref(ld);
+                                       }
+                               }                                               
                                        
                                cpc_tty->buf_rx.first = 
cpc_tty->buf_rx.first->next;
                                kfree((unsigned char *)buf);
                                buf = cpc_tty->buf_rx.first;
@@ -908,12 +909,7 @@
                return; 
        }
 
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && 
tty->ldisc.write_wakeup){
-               CPC_TTY_DBG("%s:call line disc. wakeup\n",cpc_tty->name);
-               tty->ldisc.write_wakeup (tty); 
-       }
-
-       wake_up_interruptible(&tty->write_wait); 
+       tty_wakeup(tty);
 }
 
 /*
diff -urN linux/drivers/net/wan/sdla_chdlc.c linux/drivers/net/wan/sdla_chdlc.c
--- linux/drivers/net/wan/sdla_chdlc.c  2003/11/17 01:07:40     1.11.2.4
+++ linux/drivers/net/wan/sdla_chdlc.c  2004/12/27 04:13:46     1.11.2.5
@@ -3868,11 +3868,7 @@
        if ((tty=card->tty)==NULL)
                return;
        
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup){
-               (tty->ldisc.write_wakeup)(tty);
-       }
-       wake_up_interruptible(&tty->write_wait);
+       tty_wakeup(tty);
 #if defined(SERIAL_HAVE_POLL_WAIT) || \
          (defined LINUX_2_1 && LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,15))
        wake_up_interruptible(&tty->poll_wait);
@@ -4098,6 +4094,7 @@
        char fp=0;
        struct tty_struct *tty;
        int i;
+       struct tty_ldisc *ld;
        
        if (!card->tty_open){
                dbg_printk(KERN_INFO "%s: TTY not open during receive\n",
@@ -4185,8 +4182,11 @@
                        len -= offset;
                }
                sdla_peek(&card->hw, addr, card->tty_rx+offset, len);
-               if (tty->ldisc.receive_buf){
-                       tty->ldisc.receive_buf(tty,card->tty_rx,&fp,olen);
+               ld = tty_ldisc_ref(tty);
+               if (ld) {
+                       if (ld->receive_buf)
+                               ld->receive_buf(tty,card->tty_rx,&fp,olen);
+                       tty_ldisc_deref(ld);
                }else{
                        if (net_ratelimit()){
                                printk(KERN_INFO 
@@ -4493,14 +4493,11 @@
        if (!tty)
                return;
        
-       wake_up_interruptible(&tty->write_wait);
 #if defined(SERIAL_HAVE_POLL_WAIT) || \
          (defined LINUX_2_1 && LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,15))
        wake_up_interruptible(&tty->poll_wait);
 #endif
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
 
        return;
 }
diff -urN linux/drivers/net/wan/x25_asy.c linux/drivers/net/wan/x25_asy.c
--- linux/drivers/net/wan/x25_asy.c     2001/10/19 01:24:40     1.7
+++ linux/drivers/net/wan/x25_asy.c     2004/12/27 04:13:46     1.7.2.1
@@ -619,9 +619,7 @@
        if (tty->driver.flush_buffer)  {
                tty->driver.flush_buffer(tty);
        }
-       if (tty->ldisc.flush_buffer)  {
-               tty->ldisc.flush_buffer(tty);
-       }
+       tty_ldisc_flush(tty);
 
        /* Restore default settings */
        sl->dev->type = ARPHRD_X25;
diff -urN linux/drivers/net/wan/8253x/8253xsyn.c 
linux/drivers/net/wan/8253x/8253xsyn.c
--- linux/drivers/net/wan/8253x/Attic/8253xsyn.c        2002/06/26 22:36:01     
1.1.2.1
+++ linux/drivers/net/wan/8253x/Attic/8253xsyn.c        2004/12/27 04:13:48     
1.1.2.2
@@ -1108,10 +1108,7 @@
        {
                tty->driver.flush_buffer(tty);
        }
-       if (tty->ldisc.flush_buffer)
-       {
-               tty->ldisc.flush_buffer(tty);
-       }
+       tty_ldisc_flush(tty);
        tty->closing = 0;
        port->event = 0;
        port->tty = 0;
diff -urN linux/drivers/net/wan/8253x/8253xtty.c 
linux/drivers/net/wan/8253x/8253xtty.c
--- linux/drivers/net/wan/8253x/Attic/8253xtty.c        2003/07/05 03:23:40     
1.1.2.2
+++ linux/drivers/net/wan/8253x/Attic/8253xtty.c        2004/12/27 04:13:48     
1.1.2.3
@@ -691,10 +691,7 @@
        port->DoingInterrupt = 1;
        if (test_and_clear_bit(SAB8253X_EVENT_WRITE_WAKEUP, &port->event)) 
        {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup)(tty);
-               wake_up_interruptible(&tty->write_wait); /* in case tty driver 
waiting on write */
+               tty_wakeup(tty);
        }
        port->DoingInterrupt = 0;
 }
@@ -2001,10 +1998,7 @@
        {
                tty->driver.flush_buffer(tty);
        }
-       if (tty->ldisc.flush_buffer)
-       {
-               tty->ldisc.flush_buffer(tty);
-       }
+       tty_ldisc_flush(tty);
        tty->closing = 0;
        port->event = 0;
        port->tty = 0;
diff -urN linux/drivers/net/wan/8253x/8253xutl.c 
linux/drivers/net/wan/8253x/8253xutl.c
--- linux/drivers/net/wan/8253x/Attic/8253xutl.c        2002/06/26 22:36:01     
1.1.2.1
+++ linux/drivers/net/wan/8253x/Attic/8253xutl.c        2004/12/27 04:13:48     
1.1.2.2
@@ -1412,11 +1412,6 @@
        WRITEB(port,cmdr,SAB82532_CMDR_XRES);
        restore_flags(flags);
        
-       wake_up_interruptible(&tty->write_wait); /* wake up tty driver */
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-       {
-               (*tty->ldisc.write_wakeup)(tty);
-       }
+       tty_wakeup(tty);
 }
 
diff -urN linux/drivers/parport/ieee1284.c linux/drivers/parport/ieee1284.c
--- linux/drivers/parport/ieee1284.c    2001/11/06 07:56:01     1.12
+++ linux/drivers/parport/ieee1284.c    2004/12/27 04:13:48     1.12.2.1
@@ -1,7 +1,7 @@
 /* $Id: parport_ieee1284.c,v 1.4 1997/10/19 21:37:21 philip Exp $
  * IEEE-1284 implementation for parport.
  *
- * Authors: Phil Blundell <Philip.Blundell@pobox.com>
+ * Authors: Phil Blundell <philb@gnu.org>
  *          Carsten Gross <carsten@sol.wohnheim.uni-ulm.de>
  *         Jose Renau <renau@acm.org>
  *          Tim Waugh <tim@cyberelk.demon.co.uk> (largely rewritten)
diff -urN linux/drivers/parport/parport_arc.c 
linux/drivers/parport/parport_arc.c
--- linux/drivers/parport/parport_arc.c 2001/03/09 20:34:14     1.2
+++ linux/drivers/parport/parport_arc.c 2004/12/27 04:13:48     1.2.2.1
@@ -1,6 +1,6 @@
 /* Low-level parallel port routines for Archimedes onboard hardware
  *
- * Author: Phil Blundell <Philip.Blundell@pobox.com>
+ * Author: Phil Blundell <philb@gnu.org>
  */
 
 /* This driver is for the parallel port hardware found on Acorn's old
diff -urN linux/drivers/parport/parport_gsc.c 
linux/drivers/parport/parport_gsc.c
--- linux/drivers/parport/parport_gsc.c 2002/09/11 12:45:09     1.5.2.1
+++ linux/drivers/parport/parport_gsc.c 2004/12/27 04:13:48     1.5.2.2
@@ -12,7 +12,7 @@
  * 
  * based on parport_pc.c by 
  *         Grant Guenther <grant@torque.net>
- *         Phil Blundell <Philip.Blundell@pobox.com>
+ *         Phil Blundell <philb@gnu.org>
  *          Tim Waugh <tim@cyberelk.demon.co.uk>
  *         Jose Renau <renau@acm.org>
  *          David Campbell <campbell@torque.net>
diff -urN linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
--- linux/drivers/parport/parport_pc.c  2004/11/19 00:28:41     1.39.2.7
+++ linux/drivers/parport/parport_pc.c  2004/12/27 04:13:48     1.39.2.8
@@ -1,6 +1,6 @@
 /* Low-level parallel-port routines for 8255-based PC-style hardware.
  * 
- * Authors: Phil Blundell <Philip.Blundell@pobox.com>
+ * Authors: Phil Blundell <philb@gnu.org>
  *          Tim Waugh <tim@cyberelk.demon.co.uk>
  *         Jose Renau <renau@acm.org>
  *          David Campbell <campbell@torque.net>
diff -urN linux/drivers/parport/parport_sunbpp.c 
linux/drivers/parport/parport_sunbpp.c
--- linux/drivers/parport/parport_sunbpp.c      2001/08/22 03:24:45     1.6
+++ linux/drivers/parport/parport_sunbpp.c      2004/12/27 04:13:48     1.6.2.1
@@ -4,7 +4,7 @@
  * Author: Derrick J. Brashear <shadow@dementia.org>
  *
  * based on work by:
- *          Phil Blundell <Philip.Blundell@pobox.com>
+ *          Phil Blundell <philb@gnu.org>
  *          Tim Waugh <tim@cyberelk.demon.co.uk>
  *         Jose Renau <renau@acm.org>
  *          David Campbell <campbell@tirian.che.curtin.edu.au>
diff -urN linux/drivers/parport/probe.c linux/drivers/parport/probe.c
--- linux/drivers/parport/probe.c       2001/06/14 04:24:07     1.6
+++ linux/drivers/parport/probe.c       2004/12/27 04:13:48     1.6.2.1
@@ -2,7 +2,7 @@
  * Parallel port device probing code
  *
  * Authors:    Carsten Gross, carsten@sol.wohnheim.uni-ulm.de
- *             Philip Blundell <Philip.Blundell@pobox.com>
+ *             Philip Blundell <philb@gnu.org>
  */
 
 #include <linux/parport.h>
diff -urN linux/drivers/s390/char/con3215.c linux/drivers/s390/char/con3215.c
--- linux/drivers/s390/char/con3215.c   2003/08/13 17:19:20     1.8.2.2
+++ linux/drivers/s390/char/con3215.c   2004/12/27 04:13:48     1.8.2.3
@@ -363,10 +363,7 @@
        tty = raw->tty;
        if (tty != NULL &&
            RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup)(tty);
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
        }
 }
 
@@ -978,10 +975,7 @@
 
        raw = (raw3215_info *) tty->driver_data;
        raw3215_flush_buffer(raw);
-       wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
 }
 
 /*
diff -urN linux/drivers/s390/char/tubtty.c linux/drivers/s390/char/tubtty.c
--- linux/drivers/s390/char/Attic/tubtty.c      2003/01/11 17:53:15     1.4.2.3
+++ linux/drivers/s390/char/Attic/tubtty.c      2004/12/27 04:13:48     1.4.2.4
@@ -445,10 +445,7 @@
                ob->bc_cnt = 0;
                TUBUNLOCK(tubp->irq, flags);
        }
-       wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
 }
 
 static int
@@ -646,10 +643,7 @@
        }
 
        if (tty != NULL) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup != NULL)
-                       (tty->ldisc.write_wakeup)(tty);
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
        }
 do_unlock:
        TUBUNLOCK(tubp->irq, flags);
diff -urN linux/drivers/s390/net/ctctty.c linux/drivers/s390/net/ctctty.c
--- linux/drivers/s390/net/ctctty.c     2003/11/17 01:07:40     1.2.2.3
+++ linux/drivers/s390/net/ctctty.c     2004/12/27 04:13:49     1.2.2.4
@@ -362,9 +362,8 @@
 
                info->flags &= ~CTC_ASYNC_TX_LINESTAT;
                if (tty) {
-                       if (wake && (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                           tty->ldisc.write_wakeup)
-                               (tty->ldisc.write_wakeup)(tty);
+                       if (wake)
+                               tty_wakeup(tty);
                        wake_up_interruptible(&tty->write_wait);
                }
        }
@@ -655,10 +654,7 @@
        skb_queue_purge(&info->tx_queue);
        info->lsr |= UART_LSR_TEMT;
        restore_flags(flags);
-       wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup) (tty);
+       tty_wakeup(tty);
 }
 
 static void
@@ -1168,8 +1164,7 @@
        ctc_tty_shutdown(info);
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
        spin_lock_irqsave(&ctc_tty_lock, saveflags);
        info->tty = 0;
        spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
diff -urN linux/drivers/sbus/char/aurora.c linux/drivers/sbus/char/aurora.c
--- linux/drivers/sbus/char/aurora.c    2002/09/11 12:45:10     1.13.2.2
+++ linux/drivers/sbus/char/aurora.c    2004/12/27 04:13:49     1.13.2.3
@@ -1573,8 +1573,7 @@
        aurora_shutdown_port(bp, port);
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
        tty->closing = 0;
        port->event = 0;
        port->tty = 0;
@@ -1785,11 +1784,8 @@
        save_flags(flags); cli();
        port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
        restore_flags(flags);
-       
-       wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+
+       tty_wakeup(tty);        
 #ifdef AURORA_DEBUG
        printk("aurora_flush_buffer: end\n");
 #endif
@@ -2286,10 +2282,7 @@
                return;
 
        if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup)(tty);
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
        }
 #ifdef AURORA_DEBUG
        printk("do_softint: end\n");
diff -urN linux/drivers/sbus/char/sab82532.c linux/drivers/sbus/char/sab82532.c
--- linux/drivers/sbus/char/Attic/sab82532.c    2002/06/26 22:36:04     1.28.2.1
+++ linux/drivers/sbus/char/Attic/sab82532.c    2004/12/27 04:13:49     1.28.2.2
@@ -669,10 +669,7 @@
                return;
 
        if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup)(tty);
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
        }
 }
 
@@ -1206,10 +1203,7 @@
        info->xmit.head = info->xmit.tail = 0;
        restore_flags(flags);
 
-       wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
 }
 
 /*
@@ -1667,8 +1661,7 @@
        shutdown(info);
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
        tty->closing = 0;
        info->event = 0;
        info->tty = 0;
diff -urN linux/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c
--- linux/drivers/sbus/char/Attic/su.c  2002/06/26 22:36:04     1.25.2.1
+++ linux/drivers/sbus/char/Attic/su.c  2004/12/27 04:13:49     1.25.2.2
@@ -698,10 +698,7 @@
                return;
 
        if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup)(tty);
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
        }
 }
 
@@ -1313,10 +1310,7 @@
        save_flags(flags); cli();
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
        restore_flags(flags);
-       wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
 }
 
 /*
@@ -1815,8 +1809,7 @@
        shutdown(info);
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
        tty->closing = 0;
        info->event = 0;
        info->tty = 0;
diff -urN linux/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c
--- linux/drivers/sbus/char/Attic/zs.c  2002/06/26 22:36:04     1.25.2.2
+++ linux/drivers/sbus/char/Attic/zs.c  2004/12/27 04:13:49     1.25.2.3
@@ -746,10 +746,7 @@
                return;
 
        if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup)(tty);
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
        }
 }
 
@@ -1199,10 +1196,7 @@
        cli();
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
        sti();
-       wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
 }
 
 /*
@@ -1600,15 +1594,14 @@
        shutdown(info);
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
        tty->closing = 0;
        info->event = 0;
        info->tty = 0;
-       if (tty->ldisc.num != ldiscs[N_TTY].num) {
+       if (tty->ldisc.num != N_TTY) {
                if (tty->ldisc.close)
                        (tty->ldisc.close)(tty);
-               tty->ldisc = ldiscs[N_TTY];
+               tty->ldisc = *(tty_ldisc_get(N_TTY));
                tty->termios->c_line = N_TTY;
                if (tty->ldisc.open)
                        (tty->ldisc.open)(tty);
diff -urN linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- linux/drivers/scsi/Attic/Config.in  2004/11/29 17:47:17     1.36.2.14
+++ linux/drivers/scsi/Attic/Config.in  2004/12/27 04:13:49     1.36.2.15
@@ -72,7 +72,7 @@
 dep_tristate '  AHCI SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_AHCI 
$CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
 dep_tristate '  ServerWorks Frodo / Apple K2 SATA support (EXPERIMENTAL)' 
CONFIG_SCSI_SATA_SVW $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
 dep_tristate '  Intel PIIX/ICH SATA support' CONFIG_SCSI_ATA_PIIX 
$CONFIG_SCSI_SATA $CONFIG_PCI
-dep_tristate '  NVIDIA SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_NV 
$CONFIG_SCSI_SATA $CONFIG_PCI
+dep_tristate '  NVIDIA SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_NV 
$CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
 dep_tristate '  Promise SATA TX2/TX4 support (EXPERIMENTAL)' 
CONFIG_SCSI_SATA_PROMISE $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
 dep_tristate '  Promise SATA SX4 support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SX4 
$CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
 dep_tristate '  Silicon Image SATA support (EXPERIMENTAL)' 
CONFIG_SCSI_SATA_SIL $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
diff -urN linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c
--- linux/drivers/scsi/advansys.c       2004/11/19 00:28:43     1.22.2.3
+++ linux/drivers/scsi/advansys.c       2004/12/27 04:13:49     1.22.2.4
@@ -713,7 +713,7 @@
      Tom Rini <trini@kernel.crashing.org> provided the CONFIG_ISA
      patch and helped with PowerPC wide and narrow board support.
 
-     Philip Blundell <philip.blundell@pobox.com> provided an
+     Philip Blundell <philb@gnu.org> provided an
      advansys_interrupts_enabled patch.
 
      Dave Jones <dave@denial.force9.co.uk> reported the compiler
diff -urN linux/drivers/scsi/ahci.c linux/drivers/scsi/ahci.c
--- linux/drivers/scsi/ahci.c   2004/11/29 17:47:17     1.2.2.1
+++ linux/drivers/scsi/ahci.c   2004/12/27 04:13:49     1.2.2.2
@@ -231,7 +231,8 @@
        {
                .sht            = &ahci_sht,
                .host_flags     = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO,
+                                 ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
+                                 ATA_FLAG_PIO_DMA,
                .pio_mask       = 0x03, /* pio3-4 */
                .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
                .port_ops       = &ahci_ops,
diff -urN linux/drivers/scsi/dpt_i2o.c linux/drivers/scsi/dpt_i2o.c
--- linux/drivers/scsi/dpt_i2o.c        2004/11/19 00:28:43     1.4.2.3
+++ linux/drivers/scsi/dpt_i2o.c        2004/12/27 04:13:49     1.4.2.4
@@ -3,7 +3,7 @@
                              -------------------
     begin                : Thu Sep 7 2000
     copyright            : (C) 2000 by Adaptec
-    email                : deanna_bonds@adaptec.com
+    email                : aacraid@adaptec.com
 
                           July 30, 2001 First version being submitted
                           for inclusion in the kernel.  V2.4
diff -urN linux/drivers/scsi/dpti.h linux/drivers/scsi/dpti.h
--- linux/drivers/scsi/dpti.h   2001/10/19 01:24:42     1.1
+++ linux/drivers/scsi/dpti.h   2004/12/27 04:13:49     1.1.2.1
@@ -3,7 +3,7 @@
                              -------------------
     begin                : Thu Sep 7 2000
     copyright            : (C) 2001 by Adaptec
-    email                : deanna_bonds@adaptec.com
+    email                : aacraid@adaptec.com
 
     See README.dpti for history, notes, license info, and credits
  ***************************************************************************/
diff -urN linux/drivers/scsi/libata-core.c linux/drivers/scsi/libata-core.c
--- linux/drivers/scsi/libata-core.c    2004/11/29 17:47:17     1.16.2.3
+++ linux/drivers/scsi/libata-core.c    2004/12/27 04:13:49     1.16.2.4
@@ -1949,8 +1949,6 @@
        sg->page = virt_to_page(buf);
        sg->offset = (unsigned long) buf & ~PAGE_MASK;
        sg_dma_len(sg) = buflen;
-
-       WARN_ON(buflen > PAGE_SIZE);
 }
 
 void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
@@ -2693,6 +2691,30 @@
        VPRINTK("EXIT\n");
 }
 
+static inline int ata_should_dma_map(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+
+       switch (qc->tf.protocol) {
+       case ATA_PROT_DMA:
+       case ATA_PROT_ATAPI_DMA:
+               return 1;
+
+       case ATA_PROT_ATAPI:
+       case ATA_PROT_PIO:
+       case ATA_PROT_PIO_MULT:
+               if (ap->flags & ATA_FLAG_PIO_DMA)
+                       return 1;
+
+               /* fall through */
+       
+       default:
+               return 0;
+       }
+
+       /* never reached */
+}
+
 /**
  *     ata_qc_issue - issue taskfile to device
  *     @qc: command to issue to device
@@ -2713,12 +2735,16 @@
 {
        struct ata_port *ap = qc->ap;
 
-       if (qc->flags & ATA_QCFLAG_SG) {
-               if (ata_sg_setup(qc))
-                       goto err_out;
-       } else if (qc->flags & ATA_QCFLAG_SINGLE) {
-               if (ata_sg_setup_one(qc))
-                       goto err_out;
+       if (ata_should_dma_map(qc)) {
+               if (qc->flags & ATA_QCFLAG_SG) {
+                       if (ata_sg_setup(qc))
+                               goto err_out;
+               } else if (qc->flags & ATA_QCFLAG_SINGLE) {
+                       if (ata_sg_setup_one(qc))
+                               goto err_out;
+               }
+       } else {
+               qc->flags &= ~ATA_QCFLAG_DMAMAP;
        }
 
        ap->ops->qc_prep(qc);
diff -urN linux/drivers/scsi/libata-scsi.c linux/drivers/scsi/libata-scsi.c
--- linux/drivers/scsi/libata-scsi.c    2004/11/29 17:47:17     1.10.2.3
+++ linux/drivers/scsi/libata-scsi.c    2004/12/27 04:13:49     1.10.2.4
@@ -860,7 +860,7 @@
        };
        memcpy(rbuf, hdr, sizeof(hdr));
 
-       if (buflen > (ATA_SERNO_LEN + 4))
+       if (buflen > (ATA_SERNO_LEN + 4 - 1))
                ata_dev_id_string(args->id, (unsigned char *) &rbuf[4],
                                  ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
 
@@ -889,7 +889,7 @@
        rbuf[3] = 4 + strlen(inq_83_str);       /* page len */
 
        /* our one and only identification descriptor (vendor-specific) */
-       if (buflen > (strlen(inq_83_str) + 4 + 4)) {
+       if (buflen > (strlen(inq_83_str) + 4 + 4 - 1)) {
                rbuf[4 + 0] = 2;        /* code set: ASCII */
                rbuf[4 + 3] = strlen(inq_83_str);
                memcpy(rbuf + 4 + 4, inq_83_str, strlen(inq_83_str));
diff -urN linux/drivers/scsi/aacraid/README linux/drivers/scsi/aacraid/README
--- linux/drivers/scsi/aacraid/README   2003/08/13 17:19:21     1.1.2.4
+++ linux/drivers/scsi/aacraid/README   2004/12/27 04:13:50     1.1.2.5
@@ -30,7 +30,7 @@
 Alan Cox <alan@redhat.com>
 Christoph Hellwig <hch@infradead.org>  (small cleanups/fixes)
 Matt Domsch <matt_domsch@dell.com>     (revision ioctl, adapter messages)
-Deanna Bonds <deanna_bonds@adaptec.com> (non-DASD support, PAE fibs and 64 
bit, added new adaptec controllers
+Deanna Bonds                            (non-DASD support, PAE fibs and 64 
bit, added new adaptec controllers
                                         added new ioctls, changed scsi 
interface to use new error handler,
                                         increased the number of fibs and 
outstanding commands to a container)
 
diff -urN linux/drivers/scsi/dpt/dpti_ioctl.h 
linux/drivers/scsi/dpt/dpti_ioctl.h
--- linux/drivers/scsi/dpt/dpti_ioctl.h 2001/10/19 01:24:46     1.1
+++ linux/drivers/scsi/dpt/dpti_ioctl.h 2004/12/27 04:13:50     1.1.2.1
@@ -3,7 +3,7 @@
                              -------------------
     begin                : Thu Sep 7 2000
     copyright            : (C) 2001 by Adaptec
-    email                : deanna_bonds@adaptec.com
+    email                : aacraid@adaptec.com
 
     See README.dpti for history, notes, license info, and credits
  ***************************************************************************/
diff -urN linux/drivers/tc/zs.c linux/drivers/tc/zs.c
--- linux/drivers/tc/zs.c       2004/07/08 12:00:08     1.19.2.23
+++ linux/drivers/tc/zs.c       2004/12/27 04:13:50     1.19.2.24
@@ -675,10 +675,7 @@
                return;
 
        if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup)(tty);
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
        }
 }
 
@@ -1000,10 +997,7 @@
        cli();
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
        sti();
-       wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
 }
 
 /*
@@ -1411,8 +1405,7 @@
        shutdown(info);
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
        tty->closing = 0;
        info->event = 0;
        info->tty = 0;
diff -urN linux/drivers/usb/acm.c linux/drivers/usb/acm.c
--- linux/drivers/usb/Attic/acm.c       2003/11/17 01:07:42     1.32.2.4
+++ linux/drivers/usb/Attic/acm.c       2004/12/27 04:13:50     1.32.2.5
@@ -285,10 +285,7 @@
 
        if (!ACM_READY(acm)) return;
 
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && 
tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
-
-       wake_up_interruptible(&tty->write_wait);
+       tty_wakeup(tty);
 }
 
 /*
diff -urN linux/drivers/usb/bluetooth.c linux/drivers/usb/bluetooth.c
--- linux/drivers/usb/Attic/bluetooth.c 2003/11/17 01:07:42     1.17.2.2
+++ linux/drivers/usb/Attic/bluetooth.c 2004/12/27 04:13:50     1.17.2.3
@@ -1017,6 +1017,7 @@
 {
        struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct 
usb_bluetooth *)private, __FUNCTION__);
        struct tty_struct *tty;
+       struct tty_ldisc *ld;
 
        dbg("%s", __FUNCTION__);
 
@@ -1025,9 +1026,15 @@
        }
 
        tty = bluetooth->tty;
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && 
tty->ldisc.write_wakeup) {
-               dbg("%s - write wakeup call.", __FUNCTION__);
-               (tty->ldisc.write_wakeup)(tty);
+       if (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) {
+               ld = tty_ldisc_ref(tty);
+               if(ld) {
+                       if(ld->write_wakeup) {
+                               ld->write_wakeup(tty);
+                               dbg("%s - write wakeup call.", __FUNCTION__);
+                       }
+                       tty_ldisc_deref(tty);
+               }
        }
 
        wake_up_interruptible(&tty->write_wait);
diff -urN linux/drivers/usb/gadget/Config.in linux/drivers/usb/gadget/Config.in
--- linux/drivers/usb/gadget/Attic/Config.in    2004/08/14 18:38:56     1.1.2.4
+++ linux/drivers/usb/gadget/Attic/Config.in    2004/12/27 04:13:50     1.1.2.5
@@ -52,9 +52,9 @@
   comment 'USB Gadget Drivers'
 
   dep_tristate '  Gadget Zero (DEVELOPMENT)' CONFIG_USB_ZERO 
$CONFIG_USB_GADGET_CONTROLLER
-  dep_tristate '  Ethernet Gadget (EXPERIMENTAL)' CONFIG_USB_ETH 
$CONFIG_USB_GADGET_CONTROLLER $CONFIG_NET
+  dep_tristate '  Ethernet Gadget' CONFIG_USB_ETH 
$CONFIG_USB_GADGET_CONTROLLER $CONFIG_NET
   if [ "$CONFIG_USB_ETH" = "y" -o "$CONFIG_USB_ETH" = "m" ] ; then
-    bool       '    RNDIS support (EXPERIMENTAL)' CONFIG_USB_ETH_RNDIS
+    dep_bool       '    RNDIS support (EXPERIMENTAL)' CONFIG_USB_ETH_RNDIS 
$CONFIG_EXPERIMENTAL
   fi
   dep_tristate '  File-backed Storage Gadget (DEVELOPMENT)' 
CONFIG_USB_FILE_STORAGE $CONFIG_USB_GADGET_CONTROLLER
   dep_mbool '    File-backed Storage Gadget test mode' 
CONFIG_USB_FILE_STORAGE_TEST $CONFIG_USB_FILE_STORAGE
diff -urN linux/drivers/usb/gadget/epautoconf.c 
linux/drivers/usb/gadget/epautoconf.c
--- linux/drivers/usb/gadget/epautoconf.c       2004/08/14 18:38:56     1.3.2.1
+++ linux/drivers/usb/gadget/epautoconf.c       2004/12/27 04:13:50     1.3.2.2
@@ -56,6 +56,9 @@
  *
  * Type suffixes are "-bulk", "-iso", or "-int".  Numbers are decimal.
  * Less common restrictions are implied by gadget_is_*().
+ *
+ * NOTE:  each endpoint is unidirectional, as specified by its USB
+ * descriptor.
  */
 static int __init
 ep_matches (
@@ -193,7 +196,7 @@
                if (0 == strcmp (ep->name, name))
                        return ep;
        }
-       return 0;
+       return NULL;
 }
 
 /**
@@ -281,7 +284,7 @@
        }
 
        /* Fail */
-       return 0;
+       return NULL;
 }
 
 /**
@@ -298,7 +301,7 @@
        struct usb_ep   *ep;
 
        list_for_each_entry (ep, &gadget->ep_list, ep_list) {
-               ep->driver_data = 0;
+               ep->driver_data = NULL;
        }
 #ifdef MANY_ENDPOINTS
        in_epnum = 0;
diff -urN linux/drivers/usb/gadget/ether.c linux/drivers/usb/gadget/ether.c
--- linux/drivers/usb/gadget/ether.c    2004/08/14 18:38:56     1.5.2.4
+++ linux/drivers/usb/gadget/ether.c    2004/12/27 04:13:50     1.5.2.5
@@ -62,6 +62,7 @@
 
 /*
  * Ethernet gadget driver -- with CDC and non-CDC options
+ * Builds on hardware support for a full duplex link.
  *
  * CDC Ethernet is the standard USB solution for sending Ethernet frames
  * using USB.  Real hardware tends to use the same framing protocol but look
@@ -82,7 +83,7 @@
  */
 
 #define DRIVER_DESC            "Ethernet Gadget"
-#define DRIVER_VERSION         "St Patrick's Day 2004"
+#define DRIVER_VERSION         "Equinox 2004"
 
 static const char shortname [] = "ether";
 static const char driver_desc [] = DRIVER_DESC;
@@ -239,6 +240,10 @@
 #define        DEV_CONFIG_CDC
 #endif
 
+#ifdef CONFIG_USB_GADGET_LH7A40X
+#define DEV_CONFIG_CDC
+#endif
+
 #ifdef CONFIG_USB_GADGET_MQ11XX
 #define        DEV_CONFIG_CDC
 #endif
@@ -247,6 +252,14 @@
 #define        DEV_CONFIG_CDC
 #endif
 
+#ifdef CONFIG_USB_GADGET_N9604
+#define        DEV_CONFIG_CDC
+#endif
+
+#ifdef CONFIG_USB_GADGET_PXA27X
+#define DEV_CONFIG_CDC
+#endif
+
 
 /* For CDC-incapable hardware, choose the simple cdc subset.
  * Anything that talks bulk (without notable bugs) can do this.
@@ -355,6 +368,9 @@
  *
  * NOTE:  Controllers like superh_udc should probably be able to use
  * an RNDIS-only configuration.
+ *
+ * FIXME define some higher-powered configurations to make it easier
+ * to recharge batteries ...
  */
 
 #define DEV_CONFIG_VALUE       1       /* cdc or subset */
@@ -378,6 +394,14 @@
        .bNumConfigurations =   1,
 };
 
+static struct usb_otg_descriptor
+otg_descriptor = {
+       .bLength =              sizeof otg_descriptor,
+       .bDescriptorType =      USB_DT_OTG,
+
+       .bmAttributes =         USB_OTG_SRP,
+};
+
 static struct usb_config_descriptor
 eth_config = {
        .bLength =              sizeof eth_config,
@@ -388,11 +412,11 @@
        .bConfigurationValue =  DEV_CONFIG_VALUE,
        .iConfiguration =       STRING_CDC,
        .bmAttributes =         USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
-       .bMaxPower =            1,
+       .bMaxPower =            50,
 };
 
 #ifdef CONFIG_USB_ETH_RNDIS
-static const struct usb_config_descriptor 
+static struct usb_config_descriptor 
 rndis_config = {
        .bLength =              sizeof rndis_config,
        .bDescriptorType =      USB_DT_CONFIG,
@@ -402,7 +426,7 @@
        .bConfigurationValue =  DEV_RNDIS_CONFIG_VALUE,
        .iConfiguration =       STRING_RNDIS,
        .bmAttributes =         USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
-       .bMaxPower =            1,
+       .bMaxPower =            50,
 };
 #endif
 
@@ -688,7 +712,8 @@
        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
 };
 
-static const struct usb_descriptor_header *fs_eth_function [10] = {
+static const struct usb_descriptor_header *fs_eth_function [11] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
 #ifdef DEV_CONFIG_CDC
        /* "cdc" mode descriptors */
        (struct usb_descriptor_header *) &control_intf,
@@ -702,24 +727,25 @@
        (struct usb_descriptor_header *) &data_intf,
        (struct usb_descriptor_header *) &fs_source_desc,
        (struct usb_descriptor_header *) &fs_sink_desc,
-       0,
+       NULL,
 #endif /* DEV_CONFIG_CDC */
 };
 
 static inline void __init fs_subset_descriptors(void)
 {
 #ifdef DEV_CONFIG_SUBSET
-       fs_eth_function[0] = (struct usb_descriptor_header *) &subset_data_intf;
-       fs_eth_function[1] = (struct usb_descriptor_header *) &fs_source_desc;
-       fs_eth_function[2] = (struct usb_descriptor_header *) &fs_sink_desc;
-       fs_eth_function[3] = 0;
+       fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
+       fs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc;
+       fs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc;
+       fs_eth_function[4] = NULL;
 #else
-       fs_eth_function[0] = 0;
+       fs_eth_function[1] = NULL;
 #endif
 }
 
 #ifdef CONFIG_USB_ETH_RNDIS
 static const struct usb_descriptor_header *fs_rndis_function [] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
        /* control interface matches ACM, not Ethernet */
        (struct usb_descriptor_header *) &rndis_control_intf,
        (struct usb_descriptor_header *) &header_desc,
@@ -731,7 +757,7 @@
        (struct usb_descriptor_header *) &rndis_data_intf,
        (struct usb_descriptor_header *) &fs_source_desc,
        (struct usb_descriptor_header *) &fs_sink_desc,
-       0,
+       NULL,
 };
 #endif
 
@@ -783,7 +809,8 @@
        .bNumConfigurations =   1,
 };
 
-static const struct usb_descriptor_header *hs_eth_function [10] = {
+static const struct usb_descriptor_header *hs_eth_function [11] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
 #ifdef DEV_CONFIG_CDC
        /* "cdc" mode descriptors */
        (struct usb_descriptor_header *) &control_intf,
@@ -797,24 +824,25 @@
        (struct usb_descriptor_header *) &data_intf,
        (struct usb_descriptor_header *) &hs_source_desc,
        (struct usb_descriptor_header *) &hs_sink_desc,
-       0,
+       NULL,
 #endif /* DEV_CONFIG_CDC */
 };
 
 static inline void __init hs_subset_descriptors(void)
 {
 #ifdef DEV_CONFIG_SUBSET
-       hs_eth_function[0] = (struct usb_descriptor_header *) &subset_data_intf;
-       hs_eth_function[1] = (struct usb_descriptor_header *) &fs_source_desc;
-       hs_eth_function[2] = (struct usb_descriptor_header *) &fs_sink_desc;
-       hs_eth_function[3] = 0;
+       hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
+       hs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc;
+       hs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc;
+       hs_eth_function[4] = NULL;
 #else
-       hs_eth_function[0] = 0;
+       hs_eth_function[1] = NULL;
 #endif
 }
 
 #ifdef CONFIG_USB_ETH_RNDIS
 static const struct usb_descriptor_header *hs_rndis_function [] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
        /* control interface matches ACM, not Ethernet */
        (struct usb_descriptor_header *) &rndis_control_intf,
        (struct usb_descriptor_header *) &header_desc,
@@ -826,7 +854,7 @@
        (struct usb_descriptor_header *) &rndis_data_intf,
        (struct usb_descriptor_header *) &hs_source_desc,
        (struct usb_descriptor_header *) &hs_sink_desc,
-       0,
+       NULL,
 };
 #endif
 
@@ -849,7 +877,7 @@
 
 /* descriptors that are built on-demand */
 
-static char                            manufacturer [40];
+static char                            manufacturer [50];
 static char                            product_desc [40] = DRIVER_DESC;
 
 #ifdef DEV_CONFIG_CDC
@@ -857,7 +885,7 @@
 static char                            ethaddr [2 * ETH_ALEN + 1];
 #endif
 
-/* static strings, in iso 8859/1 */
+/* static strings, in UTF-8 */
 static struct usb_string               strings [] = {
        { STRING_MANUFACTURER,  manufacturer, },
        { STRING_PRODUCT,       product_desc, },
@@ -887,19 +915,21 @@
  * complications: class descriptors, and an altsetting.
  */
 static int
-config_buf (enum usb_device_speed speed, u8 *buf, u8 type, unsigned index)
-{
-       int                             len;
+config_buf (enum usb_device_speed speed,
+       u8 *buf, u8 type,
+       unsigned index, int is_otg)
+{
+       int                                     len;
+       const struct usb_config_descriptor      *config;
+       const struct usb_descriptor_header      **function;
 #ifdef CONFIG_USB_GADGET_DUALSPEED
        int                             hs = (speed == USB_SPEED_HIGH);
 
        if (type == USB_DT_OTHER_SPEED_CONFIG)
                hs = !hs;
-#define which_config(t)        (hs ? & t ## _config   : & t ## _config)
-#define which_fn(t)    (hs ? & hs_ ## t ## _function : & fs_ ## t ## _function)
+#define which_fn(t)    (hs ? hs_ ## t ## _function : fs_ ## t ## _function)
 #else
-#define        which_config(t) (& t ## _config)
-#define        which_fn(t)     (& fs_ ## t ## _function)
+#define        which_fn(t)     (fs_ ## t ## _function)
 #endif
 
        if (index >= device_desc.bNumConfigurations)
@@ -909,15 +939,21 @@
        /* list the RNDIS config first, to make Microsoft's drivers
         * happy. DOCSIS 1.0 needs this too.
         */
-       if (device_desc.bNumConfigurations == 2 && index == 0)
-               len = usb_gadget_config_buf (which_config (rndis), buf,
-                       USB_BUFSIZ, (const struct usb_descriptor_header **)
-                               which_fn (rndis));
-       else
+       if (device_desc.bNumConfigurations == 2 && index == 0) {
+               config = &rndis_config;
+               function = which_fn (rndis);
+       } else
 #endif
-               len = usb_gadget_config_buf (which_config (eth), buf,
-                       USB_BUFSIZ, (const struct usb_descriptor_header **)
-                               which_fn (eth));
+       {
+               config = &eth_config;
+               function = which_fn (eth);
+       }
+
+       /* for now, don't advertise srp-only devices */
+       if (!is_otg)
+               function++;
+
+       len = usb_gadget_config_buf (config, buf, USB_BUFSIZ, function);
        if (len < 0)
                return len;
        ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
@@ -1068,8 +1104,8 @@
                if (dev->status_ep)
                        (void) usb_ep_disable (dev->status_ep);
 #endif
-               dev->status_ep = 0;
-               dev->status = 0;
+               dev->status_ep = NULL;
+               dev->status = NULL;
 #if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS)
                if (dev->rndis || !dev->cdc) {
                        if (dev->in_ep)
@@ -1078,10 +1114,10 @@
                                (void) usb_ep_disable (dev->out_ep);
                }
 #endif
-               dev->in_ep = 0;
-               dev->in = 0;
-               dev->out_ep = 0;
-               dev->out = 0;
+               dev->in_ep = NULL;
+               dev->in = NULL;
+               dev->out_ep = NULL;
+               dev->out = NULL;
        } else
 
        /* activate non-CDC configs right away
@@ -1128,7 +1164,7 @@
                        list_del (&req->list);
                        usb_ep_free_request (dev->in_ep, req);
                }
-               dev->in_ep = 0;
+               dev->in_ep = NULL;
        }
        if (dev->out_ep) {
                usb_ep_disable (dev->out_ep);
@@ -1138,12 +1174,12 @@
                        list_del (&req->list);
                        usb_ep_free_request (dev->out_ep, req);
                }
-               dev->out_ep = 0;
+               dev->out_ep = NULL;
        }
 
        if (dev->status_ep) {
                usb_ep_disable (dev->status_ep);
-               dev->status_ep = 0;
+               dev->status_ep = NULL;
        }
        dev->config = 0;
 }
@@ -1187,13 +1223,20 @@
                result = -EINVAL;
                /* FALL THROUGH */
        case 0:
-               return result;
+               break;
        }
 
-       if (result)
-               eth_reset_config (dev);
-       else {
+       if (result) {
+               if (number)
+                       eth_reset_config (dev);
+               usb_gadget_vbus_draw(dev->gadget,
+                               dev->gadget->is_otg ? 8 : 100);
+       } else {
                char *speed;
+               unsigned power;
+
+               power = 2 * eth_config.bMaxPower;
+               usb_gadget_vbus_draw(dev->gadget, power);
 
                switch (gadget->speed) {
                case USB_SPEED_FULL:    speed = "full"; break;
@@ -1204,8 +1247,8 @@
                }
 
                dev->config = number;
-               INFO (dev, "%s speed config #%d: %s, using %s\n",
-                               speed, number, driver_desc,
+               INFO (dev, "%s speed config #%d: %d mA, %s, using %s\n",
+                               speed, number, power, driver_desc,
                                dev->rndis
                                        ? "RNDIS"
                                        : (dev->cdc
@@ -1364,8 +1407,9 @@
 static void rndis_response_complete (struct usb_ep *ep, struct usb_request 
*req)
 {
        if (req->status || req->actual != req->length)
-               DEBUG (dev, "rndis response complete --> %d, %d/%d\n",
-                      req->status, req->actual, req->length);
+               DEBUG ((struct eth_dev *) ep->driver_data,
+                       "rndis response complete --> %d, %d/%d\n",
+                       req->status, req->actual, req->length);
 
        /* done sending after CDC_GET_ENCAPSULATED_RESPONSE */
 }
@@ -1404,6 +1448,7 @@
        /* descriptors just go into the pre-allocated ep0 buffer,
         * while config change events may enable network traffic.
         */
+       req->complete = eth_setup_complete;
        switch (ctrl->bRequest) {
 
        case USB_REQ_GET_DESCRIPTOR:
@@ -1431,7 +1476,8 @@
                case USB_DT_CONFIG:
                        value = config_buf (gadget->speed, req->buf,
                                        ctrl->wValue >> 8,
-                                       ctrl->wValue & 0xff);
+                                       ctrl->wValue & 0xff,
+                                       gadget->is_otg);
                        if (value >= 0)
                                value = min (ctrl->wLength, (u16) value);
                        break;
@@ -1448,6 +1494,10 @@
        case USB_REQ_SET_CONFIGURATION:
                if (ctrl->bRequestType != 0)
                        break;
+               if (gadget->a_hnp_support)
+                       DEBUG (dev, "HNP available\n");
+               else if (gadget->a_alt_hnp_support)
+                       DEBUG (dev, "HNP needs a different root port\n");
                spin_lock (&dev->lock);
                value = eth_set_config (dev, ctrl->wValue, GFP_ATOMIC);
                spin_unlock (&dev->lock);
@@ -1520,7 +1570,7 @@

[%d lines skipped]
299diff -urN linux/drivers/usb/gadget/gadget_chips.h 
linux/drivers/usb/gadget/gadget_chips.h
--- linux/drivers/usb/gadget/gadget_chips.h     2004/08/14 18:38:56     1.1.2.2
+++ linux/drivers/usb/gadget/gadget_chips.h     2004/12/27 04:13:50     1.1.2.3
@@ -44,6 +44,12 @@
 #define        gadget_is_sa1100(g)     0
 #endif
 
+#ifdef CONFIG_USB_GADGET_LH7A40X
+#define        gadget_is_lh7a40x(g)    !strcmp("lh7a40x_udc", (g)->name)
+#else
+#define        gadget_is_lh7a40x(g)    0
+#endif
+
 #ifdef CONFIG_USB_GADGET_MQ11XX
 #define        gadget_is_mq11xx(g)     !strcmp("mq11xx_udc", (g)->name)
 #else
@@ -56,6 +62,18 @@
 #define        gadget_is_omap(g)       0
 #endif
 
+#ifdef CONFIG_USB_GADGET_N9604
+#define        gadget_is_n9604(g)      !strcmp("n9604_udc", (g)->name)
+#else
+#define        gadget_is_n9604(g)      0
+#endif
+
+#ifdef CONFIG_USB_GADGET_PXA27X
+#define        gadget_is_pxa27x(g)     !strcmp("pxa27x_udc", (g)->name)
+#else
+#define        gadget_is_pxa27x(g)     0
+#endif
+
 // CONFIG_USB_GADGET_AT91RM9200
 // CONFIG_USB_GADGET_SX2
 // CONFIG_USB_GADGET_AU1X00
diff -urN linux/drivers/usb/gadget/rndis.c linux/drivers/usb/gadget/rndis.c
--- linux/drivers/usb/gadget/rndis.c    2004/08/14 18:38:56     1.6.2.1
+++ linux/drivers/usb/gadget/rndis.c    2004/12/27 04:13:50     1.6.2.2
@@ -70,8 +70,6 @@
 
 #define RNDIS_MAX_CONFIGS      1
 
-static struct proc_dir_entry *rndis_connect_dir;
-static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];
 
 static rndis_params rndis_per_dev_params [RNDIS_MAX_CONFIGS];
 
@@ -1275,7 +1273,12 @@
        return 0;
 }
 
-int rndis_proc_read (char *page, char **start, off_t off, int count, int *eof, 
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+
+#include <asm/uaccess.h>
+
+static int rndis_proc_read (char *page, char **start, off_t off, int count, 
int *eof, 
                     void *data)
 {
        char *out = page;
@@ -1320,14 +1323,18 @@
        return len;
 }
 
-int rndis_proc_write (struct file *file, const char *buffer, 
+static int rndis_proc_write (struct file *file, const char __user *buffer, 
                      unsigned long count, void *data)
 {
+       rndis_params *p = data;
        u32 speed = 0;
        int i, fl_speed = 0;
        
        for (i = 0; i < count; i++) {
-               switch (*buffer) {
+               char c;
+               if (get_user(c, buffer))
+                       return -EFAULT;
+               switch (c) {
                case '0':
                case '1':
                case '2':
@@ -1339,21 +1346,19 @@
                case '8':
                case '9':
                        fl_speed = 1;
-                       speed = speed*10 + *buffer - '0';
+                       speed = speed*10 + c - '0';
                        break;
                case 'C':
                case 'c':
-                       rndis_signal_connect (((rndis_params *) data)
-                               ->confignr);
+                       rndis_signal_connect (p->confignr);
                        break;
                case 'D':
                case 'd':
-                       rndis_signal_disconnect (((rndis_params *) data)
-                               ->confignr);
+                       rndis_signal_disconnect(p->confignr);
                        break;
                default: 
-                       if (fl_speed) ((rndis_params *) data)->speed = speed;
-                       else DEBUG ("%c is not valid\n", *buffer);
+                       if (fl_speed) p->speed = speed;
+                       else DEBUG ("%c is not valid\n", c);
                        break;
                }
                
@@ -1363,43 +1368,40 @@
        return count;
 }
 
+#define        NAME_TEMPLATE   "driver/rndis-%03d"
+
+static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];
+
+#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
+
+
 int __init rndis_init (void)
 {
        u8 i;
-       char name [4];
 
-       /* FIXME this should probably be /proc/driver/rndis,
-        * and only if debugging is enabled
-        */
-       
-       if (!(rndis_connect_dir =  proc_mkdir ("rndis", NULL))) {
-               printk (KERN_ERR "%s: couldn't create /proc/rndis entry", 
-                       __FUNCTION__);
-               return -EIO;
-       }
-       
        for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
-               sprintf (name, "%03d", i);
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+               char name [20];
+
+               sprintf (name, NAME_TEMPLATE, i);
                if (!(rndis_connect_state [i]
-                               = create_proc_entry (name, 0660,
-                                               rndis_connect_dir))) 
+                               = create_proc_entry (name, 0660, NULL))) 
                {
                        DEBUG ("%s :remove entries", __FUNCTION__);
-                       for (i--; i > 0; i--) {
-                               sprintf (name, "%03d", i);
-                               remove_proc_entry (name, rndis_connect_dir);
+                       while (i) {
+                               sprintf (name, NAME_TEMPLATE, --i);
+                               remove_proc_entry (name, NULL);
                        }
                        DEBUG ("\n");
-                       
-                       remove_proc_entry ("000", rndis_connect_dir);
-                       remove_proc_entry ("rndis", NULL);
                        return -EIO;
                }
+
                rndis_connect_state [i]->nlink = 1;
                rndis_connect_state [i]->write_proc = rndis_proc_write;
                rndis_connect_state [i]->read_proc = rndis_proc_read;
                rndis_connect_state [i]->data = (void *)
                                (rndis_per_dev_params + i);
+#endif
                rndis_per_dev_params [i].confignr = i;
                rndis_per_dev_params [i].used = 0;
                rndis_per_dev_params [i].state = RNDIS_UNINITIALIZED;
@@ -1413,14 +1415,14 @@
 
 void rndis_exit (void)
 {
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
        u8 i;
-       char name [4];
+       char name [20];
        
        for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
-               sprintf (name, "%03d", i);
-               remove_proc_entry (name, rndis_connect_dir);
+               sprintf (name, NAME_TEMPLATE, i);
+               remove_proc_entry (name, NULL);
        }
-       remove_proc_entry ("rndis", NULL);
-       return;
+#endif
 }
 
diff -urN linux/drivers/usb/gadget/zero.c linux/drivers/usb/gadget/zero.c
--- linux/drivers/usb/gadget/zero.c     2004/08/14 18:38:56     1.2.2.4
+++ linux/drivers/usb/gadget/zero.c     2004/12/27 04:13:50     1.2.2.5
@@ -200,8 +200,13 @@
  * DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
  * Instead:  allocate your own, using normal USB-IF procedures.
  */
+#ifndef        CONFIG_USB_ZERO_HNPTEST
 #define DRIVER_VENDOR_NUM      0x0525          /* NetChip */
 #define DRIVER_PRODUCT_NUM     0xa4a0          /* Linux-USB "Gadget Zero" */
+#else
+#define DRIVER_VENDOR_NUM      0x1a0a          /* OTG test device IDs */
+#define DRIVER_PRODUCT_NUM     0xbadd
+#endif
 
 /*-------------------------------------------------------------------------*/
 
@@ -265,6 +270,14 @@
        .bMaxPower =            1,      /* self-powered */
 };
 
+static struct usb_otg_descriptor
+otg_descriptor = {
+       .bLength =              sizeof otg_descriptor,
+       .bDescriptorType =      USB_DT_OTG,
+
+       .bmAttributes =         USB_OTG_SRP,
+};
+
 /* one interface in each configuration */
 
 static const struct usb_interface_descriptor
@@ -308,17 +321,19 @@
 };
 
 static const struct usb_descriptor_header *fs_source_sink_function [] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
        (struct usb_descriptor_header *) &source_sink_intf,
        (struct usb_descriptor_header *) &fs_sink_desc,
        (struct usb_descriptor_header *) &fs_source_desc,
-       0,
+       NULL,
 };
 
 static const struct usb_descriptor_header *fs_loopback_function [] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
        (struct usb_descriptor_header *) &loopback_intf,
        (struct usb_descriptor_header *) &fs_sink_desc,
        (struct usb_descriptor_header *) &fs_source_desc,
-       0,
+       NULL,
 };
 
 #ifdef CONFIG_USB_GADGET_DUALSPEED
@@ -362,17 +377,19 @@
 };
 
 static const struct usb_descriptor_header *hs_source_sink_function [] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
        (struct usb_descriptor_header *) &source_sink_intf,
        (struct usb_descriptor_header *) &hs_source_desc,
        (struct usb_descriptor_header *) &hs_sink_desc,
-       0,
+       NULL,
 };
 
 static const struct usb_descriptor_header *hs_loopback_function [] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
        (struct usb_descriptor_header *) &loopback_intf,
        (struct usb_descriptor_header *) &hs_source_desc,
        (struct usb_descriptor_header *) &hs_sink_desc,
-       0,
+       NULL,
 };
 
 /* maxpacket and other transfer characteristics vary by speed. */
@@ -385,10 +402,10 @@
 
 #endif /* !CONFIG_USB_GADGET_DUALSPEED */
 
-static char                            manufacturer [40];
+static char                            manufacturer [50];
 static char                            serial [40];
 
-/* static strings, in iso 8859/1 */
+/* static strings, in UTF-8 */
 static struct usb_string               strings [] = {
        { STRING_MANUFACTURER, manufacturer, },
        { STRING_PRODUCT, longname, },
@@ -450,6 +467,10 @@
                        ? fs_source_sink_function
                        : fs_loopback_function;
 
+       /* for now, don't advertise srp-only devices */
+       if (!gadget->is_otg)
+               function++;
+
        len = usb_gadget_config_buf (is_source_sink
                                        ? &source_sink_config
                                        : &loopback_config,
@@ -474,7 +495,7 @@
                                &req->dma, GFP_ATOMIC);
                if (!req->buf) {
                        usb_ep_free_request (ep, req);
-                       req = 0;
+                       req = NULL;
                }
        }
        return req;
@@ -491,7 +512,7 @@
 
 /* optionally require specific source/sink data patterns  */
 
-static inline int
+static int
 check_read_data (
        struct zero_dev         *dev,
        struct usb_ep           *ep,
@@ -525,7 +546,7 @@
        return 0;
 }
 
-static inline void
+static void
 reinit_write_data (
        struct zero_dev         *dev,
        struct usb_ep           *ep,
@@ -605,7 +626,7 @@
 
        req = alloc_ep_req (ep, buflen);
        if (!req)
-               return 0;
+               return NULL;
 
        memset (req->buf, 0, req->length);
        req->complete = source_sink_complete;
@@ -619,7 +640,7 @@
 
                ERROR (dev, "start %s --> %d\n", ep->name, status);
                free_ep_req (ep, req);
-               req = 0;
+               req = NULL;
        }
 
        return req;
@@ -810,13 +831,14 @@
         */
        if (dev->in_ep) {
                usb_ep_disable (dev->in_ep);
-               dev->in_ep = 0;
+               dev->in_ep = NULL;
        }
        if (dev->out_ep) {
                usb_ep_disable (dev->out_ep);
-               dev->out_ep = 0;
+               dev->out_ep = NULL;
        }
        dev->config = 0;
+       del_timer (&dev->resume);
 }
 
 /* change our operational config.  this code must agree with the code
@@ -908,6 +930,7 @@
        /* usually this stores reply data in the pre-allocated ep0 buffer,
         * but config change events will reconfigure hardware.
         */
+       req->zero = 0;
        switch (ctrl->bRequest) {
 
        case USB_REQ_GET_DESCRIPTOR:
@@ -943,7 +966,8 @@
                case USB_DT_STRING:
                        /* wIndex == language code.
                         * this driver only handles one language, you can
-                        * add others even if they don't use iso8859/1
+                        * add string tables for other languages, using
+                        * any UTF-8 characters
                         */
                        value = usb_gadget_get_string (&stringtab,
                                        ctrl->wValue & 0xff, req->buf);
@@ -957,6 +981,12 @@
        case USB_REQ_SET_CONFIGURATION:
                if (ctrl->bRequestType != 0)
                        goto unknown;
+               if (gadget->a_hnp_support)
+                       DBG (dev, "HNP available\n");
+               else if (gadget->a_alt_hnp_support)
+                       DBG (dev, "HNP needs a different root port\n");
+               else
+                       VDBG (dev, "HNP inactive\n");
                spin_lock (&dev->lock);
                value = zero_set_config (dev, ctrl->wValue, GFP_ATOMIC);
                spin_unlock (&dev->lock);
@@ -1043,6 +1073,8 @@
        /* respond with data transfer before status phase? */
        if (value >= 0) {
                req->length = value;
+               req->zero = value < ctrl->wLength
+                               && (value % gadget->ep0->maxpacket) == 0;
                value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
                if (value < 0) {
                        DBG (dev, "ep_queue --> %d\n", value);
@@ -1084,8 +1116,10 @@
        /* normally the host would be woken up for something
         * more significant than just a timer firing...
         */
-       status = usb_gadget_wakeup (dev->gadget);
-       DBG (dev, "wakeup --> %d\n", status);
+       if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
+               status = usb_gadget_wakeup (dev->gadget);
+               DBG (dev, "wakeup --> %d\n", status);
+       }
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1102,7 +1136,7 @@
                free_ep_req (gadget->ep0, dev->req);
        del_timer_sync (&dev->resume);
        kfree (dev);
-       set_gadget_data (gadget, 0);
+       set_gadget_data (gadget, NULL);
 }
 
 static int
@@ -1158,6 +1192,12 @@
                device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207);
        } else if (gadget_is_omap (gadget)) {
                device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208);
+       } else if (gadget_is_lh7a40x(gadget)) {
+               device_desc.bcdDevice = __constant_cpu_to_le16 (0x0209);
+       } else if (gadget_is_n9604(gadget)) {
+               device_desc.bcdDevice = __constant_cpu_to_le16 (0x0210);
+       } else if (gadget_is_pxa27x(gadget)) {
+               device_desc.bcdDevice = __constant_cpu_to_le16 (0x0211);
        } else {
                /* gadget zero is so simple (for now, no altsettings) that
                 * it SHOULD NOT have problems with bulk-capable hardware.
@@ -1203,6 +1243,18 @@
        hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
 #endif
 
+       if (gadget->is_otg) {
+               otg_descriptor.bmAttributes |= USB_OTG_HNP,
+               source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+               loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+       }
+
+       if (gadget->is_otg) {
+               otg_descriptor.bmAttributes |= USB_OTG_HNP,
+               source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+               loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+       }
+
        usb_gadget_set_selfpowered (gadget);
 
        init_timer (&dev->resume);
diff -urN linux/drivers/usb/serial/digi_acceleport.c 
linux/drivers/usb/serial/digi_acceleport.c
--- linux/drivers/usb/serial/digi_acceleport.c  2002/09/11 12:45:20     1.19.2.2
+++ linux/drivers/usb/serial/digi_acceleport.c  2004/12/27 04:13:50     1.19.2.3
@@ -614,14 +614,7 @@
        wake_up_interruptible( &port->write_wait );
 
        /* wake up line discipline */
-       if( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
-       && tty->ldisc.write_wakeup )
-               (tty->ldisc.write_wakeup)(tty);
-
-       /* wake up other tty processes */
-       wake_up_interruptible( &tty->write_wait );
-       /* For 2.2.16 backport -- wake_up_interruptible( &tty->poll_wait ); */
-
+       tty_wakeup(tty);
 }
 
 
@@ -1557,8 +1550,7 @@
        /* flush driver and line discipline buffers */
        if( tty->driver.flush_buffer )
                tty->driver.flush_buffer( tty );
-       if( tty->ldisc.flush_buffer )
-               tty->ldisc.flush_buffer( tty );
+       tty_ldisc_flush(tty);
 
        if (port->serial->dev) {
                /* wait for transmit idle */
diff -urN linux/drivers/usb/serial/io_edgeport.c 
linux/drivers/usb/serial/io_edgeport.c
--- linux/drivers/usb/serial/io_edgeport.c      2004/08/14 18:38:56     1.9.2.10
+++ linux/drivers/usb/serial/io_edgeport.c      2004/12/27 04:13:50     1.9.2.11
@@ -902,12 +902,7 @@
 
        if (tty && edge_port->open) {
                /* let the tty driver wakeup if it has a special write_wakeup 
function */
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && 
tty->ldisc.write_wakeup) {
-                       (tty->ldisc.write_wakeup)(tty);
-               }
-
-               /* tell the tty driver that something has changed */
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
        }
 
        // Release the Write URB
diff -urN linux/drivers/usb/serial/io_ti.c linux/drivers/usb/serial/io_ti.c
--- linux/drivers/usb/serial/io_ti.c    2003/11/17 01:07:42     1.1.2.4
+++ linux/drivers/usb/serial/io_ti.c    2004/12/27 04:13:50     1.1.2.5
@@ -1800,12 +1800,7 @@
        tty = port->tty;
        if (tty) {
                /* let the tty driver wakeup if it has a special write_wakeup 
function */
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && 
tty->ldisc.write_wakeup) {
-                       (tty->ldisc.write_wakeup)(tty);
-               }
-
-               /* tell the tty driver that something has changed */
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
        }
 }
 
diff -urN linux/drivers/usb/serial/keyspan_pda.c 
linux/drivers/usb/serial/keyspan_pda.c
--- linux/drivers/usb/serial/keyspan_pda.c      2003/11/17 01:07:42     1.18.2.2
+++ linux/drivers/usb/serial/keyspan_pda.c      2004/12/27 04:13:50     1.18.2.3
@@ -183,13 +183,7 @@
        wake_up_interruptible( &port->write_wait );
 
        /* wake up line discipline */
-       if( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
-       && tty->ldisc.write_wakeup )
-               (tty->ldisc.write_wakeup)(tty);
-
-       /* wake up other tty processes */
-       wake_up_interruptible( &tty->write_wait );
-       /* For 2.2.16 backport -- wake_up_interruptible( &tty->poll_wait ); */
+       tty_wakeup(tty);
 }
 
 static void keyspan_pda_request_unthrottle( struct usb_serial *serial )
diff -urN linux/drivers/usb/serial/mct_u232.c 
linux/drivers/usb/serial/mct_u232.c
--- linux/drivers/usb/serial/mct_u232.c 2004/08/14 18:38:57     1.9.2.4
+++ linux/drivers/usb/serial/mct_u232.c 2004/12/27 04:13:50     1.9.2.5
@@ -569,11 +569,7 @@
 
        if (write_blocking) {
                wake_up_interruptible(&port->write_wait);
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup)(tty);
-               wake_up_interruptible(&tty->write_wait);
-               
+               tty_wakeup(tty);
        } else {
                /* from generic_write_bulk_callback */
                queue_task(&port->tqueue, &tq_immediate);
diff -urN linux/drivers/usb/serial/usbserial.c 
linux/drivers/usb/serial/usbserial.c
--- linux/drivers/usb/serial/Attic/usbserial.c  2004/11/19 00:28:46     1.24.2.9
+++ linux/drivers/usb/serial/Attic/usbserial.c  2004/12/27 04:13:50     
1.24.2.10
@@ -1326,6 +1326,7 @@
        struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
        struct tty_struct *tty;
        unsigned long flags;
+       struct tty_ldisc *ld;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
        
@@ -1341,9 +1342,15 @@
        if (!tty)
                return;
 
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && 
tty->ldisc.write_wakeup) {
-               dbg("%s - write wakeup call.", __FUNCTION__);
-               (tty->ldisc.write_wakeup)(tty);
+       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))) {
+               ld = tty_ldisc_ref(tty);
+               if(ld) {
+                       if(ld->write_wakeup) {
+                               ld->write_wakeup(tty);
+                               dbg("%s - write wakeup call.", __FUNCTION__);
+                       }
+                       tty_ldisc_deref(ld);
+               }
        }
 
        wake_up_interruptible(&tty->write_wait);
diff -urN linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c
--- linux/drivers/video/fbmem.c 2004/08/14 18:38:57     1.50.2.13
+++ linux/drivers/video/fbmem.c 2004/12/27 04:13:51     1.50.2.14
@@ -410,6 +410,7 @@
        struct fb_info *info = registered_fb[fbidx];
        struct fb_ops *fb = info->fbops;
        struct fb_fix_screeninfo fix;
+       unsigned int size;
 
        if (! fb || ! info->disp)
                return -ENODEV;
@@ -418,10 +419,12 @@
                return -EINVAL;
 
        fb->fb_get_fix(&fix,PROC_CONSOLE(info), info);
-       if (p >= fix.smem_len)
+       size = info->mapped_vram ? info->mapped_vram : fix.smem_len;
+       
+       if (p >= size)
            return 0;
-       if (count > fix.smem_len - p)
-               count = fix.smem_len - p;
+       if (count > size - p)
+               count = size - p;
        if (count) {
            char *base_addr;
 
@@ -444,6 +447,7 @@
        struct fb_ops *fb = info->fbops;
        struct fb_fix_screeninfo fix;
        int err;
+       unsigned int size;
 
        if (! fb || ! info->disp)
                return -ENODEV;
@@ -452,11 +456,13 @@
                return -EINVAL;
 
        fb->fb_get_fix(&fix, PROC_CONSOLE(info), info);
-       if (p > fix.smem_len)
+       size = info->mapped_vram ? info->mapped_vram : fix.smem_len;
+       
+       if (p > size)
            return -ENOSPC;
        err = 0;
-       if (count > fix.smem_len - p) {
-           count = fix.smem_len - p;
+       if (count > size - p) {
+           count = size - p;
            err = -ENOSPC;
        }
        if (count) {
@@ -619,7 +625,10 @@
 
        /* frame buffer memory */
        start = fix.smem_start;
-       len = PAGE_ALIGN((start & ~PAGE_MASK)+fix.smem_len);
+       if (info->mapped_vram)
+               len = PAGE_ALIGN((start & ~PAGE_MASK) + info->mapped_vram);
+       else
+               len = PAGE_ALIGN((start & ~PAGE_MASK) + fix.smem_len);
        if (off >= len) {
                /* memory mapped io */
                off -= len;
diff -urN linux/drivers/video/radeonfb.c linux/drivers/video/radeonfb.c
--- linux/drivers/video/radeonfb.c      2004/11/19 00:28:47     1.4.2.8
+++ linux/drivers/video/radeonfb.c      2004/12/27 04:13:51     1.4.2.9
@@ -176,7 +176,8 @@
 #define RTRACE         if(0) printk
 #endif
 
-
+#define MAX_MAPPED_VRAM (2048*2048*4)
+#define MIN_MAPPED_VRAM (1024*768*1)
 
 enum radeon_chips {
        RADEON_QD,
@@ -218,6 +219,7 @@
        RADEON_NH,
        RADEON_NI,
        RADEON_AP,
+       RADEON_AQ,
        RADEON_AR,
 };
 
@@ -279,6 +281,7 @@
        { "9800 NH", RADEON_R350 },
        { "9800 NI", RADEON_R350 },
        { "9600 AP", RADEON_RV350 },
+       { "9600 AQ", RADEON_RV350 },
        { "9600 AR", RADEON_RV350 },
 };
 
@@ -334,6 +337,7 @@
        { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Yd, PCI_ANY_ID, 
PCI_ANY_ID, 0, 0, RADEON_Yd},
        { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_AD, PCI_ANY_ID, 
PCI_ANY_ID, 0, 0, RADEON_AD},
        { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_AP, PCI_ANY_ID, 
PCI_ANY_ID, 0, 0, RADEON_AP},
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_AQ, PCI_ANY_ID, 
PCI_ANY_ID, 0, 0, RADEON_AQ},
        { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_AR, PCI_ANY_ID, 
PCI_ANY_ID, 0, 0, RADEON_AR},
        { 0, }
 };
@@ -499,7 +503,7 @@
 
        short chipset;
        unsigned char arch;
-       int video_ram;
+       unsigned int video_ram;
        u8 rev;
        int pitch, bpp, depth;
        int xres, yres, pixclock;
@@ -1626,6 +1630,7 @@
                                  const struct pci_device_id *ent)
 {
        struct radeonfb_info *rinfo;
+       struct fb_info *fb_info;
        struct radeon_chip_info *rci = &radeon_chip_info[ent->driver_data];
        u32 tmp;
        int i, j;
@@ -1640,6 +1645,7 @@
 
        memset (rinfo, 0, sizeof (struct radeonfb_info));
 
+       fb_info = (struct fb_info *)rinfo;
        rinfo->pdev = pdev;
        strncpy(rinfo->name, rci->name, 16);
        rinfo->arch = rci->arch;
@@ -1824,8 +1830,16 @@
                }
        }
 
-       rinfo->fb_base = (unsigned long) ioremap (rinfo->fb_base_phys,
-                                                 rinfo->video_ram);
+       fb_info->mapped_vram = min_t(unsigned int, MAX_MAPPED_VRAM, 
rinfo->video_ram);
+       do {
+               rinfo->fb_base = (unsigned long) ioremap (rinfo->fb_base_phys,
+                                                 fb_info->mapped_vram);
+               if (rinfo->fb_base)
+                       break;
+
+               fb_info->mapped_vram /= 2;
+       } while(fb_info->mapped_vram > MIN_MAPPED_VRAM);
+       
        if (!rinfo->fb_base) {
                printk ("radeonfb: cannot map FB\n");
                iounmap ((void*)rinfo->mmio_base);
@@ -1836,6 +1850,7 @@
                kfree (rinfo);
                return -ENODEV;
        }
+       RTRACE(KERN_INFO "radeonfb: mapped %dk videoram\n", 
fb_info->mapped_vram/1024);
 
        /* currcon not yet configured, will be set by first switch */
        rinfo->currcon = -1;
@@ -2199,13 +2214,14 @@
                 {-1, -1}
         };
         int i;
+       struct fb_info *fb_info = (struct fb_info *)rinfo;
                 
         /* use highest possible virtual resolution */
         if (v->xres_virtual == -1 && v->yres_virtual == -1) {
                 printk("radeonfb: using max available virtual resolution\n");
                 for (i=0; modes[i].xres != -1; i++) {
                         if (modes[i].xres * nom / den * modes[i].yres <
-                            rinfo->video_ram / 2)
+                            fb_info->mapped_vram / 2)
                                 break;
                 }
                 if (modes[i].xres == -1) {
@@ -2218,15 +2234,15 @@
                 printk("radeonfb: virtual resolution set to max of %dx%d\n",
                         v->xres_virtual, v->yres_virtual);
         } else if (v->xres_virtual == -1) {
-                v->xres_virtual = (rinfo->video_ram * den /   
+                v->xres_virtual = (fb_info->mapped_vram * den /   
                                 (nom * v->yres_virtual * 2)) & ~15;
         } else if (v->yres_virtual == -1) {
                 v->xres_virtual = (v->xres_virtual + 15) & ~15;
-                v->yres_virtual = rinfo->video_ram * den /
+                v->yres_virtual = fb_info->mapped_vram * den /
                         (nom * v->xres_virtual *2);
         } else {
                 if (v->xres_virtual * nom / den * v->yres_virtual >
-                        rinfo->video_ram) {
+                        fb_info->mapped_vram) {
                         return -EINVAL;
                 }
         }
@@ -2430,6 +2446,9 @@
                         return -EINVAL;
         }
 
+       if (((v.xres_virtual * v.yres_virtual * nom) / den) > info->mapped_vram)
+               return -EINVAL;
+
         if (radeonfb_do_maximize(rinfo, var, &v, nom, den) < 0)
                 return -EINVAL;  
                 
diff -urN linux/drivers/video/vga16fb.c linux/drivers/video/vga16fb.c
--- linux/drivers/video/vga16fb.c       2004/11/29 17:47:17     1.12.2.1
+++ linux/drivers/video/vga16fb.c       2004/12/27 04:13:51     1.12.2.2
@@ -142,7 +142,7 @@
        memset(fix, 0, sizeof(struct fb_fix_screeninfo));
        strcpy(fix->id,"VGA16 VGA");
 
-       fix->smem_start = VGA_MAP_MEM(VGA_FB_PHYS);
+       fix->smem_start = VGA_FB_PHYS;
        fix->smem_len = VGA_FB_PHYS_LEN;
        fix->type = FB_TYPE_VGA_PLANES;
        fix->visual = FB_VISUAL_PSEUDOCOLOR;
@@ -896,7 +896,7 @@
 
        /* XXX share VGA_FB_PHYS region with vgacon */
 
-        vga16fb.video_vbase = ioremap(VGA_MAP_MEM(VGA_FB_PHYS), 
VGA_FB_PHYS_LEN);
+        vga16fb.video_vbase = ioremap(VGA_FB_PHYS, VGA_FB_PHYS_LEN);
        if (!vga16fb.video_vbase) {
                printk(KERN_ERR "vga16fb: unable to map device\n");
                return -ENOMEM;
diff -urN linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- linux/fs/binfmt_aout.c      2001/11/06 07:56:08     1.37
+++ linux/fs/binfmt_aout.c      2004/12/27 04:13:51     1.37.2.1
@@ -39,13 +39,18 @@
        NULL, THIS_MODULE, load_aout_binary, load_aout_library, aout_core_dump, 
PAGE_SIZE
 };
 
-static void set_brk(unsigned long start, unsigned long end)
+#define BAD_ADDR(x)    ((unsigned long)(x) >= TASK_SIZE)
+
+static int set_brk(unsigned long start, unsigned long end)
 {
        start = PAGE_ALIGN(start);
        end = PAGE_ALIGN(end);
-       if (end <= start)
-               return;
-       do_brk(start, end - start);
+       if (end > start) {
+               unsigned long addr = do_brk(start, end - start);
+               if (BAD_ADDR(addr))
+                       return addr;
+       }
+       return 0;
 }
 
 /*
@@ -405,7 +410,11 @@
 beyond_if:
        set_binfmt(&aout_format);
 
-       set_brk(current->mm->start_brk, current->mm->brk);
+       retval = set_brk(current->mm->start_brk, current->mm->brk);
+       if (retval < 0) {
+               send_sig(SIGKILL, current, 0);
+               return retval;
+       }
 
        retval = setup_arg_pages(bprm); 
        if (retval < 0) { 
diff -urN linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- linux/fs/binfmt_elf.c       2004/11/29 17:47:18     1.52.2.13
+++ linux/fs/binfmt_elf.c       2004/12/27 04:13:51     1.52.2.14
@@ -383,6 +383,12 @@
        }
 
        *interp_load_addr = load_addr;
+       /*
+        * XXX: is everything deallocated properly if this happens
+        * to be ~0UL (that is, we succeeded, but the header is broken
+        * and thus the caller will think that we failed)? We'd better
+        * switch to out-of-band error reporting.
+        */
        error = ((unsigned long) interp_elf_ex->e_entry) + load_addr;
 
 out_close:
@@ -483,12 +489,13 @@
 
        /* Now read in all of the header information */
 
-       retval = -ENOMEM;
        if (elf_ex.e_phentsize != sizeof(struct elf_phdr))
                goto out;
-       if (elf_ex.e_phnum > 65536U / sizeof(struct elf_phdr))
+       if (elf_ex.e_phnum < 1 ||
+           elf_ex.e_phnum > 65536U / sizeof(struct elf_phdr))
                goto out;
        size = elf_ex.e_phnum * sizeof(struct elf_phdr);
+       retval = -ENOMEM;
        elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL);
        if (!elf_phdata)
                goto out;
@@ -534,10 +541,12 @@
                         * is an a.out format binary
                         */
 
-                       retval = -ENOMEM;
+                       retval = -ENOEXEC;
                        if (elf_ppnt->p_filesz > PATH_MAX || 
-                           elf_ppnt->p_filesz == 0)
+                           elf_ppnt->p_filesz < 2)
                                goto out_free_file;
+
+                       retval = -ENOMEM;
                        elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz,
                                                           GFP_KERNEL);
                        if (!elf_interpreter)
@@ -552,7 +561,7 @@
                                goto out_free_interp;
                        }
                        /* make sure path is NULL terminated */
-                       retval = -EINVAL;
+                       retval = -ENOEXEC;
                        if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0')
                                goto out_free_interp;
 
@@ -798,8 +807,9 @@
                                                    interpreter,
                                                    &interp_load_addr);
                if (BAD_ADDR(elf_entry)) {
-                       printk(KERN_ERR "Unable to load interpreter\n");
-                       send_sig(SIGSEGV, current, 0);
+                       printk(KERN_ERR "Unable to load interpreter %.128s\n",
+                               elf_interpreter);
+                       force_sig(SIGSEGV, current);
                        retval = -ENOEXEC; /* Nobody gets to see this, but.. */
                        goto out_free_dentry;
                }
diff -urN linux/fs/exec.c linux/fs/exec.c
--- linux/fs/exec.c     2004/11/29 17:47:18     1.59.2.10
+++ linux/fs/exec.c     2004/12/27 04:13:51     1.59.2.11
@@ -327,7 +327,7 @@
 {
        unsigned long stack_base;
        struct vm_area_struct *mpnt;
-       int i;
+       int i, ret;
 
        stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
 
@@ -351,7 +351,11 @@
                mpnt->vm_pgoff = 0;
                mpnt->vm_file = NULL;
                mpnt->vm_private_data = (void *) 0;
-               insert_vm_struct(current->mm, mpnt);
+               if ((ret = insert_vm_struct(current->mm, mpnt))) {
+                       up_write(&current->mm->mmap_sem);
+                       kmem_cache_free(vm_area_cachep, mpnt);
+                       return ret;
+               }
                current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> 
PAGE_SHIFT;
        } 
 
diff -urN linux/fs/namei.c linux/fs/namei.c
--- linux/fs/namei.c    2004/11/19 00:28:47     1.58.2.8
+++ linux/fs/namei.c    2004/12/27 04:13:51     1.58.2.9
@@ -326,7 +326,7 @@
 }
 
 /*
- * This limits recursive symlink follows to 8, while
+ * This limits recursive symlink follows to 5, while
  * limiting consecutive symlinks to 40.
  *
  * Without that kind of total limit, nasty chains of consecutive
diff -urN linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- linux/fs/nfs/dir.c  2004/08/14 18:39:01     1.41.2.5
+++ linux/fs/nfs/dir.c  2004/12/27 04:13:51     1.41.2.6
@@ -999,7 +999,7 @@
        struct inode *old_inode = old_dentry->d_inode;
        struct inode *new_inode = new_dentry->d_inode;
        struct dentry *dentry = NULL, *rehash = NULL;
-       int error;
+       int error = -EBUSY;
 
        /*
         * To prevent any new references to the target during the rename,
@@ -1025,12 +1025,6 @@
         */
        if (!new_inode)
                goto go_ahead;
-       /* If target is a hard link to the source, then noop */
-       error = 0;
-       if (NFS_FILEID(new_inode) == NFS_FILEID(old_inode))
-               goto out;
-
-       error = -EBUSY;
        if (S_ISDIR(new_inode->i_mode))
                goto out;
        else if (atomic_read(&new_dentry->d_count) > 1) {
diff -urN linux/fs/nfs/unlink.c linux/fs/nfs/unlink.c
--- linux/fs/nfs/unlink.c       2004/11/19 00:28:48     1.3.2.4
+++ linux/fs/nfs/unlink.c       2004/12/27 04:13:51     1.3.2.5
@@ -12,7 +12,6 @@
 #include <linux/sunrpc/sched.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/nfs_fs.h>
-#include <linux/wait.h>
 
 
 struct nfs_unlinkdata {
@@ -22,9 +21,6 @@
        struct rpc_task task;
        struct rpc_cred *cred;
        unsigned int    count;
-
-       wait_queue_head_t waitq;
-       int completed;
 };
 
 static struct nfs_unlinkdata   *nfs_deletes;
@@ -130,16 +126,13 @@
        if (nfs_async_handle_jukebox(task))
                return;
        if (!dir)
-               goto out;
+               return;
        dir_i = dir->d_inode;
        nfs_zap_caches(dir_i);
        NFS_PROTO(dir_i)->unlink_done(dir, &task->tk_msg);
        put_rpccred(data->cred);
        data->cred = NULL;
        dput(dir);
-out:
-       data->completed = 1;
-       wake_up(&data->waitq);
 }
 
 /**
@@ -182,8 +175,6 @@
        nfs_deletes = data;
        data->count = 1;
 
-       init_waitqueue_head(&data->waitq);
-
        task = &data->task;
        rpc_init_task(task, clnt, nfs_async_unlink_done , RPC_TASK_ASYNC);
        task->tk_calldata = data;
@@ -221,10 +212,7 @@
        data->count++;
        nfs_copy_dname(dentry, data);
        dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
-       if (data->task.tk_rpcwait == &nfs_delete_queue) {
-               struct rpc_clnt *clnt = data->task.tk_client;
+       if (data->task.tk_rpcwait == &nfs_delete_queue)
                rpc_wake_up_task(&data->task);
-               nfs_wait_event(clnt, data->waitq, data->completed == 1);
-       }
        nfs_put_unlinkdata(data);
 }
diff -urN linux/fs/proc/base.c linux/fs/proc/base.c
--- linux/fs/proc/base.c        2004/11/19 00:28:48     1.34.2.7
+++ linux/fs/proc/base.c        2004/12/27 04:13:51     1.34.2.8
@@ -166,15 +166,16 @@
        if (mm)
                atomic_inc(&mm->mm_users);
        task_unlock(task);
-       if (mm) {
-               unsigned int len = mm->env_end - mm->env_start;
+       if (mm && mm->env_start && mm->env_start < mm->env_end) {
+               unsigned long len = mm->env_end - mm->env_start;
                if (len > PAGE_SIZE)
                        len = PAGE_SIZE;
                res = access_process_vm(task, mm->env_start, buffer, len, 0);
-               if (!may_ptrace_attach(task))
+               if (res >= 0 && !may_ptrace_attach(task))
                        res = -ESRCH;
-               mmput(mm);
        }
+       if (mm)
+               mmput(mm);
        return res;
 }
 
@@ -187,31 +188,30 @@
        if (mm)
                atomic_inc(&mm->mm_users);
        task_unlock(task);
-       if (mm) {
-               int len = mm->arg_end - mm->arg_start;
+       if (mm && mm->arg_start && mm->arg_start < mm->arg_end) {
+               unsigned long len = mm->arg_end - mm->arg_start;
                if (len > PAGE_SIZE)
                        len = PAGE_SIZE;
                res = access_process_vm(task, mm->arg_start, buffer, len, 0);
-               // If the nul at the end of args has been overwritten, then
-               // assume application is using setproctitle(3).
-               if ( res > 0 && buffer[res-1] != '\0' )
-               {
-                       len = strnlen( buffer, res );
-                       if ( len < res )
-                       {
-                           res = len;
-                       }
-                       else
-                       {
+               /* If the nul at the end of args has been overwritten, then
+                  assume application is using setproctitle(3). */
+               if (res > 0 && buffer[res - 1] != '\0') {
+                       len = strnlen(buffer, res);
+                       if (len < res) {
+                               res = len;
+                       } else
+                       if (mm->env_start < mm->env_end && res <= PAGE_SIZE) {
                                len = mm->env_end - mm->env_start;
                                if (len > PAGE_SIZE - res)
                                        len = PAGE_SIZE - res;
                                res += access_process_vm(task, mm->env_start, 
buffer+res, len, 0);
-                               res = strnlen( buffer, res );
-                       }
+                               res = strnlen(buffer, res);
+                       } else
+                               res = 0;
                }
-               mmput(mm);
        }
+       if (mm)
+               mmput(mm);
        return res;
 }
 
diff -urN linux/fs/proc/proc_tty.c linux/fs/proc/proc_tty.c
--- linux/fs/proc/proc_tty.c    2004/11/29 17:47:18     1.6.4.1
+++ linux/fs/proc/proc_tty.c    2004/12/27 04:13:51     1.6.4.2
@@ -15,8 +15,6 @@
 #include <asm/bitops.h>
 
 extern struct tty_driver *tty_drivers; /* linked list of tty drivers */
-extern struct tty_ldisc ldiscs[];
-
 
 static int tty_drivers_read_proc(char *page, char **start, off_t off,
                                 int count, int *eof, void *data);
@@ -106,12 +104,15 @@
        int     i;
        int     len = 0;
        off_t   begin = 0;
-
+       struct tty_ldisc *ld;
+       
        for (i=0; i < NR_LDISCS; i++) {
-               if (!(ldiscs[i].flags & LDISC_FLAG_DEFINED))
+               ld = tty_ldisc_get(i);
+               if (ld == NULL)
                        continue;
                len += sprintf(page+len, "%-10s %2d\n",
-                              ldiscs[i].name ? ldiscs[i].name : "???", i);
+                              ld->name ? ld->name : "???", i);
+               tty_ldisc_put(i);
                if (len+begin > off+count)
                        break;
                if (len+begin < off) {
diff -urN linux/fs/xfs/Makefile linux/fs/xfs/Makefile
--- linux/fs/xfs/Makefile       2004/08/14 18:39:02     1.11.2.4
+++ linux/fs/xfs/Makefile       2004/12/27 04:13:52     1.11.2.5
@@ -57,8 +57,6 @@
 
 obj-$(CONFIG_XFS_RT)           += xfs_rtalloc.o
 obj-$(CONFIG_XFS_POSIX_ACL)    += xfs_acl.o
-obj-$(CONFIG_XFS_POSIX_CAP)    += xfs_cap.o
-obj-$(CONFIG_XFS_POSIX_MAC)    += xfs_mac.o
 
 obj-$(CONFIG_XFS_TRACE)                += xfs_dir2_trace.o
 
diff -urN linux/fs/xfs/xfs_acl.h linux/fs/xfs/xfs_acl.h
--- linux/fs/xfs/xfs_acl.h      2004/11/19 00:28:48     1.3.2.4
+++ linux/fs/xfs/xfs_acl.h      2004/12/27 04:13:52     1.3.2.5
@@ -74,8 +74,6 @@
 
 extern int xfs_acl_inherit(struct vnode *, struct vattr *, xfs_acl_t *);
 extern int xfs_acl_iaccess(struct xfs_inode *, mode_t, cred_t *);
-extern int xfs_acl_get(struct vnode *, xfs_acl_t *, xfs_acl_t *);
-extern int xfs_acl_set(struct vnode *, xfs_acl_t *, xfs_acl_t *);
 extern int xfs_acl_vtoacl(struct vnode *, xfs_acl_t *, xfs_acl_t *);
 extern int xfs_acl_vhasacl_access(struct vnode *);
 extern int xfs_acl_vhasacl_default(struct vnode *);
diff -urN linux/fs/xfs/xfs_alloc.c linux/fs/xfs/xfs_alloc.c
--- linux/fs/xfs/xfs_alloc.c    2004/11/19 00:28:48     1.7.2.3
+++ linux/fs/xfs/xfs_alloc.c    2004/12/27 04:13:52     1.7.2.4
@@ -2247,6 +2247,7 @@
        xfs_alloctype_t type;   /* input allocation type */
        int             bump_rotor = 0;
        int             no_min = 0;
+       xfs_agnumber_t  rotorstep = xfs_rotorstep; /* inode32 agf stepper */
 
        mp = args->mp;
        type = args->otype = args->type;
@@ -2310,7 +2311,9 @@
                 */
                if ((args->userdata  == XFS_ALLOC_INITIAL_USER_DATA) &&
                    (mp->m_flags & XFS_MOUNT_32BITINODES)) {
-                       args->fsbno = XFS_AGB_TO_FSB(mp, mp->m_agfrotor, 0);
+                       args->fsbno = XFS_AGB_TO_FSB(mp,
+                                       ((mp->m_agfrotor / rotorstep) %
+                                       mp->m_sb.sb_agcount), 0);
                        bump_rotor = 1;
                }
                args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno);
@@ -2326,7 +2329,8 @@
                        /*
                         * Start with the last place we left off.
                         */
-                       args->agno = sagno = mp->m_agfrotor;
+                       args->agno = sagno = (mp->m_agfrotor / rotorstep) %
+                                       mp->m_sb.sb_agcount;
                        args->type = XFS_ALLOCTYPE_THIS_AG;
                        flags = XFS_ALLOC_FLAG_TRYLOCK;
                } else if (type == XFS_ALLOCTYPE_FIRST_AG) {
@@ -2400,8 +2404,14 @@
                        }
                }
                up_read(&mp->m_peraglock);
-               if (bump_rotor || (type == XFS_ALLOCTYPE_ANY_AG))
-                       mp->m_agfrotor = (args->agno + 1) % mp->m_sb.sb_agcount;
+               if (bump_rotor || (type == XFS_ALLOCTYPE_ANY_AG)) {
+                       if (args->agno == sagno)
+                               mp->m_agfrotor = (mp->m_agfrotor + 1) %
+                                       (mp->m_sb.sb_agcount * rotorstep);
+                       else
+                               mp->m_agfrotor = (args->agno * rotorstep + 1) %
+                                       (mp->m_sb.sb_agcount * rotorstep);
+               }
                break;
        default:
                ASSERT(0);
diff -urN linux/fs/xfs/xfs_attr.c linux/fs/xfs/xfs_attr.c
--- linux/fs/xfs/xfs_attr.c     2004/11/19 00:28:49     1.9.2.5
+++ linux/fs/xfs/xfs_attr.c     2004/12/27 04:13:52     1.9.2.6
@@ -121,22 +121,14 @@
        xfs_da_args_t   args;
        int             error;
 
-       if (XFS_FORCED_SHUTDOWN(ip->i_mount))
-               return(EIO);
-
        if ((XFS_IFORK_Q(ip) == 0) ||
            (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
             ip->i_d.di_anextents == 0))
                return(ENOATTR);
 
-       if (!(flags & ATTR_KERNACCESS)) {
-               xfs_ilock(ip, XFS_ILOCK_SHARED);
-
-               if (!(flags & ATTR_SECURE) &&
-                   ((error = xfs_iaccess(ip, S_IRUSR, cred)))) {
-                       xfs_iunlock(ip, XFS_ILOCK_SHARED);
+       if (!(flags & (ATTR_KERNACCESS|ATTR_SECURE))) {
+               if ((error = xfs_iaccess(ip, S_IRUSR, cred)))
                        return(XFS_ERROR(error));
-               }
        }
 
        /*
@@ -167,9 +159,6 @@
                error = xfs_attr_node_get(&args);
        }
 
-       if (!(flags & ATTR_KERNACCESS))
-               xfs_iunlock(ip, XFS_ILOCK_SHARED);
-
        /*
         * Return the number of bytes in the value to the caller.
         */
@@ -185,7 +174,7 @@
             int flags, struct cred *cred)
 {
        xfs_inode_t     *ip = XFS_BHVTOI(bdp);
-       int             namelen;
+       int             error, namelen;
 
        XFS_STATS_INC(xs_attr_get);
 
@@ -195,7 +184,13 @@
        if (namelen >= MAXNAMELEN)
                return(EFAULT);         /* match IRIX behaviour */
 
-       return xfs_attr_fetch(ip, name, namelen, value, valuelenp, flags, cred);
+       if (XFS_FORCED_SHUTDOWN(ip->i_mount))
+               return(EIO);
+
+       xfs_ilock(ip, XFS_ILOCK_SHARED);
+       error = xfs_attr_fetch(ip, name, namelen, value, valuelenp, flags, 
cred);
+       xfs_iunlock(ip, XFS_ILOCK_SHARED);
+       return(error);
 }
 
 /*ARGSUSED*/
@@ -718,16 +713,15 @@
        mp = dp->i_mount;
        ASSERT(! XFS_NOT_DQATTACHED(mp, dp));
 
-       /* XXXsup - why on earth are we taking ILOCK_EXCL here??? */
-       xfs_ilock(dp, XFS_ILOCK_EXCL);
+       xfs_ilock(dp, XFS_ILOCK_SHARED);
        if ((XFS_IFORK_Q(dp) == 0) ||
            (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) ||
            (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
             dp->i_d.di_anextents == 0)) {
-               xfs_iunlock(dp, XFS_ILOCK_EXCL);
+               xfs_iunlock(dp, XFS_ILOCK_SHARED);
                return(0);
        }
-       xfs_iunlock(dp, XFS_ILOCK_EXCL);
+       xfs_iunlock(dp, XFS_ILOCK_SHARED);
 
        /*
         * Start our first transaction of the day.
diff -urN linux/fs/xfs/xfs_attr_leaf.h linux/fs/xfs/xfs_attr_leaf.h
--- linux/fs/xfs/xfs_attr_leaf.h        2004/02/20 01:22:20     1.2.2.3
+++ linux/fs/xfs/xfs_attr_leaf.h        2004/12/27 04:13:52     1.2.2.4
@@ -246,7 +246,6 @@
 int    xfs_attr_shortform_to_leaf(struct xfs_da_args *args);
 int    xfs_attr_shortform_remove(struct xfs_da_args *remove);
 int    xfs_attr_shortform_list(struct xfs_attr_list_context *context);
-int    xfs_attr_shortform_replace(struct xfs_da_args *args);
 int    xfs_attr_shortform_allfit(struct xfs_dabuf *bp, struct xfs_inode *dp);
 
 /*
diff -urN linux/fs/xfs/xfs_bmap_btree.h linux/fs/xfs/xfs_bmap_btree.h
--- linux/fs/xfs/xfs_bmap_btree.h       2004/11/19 00:28:49     1.7.2.3
+++ linux/fs/xfs/xfs_bmap_btree.h       2004/12/27 04:13:52     1.7.2.4
@@ -551,13 +551,6 @@
        struct xfs_btree_cur *,
        int *);
 
-int
-xfs_bmbt_insert_many(
-       struct xfs_btree_cur *,
-       int,
-       xfs_bmbt_rec_t *,
-       int *);
-
 void
 xfs_bmbt_log_block(
        struct xfs_btree_cur *,
diff -urN linux/fs/xfs/xfs_dinode.h linux/fs/xfs/xfs_dinode.h
--- linux/fs/xfs/xfs_dinode.h   2004/11/19 00:28:49     1.6.2.2
+++ linux/fs/xfs/xfs_dinode.h   2004/12/27 04:13:52     1.6.2.3
@@ -457,6 +457,8 @@
 #define XFS_DIFLAG_NOATIME_BIT   6     /* do not update atime */
 #define XFS_DIFLAG_NODUMP_BIT    7     /* do not dump */
 #define XFS_DIFLAG_RTINHERIT_BIT 8     /* create with realtime bit set */
+#define XFS_DIFLAG_PROJINHERIT_BIT  9  /* create with parents projid */
+#define XFS_DIFLAG_NOSYMLINKS_BIT  10  /* disallow symlink creation */
 #define XFS_DIFLAG_REALTIME      (1 << XFS_DIFLAG_REALTIME_BIT)
 #define XFS_DIFLAG_PREALLOC      (1 << XFS_DIFLAG_PREALLOC_BIT)
 #define XFS_DIFLAG_NEWRTBM       (1 << XFS_DIFLAG_NEWRTBM_BIT)
@@ -466,10 +468,13 @@
 #define XFS_DIFLAG_NOATIME       (1 << XFS_DIFLAG_NOATIME_BIT)
 #define XFS_DIFLAG_NODUMP        (1 << XFS_DIFLAG_NODUMP_BIT)
 #define XFS_DIFLAG_RTINHERIT     (1 << XFS_DIFLAG_RTINHERIT_BIT)
+#define XFS_DIFLAG_PROJINHERIT   (1 << XFS_DIFLAG_PROJINHERIT_BIT)
+#define XFS_DIFLAG_NOSYMLINKS    (1 << XFS_DIFLAG_NOSYMLINKS_BIT)
 
 #define XFS_DIFLAG_ANY \
        (XFS_DIFLAG_REALTIME | XFS_DIFLAG_PREALLOC | XFS_DIFLAG_NEWRTBM | \
         XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND | XFS_DIFLAG_SYNC | \
-        XFS_DIFLAG_NOATIME | XFS_DIFLAG_NODUMP | XFS_DIFLAG_RTINHERIT)
+        XFS_DIFLAG_NOATIME | XFS_DIFLAG_NODUMP | XFS_DIFLAG_RTINHERIT | \
+        XFS_DIFLAG_PROJINHERIT | XFS_DIFLAG_NOSYMLINKS)
 
 #endif /* __XFS_DINODE_H__ */
diff -urN linux/fs/xfs/xfs_fs.h linux/fs/xfs/xfs_fs.h
--- linux/fs/xfs/xfs_fs.h       2004/11/19 00:28:49     1.6.2.3
+++ linux/fs/xfs/xfs_fs.h       2004/12/27 04:13:52     1.6.2.4
@@ -77,6 +77,8 @@
 #define XFS_XFLAG_NOATIME      0x00000040      /* do not update access time */
 #define XFS_XFLAG_NODUMP       0x00000080      /* do not include in backups */
 #define XFS_XFLAG_RTINHERIT    0x00000100      /* create with rt bit set */
+#define XFS_XFLAG_PROJINHERIT  0x00000200      /* create with parents projid */
+#define XFS_XFLAG_NOSYMLINKS   0x00000400      /* disallow symlink creation */
 #define XFS_XFLAG_HASATTR      0x80000000      /* no DIFLAG for this   */
 
 /*
diff -urN linux/fs/xfs/xfs_iget.c linux/fs/xfs/xfs_iget.c
--- linux/fs/xfs/xfs_iget.c     2003/12/15 18:19:52     1.14.2.1
+++ linux/fs/xfs/xfs_iget.c     2004/12/27 04:13:52     1.14.2.2
@@ -169,6 +169,7 @@
        xfs_mount_t     *mp,
        xfs_trans_t     *tp,
        xfs_ino_t       ino,
+       uint            flags,
        uint            lock_flags,
        xfs_inode_t     **ipp,
        xfs_daddr_t     bno)
@@ -180,7 +181,6 @@
        ulong           version;
        int             error;
        /* REFERENCED */
-       int             newnode;
        xfs_chash_t     *ch;
        xfs_chashlist_t *chl, *chlnew;
        SPLDECL(s);
@@ -193,11 +193,22 @@
 
        for (ip = ih->ih_next; ip != NULL; ip = ip->i_next) {
                if (ip->i_ino == ino) {
+                       /*
+                        * If INEW is set this inode is being set up
+                        * we need to pause and try again.
+                        */
+                       if (ip->i_flags & XFS_INEW) {
+                               read_unlock(&ih->ih_lock);
+                               delay(1);
+                               XFS_STATS_INC(xs_ig_frecycle);
 
-                       inode_vp = XFS_ITOV_NULL(ip);
+                               goto again;
+                       }
 
+                       inode_vp = XFS_ITOV_NULL(ip);
                        if (inode_vp == NULL) {
-                               /* If IRECLAIM is set this inode is
+                               /*
+                                * If IRECLAIM is set this inode is
                                 * on its way out of the system,
                                 * we need to pause and try again.
                                 */
@@ -250,14 +261,15 @@
                        XFS_STATS_INC(xs_ig_found);
 
 finish_inode:
-                       if (lock_flags != 0) {
-                               xfs_ilock(ip, lock_flags);
-                       }
-
-                       newnode = (ip->i_d.di_mode == 0);
-                       if (newnode) {
+                       if (ip->i_d.di_mode == 0) {
+                               if (!(flags & IGET_CREATE))
+                                       return ENOENT;
                                xfs_iocore_inode_reinit(ip);
                        }
+       
+                       if (lock_flags != 0)
+                               xfs_ilock(ip, lock_flags);
+
                        ip->i_flags &= ~XFS_ISTALE;
 
                        vn_trace_exit(vp, "xfs_iget.found",
@@ -293,6 +305,11 @@
        if (lock_flags != 0) {
                xfs_ilock(ip, lock_flags);
        }
+               
+       if ((ip->i_d.di_mode == 0) && !(flags & IGET_CREATE)) {
+               xfs_idestroy(ip);
+               return ENOENT;
+       }
 
        /*
         * Put ip on its hash chain, unless someone else hashed a duplicate
@@ -324,6 +341,7 @@
        ih->ih_next = ip;
        ip->i_udquot = ip->i_gdquot = NULL;
        ih->ih_version++;
+       ip->i_flags |= XFS_INEW;
 
        write_unlock(&ih->ih_lock);
 
@@ -404,8 +422,6 @@
 
        XFS_MOUNT_IUNLOCK(mp);
 
-       newnode = 1;
-
  return_ip:
        ASSERT(ip->i_df.if_ext_max ==
               XFS_IFORK_DSIZE(ip) / sizeof(xfs_bmbt_rec_t));
@@ -434,6 +450,7 @@
        xfs_mount_t     *mp,
        xfs_trans_t     *tp,
        xfs_ino_t       ino,
+       uint            flags,
        uint            lock_flags,
        xfs_inode_t     **ipp,
        xfs_daddr_t     bno)
@@ -454,11 +471,10 @@
                if (inode->i_state & I_NEW) {
 inode_allocate:
                        vn_initialize(inode);
-                       error = xfs_iget_core(vp, mp, tp, ino,
-                                               lock_flags, ipp, bno);
+                       error = xfs_iget_core(vp, mp, tp, ino, flags,
+                                       lock_flags, ipp, bno);
                        if (error) {
-                               remove_inode_hash(inode);
-                               make_bad_inode(inode);
+                               vn_mark_bad(vp);
                                if (inode->i_state & I_NEW)
                                        unlock_new_inode(inode);
                                iput(inode);
@@ -582,12 +598,12 @@
 
        vn_trace_entry(vp, "xfs_iput_new", (inst_t *)__return_address);
 
-       /* We shouldn't get here without this being true, but just in case */
-       if (inode->i_state & I_NEW) {
-               remove_inode_hash(inode);
-               make_bad_inode(inode);
-               unlock_new_inode(inode);
+       if ((ip->i_d.di_mode == 0)) {
+               ASSERT(!(ip->i_flags & XFS_IRECLAIMABLE));
+               vn_mark_bad(vp);
        }
+       if (inode->i_state & I_NEW)
+               unlock_new_inode(inode);
        if (lock_flags)
                xfs_iunlock(ip, lock_flags);
        VN_RELE(vp);
diff -urN linux/fs/xfs/xfs_inode.c linux/fs/xfs/xfs_inode.c
--- linux/fs/xfs/xfs_inode.c    2004/11/19 00:28:49     1.19.2.4
+++ linux/fs/xfs/xfs_inode.c    2004/12/27 04:13:52     1.19.2.5
@@ -881,6 +881,10 @@
                        flags |= XFS_XFLAG_NODUMP;
                if (di_flags & XFS_DIFLAG_RTINHERIT)
                        flags |= XFS_XFLAG_RTINHERIT;
+               if (di_flags & XFS_DIFLAG_PROJINHERIT)
+                       flags |= XFS_XFLAG_PROJINHERIT;
+               if (di_flags & XFS_DIFLAG_NOSYMLINKS)
+                       flags |= XFS_XFLAG_NOSYMLINKS;
        }
        return flags;
 }
@@ -1159,7 +1163,8 @@
         * This is because we're setting fields here we need
         * to prevent others from looking at until we're done.
         */
-       error = xfs_trans_iget(tp->t_mountp, tp, ino, XFS_ILOCK_EXCL, &ip);
+       error = xfs_trans_iget(tp->t_mountp, tp, ino,
+                       IGET_CREATE, XFS_ILOCK_EXCL, &ip);
        if (error != 0) {
                return error;
        }
@@ -1257,6 +1262,9 @@
                        if ((pip->i_d.di_flags & XFS_DIFLAG_SYNC) &&
                            xfs_inherit_sync)
                                ip->i_d.di_flags |= XFS_DIFLAG_SYNC;
+                       if ((pip->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) &&
+                           xfs_inherit_nosymlinks)
+                               ip->i_d.di_flags |= XFS_DIFLAG_NOSYMLINKS;
                }
                /* FALLTHROUGH */
        case S_IFLNK:
diff -urN linux/fs/xfs/xfs_inode.h linux/fs/xfs/xfs_inode.h
--- linux/fs/xfs/xfs_inode.h    2004/08/14 18:39:02     1.12.2.2
+++ linux/fs/xfs/xfs_inode.h    2004/12/27 04:13:52     1.12.2.3
@@ -381,6 +381,7 @@
 #define XFS_IRECLAIM    0x0008  /* we have started reclaiming this inode    */
 #define XFS_ISTALE     0x0010  /* inode has been staled */
 #define XFS_IRECLAIMABLE 0x0020 /* inode can be reclaimed */
+#define XFS_INEW       0x0040
 
 /*
  * Flags for inode locking.
@@ -465,6 +466,9 @@
 /*
  * xfs_iget.c prototypes.
  */
+
+#define IGET_CREATE    1
+
 void           xfs_ihash_init(struct xfs_mount *);
 void           xfs_ihash_free(struct xfs_mount *);
 void           xfs_chash_init(struct xfs_mount *);
@@ -473,7 +477,7 @@
                                  struct xfs_trans *);
 void            xfs_inode_lock_init(xfs_inode_t *, struct vnode *);
 int            xfs_iget(struct xfs_mount *, struct xfs_trans *, xfs_ino_t,
-                        uint, xfs_inode_t **, xfs_daddr_t);
+                        uint, uint, xfs_inode_t **, xfs_daddr_t);
 void           xfs_iput(xfs_inode_t *, uint);
 void           xfs_iput_new(xfs_inode_t *, uint);
 void           xfs_ilock(xfs_inode_t *, uint);
@@ -508,7 +512,6 @@
 uint           xfs_dic2xflags(struct xfs_dinode_core *, xfs_arch_t);
 int            xfs_ifree(struct xfs_trans *, xfs_inode_t *,
                           struct xfs_bmap_free *);
-int            xfs_atruncate_start(xfs_inode_t *);
 void           xfs_itruncate_start(xfs_inode_t *, uint, xfs_fsize_t);
 int            xfs_itruncate_finish(struct xfs_trans **, xfs_inode_t *,
                                     xfs_fsize_t, int, int);
diff -urN linux/fs/xfs/xfs_itable.c linux/fs/xfs/xfs_itable.c
--- linux/fs/xfs/xfs_itable.c   2004/11/19 00:28:49     1.4.2.4
+++ linux/fs/xfs/xfs_itable.c   2004/12/27 04:13:52     1.4.2.5
@@ -102,7 +102,7 @@
                /* We're not being passed a pointer to a dinode.  This happens
                 * if BULKSTAT_FG_IGET is selected.  Do the iget.
                 */
-               error = xfs_iget(mp, NULL, ino, XFS_ILOCK_SHARED, &ip, bno);
+               error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, bno);
                if (error) {
                        *stat = BULKSTAT_RV_NOTHING;
                        return error;
diff -urN linux/fs/xfs/xfs_log.c linux/fs/xfs/xfs_log.c
--- linux/fs/xfs/xfs_log.c      2004/11/19 00:28:49     1.15.2.5
+++ linux/fs/xfs/xfs_log.c      2004/12/27 04:13:52     1.15.2.6
@@ -902,20 +902,15 @@
        } else {
                /*
                 * The reservation head is behind the tail.
-                * This can only happen when the AIL is empty so the tail
-                * is equal to the head and the l_roundoff value in the
-                * log structure is taking up the difference between the
-                * reservation head and the tail.  The bytes accounted for
-                * by the l_roundoff field are temporarily 'lost' to the
-                * reservation mechanism, but they are cleaned up when the
-                * log buffers that created them are reused.  These lost
-                * bytes are what allow the reservation head to fall behind
-                * the tail in the case that the log is 'empty'.
                 * In this case we just want to return the size of the
                 * log as the amount of space left.
                 */
-               ASSERT((tail_cycle == (cycle + 1)) ||
-                      ((bytes + log->l_roundoff) >= tail_bytes));
+               xfs_fs_cmn_err(CE_ALERT, log->l_mp,
+                       "xlog_space_left: head behind tail\n"
+                       "  tail_cycle = %d, tail_bytes = %d\n"
+                       "  GH   cycle = %d, GH   bytes = %d",
+                       tail_cycle, tail_bytes, cycle, bytes);
+               ASSERT(0);
                free_bytes = log->l_logsize;
        }
        return free_bytes;
@@ -1355,8 +1350,8 @@
 
 
 /*
- * Flush out the in-core log (iclog) to the on-disk log in a synchronous or
- * asynchronous fashion.  Previously, we should have moved the current iclog
+ * Flush out the in-core log (iclog) to the on-disk log in an asynchronous 
+ * fashion.  Previously, we should have moved the current iclog
  * ptr in the log to point to the next available iclog.  This allows further
  * write to continue while this code syncs out an iclog ready to go.
  * Before an in-core log can be written out, the data section must be scanned
@@ -1388,8 +1383,11 @@
        int             i, ops;
        uint            count;          /* byte count of bwrite */
        uint            count_init;     /* initial count before roundup */
+       int             roundoff;       /* roundoff to BB or stripe */
        int             split = 0;      /* split write into two regions */
        int             error;
+       SPLDECL(s);
+       int             v2 = XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb);
 
        XFS_STATS_INC(xs_log_writes);
        ASSERT(iclog->ic_refcnt == 0);
@@ -1398,23 +1396,34 @@
        count_init = log->l_iclog_hsize + iclog->ic_offset;
 
        /* Round out the log write size */
-       if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) &&
-           log->l_mp->m_sb.sb_logsunit > 1) {
+       if (v2 && log->l_mp->m_sb.sb_logsunit > 1) {
                /* we have a v2 stripe unit to use */
                count = XLOG_LSUNITTOB(log, XLOG_BTOLSUNIT(log, count_init));
        } else {
                count = BBTOB(BTOBB(count_init));
        }
-       iclog->ic_roundoff = count - count_init;
-       log->l_roundoff += iclog->ic_roundoff;
+       roundoff = count - count_init;
+       ASSERT(roundoff >= 0);
+       ASSERT((v2 && log->l_mp->m_sb.sb_logsunit > 1 && 
+                roundoff < log->l_mp->m_sb.sb_logsunit)
+               || 
+               (log->l_mp->m_sb.sb_logsunit <= 1 && 
+                roundoff < BBTOB(1)));
 
-       xlog_pack_data(log, iclog);       /* put cycle number in every block */
+       /* move grant heads by roundoff in sync */
+       s = GRANT_LOCK(log);
+       XLOG_GRANT_ADD_SPACE(log, roundoff, 'w');
+       XLOG_GRANT_ADD_SPACE(log, roundoff, 'r');
+       GRANT_UNLOCK(log, s);
+
+       /* put cycle number in every block */
+       xlog_pack_data(log, iclog, roundoff); 
 
        /* real byte length */
-       if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) {
+       if (v2) {
                INT_SET(iclog->ic_header.h_len, 
                        ARCH_CONVERT,
-                       iclog->ic_offset + iclog->ic_roundoff);
+                       iclog->ic_offset + roundoff);
        } else {
                INT_SET(iclog->ic_header.h_len, ARCH_CONVERT, iclog->ic_offset);
        }
@@ -2278,11 +2287,6 @@
                INT_SET(head->h_cycle, ARCH_CONVERT, log->l_curr_cycle);
                ASSIGN_LSN(head->h_lsn, log, ARCH_CONVERT);
                ASSERT(log->l_curr_block >= 0);
-
-               /* round off error from last write with this iclog */
-               ticket->t_curr_res -= iclog->ic_roundoff;
-               log->l_roundoff -= iclog->ic_roundoff;
-               iclog->ic_roundoff = 0;
        }
 
        /* If there is enough room to write everything, then do it.  Otherwise,
@@ -2853,7 +2857,6 @@
                                 * has already taken care of the roundoff from
                                 * the previous sync.
                                 */
-                               ASSERT(iclog->ic_roundoff == 0);
                                iclog->ic_refcnt++;
                                lsn = INT_GET(iclog->ic_header.h_lsn, 
ARCH_CONVERT);
                                xlog_state_switch_iclogs(log, iclog, 0);
diff -urN linux/fs/xfs/xfs_log_priv.h linux/fs/xfs/xfs_log_priv.h
--- linux/fs/xfs/xfs_log_priv.h 2004/04/16 03:14:20     1.8.2.2
+++ linux/fs/xfs/xfs_log_priv.h 2004/12/27 04:13:52     1.8.2.3
@@ -430,7 +430,6 @@
        int                     ic_size;
        int                     ic_offset;
        int                     ic_refcnt;
-       int                     ic_roundoff;
        int                     ic_bwritecnt;
        ushort_t                ic_state;
        char                    *ic_datap;      /* pointer to iclog data */
@@ -462,7 +461,6 @@
 #define        ic_size         hic_fields.ic_size
 #define        ic_offset       hic_fields.ic_offset
 #define        ic_refcnt       hic_fields.ic_refcnt
-#define        ic_roundoff     hic_fields.ic_roundoff
 #define        ic_bwritecnt    hic_fields.ic_bwritecnt
 #define        ic_state        hic_fields.ic_state
 #define ic_datap       hic_fields.ic_datap
@@ -498,7 +496,6 @@
        xfs_daddr_t             l_logBBstart;   /* start block of log */
        int                     l_logsize;      /* size of log in bytes */
        int                     l_logBBsize;    /* size of log in BB chunks */
-       int                     l_roundoff;     /* round off error of iclogs */
        int                     l_curr_cycle;   /* Cycle number of log writes */
        int                     l_prev_cycle;   /* Cycle number before last
                                                 * block increment */
@@ -543,10 +540,9 @@
                                xfs_daddr_t *head_blk,
                                xfs_daddr_t *tail_blk,
                                int readonly);
-extern int      xlog_print_find_oldest(xlog_t *log, xfs_daddr_t *last_blk);
 extern int      xlog_recover(xlog_t *log, int readonly);
 extern int      xlog_recover_finish(xlog_t *log, int mfsi_flags);
-extern void     xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog);
+extern void     xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog, int);
 extern void     xlog_recover_process_iunlinks(xlog_t *log);
 
 extern struct xfs_buf *xlog_get_bp(xlog_t *, int);
diff -urN linux/fs/xfs/xfs_log_recover.c linux/fs/xfs/xfs_log_recover.c
--- linux/fs/xfs/xfs_log_recover.c      2004/11/19 00:28:50     1.16.2.5
+++ linux/fs/xfs/xfs_log_recover.c      2004/12/27 04:13:52     1.16.2.6
@@ -3262,7 +3262,7 @@
                                xfs_buf_relse(agibp);
 
                                ino = XFS_AGINO_TO_INO(mp, agno, agino);
-                               error = xfs_iget(mp, NULL, ino, 0, &ip, 0);
+                               error = xfs_iget(mp, NULL, ino, 0, 0, &ip, 0);
                                ASSERT(error || (ip != NULL));
 
                                if (!error) {
@@ -3384,10 +3384,11 @@
 void
 xlog_pack_data(
        xlog_t                  *log,
-       xlog_in_core_t          *iclog)
+       xlog_in_core_t          *iclog,
+       int                     roundoff)
 {
        int                     i, j, k;
-       int                     size = iclog->ic_offset + iclog->ic_roundoff;
+       int                     size = iclog->ic_offset + roundoff;
        uint                    cycle_lsn;
        xfs_caddr_t             dp;
        xlog_in_core_2_t        *xhdr;
diff -urN linux/fs/xfs/xfs_mount.c linux/fs/xfs/xfs_mount.c
--- linux/fs/xfs/xfs_mount.c    2004/11/19 00:28:50     1.19.2.4
+++ linux/fs/xfs/xfs_mount.c    2004/12/27 04:13:52     1.19.2.5
@@ -975,7 +975,7 @@
         * Get and sanity-check the root inode.
         * Save the pointer to it in the mount structure.
         */
-       error = xfs_iget(mp, NULL, sbp->sb_rootino, XFS_ILOCK_EXCL, &rip, 0);
+       error = xfs_iget(mp, NULL, sbp->sb_rootino, 0, XFS_ILOCK_EXCL, &rip, 0);
        if (error) {
                cmn_err(CE_WARN, "XFS: failed to read root inode");
                goto error3;
@@ -1036,7 +1036,7 @@
        /*
         * Complete the quota initialisation, post-log-replay component.
         */
-       if ((error = XFS_QM_MOUNT(mp, quotamount, quotaflags)))
+       if ((error = XFS_QM_MOUNT(mp, quotamount, quotaflags, mfsi_flags)))
                goto error4;
 
        return 0;
@@ -1098,6 +1098,8 @@
 
        xfs_unmountfs_writesb(mp);
 
+       xfs_unmountfs_wait(mp);                 /* wait for async bufs */
+
        xfs_log_unmount(mp);                    /* Done! No more fs ops. */
 
        xfs_freesb(mp);
@@ -1142,6 +1144,16 @@
        xfs_free_buftarg(mp->m_ddev_targp, 0);
 }
 
+void
+xfs_unmountfs_wait(xfs_mount_t *mp)
+{
+       if (mp->m_logdev_targp != mp->m_ddev_targp)
+               xfs_wait_buftarg(mp->m_logdev_targp);
+       if (mp->m_rtdev_targp)
+               xfs_wait_buftarg(mp->m_rtdev_targp);
+       xfs_wait_buftarg(mp->m_ddev_targp);
+}
+
 int
 xfs_unmountfs_writesb(xfs_mount_t *mp)
 {
diff -urN linux/fs/xfs/xfs_mount.h linux/fs/xfs/xfs_mount.h
--- linux/fs/xfs/xfs_mount.h    2004/11/19 00:28:50     1.15.2.4
+++ linux/fs/xfs/xfs_mount.h    2004/12/27 04:13:53     1.15.2.5
@@ -133,7 +133,7 @@
 struct xfs_quotainfo;
 
 typedef int    (*xfs_qminit_t)(struct xfs_mount *, uint *, uint *);
-typedef int    (*xfs_qmmount_t)(struct xfs_mount *, uint, uint);
+typedef int    (*xfs_qmmount_t)(struct xfs_mount *, uint, uint, int);
 typedef int    (*xfs_qmunmount_t)(struct xfs_mount *);
 typedef void   (*xfs_qmdone_t)(struct xfs_mount *);
 typedef void   (*xfs_dqrele_t)(struct xfs_dquot *);
@@ -171,8 +171,8 @@
 
 #define XFS_QM_INIT(mp, mnt, fl) \
        (*(mp)->m_qm_ops.xfs_qminit)(mp, mnt, fl)
-#define XFS_QM_MOUNT(mp, mnt, fl) \
-       (*(mp)->m_qm_ops.xfs_qmmount)(mp, mnt, fl)
+#define XFS_QM_MOUNT(mp, mnt, fl, mfsi_flags) \
+       (*(mp)->m_qm_ops.xfs_qmmount)(mp, mnt, fl, mfsi_flags)
 #define XFS_QM_UNMOUNT(mp) \
        (*(mp)->m_qm_ops.xfs_qmunmount)(mp)
 #define XFS_QM_DONE(mp) \
@@ -466,6 +466,7 @@
 #define XFS_MFSI_CLIENT                0x02    /* Is a client -- skip lots of 
stuff */
 #define XFS_MFSI_NOUNLINK      0x08    /* Skip unlinked inode processing in */
                                        /* log recovery */
+#define XFS_MFSI_NO_QUOTACHECK 0x10    /* Skip quotacheck processing */
 
 /*
  * Macros for getting from mount to vfs and back.
@@ -540,6 +541,7 @@
 extern int     xfs_mountfs(struct vfs *, xfs_mount_t *mp, int);
 
 extern int     xfs_unmountfs(xfs_mount_t *, struct cred *);
+extern void    xfs_unmountfs_wait(xfs_mount_t *);
 extern void    xfs_unmountfs_close(xfs_mount_t *, struct cred *);
 extern int     xfs_unmountfs_writesb(xfs_mount_t *);
 extern int     xfs_unmount_flush(xfs_mount_t *, int);
diff -urN linux/fs/xfs/xfs_rtalloc.c linux/fs/xfs/xfs_rtalloc.c
--- linux/fs/xfs/xfs_rtalloc.c  2004/11/19 00:28:50     1.6.2.3
+++ linux/fs/xfs/xfs_rtalloc.c  2004/12/27 04:13:53     1.6.2.4
@@ -149,7 +149,7 @@
                /*
                 * Lock the inode.
                 */
-               if ((error = xfs_trans_iget(mp, tp, ino, XFS_ILOCK_EXCL, &ip)))
+               if ((error = xfs_trans_iget(mp, tp, ino, 0, XFS_ILOCK_EXCL, 
&ip)))
                        goto error_exit;
                XFS_BMAP_INIT(&flist, &firstblock);
                /*
@@ -189,7 +189,7 @@
                        /*
                         * Lock the bitmap inode.
                         */
-                       if ((error = xfs_trans_iget(mp, tp, ino, XFS_ILOCK_EXCL,
+                       if ((error = xfs_trans_iget(mp, tp, ino, 0, 
XFS_ILOCK_EXCL,
                                        &ip)))
                                goto error_exit;
                        /*
@@ -1966,7 +1966,8 @@
        /*
         * Calculate new parameters.  These are the final values to be reached.
         */
-       nrextents = do_div(nrblocks, in->extsize);
+       nrextents = nrblocks;
+       do_div(nrextents, in->extsize);
        nrbmblocks = roundup_64(nrextents, NBBY * sbp->sb_blocksize);
        nrextslog = xfs_highbit32(nrextents);
        nrsumlevels = nrextslog + 1;
@@ -2021,7 +2022,8 @@
                        XFS_RTMIN(nrblocks,
                                  nsbp->sb_rbmblocks * NBBY *
                                  nsbp->sb_blocksize * nsbp->sb_rextsize);
-               nsbp->sb_rextents = do_div(nsbp->sb_rblocks, nsbp->sb_rextsize);
+               nsbp->sb_rextents = nsbp->sb_rblocks;
+               do_div(nsbp->sb_rextents, nsbp->sb_rextsize);
                nsbp->sb_rextslog = xfs_highbit32(nsbp->sb_rextents);
                nrsumlevels = nmp->m_rsumlevels = nsbp->sb_rextslog + 1;
                nrsumsize =
@@ -2040,7 +2042,7 @@
                /*
                 * Lock out other callers by grabbing the bitmap inode lock.
                 */
-               if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino,
+               if ((error = xfs_trans_iget(mp, tp, 0, mp->m_sb.sb_rbmino,
                                XFS_ILOCK_EXCL, &ip)))
                        goto error_exit;
                ASSERT(ip == mp->m_rbmip);
@@ -2055,7 +2057,7 @@
                 * Get the summary inode into the transaction.
                 */
                if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino,
-                               XFS_ILOCK_EXCL, &ip)))
+                               0, XFS_ILOCK_EXCL, &ip)))
                        goto error_exit;
                ASSERT(ip == mp->m_rsumip);
                /*
@@ -2175,7 +2177,7 @@
        /*
         * Lock out other callers by grabbing the bitmap inode lock.
         */
-       error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, XFS_ILOCK_EXCL, &ip);
+       error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, XFS_ILOCK_EXCL, 
&ip);
        if (error) {
                return error;
        }
@@ -2238,7 +2240,7 @@
        /*
         * Synchronize by locking the bitmap inode.
         */
-       error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, XFS_ILOCK_EXCL, &ip);
+       error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, XFS_ILOCK_EXCL, 
&ip);
        if (error) {
                return error;
        }
@@ -2346,12 +2348,12 @@
        sbp = &mp->m_sb;
        if (sbp->sb_rbmino == NULLFSINO)
                return 0;
-       error = xfs_iget(mp, NULL, sbp->sb_rbmino, 0, &mp->m_rbmip, 0);
+       error = xfs_iget(mp, NULL, sbp->sb_rbmino, 0, 0, &mp->m_rbmip, 0);
        if (error)
                return error;
        ASSERT(mp->m_rbmip != NULL);
        ASSERT(sbp->sb_rsumino != NULLFSINO);
-       error = xfs_iget(mp, NULL, sbp->sb_rsumino, 0, &mp->m_rsumip, 0);
+       error = xfs_iget(mp, NULL, sbp->sb_rsumino, 0, 0, &mp->m_rsumip, 0);
        if (error) {
                VN_RELE(XFS_ITOV(mp->m_rbmip));
                return error;
@@ -2382,7 +2384,7 @@
        __uint64_t      seq;            /* sequence number of file creation */
        __uint64_t      *seqp;          /* pointer to seqno in inode */
 
-       error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, XFS_ILOCK_EXCL, &ip);
+       error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, XFS_ILOCK_EXCL, 
&ip);
        if (error)
                return error;
        ASSERT(ip == mp->m_rbmip);
diff -urN linux/fs/xfs/xfs_trans.h linux/fs/xfs/xfs_trans.h
--- linux/fs/xfs/xfs_trans.h    2004/08/14 18:39:02     1.9.2.3
+++ linux/fs/xfs/xfs_trans.h    2004/12/27 04:13:53     1.9.2.4
@@ -1007,7 +1007,7 @@
 void           xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint);
 void           xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *);
 int            xfs_trans_iget(struct xfs_mount *, xfs_trans_t *,
-                              xfs_ino_t , uint, struct xfs_inode **);
+                              xfs_ino_t , uint, uint, struct xfs_inode **);
 void           xfs_trans_ijoin(xfs_trans_t *, struct xfs_inode *, uint);
 void           xfs_trans_ihold(xfs_trans_t *, struct xfs_inode *);
 void           xfs_trans_ihold_release(xfs_trans_t *, struct xfs_inode *);
diff -urN linux/fs/xfs/xfs_trans_inode.c linux/fs/xfs/xfs_trans_inode.c
--- linux/fs/xfs/xfs_trans_inode.c      2003/12/15 18:19:52     1.4.2.1
+++ linux/fs/xfs/xfs_trans_inode.c      2004/12/27 04:13:53     1.4.2.2
@@ -95,6 +95,7 @@
        xfs_mount_t     *mp,
        xfs_trans_t     *tp,
        xfs_ino_t       ino,
+       uint            flags,
        uint            lock_flags,
        xfs_inode_t     **ipp)
 {
@@ -106,9 +107,8 @@
         * If the transaction pointer is NULL, just call the normal
         * xfs_iget().
         */
-       if (tp == NULL) {
-               return (xfs_iget(mp, NULL, ino, lock_flags, ipp, 0));
-       }
+       if (tp == NULL)
+               return xfs_iget(mp, NULL, ino, flags, lock_flags, ipp, 0);
 
        /*
         * If we find the inode in core with this transaction
@@ -148,7 +148,7 @@
        }
 
        ASSERT(lock_flags & XFS_ILOCK_EXCL);
-       error = xfs_iget(tp->t_mountp, tp, ino, lock_flags, &ip, 0);
+       error = xfs_iget(tp->t_mountp, tp, ino, flags, lock_flags, &ip, 0);
        if (error) {
                return error;
        }
@@ -186,7 +186,6 @@
        return 0;
 }
 
-
 /*
  * Add the locked inode to the transaction.
  * The inode must be locked, and it cannot be associated with any
diff -urN linux/fs/xfs/xfs_utils.c linux/fs/xfs/xfs_utils.c
--- linux/fs/xfs/xfs_utils.c    2003/12/15 18:19:52     1.7.2.1
+++ linux/fs/xfs/xfs_utils.c    2004/12/27 04:13:53     1.7.2.2
@@ -110,7 +110,7 @@
                 * reservation in the inactive routine.
                 */
                xfs_iunlock(dp, lock_mode);
-               error = xfs_iget(dp->i_mount, NULL, *inum, 0, ipp, 0);
+               error = xfs_iget(dp->i_mount, NULL, *inum, 0, 0, ipp, 0);
                xfs_ilock(dp, lock_mode);
 
                if (error) {
diff -urN linux/fs/xfs/xfs_vfsops.c linux/fs/xfs/xfs_vfsops.c
--- linux/fs/xfs/xfs_vfsops.c   2004/11/19 00:28:50     1.22.2.6
+++ linux/fs/xfs/xfs_vfsops.c   2004/12/27 04:13:53     1.22.2.7
@@ -1053,6 +1053,11 @@
                        continue;
                }
 
+               if (VN_BAD(vp)) {
+                       ip = ip->i_mnext;
+                       continue;
+               }
+
                if (XFS_FORCED_SHUTDOWN(mp) && !(flags & SYNC_CLOSE)) {
                        XFS_MOUNT_IUNLOCK(mp);
                        kmem_free(ipointer, sizeof(xfs_iptr_t));
@@ -1583,31 +1588,35 @@
        vnode_t         **vpp,
        fid_t           *fidp)
 {
-       xfs_fid_t       *xfid;
+       xfs_mount_t     *mp = XFS_BHVTOM(bdp);
+       xfs_fid_t       *xfid = (struct xfs_fid *)fidp;
        xfs_inode_t     *ip;
        int             error;
        xfs_ino_t       ino;
        unsigned int    igen;
-       xfs_mount_t     *mp;
 
-       xfid  = (struct xfs_fid *)fidp;
-       if (xfid->xfs_fid_len == sizeof(*xfid) - sizeof(xfid->xfs_fid_len)) {
-               ino  = xfid->xfs_fid_ino;
-               igen = xfid->xfs_fid_gen;
-       } else {
-               /*
-                * Invalid.  Since handles can be created in user space
-                * and passed in via gethandle(), this is not cause for
-                * a panic.
-                */
+       /*
+        * Invalid.  Since handles can be created in user space and passed in
+        * via gethandle(), this is not cause for a panic.
+        */
+       if (xfid->xfs_fid_len != sizeof(*xfid) - sizeof(xfid->xfs_fid_len))
                return XFS_ERROR(EINVAL);
-       }
-       mp = XFS_BHVTOM(bdp);
-       error = xfs_iget(mp, NULL, ino, XFS_ILOCK_SHARED, &ip, 0);
+
+       ino  = xfid->xfs_fid_ino;
+       igen = xfid->xfs_fid_gen;
+
+       /*
+        * NFS can sometimes send requests for ino 0.  Fail them gracefully.
+        */
+       if (ino == 0)
+               return XFS_ERROR(ESTALE);
+
+       error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0);
        if (error) {
                *vpp = NULL;
                return error;
        }
+
        if (ip == NULL) {
                *vpp = NULL;
                return XFS_ERROR(EIO);
diff -urN linux/fs/xfs/xfs_vnodeops.c linux/fs/xfs/xfs_vnodeops.c
--- linux/fs/xfs/xfs_vnodeops.c 2004/11/19 00:28:50     1.18.2.4
+++ linux/fs/xfs/xfs_vnodeops.c 2004/12/27 04:13:53     1.18.2.5
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -826,29 +826,34 @@
                                mp->m_sb.sb_blocklog;
                }
                if (mask & XFS_AT_XFLAGS) {
+                       uint    di_flags;
+
                        /* can't set PREALLOC this way, just preserve it */
-                       ip->i_d.di_flags =
-                               (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC);
-                       if (vap->va_xflags & XFS_XFLAG_REALTIME &&
-                           (ip->i_d.di_mode & S_IFMT) == S_IFREG) {
-                               ip->i_d.di_flags |= XFS_DIFLAG_REALTIME;
-                               ip->i_iocore.io_flags |= XFS_IOCORE_RT;
-                       } else {
-                               ip->i_iocore.io_flags &= ~XFS_IOCORE_RT;
-                       }
+                       di_flags = (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC);
                        if (vap->va_xflags & XFS_XFLAG_IMMUTABLE)
-                               ip->i_d.di_flags |= XFS_DIFLAG_IMMUTABLE;
+                               di_flags |= XFS_DIFLAG_IMMUTABLE;
                        if (vap->va_xflags & XFS_XFLAG_APPEND)
-                               ip->i_d.di_flags |= XFS_DIFLAG_APPEND;
+                               di_flags |= XFS_DIFLAG_APPEND;
                        if (vap->va_xflags & XFS_XFLAG_SYNC)
-                               ip->i_d.di_flags |= XFS_DIFLAG_SYNC;
+                               di_flags |= XFS_DIFLAG_SYNC;
                        if (vap->va_xflags & XFS_XFLAG_NOATIME)
-                               ip->i_d.di_flags |= XFS_DIFLAG_NOATIME;
+                               di_flags |= XFS_DIFLAG_NOATIME;
                        if (vap->va_xflags & XFS_XFLAG_NODUMP)
-                               ip->i_d.di_flags |= XFS_DIFLAG_NODUMP;
-                       if ((vap->va_xflags & XFS_XFLAG_RTINHERIT) &&
-                           (ip->i_d.di_mode & S_IFMT) == S_IFDIR)
-                               ip->i_d.di_flags |= XFS_DIFLAG_RTINHERIT;
+                               di_flags |= XFS_DIFLAG_NODUMP;
+                       if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
+                               if (vap->va_xflags & XFS_XFLAG_RTINHERIT)
+                                       di_flags |= XFS_DIFLAG_RTINHERIT;
+                               if (vap->va_xflags & XFS_XFLAG_NOSYMLINKS)
+                                       di_flags |= XFS_DIFLAG_NOSYMLINKS;
+                       } else {
+                               if (vap->va_xflags & XFS_XFLAG_REALTIME) {
+                                       di_flags |= XFS_DIFLAG_REALTIME;
+                                       ip->i_iocore.io_flags |= XFS_IOCORE_RT;
+                               } else {
+                                       ip->i_iocore.io_flags &= ~XFS_IOCORE_RT;
+                               }
+                       }
+                       ip->i_d.di_flags = di_flags;
                }
                xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
                timeflags |= XFS_ICHGTIME_CHG;
@@ -1606,7 +1611,7 @@
         * If the inode is already free, then there can be nothing
         * to clean up here.
         */
-       if (ip->i_d.di_mode == 0) {
+       if (ip->i_d.di_mode == 0 || VN_BAD(vp)) {
                ASSERT(ip->i_df.if_real_bytes == 0);
                ASSERT(ip->i_df.if_broot_bytes == 0);
                return VN_INACTIVE_CACHE;
@@ -3390,6 +3395,14 @@
        xfs_ilock(dp, XFS_ILOCK_EXCL);
 
        /*
+        * Check whether the directory allows new symlinks or not.
+        */
+       if (dp->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) {
+               error = XFS_ERROR(EPERM);
+               goto error_return;
+       }
+
+       /*
         * Reserve disk quota : blocks and inode.
         */
        error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0);
@@ -3795,11 +3808,17 @@
        vnode_t         *vp;
 
        vp = BHV_TO_VNODE(bdp);
+       ip = XFS_BHVTOI(bdp);
 
        vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);
 
        ASSERT(!VN_MAPPED(vp));
-       ip = XFS_BHVTOI(bdp);
+
+       /* bad inode, get out here ASAP */
+       if (VN_BAD(vp)) {
+               xfs_ireclaim(ip);
+               return 0;
+       }
 
        if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) {
                if (ip->i_d.di_size > 0) {
@@ -3877,8 +3896,12 @@
        int             sync_mode)
 {
        xfs_ihash_t     *ih = ip->i_hash;
+       vnode_t         *vp = XFS_ITOV_NULL(ip);
        int             error;
 
+       if (vp && VN_BAD(vp))
+               return 0;
+
        /* The hash lock here protects a thread in xfs_iget_core from
         * racing with us on linking the inode back with a vnode.
         * Once we have the XFS_IRECLAIM flag set it will not touch
@@ -3886,8 +3909,7 @@
         */
        write_lock(&ih->ih_lock);
        if ((ip->i_flags & XFS_IRECLAIM) ||
-           (!(ip->i_flags & XFS_IRECLAIMABLE) &&
-             (XFS_ITOV_NULL(ip) == NULL))) {
+           (!(ip->i_flags & XFS_IRECLAIMABLE) && vp == NULL)) {
                write_unlock(&ih->ih_lock);
                if (locked) {
                        xfs_ifunlock(ip);
@@ -3954,15 +3976,13 @@
 xfs_finish_reclaim_all(xfs_mount_t *mp, int noblock)
 {
        int             purged;
-       struct list_head        *curr, *next;
-       xfs_inode_t     *ip;
+       xfs_inode_t     *ip, *n;
        int             done = 0;
 
        while (!done) {
                purged = 0;
                XFS_MOUNT_ILOCK(mp);
-               list_for_each_safe(curr, next, &mp->m_del_inodes) {
-                       ip = list_entry(curr, xfs_inode_t, i_reclaim);
+               list_for_each_entry_safe(ip, n, &mp->m_del_inodes, i_reclaim) {
                        if (noblock) {
                                if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0)
                                        continue;
diff -urN linux/fs/xfs/xfs_cap.c linux/fs/xfs/xfs_cap.c
--- linux/fs/xfs/Attic/xfs_cap.c        Mon Dec 27 04:13:53 2004        1.5.2.1
+++ linux/fs/xfs/Attic/xfs_cap.c        1970/01/01 00:00:002002
@@ -1,206 +0,0 @@
-/*
- * Copyright (c) 2002 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.  Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-
-#include "xfs.h"
-
-STATIC int xfs_cap_allow_set(vnode_t *);
-
-
-/*
- * Test for existence of capability attribute as efficiently as possible.
- */
-int
-xfs_cap_vhascap(
-       vnode_t         *vp)
-{
-       int             error;
-       int             len = sizeof(xfs_cap_set_t);
-       int             flags = ATTR_KERNOVAL|ATTR_ROOT;
-
-       VOP_ATTR_GET(vp, SGI_CAP_LINUX, NULL, &len, flags, sys_cred, error);
-       return (error == 0);
-}
-
-/*
- * Convert from extended attribute representation to in-memory for XFS.
- */
-STATIC int
-posix_cap_xattr_to_xfs(
-       posix_cap_xattr         *src,
-       size_t                  size,
-       xfs_cap_set_t           *dest)
-{
-       if (!src || !dest)
-               return EINVAL;
-
-       if (src->c_version != cpu_to_le32(POSIX_CAP_XATTR_VERSION))
-               return EINVAL;
-       if (src->c_abiversion != cpu_to_le32(_LINUX_CAPABILITY_VERSION))
-               return EINVAL;
-
-       if (size < sizeof(posix_cap_xattr))
-               return EINVAL;
-
-       ASSERT(sizeof(dest->cap_effective) == sizeof(src->c_effective));
-
-       dest->cap_effective     = src->c_effective;
-       dest->cap_permitted     = src->c_permitted;
-       dest->cap_inheritable   = src->c_inheritable;
-
-       return 0;
-}
-
-/*
- * Convert from in-memory XFS to extended attribute representation.
- */
-STATIC int
-posix_cap_xfs_to_xattr(
-       xfs_cap_set_t           *src,
-       posix_cap_xattr         *xattr_cap,
-       size_t                  size)
-{
-       size_t                  new_size = posix_cap_xattr_size();
-
-       if (size < new_size)
-               return -ERANGE;
-
-       ASSERT(sizeof(xattr_cap->c_effective) == sizeof(src->cap_effective));
-
-       xattr_cap->c_version    = cpu_to_le32(POSIX_CAP_XATTR_VERSION);
-       xattr_cap->c_abiversion = cpu_to_le32(_LINUX_CAPABILITY_VERSION);
-       xattr_cap->c_effective  = src->cap_effective;
-       xattr_cap->c_permitted  = src->cap_permitted;
-       xattr_cap->c_inheritable= src->cap_inheritable;
-
-       return new_size;
-}
-
-int
-xfs_cap_vget(
-       vnode_t         *vp,
-       void            *cap,
-       size_t          size)
-{
-       int             error;
-       int             len = sizeof(xfs_cap_set_t);
-       int             flags = ATTR_ROOT;
-       xfs_cap_set_t   xfs_cap = { 0 };
-       posix_cap_xattr *xattr_cap = cap;
-       char            *data = (char *)&xfs_cap;
-
-       VN_HOLD(vp);
-       if ((error = _MAC_VACCESS(vp, NULL, VREAD)))
-               goto out;
-
-       if (!size) {
-               flags |= ATTR_KERNOVAL;
-               data = NULL;
-       }
-       VOP_ATTR_GET(vp, SGI_CAP_LINUX, data, &len, flags, sys_cred, error);
-       if (error)
-               goto out;
-       ASSERT(len == sizeof(xfs_cap_set_t));
-
-       error = (size)? -posix_cap_xattr_size() :
-                       -posix_cap_xfs_to_xattr(&xfs_cap, xattr_cap, size);
-out:
-       VN_RELE(vp);
-       return -error;
-}
-
-int
-xfs_cap_vremove(
-       vnode_t         *vp)
-{
-       int             error;
-
-       VN_HOLD(vp);
-       error = xfs_cap_allow_set(vp);
-       if (!error) {
-               VOP_ATTR_REMOVE(vp, SGI_CAP_LINUX, ATTR_ROOT, sys_cred, error);
-               if (error == ENOATTR)
-                       error = 0;      /* 'scool */
-       }
-       VN_RELE(vp);
-       return -error;
-}
-
-int
-xfs_cap_vset(
-       vnode_t                 *vp,
-       void                    *cap,
-       size_t                  size)
-{
-       posix_cap_xattr         *xattr_cap = cap;
-       xfs_cap_set_t           xfs_cap;
-       int                     error;
-
-       if (!cap)
-               return -EINVAL;
-
-       error = posix_cap_xattr_to_xfs(xattr_cap, size, &xfs_cap);
-       if (error)
-               return -error;
-
-       VN_HOLD(vp);
-       error = xfs_cap_allow_set(vp);
-       if (error)
-               goto out;
-
-       VOP_ATTR_SET(vp, SGI_CAP_LINUX, (char *)&xfs_cap,
-                       sizeof(xfs_cap_set_t), ATTR_ROOT, sys_cred, error);
-out:
-       VN_RELE(vp);
-       return -error;
-}
-
-STATIC int
-xfs_cap_allow_set(
-       vnode_t         *vp)
-{
-       vattr_t         va;
-       int             error;
-
-       if (vp->v_vfsp->vfs_flag & VFS_RDONLY)
-               return EROFS;
-       if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND))
-               return EPERM;
-       if ((error = _MAC_VACCESS(vp, NULL, VWRITE)))
-               return error;
-       va.va_mask = XFS_AT_UID;
-       VOP_GETATTR(vp, &va, 0, NULL, error);
-       if (error)
-               return error;
-       if (va.va_uid != current->fsuid && !capable(CAP_FOWNER))
-               return EPERM;
-       return error;
-}
diff -urN linux/fs/xfs/xfs_mac.c linux/fs/xfs/xfs_mac.c
--- linux/fs/xfs/Attic/xfs_mac.c        Mon Dec 27 04:13:53 2004        1.2.2.1
+++ linux/fs/xfs/Attic/xfs_mac.c        1970/01/01 00:00:002002
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.  Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-
-#include "xfs.h"
-
-static xfs_mac_label_t *mac_low_high_lp;
-static xfs_mac_label_t *mac_high_low_lp;
-static xfs_mac_label_t *mac_admin_high_lp;
-static xfs_mac_label_t *mac_equal_equal_lp;
-
-/*
- * Test for the existence of a MAC label as efficiently as possible.
- */
-int
-xfs_mac_vhaslabel(
-       vnode_t         *vp)
-{
-       int             error;
-       int             len = sizeof(xfs_mac_label_t);
-       int             flags = ATTR_KERNOVAL|ATTR_ROOT;
-
-       VOP_ATTR_GET(vp, SGI_MAC_FILE, NULL, &len, flags, sys_cred, error);
-       return (error == 0);
-}
-
-int
-xfs_mac_iaccess(xfs_inode_t *ip, mode_t mode, struct cred *cr)
-{
-       xfs_mac_label_t mac;
-       xfs_mac_label_t *mp = mac_high_low_lp;
-
-       if (cr == NULL || sys_cred == NULL ) {
-               return EACCES;
-       }
-
-       if (xfs_attr_fetch(ip, SGI_MAC_FILE, (char *)&mac, sizeof(mac)) == 0) {
-               if ((mp = mac_add_label(&mac)) == NULL) {
-                       return mac_access(mac_high_low_lp, cr, mode);
-               }
-       }
-
-       return mac_access(mp, cr, mode);
-}
diff -urN linux/fs/xfs/linux-2.4/xfs_aops.c linux/fs/xfs/linux-2.4/xfs_aops.c
--- linux/fs/xfs/linux-2.4/Attic/xfs_aops.c     2004/11/19 00:28:50     1.1.2.2
+++ linux/fs/xfs/linux-2.4/Attic/xfs_aops.c     2004/12/27 04:13:53     1.1.2.3
@@ -516,13 +516,13 @@
 xfs_submit_page(
        struct page             *page,
        struct buffer_head      *bh_arr[],
-       int                     cnt)
+       int                     bh_count)
 {
        struct buffer_head      *bh;
        int                     i;
 
-       if (cnt) {
-               for (i = 0; i < cnt; i++) {
+       if (bh_count) {
+               for (i = 0; i < bh_count; i++) {
                        bh = bh_arr[i];
                        set_buffer_async_io(bh);
                        if (buffer_unwritten(bh))
@@ -531,12 +531,13 @@
                        clear_buffer_dirty(bh);
                }
 
-               for (i = 0; i < cnt; i++) {
+               for (i = 0; i < bh_count; i++) {
                        refile_buffer(bh_arr[i]);
                        submit_bh(WRITE, bh_arr[i]);
                }
-       } else
+       } else {
                unlock_page(page);
+       }
 }
 
 /*
@@ -570,11 +571,13 @@
        bh = head = page_buffers(page);
        do {
                offset = i << bbits;
+               if (offset >= end)
+                       break;
                if (!(PageUptodate(page) || buffer_uptodate(bh)))
                        continue;
                if (buffer_mapped(bh) && all_bh &&
                    !buffer_unwritten(bh) && !buffer_delay(bh)) {
-                       if (startio && (offset < end)) {
+                       if (startio) {
                                lock_buffer(bh);
                                bh_arr[index++] = bh;
                        }
@@ -602,7 +605,7 @@
                                ASSERT(private);
                        }
                }
-               if (startio && (offset < end)) {
+               if (startio) {
                        bh_arr[index++] = bh;
                } else {
                        unlock_buffer(bh);
diff -urN linux/fs/xfs/linux-2.4/xfs_buf.c linux/fs/xfs/linux-2.4/xfs_buf.c
--- linux/fs/xfs/linux-2.4/Attic/xfs_buf.c      2004/11/19 00:28:50     1.1.2.2
+++ linux/fs/xfs/linux-2.4/Attic/xfs_buf.c      2004/12/27 04:13:53     1.1.2.3
@@ -626,7 +626,7 @@
  *     which may imply that this call will block until those buffers
  *     are unlocked.  No I/O is implied by this call.
  */
-STATIC xfs_buf_t *
+xfs_buf_t *
 _pagebuf_find(                         /* find buffer for block        */
        xfs_buftarg_t           *target,/* target for block             */
        loff_t                  ioff,   /* starting offset of range     */
@@ -719,39 +719,14 @@
        return (pb);
 }
 
-
-/*
- *     pagebuf_find
- *
- *     pagebuf_find returns a buffer matching the specified range of
- *     data for the specified target, if any of the relevant blocks
- *     are in memory.  The buffer may have unallocated holes, if
- *     some, but not all, of the blocks are in memory.  Even where
- *     pages are present in the buffer, not all of every page may be
- *     valid.
- */
-xfs_buf_t *
-pagebuf_find(                          /* find buffer for block        */
-                                       /* if the block is in memory    */
-       xfs_buftarg_t           *target,/* target for block             */
-       loff_t                  ioff,   /* starting offset of range     */
-       size_t                  isize,  /* length of range              */
-       page_buf_flags_t        flags)  /* PBF_TRYLOCK                  */
-{
-       return _pagebuf_find(target, ioff, isize, flags, NULL);
-}
-
 /*
- *     pagebuf_get
+ *     xfs_buf_get_flags assembles a buffer covering the specified range.
  *
- *     pagebuf_get assembles a buffer covering the specified range.
- *     Some or all of the blocks in the range may be valid.  Storage
- *     in memory for all portions of the buffer will be allocated,
- *     although backing storage may not be.  If PBF_READ is set in
- *     flags, pagebuf_iostart is called also.
+ *     Storage in memory for all portions of the buffer will be allocated,
+ *     although backing storage may not be.
  */
 xfs_buf_t *
-pagebuf_get(                           /* allocate a buffer            */
+xfs_buf_get_flags(                     /* allocate a buffer            */
        xfs_buftarg_t           *target,/* target for buffer            */
        loff_t                  ioff,   /* starting offset of range     */
        size_t                  isize,  /* length of range              */
@@ -781,8 +756,8 @@
        if (!(pb->pb_flags & PBF_MAPPED)) {
                error = _pagebuf_map_pages(pb, flags);
                if (unlikely(error)) {
-                       printk(KERN_WARNING
-                              "pagebuf_get: failed to map pages\n");
+                       printk(KERN_WARNING "%s: failed to map pages\n",
+                                       __FUNCTION__);
                        goto no_buffer;
                }
        }
@@ -796,30 +771,50 @@
        pb->pb_bn = ioff;
        pb->pb_count_desired = pb->pb_buffer_length;
 
-       if (flags & PBF_READ) {
+       PB_TRACE(pb, "get", (unsigned long)flags);
+       return pb;
+
+ no_buffer:
+       if (flags & (PBF_LOCK | PBF_TRYLOCK))
+               pagebuf_unlock(pb);
+       pagebuf_rele(pb);
+       return NULL;
+}
+
+xfs_buf_t *
+xfs_buf_read_flags(
+       xfs_buftarg_t           *target,
+       loff_t                  ioff,
+       size_t                  isize,
+       page_buf_flags_t        flags)
+{
+       xfs_buf_t               *pb;
+
+       flags |= PBF_READ;
+
+       pb = xfs_buf_get_flags(target, ioff, isize, flags);
+       if (pb) {
                if (PBF_NOT_DONE(pb)) {
-                       PB_TRACE(pb, "get_read", (unsigned long)flags);
+                       PB_TRACE(pb, "read", (unsigned long)flags);
                        XFS_STATS_INC(pb_get_read);
                        pagebuf_iostart(pb, flags);
                } else if (flags & PBF_ASYNC) {
-                       PB_TRACE(pb, "get_read_async", (unsigned long)flags);
+                       PB_TRACE(pb, "read_async", (unsigned long)flags);
                        /*
                         * Read ahead call which is already satisfied,
                         * drop the buffer
                         */
                        goto no_buffer;
                } else {
-                       PB_TRACE(pb, "get_read_done", (unsigned long)flags);
+                       PB_TRACE(pb, "read_done", (unsigned long)flags);
                        /* We do not want read in the flags */
                        pb->pb_flags &= ~PBF_READ;
                }
-       } else {
-               PB_TRACE(pb, "get_write", (unsigned long)flags);
        }
 
        return pb;
 
-no_buffer:
+ no_buffer:
        if (flags & (PBF_LOCK | PBF_TRYLOCK))
                pagebuf_unlock(pb);
        pagebuf_rele(pb);
@@ -857,8 +852,8 @@
        size_t                  isize,
        page_buf_flags_t        flags)
 {
-       flags |= (PBF_TRYLOCK|PBF_READ|PBF_ASYNC|PBF_READ_AHEAD);
-       pagebuf_get(target, ioff, isize, flags);
+       flags |= (PBF_TRYLOCK|PBF_ASYNC|PBF_READ_AHEAD);
+       xfs_buf_read_flags(target, ioff, isize, flags);
 }
 
 xfs_buf_t *
@@ -1434,6 +1429,34 @@
  *     Handling of buftargs.
  */
 
+/*
+ * Wait for any bufs with callbacks that have been submitted but
+ * have not yet returned... walk the hash list for the target.
+ */
+void
+xfs_wait_buftarg(
+       xfs_buftarg_t *target)
+{
+       xfs_buf_t       *pb, *n;
+       pb_hash_t       *h;
+       int             i;
+
+       for (i = 0; i < NHASH; i++) {
+               h = &pbhash[i];
+again:
+               spin_lock(&h->pb_hash_lock);
+               list_for_each_entry_safe(pb, n, &h->pb_hash, pb_hash_list) {
+                       if (pb->pb_target == target &&
+                                       !(pb->pb_flags & PBF_FS_MANAGED)) {
+                               spin_unlock(&h->pb_hash_lock);
+                               delay(100);
+                               goto again;
+                       }
+               }
+               spin_unlock(&h->pb_hash_lock);
+       }
+}
+
 void
 xfs_free_buftarg(
        xfs_buftarg_t           *btp,
diff -urN linux/fs/xfs/linux-2.4/xfs_buf.h linux/fs/xfs/linux-2.4/xfs_buf.h
--- linux/fs/xfs/linux-2.4/Attic/xfs_buf.h      2004/11/19 00:28:50     1.1.2.2
+++ linux/fs/xfs/linux-2.4/Attic/xfs_buf.h      2004/12/27 04:13:53     1.1.2.3
@@ -183,20 +183,36 @@
 
 /* Finding and Reading Buffers */
 
-extern xfs_buf_t *pagebuf_find(        /* find buffer for block if     */
+extern xfs_buf_t *_pagebuf_find(       /* find buffer for block if     */
                                        /* the block is in memory       */
                xfs_buftarg_t *,        /* inode for block              */
                loff_t,                 /* starting offset of range     */
                size_t,                 /* length of range              */
-               page_buf_flags_t);      /* PBF_LOCK                     */
+               page_buf_flags_t,       /* PBF_LOCK                     */
+               xfs_buf_t *);           /* newly allocated buffer       */
 
-extern xfs_buf_t *pagebuf_get(         /* allocate a buffer            */
+#define xfs_incore(buftarg,blkno,len,lockit) \
+       _pagebuf_find(buftarg, blkno ,len, lockit, NULL)
+
+extern xfs_buf_t *xfs_buf_get_flags(   /* allocate a buffer            */
                xfs_buftarg_t *,        /* inode for buffer             */
                loff_t,                 /* starting offset of range     */
                size_t,                 /* length of range              */
                page_buf_flags_t);      /* PBF_LOCK, PBF_READ,          */
                                        /* PBF_ASYNC                    */
 
+#define xfs_buf_get(target, blkno, len, flags) \
+       xfs_buf_get_flags((target), (blkno), (len), PBF_LOCK | PBF_MAPPED)
+
+extern xfs_buf_t *xfs_buf_read_flags(  /* allocate and read a buffer   */
+               xfs_buftarg_t *,        /* inode for buffer             */
+               loff_t,                 /* starting offset of range     */
+               size_t,                 /* length of range              */
+               page_buf_flags_t);      /* PBF_LOCK, PBF_ASYNC          */
+
+#define xfs_buf_read(target, blkno, len, flags) \
+       xfs_buf_read_flags((target), (blkno), (len), PBF_LOCK | PBF_MAPPED)
+
 extern xfs_buf_t *pagebuf_lookup(
                xfs_buftarg_t *,
                loff_t,                 /* starting offset of range     */
@@ -524,18 +540,6 @@
 #define XFS_BUF_SET_VTYPE(bp, type)
 #define XFS_BUF_SET_REF(bp, ref)
 
-#define xfs_buf_read(target, blkno, len, flags) \
-               pagebuf_get((target), (blkno), (len), \
-                       PBF_LOCK | PBF_READ | PBF_MAPPED)
-#define xfs_buf_get(target, blkno, len, flags) \
-               pagebuf_get((target), (blkno), (len), \
-                       PBF_LOCK | PBF_MAPPED)
-
-#define xfs_buf_read_flags(target, blkno, len, flags) \
-               pagebuf_get((target), (blkno), (len), PBF_READ | (flags))
-#define xfs_buf_get_flags(target, blkno, len, flags) \
-               pagebuf_get((target), (blkno), (len), (flags))
-
 static inline int      xfs_bawrite(void *mp, xfs_buf_t *bp)
 {
        bp->pb_fspriv3 = mp;
@@ -560,10 +564,6 @@
 #define xfs_biodone(pb)                    \
            pagebuf_iodone(pb, (pb->pb_flags & PBF_FS_DATAIOD), 0)
 
-#define xfs_incore(buftarg,blkno,len,lockit) \
-           pagebuf_find(buftarg, blkno ,len, lockit)
-
-
 #define xfs_biomove(pb, off, len, data, rw) \
            pagebuf_iomove((pb), (off), (len), (data), \
                ((rw) == XFS_B_WRITE) ? PBRW_WRITE : PBRW_READ)
@@ -617,6 +617,7 @@
  
 extern xfs_buftarg_t *xfs_alloc_buftarg(struct block_device *);
 extern void xfs_free_buftarg(xfs_buftarg_t *, int);
+extern void xfs_wait_buftarg(xfs_buftarg_t *);
 extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int);
 extern void xfs_incore_relse(xfs_buftarg_t *, int, int);
 extern int xfs_flush_buftarg(xfs_buftarg_t *, int);
diff -urN linux/fs/xfs/linux-2.4/xfs_file.c linux/fs/xfs/linux-2.4/xfs_file.c
--- linux/fs/xfs/linux-2.4/Attic/xfs_file.c     2004/08/14 18:39:02     1.1.2.1
+++ linux/fs/xfs/linux-2.4/Attic/xfs_file.c     2004/12/27 04:13:53     1.1.2.2
@@ -322,7 +322,7 @@
        vattr_t         va = { .va_mask = XFS_AT_UPDATIME };
        int             error;
 
-       if ((vp->v_type == VREG) && (vp->v_vfsp->vfs_flag & VFS_DMI)) {
+       if (vp->v_vfsp->vfs_flag & VFS_DMI) {
                xfs_mount_t     *mp = XFS_VFSTOM(vp->v_vfsp);
 
                error = -XFS_SEND_MMAP(mp, vma, 0);
@@ -333,6 +333,8 @@
        vma->vm_ops = &linvfs_file_vm_ops;
 
        VOP_SETATTR(vp, &va, XFS_AT_UPDATIME, NULL, error);
+       if (!error)
+               vn_revalidate(vp);      /* update Linux inode flags */
        return 0;
 }
 
@@ -394,7 +396,7 @@
        vnode_t         *vp = LINVFS_GET_VP(vma->vm_file->f_dentry->d_inode);
        int             error = 0;
 
-       if ((vp->v_type == VREG) && (vp->v_vfsp->vfs_flag & VFS_DMI)) {
+       if (vp->v_vfsp->vfs_flag & VFS_DMI) {
                if ((vma->vm_flags & VM_MAYSHARE) &&
                    (newflags & PROT_WRITE) && !(vma->vm_flags & PROT_WRITE)) {
                        xfs_mount_t     *mp = XFS_VFSTOM(vp->v_vfsp);
diff -urN linux/fs/xfs/linux-2.4/xfs_fs_subr.h 
linux/fs/xfs/linux-2.4/xfs_fs_subr.h
--- linux/fs/xfs/linux-2.4/Attic/xfs_fs_subr.h  2004/08/14 18:39:02     1.1.2.1
+++ linux/fs/xfs/linux-2.4/Attic/xfs_fs_subr.h  2004/12/27 04:13:53     1.1.2.2
@@ -40,7 +40,6 @@
 
 extern int     fs_noerr(void);
 extern int     fs_nosys(void);
-extern int     fs_nodev(void);
 extern void    fs_noval(void);
 extern void    fs_tosspages(bhv_desc_t *, xfs_off_t, xfs_off_t, int);
 extern void    fs_flushinval_pages(bhv_desc_t *, xfs_off_t, xfs_off_t, int);
diff -urN linux/fs/xfs/linux-2.4/xfs_globals.c 
linux/fs/xfs/linux-2.4/xfs_globals.c
--- linux/fs/xfs/linux-2.4/Attic/xfs_globals.c  2004/08/14 18:39:02     1.1.2.1
+++ linux/fs/xfs/linux-2.4/Attic/xfs_globals.c  2004/12/27 04:13:53     1.1.2.2
@@ -66,6 +66,8 @@
        .inherit_noatim = {     0,      1,      1       },
        .xfs_buf_timer  = {     100/2,  100,    30*100  },
        .xfs_buf_age    = {     1*100,  15*100, 300*100 },
+       .inherit_nosym  = {     0,      0,      1       },
+       .rotorstep      = {     1,      1,      255     },
 };
 
 /*
diff -urN linux/fs/xfs/linux-2.4/xfs_ioctl.c linux/fs/xfs/linux-2.4/xfs_ioctl.c
--- linux/fs/xfs/linux-2.4/Attic/xfs_ioctl.c    2004/11/19 00:28:50     1.1.2.2
+++ linux/fs/xfs/linux-2.4/Attic/xfs_ioctl.c    2004/12/27 04:13:53     1.1.2.3
@@ -268,7 +268,7 @@
        /*
         * Get the XFS inode, building a vnode to go with it.
         */
-       error = xfs_iget(mp, NULL, ino, XFS_ILOCK_SHARED, &ip, 0);
+       error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0);
        if (error)
                return error;
        if (ip == NULL)
diff -urN linux/fs/xfs/linux-2.4/xfs_iops.c linux/fs/xfs/linux-2.4/xfs_iops.c
--- linux/fs/xfs/linux-2.4/Attic/xfs_iops.c     2004/08/14 18:39:02     1.1.2.1
+++ linux/fs/xfs/linux-2.4/Attic/xfs_iops.c     2004/12/27 04:13:53     1.1.2.2
@@ -173,8 +173,9 @@
                                 */
                                teardown.d_inode = ip = LINVFS_GET_IP(vp);
                                teardown.d_name = dentry->d_name;
-                               remove_inode_hash(ip);
-                               make_bad_inode(ip);
+
+                               vn_mark_bad(vp);
+
                                if (S_ISDIR(mode))
                                        VOP_RMDIR(dvp, &teardown, NULL, err2);
                                else
@@ -302,7 +303,7 @@
 {
        struct inode    *ip;
        vattr_t         va;
-       vnode_t         *dvp;   /* directory containing name to remove */
+       vnode_t         *dvp;   /* directory containing name of symlink */
        vnode_t         *cvp;   /* used to lookup symlink to put in dentry */
        int             error;
 
diff -urN linux/fs/xfs/linux-2.4/xfs_linux.h linux/fs/xfs/linux-2.4/xfs_linux.h
--- linux/fs/xfs/linux-2.4/Attic/xfs_linux.h    2004/11/19 00:28:50     1.1.2.2
+++ linux/fs/xfs/linux-2.4/Attic/xfs_linux.h    2004/12/27 04:13:53     1.1.2.3
@@ -79,6 +79,7 @@
 #include <linux/pagemap.h>
 #include <linux/seq_file.h>
 #include <linux/init.h>
+#include <linux/list.h>
 #include <linux/proc_fs.h>
 
 #include <asm/page.h>
@@ -141,6 +142,8 @@
 #define xfs_inherit_noatime    xfs_params.inherit_noatim.val
 #define xfs_buf_timer_centisecs        xfs_params.xfs_buf_timer.val
 #define xfs_buf_age_centisecs  xfs_params.xfs_buf_age.val
+#define xfs_inherit_nosymlinks xfs_params.inherit_nosym.val
+#define xfs_rotorstep          xfs_params.rotorstep.val
 
 #define current_cpu()          smp_processor_id()
 #define current_pid()          (current->pid)
diff -urN linux/fs/xfs/linux-2.4/xfs_lrw.c linux/fs/xfs/linux-2.4/xfs_lrw.c
--- linux/fs/xfs/linux-2.4/Attic/xfs_lrw.c      2004/11/19 00:28:50     1.1.2.2
+++ linux/fs/xfs/linux-2.4/Attic/xfs_lrw.c      2004/12/27 04:13:53     1.1.2.3
@@ -336,11 +336,12 @@
                ret = generic_file_read(file, buf, size, offset);
        }
 
+       if (ret > 0)
+               XFS_STATS_ADD(xs_read_bytes, ret);
+
        if (!(ioflags & IO_ISLOCKED))
                xfs_iunlock(ip, XFS_IOLOCK_SHARED);
 
-       XFS_STATS_ADD(xs_read_bytes, ret);
-
        if (unlikely(ioflags & IO_INVIS)) {
                /* generic_file_read updates the atime but we need to
                 * undo that because this I/O was supposed to be invisible.
diff -urN linux/fs/xfs/linux-2.4/xfs_super.c linux/fs/xfs/linux-2.4/xfs_super.c
--- linux/fs/xfs/linux-2.4/Attic/xfs_super.c    2004/11/19 00:28:50     1.1.2.2
+++ linux/fs/xfs/linux-2.4/Attic/xfs_super.c    2004/12/27 04:13:53     1.1.2.3
@@ -129,8 +129,7 @@
        vnode_t                 *vp = LINVFS_GET_VP(inode);
 
        if (vp->v_type == VNON) {
-               remove_inode_hash(inode);
-               make_bad_inode(inode);
+               vn_mark_bad(vp);
        } else if (S_ISREG(inode->i_mode)) {
                inode->i_op = &linvfs_file_inode_operations;
                inode->i_fop = &linvfs_file_operations;
@@ -211,21 +210,21 @@
                bhv_insert(VN_BHV_HEAD(vp), inode_bhv);
        }
 
-       vp->v_type = IFTOVT(ip->i_d.di_mode);
-
-       /* Have we been called during the new inode create process,
-        * in which case we are too early to fill in the Linux inode.
+       /*
+        * We need to set the ops vectors, and unlock the inode, but if
+        * we have been called during the new inode create process, it is
+        * too early to fill in the Linux inode.  We will get called a
+        * second time once the inode is properly set up, and then we can
+        * finish our work.
         */
-       if (vp->v_type == VNON)
-               return;
+       if (ip->i_d.di_mode != 0 && unlock && (inode->i_state & I_NEW)) {
+               vp->v_type = IFTOVT(ip->i_d.di_mode);
+               xfs_revalidate_inode(XFS_BHVTOM(bdp), vp, ip);
+               xfs_set_inodeops(inode);
 
-       xfs_revalidate_inode(XFS_BHVTOM(bdp), vp, ip);
+               ip->i_flags &= ~XFS_INEW;
+               barrier();
 
-       /* For new inodes we need to set the ops vectors,
-        * and unlock the inode.
-        */
-       if (unlock && (inode->i_state & I_NEW)) {
-               xfs_set_inodeops(inode);
                unlock_new_inode(inode);
        }
 }
@@ -253,25 +252,6 @@
        return iget_locked(vfsp->vfs_super, ino);
 }
 
-void
-xfs_flush_inode(
-       xfs_inode_t     *ip)
-{
-       struct inode    *inode = LINVFS_GET_IP(XFS_ITOV(ip));
-
-       filemap_fdatawrite(inode->i_mapping);
-}
-
-void
-xfs_flush_device(
-       xfs_inode_t     *ip)
-{
-       struct inode    *inode = LINVFS_GET_IP(XFS_ITOV(ip));
-
-       fsync_no_super(inode->i_dev);
-       xfs_log_force(ip->i_mount, (xfs_lsn_t)0, XFS_LOG_FORCE|XFS_LOG_SYNC);
-}
-
 struct dentry *
 d_alloc_anon(struct inode *inode)
 {
@@ -427,14 +407,105 @@
 }
 
 
+/*
+ * Enqueue a work item to be picked up by the vfs xfssyncd thread.
+ * Doing this has two advantages:
+ * - It saves on stack space, which is tight in certain situations
+ * - It can be used (with care) as a mechanism to avoid deadlocks.
+ * Flushing while allocating in a full filesystem requires both.
+ */
+STATIC void
+xfs_syncd_queue_work(
+       struct vfs      *vfs,
+       void            *data,
+       void            (*syncer)(vfs_t *, void *))
+{
+       vfs_sync_work_t *work;
+
+       work = kmem_alloc(sizeof(struct vfs_sync_work), KM_SLEEP);
+       INIT_LIST_HEAD(&work->w_list);
+       work->w_syncer = syncer;
+       work->w_data = data;
+       work->w_vfs = vfs;
+       spin_lock(&vfs->vfs_sync_lock);
+       list_add_tail(&work->w_list, &vfs->vfs_sync_list);
+       spin_unlock(&vfs->vfs_sync_lock);
+       wake_up_process(vfs->vfs_sync_task);
+}
+
+/*
+ * Flush delayed allocate data, attempting to free up reserved space
+ * from existing allocations.  At this point a new allocation attempt
+ * has failed with ENOSPC and we are in the process of scratching our
+ * heads, looking about for more room...
+ */
+STATIC void
+xfs_flush_inode_work(
+       vfs_t           *vfs,
+       void            *inode)
+{
+       filemap_fdatawrite(((struct inode *)inode)->i_mapping);
+       iput((struct inode *)inode);
+}
+
+void
+xfs_flush_inode(
+       xfs_inode_t     *ip)
+{
+       struct inode    *inode = LINVFS_GET_IP(XFS_ITOV(ip));
+       struct vfs      *vfs = XFS_MTOVFS(ip->i_mount);
+
+       igrab(inode);
+       xfs_syncd_queue_work(vfs, inode, xfs_flush_inode_work);
+       delay(HZ/2);
+}
+
+/*
+ * This is the "bigger hammer" version of xfs_flush_inode_work...
+ * (IOW, "If at first you don't succeed, use a Bigger Hammer").
+ */
+STATIC void
+xfs_flush_device_work(
+       vfs_t           *vfs,
+       void            *inode)
+{
+       fsync_no_super(((struct inode *)inode)->i_dev);
+       iput((struct inode *)inode);
+}
+
+void
+xfs_flush_device(
+       xfs_inode_t     *ip)
+{
+       struct inode    *inode = LINVFS_GET_IP(XFS_ITOV(ip));
+       struct vfs      *vfs = XFS_MTOVFS(ip->i_mount);
+
+       igrab(inode);
+       xfs_syncd_queue_work(vfs, inode, xfs_flush_device_work);
+       delay(HZ/2);
+       xfs_log_force(ip->i_mount, (xfs_lsn_t)0, XFS_LOG_FORCE|XFS_LOG_SYNC);
+}
+
 #define SYNCD_FLAGS    (SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR|SYNC_REFCACHE)
+STATIC void
+vfs_sync_worker(
+       vfs_t           *vfsp,
+       void            *unused)
+{
+       int             error;
+
+       if (!(vfsp->vfs_flag & VFS_RDONLY))
+               VFS_SYNC(vfsp, SYNCD_FLAGS, NULL, error);
+}
 
 STATIC int
 xfssyncd(
        void                    *arg)
 {
+       long                    timeleft;
        vfs_t                   *vfsp = (vfs_t *) arg;
-       int                     error;
+       struct list_head        tmp;
+       struct vfs_sync_work    *work, *n;
 
        daemonize();
        reparent_to_init();
@@ -445,18 +516,38 @@
 
        sprintf(current->comm, "xfssyncd");
 
+       vfsp->vfs_sync_work.w_vfs = vfsp;
+       vfsp->vfs_sync_work.w_syncer = vfs_sync_worker;
        vfsp->vfs_sync_task = current;
        wmb();
        wake_up(&vfsp->vfs_wait_sync_task);
 
+       INIT_LIST_HEAD(&tmp);
+       timeleft = (xfs_syncd_centisecs * HZ) / 100;
        for (;;) {
                set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout((xfs_syncd_centisecs * HZ) / 100);
+               timeleft = schedule_timeout(timeleft);
                if (vfsp->vfs_flag & VFS_UMOUNT)
                        break;
-               if (vfsp->vfs_flag & VFS_RDONLY)
-                       continue;
-               VFS_SYNC(vfsp, SYNCD_FLAGS, NULL, error);
+
+               spin_lock(&vfsp->vfs_sync_lock);
+               if (!timeleft) {
+                       timeleft = (xfs_syncd_centisecs * HZ) / 100;
+                       INIT_LIST_HEAD(&vfsp->vfs_sync_work.w_list);
+                       list_add_tail(&vfsp->vfs_sync_work.w_list,
+                                       &vfsp->vfs_sync_list);
+               }
+               list_for_each_entry_safe(work, n, &vfsp->vfs_sync_list, w_list)
+                       list_move(&work->w_list, &tmp);
+               spin_unlock(&vfsp->vfs_sync_lock);
+
+               list_for_each_entry_safe(work, n, &tmp, w_list) {
+                       (*work->w_syncer)(vfsp, work->w_data);
+                       list_del(&work->w_list);
+                       if (work == &vfsp->vfs_sync_work)
+                               continue;
+                       kmem_free(work, sizeof(struct vfs_sync_work));
+               }
        }
 
        vfsp->vfs_sync_task = NULL;
diff -urN linux/fs/xfs/linux-2.4/xfs_sysctl.c 
linux/fs/xfs/linux-2.4/xfs_sysctl.c
--- linux/fs/xfs/linux-2.4/Attic/xfs_sysctl.c   2004/08/14 18:39:02     1.1.2.1
+++ linux/fs/xfs/linux-2.4/Attic/xfs_sysctl.c   2004/12/27 04:13:53     1.1.2.2
@@ -160,6 +160,16 @@
        &sysctl_intvec, NULL,
        &xfs_params.xfs_buf_age.min, &xfs_params.xfs_buf_age.max},
 
+       {XFS_INHERIT_NOSYM, "inherit_nosymlinks", &xfs_params.inherit_nosym.val,
+       sizeof(int), 0644, NULL, &proc_dointvec_minmax,
+       &sysctl_intvec, NULL,
+       &xfs_params.inherit_nosym.min, &xfs_params.inherit_nosym.max},
+
+       {XFS_ROTORSTEP, "rotorstep", &xfs_params.rotorstep.val,
+       sizeof(int), 0644, NULL, &proc_dointvec_minmax,
+       &sysctl_intvec, NULL, 
+       &xfs_params.rotorstep.min, &xfs_params.rotorstep.max},
+
        /* please keep this the last entry */
 #ifdef CONFIG_PROC_FS
        {XFS_STATS_CLEAR, "stats_clear", &xfs_params.stats_clear.val,
diff -urN linux/fs/xfs/linux-2.4/xfs_sysctl.h 
linux/fs/xfs/linux-2.4/xfs_sysctl.h
--- linux/fs/xfs/linux-2.4/Attic/xfs_sysctl.h   2004/08/14 18:39:02     1.1.2.1
+++ linux/fs/xfs/linux-2.4/Attic/xfs_sysctl.h   2004/12/27 04:13:53     1.1.2.2
@@ -61,6 +61,8 @@
        xfs_sysctl_val_t inherit_noatim;/* Inherit the "noatime" inode flag. */
        xfs_sysctl_val_t xfs_buf_timer; /* Interval between xfsbufd wakeups. */
        xfs_sysctl_val_t xfs_buf_age;   /* Metadata buffer age before flush. */
+       xfs_sysctl_val_t inherit_nosym; /* Inherit the "nosymlinks" flag. */
+       xfs_sysctl_val_t rotorstep;     /* inode32 AG rotoring control knob */
 } xfs_param_t;
 
 /*
@@ -97,6 +99,8 @@
        XFS_BUF_TIMER = 16,
        XFS_BUF_AGE = 17,
        /* XFS_IO_BYPASS = 18, */
+       XFS_INHERIT_NOSYM = 19,
+       XFS_ROTORSTEP = 20,
 };
 
 extern xfs_param_t     xfs_params;
diff -urN linux/fs/xfs/linux-2.4/xfs_vfs.c linux/fs/xfs/linux-2.4/xfs_vfs.c
--- linux/fs/xfs/linux-2.4/Attic/xfs_vfs.c      2004/11/19 00:28:50     1.1.2.2
+++ linux/fs/xfs/linux-2.4/Attic/xfs_vfs.c      2004/12/27 04:13:53     1.1.2.3
@@ -262,6 +262,8 @@
 
        vfsp = kmem_zalloc(sizeof(vfs_t), KM_SLEEP);
        bhv_head_init(VFS_BHVHEAD(vfsp), "vfs");
+       INIT_LIST_HEAD(&vfsp->vfs_sync_list);
+       vfsp->vfs_sync_lock = SPIN_LOCK_UNLOCKED;
        init_waitqueue_head(&vfsp->vfs_wait_sync_task);
        init_waitqueue_head(&vfsp->vfs_wait_unfrozen);
        return vfsp;
diff -urN linux/fs/xfs/linux-2.4/xfs_vfs.h linux/fs/xfs/linux-2.4/xfs_vfs.h
--- linux/fs/xfs/linux-2.4/Attic/xfs_vfs.h      2004/11/19 00:28:50     1.1.2.2
+++ linux/fs/xfs/linux-2.4/Attic/xfs_vfs.h      2004/12/27 04:13:53     1.1.2.3
@@ -36,6 +36,7 @@
 #include "xfs_fs.h"
 
 struct fid;
+struct vfs;
 struct cred;
 struct vnode;
 struct statfs;
@@ -45,13 +46,23 @@
 
 typedef struct statfs xfs_statfs_t;
 
+typedef struct vfs_sync_work {
+       struct list_head        w_list;
+       struct vfs              *w_vfs;
+       void                    *w_data;        /* syncer routine argument */
+       void                    (*w_syncer)(struct vfs *, void *);
+} vfs_sync_work_t;
+
 typedef struct vfs {
        u_int                   vfs_flag;       /* flags */
        xfs_fsid_t              vfs_fsid;       /* file system ID */
        xfs_fsid_t              *vfs_altfsid;   /* An ID fixed for life of FS */
        bhv_head_t              vfs_bh;         /* head of vfs behavior chain */
-       struct super_block      *vfs_super;     /* Linux superblock structure */
-       struct task_struct      *vfs_sync_task;
+       struct super_block      *vfs_super;     /* generic superblock pointer */
+       struct task_struct      *vfs_sync_task; /* generalised sync thread */
+       vfs_sync_work_t         vfs_sync_work;  /* work item for VFS_SYNC */
+       struct list_head        vfs_sync_list;  /* sync thread work item list */
+       spinlock_t              vfs_sync_lock;  /* work item list lock */
        wait_queue_head_t       vfs_wait_sync_task;
        int                     vfs_frozen;
        wait_queue_head_t       vfs_wait_unfrozen;
diff -urN linux/fs/xfs/linux-2.4/xfs_vnode.c linux/fs/xfs/linux-2.4/xfs_vnode.c
--- linux/fs/xfs/linux-2.4/Attic/xfs_vnode.c    2004/08/14 18:39:02     1.1.2.1
+++ linux/fs/xfs/linux-2.4/Attic/xfs_vnode.c    2004/12/27 04:13:53     1.1.2.2
@@ -186,8 +186,7 @@
         * returning NULL here is OK.
         */
        if (inode->i_state & I_NEW) {
-               remove_inode_hash(inode);
-               make_bad_inode(inode);
+               vn_mark_bad(vp);
                unlock_new_inode(inode);
                iput(inode);
                return NULL;
diff -urN linux/fs/xfs/linux-2.4/xfs_vnode.h linux/fs/xfs/linux-2.4/xfs_vnode.h
--- linux/fs/xfs/linux-2.4/Attic/xfs_vnode.h    2004/08/14 18:39:02     1.1.2.1
+++ linux/fs/xfs/linux-2.4/Attic/xfs_vnode.h    2004/12/27 04:13:53     1.1.2.2
@@ -594,6 +594,23 @@
                (LINVFS_GET_IP(vp)->i_ctime = (__int32_t)(tvp)->tv_sec)
 
 /*
+ * Dealing with bad inodes
+ */
+static inline void vn_mark_bad(struct vnode *vp)
+{
+       struct inode *inode = LINVFS_GET_IP(vp);
+
+       remove_inode_hash(inode);
+       make_bad_inode(inode);
+}
+
+static inline int VN_BAD(struct vnode *vp)
+{
+       return is_bad_inode(LINVFS_GET_IP(vp));
+}
+
+
+/*
  * Some useful predicates.
  */
 #define        VN_MAPPED(vp)   ((LINVFS_GET_IP(vp)->i_mapping->i_mmap != NULL) 
|| \
diff -urN linux/fs/xfs/quota/xfs_qm.c linux/fs/xfs/quota/xfs_qm.c
--- linux/fs/xfs/quota/xfs_qm.c 2004/11/19 00:28:50     1.5.2.4
+++ linux/fs/xfs/quota/xfs_qm.c 2004/12/27 04:13:54     1.5.2.5
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -85,7 +85,6 @@
 
 STATIC void    xfs_qm_list_init(xfs_dqlist_t *, char *, int);
 STATIC void    xfs_qm_list_destroy(xfs_dqlist_t *);
-STATIC int     xfs_qm_quotacheck(xfs_mount_t *);
 
 STATIC int     xfs_qm_init_quotainos(xfs_mount_t *);
 STATIC int     xfs_qm_shake(int, unsigned int);
@@ -349,7 +348,8 @@
  */
 int
 xfs_qm_mount_quotas(
-       xfs_mount_t     *mp)
+       xfs_mount_t     *mp,
+       int             mfsi_flags)
 {
        unsigned long   s;
        int             error = 0;
@@ -398,22 +398,16 @@
        /*
         * If any of the quotas are not consistent, do a quotacheck.
         */
-       if (XFS_QM_NEED_QUOTACHECK(mp)) {
+       if (XFS_QM_NEED_QUOTACHECK(mp) &&
+               !(mfsi_flags & XFS_MFSI_NO_QUOTACHECK)) {
 #ifdef DEBUG
                cmn_err(CE_NOTE, "Doing a quotacheck. Please wait.");
 #endif
                if ((error = xfs_qm_quotacheck(mp))) {
-                       cmn_err(CE_WARN, "Quotacheck unsuccessful (Error %d): "
-                               "Disabling quotas.",
-                               error);
-                       /*
-                        * We must turn off quotas.
+                       /* Quotacheck has failed and quotas have
+                        * been disabled.
                         */
-                       ASSERT(mp->m_quotainfo != NULL);
-                       ASSERT(xfs_Gqm != NULL);
-                       xfs_qm_destroy_quotainfo(mp);
-                       mp->m_qflags = 0;
-                       goto write_changes;
+                       return XFS_ERROR(error);
                }
 #ifdef DEBUG
                cmn_err(CE_NOTE, "Done quotacheck.");
@@ -1788,7 +1782,7 @@
         * the case in all other instances. It's OK that we do this because
         * quotacheck is done only at mount time.
         */
-       if ((error = xfs_iget(mp, NULL, ino, XFS_ILOCK_EXCL, &ip, bno))) {
+       if ((error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_EXCL, &ip, bno))) {
                *res = BULKSTAT_RV_NOTHING;
                return (error);
        }
@@ -1875,9 +1869,9 @@
 
 /*
  * Walk thru all the filesystem inodes and construct a consistent view
- * of the disk quota world.
+ * of the disk quota world. If the quotacheck fails, disable quotas.
  */
-STATIC int
+int
 xfs_qm_quotacheck(
        xfs_mount_t     *mp)
 {
@@ -1973,7 +1967,20 @@
        XQM_LIST_PRINT(&(XFS_QI_MPL_LIST(mp)), MPL_NEXT, "++++ Mp list +++");
 
  error_return:
-       cmn_err(CE_NOTE, "XFS quotacheck %s: Done.", mp->m_fsname);
+       if (error) {
+               cmn_err(CE_WARN, "XFS quotacheck %s: Unsuccessful (Error %d): "
+                       "Disabling quotas.",
+                       mp->m_fsname, error);
+               /*
+                * We must turn off quotas.
+                */
+               ASSERT(mp->m_quotainfo != NULL);
+               ASSERT(xfs_Gqm != NULL);
+               xfs_qm_destroy_quotainfo(mp);
+               xfs_mount_reset_sbqflags(mp);
+       } else {
+               cmn_err(CE_NOTE, "XFS quotacheck %s: Done.", mp->m_fsname);
+       }
        return (error);
 }
 
@@ -2003,14 +2010,14 @@
                    mp->m_sb.sb_uquotino != NULLFSINO) {
                        ASSERT(mp->m_sb.sb_uquotino > 0);
                        if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
-                                            0, &uip, 0)))
+                                            0, 0, &uip, 0)))
                                return XFS_ERROR(error);
                }
                if (XFS_IS_GQUOTA_ON(mp) &&
                    mp->m_sb.sb_gquotino != NULLFSINO) {
                        ASSERT(mp->m_sb.sb_gquotino > 0);
                        if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
-                                            0, &gip, 0))) {
+                                            0, 0, &gip, 0))) {
                                if (uip)
                                        VN_RELE(XFS_ITOV(uip));
                                return XFS_ERROR(error);
diff -urN linux/fs/xfs/quota/xfs_qm.h linux/fs/xfs/quota/xfs_qm.h
--- linux/fs/xfs/quota/xfs_qm.h 2004/11/19 00:28:50     1.2.2.2
+++ linux/fs/xfs/quota/xfs_qm.h 2004/12/27 04:13:54     1.2.2.3
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -182,17 +182,19 @@
 #define XFS_QM_HOLD(xqm)       ((xqm)->qm_nrefs++)
 #define XFS_QM_RELE(xqm)       ((xqm)->qm_nrefs--)
 
+extern void            xfs_mount_reset_sbqflags(xfs_mount_t *);
+
 extern int             xfs_qm_init_quotainfo(xfs_mount_t *);
 extern void            xfs_qm_destroy_quotainfo(xfs_mount_t *);
-extern int             xfs_qm_mount_quotas(xfs_mount_t *);
+extern int             xfs_qm_mount_quotas(xfs_mount_t *, int);
 extern void            xfs_qm_mount_quotainit(xfs_mount_t *, uint);
+extern int             xfs_qm_quotacheck(xfs_mount_t *);
 extern void            xfs_qm_unmount_quotadestroy(xfs_mount_t *);
 extern int             xfs_qm_unmount_quotas(xfs_mount_t *);
 extern int             xfs_qm_write_sb_changes(xfs_mount_t *, __int64_t);
 extern int             xfs_qm_sync(xfs_mount_t *, short);
 
 /* dquot stuff */
-extern void            xfs_qm_dqunlink(xfs_dquot_t *);
 extern boolean_t       xfs_qm_dqalloc_incore(xfs_dquot_t **);
 extern int             xfs_qm_dqattach(xfs_inode_t *, uint);
 extern void            xfs_qm_dqdetach(xfs_inode_t *);
diff -urN linux/fs/xfs/quota/xfs_qm_bhv.c linux/fs/xfs/quota/xfs_qm_bhv.c
--- linux/fs/xfs/quota/xfs_qm_bhv.c     2003/12/15 18:19:53     1.2.2.1
+++ linux/fs/xfs/quota/xfs_qm_bhv.c     2004/12/27 04:13:54     1.2.2.2
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -207,10 +207,9 @@
 }
 
 /*
- * When xfsquotas isn't installed and the superblock had quotas, we need to
- * clear the quotaflags from superblock.
+ * Clear the quotaflags in memory and in the superblock.
  */
-STATIC void
+void
 xfs_mount_reset_sbqflags(
        xfs_mount_t             *mp)
 {
@@ -241,6 +240,8 @@
        if (xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
                                      XFS_DEFAULT_LOG_COUNT)) {
                xfs_trans_cancel(tp, 0);
+               xfs_fs_cmn_err(CE_ALERT, mp,
+                       "xfs_mount_reset_sbqflags: Superblock update failed!");
                return;
        }
        xfs_mod_sb(tp, XFS_SB_QFLAGS);
@@ -294,15 +295,12 @@
                 */
                if (quotaondisk && !XFS_QM_NEED_QUOTACHECK(mp)) {
                        /*
-                        * If the xfs quota code isn't installed,
-                        * we have to reset the quotachk'd bit.
                         * If an error occured, qm_mount_quotas code
                         * has already disabled quotas. So, just finish
                         * mounting, and get on with the boring life
                         * without disk quotas.
                         */
-                       if (xfs_qm_mount_quotas(mp))
-                               xfs_mount_reset_sbqflags(mp);
+                       xfs_qm_mount_quotas(mp, 0);
                } else {
                        /*
                         * Clear the quota flags, but remember them. This
@@ -324,13 +322,13 @@
 xfs_qm_endmount(
        xfs_mount_t     *mp,
        uint            needquotamount,
-       uint            quotaflags)
+       uint            quotaflags,
+       int             mfsi_flags)
 {
        if (needquotamount) {
                ASSERT(mp->m_qflags == 0);
                mp->m_qflags = quotaflags;
-               if (xfs_qm_mount_quotas(mp))
-                       xfs_mount_reset_sbqflags(mp);
+               xfs_qm_mount_quotas(mp, mfsi_flags);
        }
 
 #if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
diff -urN linux/fs/xfs/quota/xfs_qm_syscalls.c 
linux/fs/xfs/quota/xfs_qm_syscalls.c
--- linux/fs/xfs/quota/xfs_qm_syscalls.c        2004/11/19 00:28:50     1.2.2.3
+++ linux/fs/xfs/quota/xfs_qm_syscalls.c        2004/12/27 04:13:54     1.2.2.4
@@ -404,7 +404,7 @@
        }
 
        if ((flags & XFS_DQ_USER) && mp->m_sb.sb_uquotino != NULLFSINO) {
-               error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, &qip, 0);
+               error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, 0, &qip, 0);
                if (! error) {
                        (void) xfs_truncate_file(mp, qip);
                        VN_RELE(XFS_ITOV(qip));
@@ -412,7 +412,7 @@
        }
 
        if ((flags & XFS_DQ_GROUP) && mp->m_sb.sb_gquotino != NULLFSINO) {
-               error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, &qip, 0);
+               error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, 0, &qip, 0);
                if (! error) {
                        (void) xfs_truncate_file(mp, qip);
                        VN_RELE(XFS_ITOV(qip));
@@ -555,11 +555,13 @@
                gip = mp->m_quotainfo->qi_gquotaip;
        }
        if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) {
-               if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, &uip, 0) == 0)
+               if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
+                                       0, 0, &uip, 0) == 0)
                        tempuqip = B_TRUE;
        }
        if (!gip && mp->m_sb.sb_gquotino != NULLFSINO) {
-               if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, &gip, 0) == 0)
+               if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
+                                       0, 0, &gip, 0) == 0)
                        tempgqip = B_TRUE;
        }
        if (uip) {
@@ -1338,7 +1340,7 @@
        ipreleased = B_FALSE;
  again:
        lock_flags = XFS_ILOCK_SHARED;
-       if ((error = xfs_iget(mp, NULL, ino, lock_flags, &ip, bno))) {
+       if ((error = xfs_iget(mp, NULL, ino, 0, lock_flags, &ip, bno))) {
                *res = BULKSTAT_RV_NOTHING;
                return (error);
        }
diff -urN linux/include/asm-sparc/elf.h linux/include/asm-sparc/elf.h
--- linux/include/asm-sparc/elf.h       2000/07/15 03:32:28     1.11
+++ linux/include/asm-sparc/elf.h       2004/12/27 04:13:54     1.11.4.1
@@ -81,7 +81,7 @@
    the loader.  We need to make sure that it is out of the way of the program
    that it will "exec", and that there is sufficient room for the brk.  */
 
-#define ELF_ET_DYN_BASE         (0x08000000)
+#define ELF_ET_DYN_BASE         (TASK_UNMAPPED_BASE)
 
 /* This yields a mask that user programs can use to figure out what
    instruction set this cpu supports.  This can NOT be done in userspace
diff -urN linux/include/asm-x86_64/socket32.h 
linux/include/asm-x86_64/socket32.h
--- linux/include/asm-x86_64/Attic/socket32.h   2002/09/11 12:45:38     1.1.2.1
+++ linux/include/asm-x86_64/Attic/socket32.h   2004/12/27 04:13:54     1.1.2.2
@@ -45,6 +45,11 @@
                                    (struct cmsghdr32 *)(ctl) : \
                                    (struct cmsghdr32 *)NULL)
 #define CMSG32_FIRSTHDR(msg)   __CMSG32_FIRSTHDR((msg)->msg_control, 
(msg)->msg_controllen)
+#define CMSG32_OK(ucmlen, ucmsg, mhdr) \
+       ((ucmlen) >= sizeof(struct cmsghdr) && \
+        (ucmlen) <= (unsigned long) \
+        ((mhdr)->msg_controllen - \
+         ((char *)(ucmsg) - (char *)(mhdr)->msg_control)))
 
 __inline__ struct cmsghdr32 *__cmsg32_nxthdr(void *__ctl, __kernel_size_t 
__size,
                                              struct cmsghdr32 *__cmsg, int 
__cmsg_len)
diff -urN linux/include/linux/delay.h linux/include/linux/delay.h
--- linux/include/linux/delay.h 2001/01/11 04:02:45     1.4
+++ linux/include/linux/delay.h 2004/12/27 04:13:54     1.4.2.1
@@ -9,9 +9,64 @@
 
 extern unsigned long loops_per_jiffy;
 
+#include <linux/time.h>
+#include <linux/sched.h>
 #include <asm/delay.h>
 
 /*
+ * Convert jiffies to milliseconds and back.
+ *
+ * Avoid unnecessary multiplications/divisions in the
+ * two most common HZ cases:
+ */
+static inline unsigned int jiffies_to_msecs(const unsigned long j)
+{
+#if HZ <= 1000 && !(1000 % HZ)
+       return (1000 / HZ) * j;
+#elif HZ > 1000 && !(HZ % 1000)
+       return (j + (HZ / 1000) - 1)/(HZ / 1000);
+#else
+       return (j * 1000) / HZ;
+#endif
+}
+
+static inline unsigned int jiffies_to_usecs(const unsigned long j)
+{
+#if HZ <= 1000 && !(1000 % HZ)
+       return (1000000 / HZ) * j;
+#elif HZ > 1000 && !(HZ % 1000)
+       return (j*1000 + (HZ - 1000))/(HZ / 1000);
+#else
+       return (j * 1000000) / HZ;
+#endif
+}
+
+static inline unsigned long msecs_to_jiffies(const unsigned int m)
+{
+       if (m > jiffies_to_msecs(MAX_JIFFY_OFFSET))
+               return MAX_JIFFY_OFFSET;
+#if HZ <= 1000 && !(1000 % HZ)
+       return (m + (1000 / HZ) - 1) / (1000 / HZ);
+#elif HZ > 1000 && !(HZ % 1000)
+       return m * (HZ / 1000);
+#else
+       return (m * HZ + 999) / 1000;
+#endif
+}
+
+static inline void msleep(unsigned long msecs)
+{
+        set_current_state(TASK_UNINTERRUPTIBLE);
+        schedule_timeout(msecs_to_jiffies(msecs) + 1);
+}
+
+static inline void ssleep(unsigned long secs)
+{
+        set_current_state(TASK_UNINTERRUPTIBLE);
+        schedule_timeout((HZ * secs) + 1);
+}
+
+/*
  * Using udelay() for intervals greater than a few milliseconds can
  * risk overflow for high loops_per_jiffy (high bogomips) machines. The
  * mdelay() provides a wrapper to prevent this.  For delays greater
diff -urN linux/include/linux/dqblk_xfs.h linux/include/linux/dqblk_xfs.h
--- linux/include/linux/dqblk_xfs.h     2003/12/15 18:19:53     1.2.2.2
+++ linux/include/linux/dqblk_xfs.h     2004/12/27 04:13:54     1.2.2.3
@@ -1,34 +1,22 @@
 /*
- * Copyright (c) 1995-2001 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 1995-2001,2004 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2.1 of the GNU Lesser General Public License
  * as published by the Free Software Foundation.
  *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ * USA
  *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.  Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
- * USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ * Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ * Mountain View, CA 94043, USA, or: http://www.sgi.com
  */
 #ifndef _LINUX_DQBLK_XFS_H
 #define _LINUX_DQBLK_XFS_H
@@ -40,12 +28,12 @@
  */
 
 #define XQM_CMD(x)     (('X'<<8)+(x))  /* note: forms first QCMD argument */
-#define Q_XQUOTAON     XQM_CMD(0x1)    /* enable accounting/enforcement */
-#define Q_XQUOTAOFF    XQM_CMD(0x2)    /* disable accounting/enforcement */
-#define Q_XGETQUOTA    XQM_CMD(0x3)    /* get disk limits and usage */
-#define Q_XSETQLIM     XQM_CMD(0x4)    /* set disk limits */
-#define Q_XGETQSTAT    XQM_CMD(0x5)    /* get quota subsystem status */
-#define Q_XQUOTARM     XQM_CMD(0x6)    /* free disk space used by dquots */
+#define Q_XQUOTAON     XQM_CMD(1)      /* enable accounting/enforcement */
+#define Q_XQUOTAOFF    XQM_CMD(2)      /* disable accounting/enforcement */
+#define Q_XGETQUOTA    XQM_CMD(3)      /* get disk limits and usage */
+#define Q_XSETQLIM     XQM_CMD(4)      /* set disk limits */
+#define Q_XGETQSTAT    XQM_CMD(5)      /* get quota subsystem status */
+#define Q_XQUOTARM     XQM_CMD(6)      /* free disk space used by dquots */
 
 /*
  * fs_disk_quota structure:
@@ -105,15 +93,30 @@
 #define FS_DQ_TIMER_MASK       (FS_DQ_BTIMER | FS_DQ_ITIMER | FS_DQ_RTBTIMER)
 
 /*
+ * Warning counts are set in both super user's dquot and others. For others,
+ * warnings are set/cleared by the administrators (or automatically by going
+ * below the soft limit).  Superusers warning values set the warning limits
+ * for the rest.  In case these values are zero, the DQ_{F,B}WARNLIMIT values
+ * defined below are used. 
+ * These values also apply only to the d_fieldmask field for Q_XSETQLIM.
+ */
+#define FS_DQ_BWARNS   (1<<9)
+#define FS_DQ_IWARNS   (1<<10)
+#define FS_DQ_RTBWARNS (1<<11)
+#define FS_DQ_WARNS_MASK       (FS_DQ_BWARNS | FS_DQ_IWARNS | FS_DQ_RTBWARNS)
+
+/*
  * Various flags related to quotactl(2).  Only relevant to XFS filesystems.
  */
 #define XFS_QUOTA_UDQ_ACCT     (1<<0)  /* user quota accounting */
 #define XFS_QUOTA_UDQ_ENFD     (1<<1)  /* user quota limits enforcement */
 #define XFS_QUOTA_GDQ_ACCT     (1<<2)  /* group quota accounting */
 #define XFS_QUOTA_GDQ_ENFD     (1<<3)  /* group quota limits enforcement */
+#define XFS_QUOTA_PDQ_ACCT     (1<<4)  /* project quota accounting */
+#define XFS_QUOTA_PDQ_ENFD     (1<<5)  /* project quota limits enforcement */
 
 #define XFS_USER_QUOTA         (1<<0)  /* user quota type */
-#define XFS_PROJ_QUOTA         (1<<1)  /* (IRIX) project quota type */
+#define XFS_PROJ_QUOTA         (1<<1)  /* project quota type */
 #define XFS_GROUP_QUOTA                (1<<2)  /* group quota type */
 
 /*
diff -urN linux/include/linux/fb.h linux/include/linux/fb.h
--- linux/include/linux/fb.h    2003/12/01 17:09:48     1.23.4.4
+++ linux/include/linux/fb.h    2004/12/27 04:13:54     1.23.4.5
@@ -323,6 +323,7 @@
    struct fb_cmap cmap;                 /* Current cmap */
    struct fb_ops *fbops;
    char *screen_base;                   /* Virtual address */
+   u32 mapped_vram;                    /* ioremap()'ed VRAM */
    struct display *disp;               /* initial display variable */
    struct vc_data *display_fg;         /* Console visible on this display */
    char fontname[40];                  /* default font name */
diff -urN linux/include/linux/libata-compat.h 
linux/include/linux/libata-compat.h
--- linux/include/linux/Attic/libata-compat.h   2004/11/29 17:47:18     1.1.2.1
+++ linux/include/linux/Attic/libata-compat.h   2004/12/27 04:13:54     1.1.2.2
@@ -6,31 +6,15 @@
 
 #define MODULE_VERSION(ver_str)
 
-static inline unsigned long msecs_to_jiffies(unsigned long msecs)
-{
-       return ((HZ * msecs + 999) / 1000);
-}
 struct device {
        struct pci_dev pdev;
 };
 
-static inline void msleep(unsigned long msecs)
-{
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       schedule_timeout(msecs_to_jiffies(msecs) + 1);
-}
-
 static inline void libata_msleep(unsigned long msecs)
 {
        msleep(msecs);
 }
 
-static inline void ssleep(unsigned long secs)
-{
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       schedule_timeout((HZ * secs) + 1);
-}
-
 static inline struct pci_dev *to_pci_dev(struct device *dev)
 {
        return (struct pci_dev *) dev;
diff -urN linux/include/linux/libata.h linux/include/linux/libata.h
--- linux/include/linux/libata.h        2004/11/29 17:47:18     1.11.2.3
+++ linux/include/linux/libata.h        2004/12/27 04:13:54     1.11.2.4
@@ -113,6 +113,7 @@
        ATA_FLAG_SRST           = (1 << 5), /* use ATA SRST, not E.D.D. */
        ATA_FLAG_MMIO           = (1 << 6), /* use MMIO, not PIO */
        ATA_FLAG_SATA_RESET     = (1 << 7), /* use COMRESET */
+       ATA_FLAG_PIO_DMA        = (1 << 8), /* PIO cmds via DMA */
 
        ATA_QCFLAG_ACTIVE       = (1 << 1), /* cmd not yet ack'd to scsi lyer */
        ATA_QCFLAG_SG           = (1 << 3), /* have s/g table? */
diff -urN linux/include/linux/mm.h linux/include/linux/mm.h
--- linux/include/linux/mm.h    2004/11/29 17:47:18     1.63.2.8
+++ linux/include/linux/mm.h    2004/12/27 04:13:54     1.63.2.9
@@ -548,7 +548,7 @@
 /* mmap.c */
 extern void lock_vma_mappings(struct vm_area_struct *);
 extern void unlock_vma_mappings(struct vm_area_struct *);
-extern void insert_vm_struct(struct mm_struct *, struct vm_area_struct *);
+extern int insert_vm_struct(struct mm_struct *, struct vm_area_struct *);
 extern void __insert_vm_struct(struct mm_struct *, struct vm_area_struct *);
 extern void build_mmap_rb(struct mm_struct *);
 extern void exit_mmap(struct mm_struct *);
diff -urN linux/include/linux/pci_ids.h linux/include/linux/pci_ids.h
--- linux/include/linux/pci_ids.h       2004/11/29 17:47:18     1.50.2.23
+++ linux/include/linux/pci_ids.h       2004/12/27 04:13:54     1.50.2.24
@@ -303,6 +303,7 @@
 #define PCI_DEVICE_ID_ATI_RADEON_NI    0x4e49
 /* Radeon RV350 (9600) */
 #define PCI_DEVICE_ID_ATI_RADEON_AP    0x4150
+#define PCI_DEVICE_ID_ATI_RADEON_AQ    0x4151
 #define PCI_DEVICE_ID_ATI_RADEON_AR    0x4152
 /* Radeon M6 */
 #define PCI_DEVICE_ID_ATI_RADEON_LY    0x4c59
diff -urN linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- linux/include/linux/proc_fs.h       2004/11/19 00:28:51     1.39.2.3
+++ linux/include/linux/proc_fs.h       2004/12/27 04:13:54     1.39.2.4
@@ -144,6 +144,8 @@
 extern struct proc_dir_entry *proc_mknod(const char *,mode_t,
                struct proc_dir_entry *,kdev_t);
 extern struct proc_dir_entry *proc_mkdir(const char *,struct proc_dir_entry *);
+extern struct proc_dir_entry *proc_mkdir_mode(const char *name, mode_t mode,
+                       struct proc_dir_entry *parent);
 
 static inline struct proc_dir_entry *create_proc_read_entry(const char *name,
        mode_t mode, struct proc_dir_entry *base, 
diff -urN linux/include/linux/socket.h linux/include/linux/socket.h
--- linux/include/linux/socket.h        2004/11/19 00:28:51     1.21.2.4
+++ linux/include/linux/socket.h        2004/12/27 04:13:54     1.21.2.5
@@ -87,6 +87,10 @@
                                  (struct cmsghdr *)(ctl) : \
                                  (struct cmsghdr *)NULL)
 #define CMSG_FIRSTHDR(msg)     __CMSG_FIRSTHDR((msg)->msg_control, 
(msg)->msg_controllen)
+#define CMSG_OK(mhdr, cmsg) ((cmsg)->cmsg_len >= sizeof(struct cmsghdr) && \
+                            (cmsg)->cmsg_len <= (unsigned long) \
+                            ((mhdr)->msg_controllen - \
+                             ((char *)(cmsg) - (char *)(mhdr)->msg_control)))
 
 /*
  *     This mess will go away with glibc
diff -urN linux/include/linux/tty.h linux/include/linux/tty.h
--- linux/include/linux/tty.h   2003/07/05 03:23:47     1.27.2.2
+++ linux/include/linux/tty.h   2004/12/27 04:13:54     1.27.2.3
@@ -260,6 +260,7 @@
        int     magic;
        struct tty_driver driver;
        struct tty_ldisc ldisc;
+       struct semaphore termios_sem;
        struct termios *termios, *termios_locked;
        int pgrp;
        int session;
@@ -322,26 +323,28 @@
  * tty->write.  Thus, you must use the inline functions set_bit() and
  * clear_bit() to make things atomic.
  */
-#define TTY_THROTTLED 0
-#define TTY_IO_ERROR 1
-#define TTY_OTHER_CLOSED 2
-#define TTY_EXCLUSIVE 3
-#define TTY_DEBUG 4
-#define TTY_DO_WRITE_WAKEUP 5
-#define TTY_PUSH 6
-#define TTY_CLOSING 7
-#define TTY_DONT_FLIP 8
-#define TTY_HW_COOK_OUT 14
-#define TTY_HW_COOK_IN 15
-#define TTY_PTY_LOCK 16
-#define TTY_NO_WRITE_SPLIT 17
+#define TTY_THROTTLED          0       /* Call unthrottle() at threshold min */
+#define TTY_IO_ERROR           1       /* Canse an I/O error (may be no ldisc 
too) */
+#define TTY_OTHER_CLOSED       2       /* Other side (if any) has closed */
+#define TTY_EXCLUSIVE          3       /* Exclusive open mode */
+#define TTY_DEBUG              4       /* Debugging */
+#define TTY_DO_WRITE_WAKEUP    5       /* Call write_wakeup after queuing new 
*/
+#define TTY_PUSH               6       /* n_tty private */
+#define TTY_CLOSING            7       /* ->close() in progress */
+#define TTY_DONT_FLIP          8       /* Defer buffer flip */
+#define TTY_LDISC              9       /* Line discipline attached */
+#define TTY_HW_COOK_OUT        14      /* Hardware can do output cooking */
+#define TTY_HW_COOK_IN         15      /* Hardware can do input cooking */
+#define TTY_PTY_LOCK           16      /* pty private */
+#define TTY_NO_WRITE_SPLIT     17      /* Preserve write boundaries to driver 
*/
+#define TTY_HUPPED             18      /* Post driver->hangup() */
 
 #define TTY_WRITE_FLUSH(tty) tty_write_flush((tty))
 
 extern void tty_write_flush(struct tty_struct *);
 
 extern struct termios tty_std_termios;
-extern struct tty_ldisc ldiscs[];
+extern struct tty_ldisc tty_ldiscs[];
 extern int fg_console, last_console, want_console;
 
 extern int kmsg_redirect;
@@ -396,6 +399,17 @@
 extern void tty_flip_buffer_push(struct tty_struct *tty);
 extern int tty_get_baud_rate(struct tty_struct *tty);
 
+extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *);
+extern void tty_ldisc_deref(struct tty_ldisc *);
+extern struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *);
+
+extern struct tty_ldisc *tty_ldisc_get(int);
+extern void tty_ldisc_put(int);
+
+extern void tty_wakeup(struct tty_struct *tty);
+extern void tty_ldisc_flush(struct tty_struct *tty);
+
+
 /* n_tty.c */
 extern struct tty_ldisc tty_ldisc_N_TTY;
 
diff -urN linux/include/linux/tty_ldisc.h linux/include/linux/tty_ldisc.h
--- linux/include/linux/tty_ldisc.h     2001/08/26 14:26:08     1.6
+++ linux/include/linux/tty_ldisc.h     2004/12/27 04:13:54     1.6.2.1
@@ -95,6 +95,13 @@
  *     that line discpline should try to send more characters to the
  *     low-level driver for transmission.  If the line discpline does
  *     not have any more data to send, it can just return.
+ *
+ * int (*hangup)(struct tty_struct *)
+ *
+ *     Called on a hangup. Tells the discipline that it should
+ *     cease I/O to the tty driver. Can sleep. The driver should
+ *     seek to perform this action quickly but should wait until
+ *     any pending driver I/O is completed.
  */
 
 #include <linux/fs.h>
@@ -121,6 +128,7 @@
        void    (*set_termios)(struct tty_struct *tty, struct termios * old);
        unsigned int (*poll)(struct tty_struct *, struct file *,
                             struct poll_table_struct *);
+       int     (*hangup)(struct tty_struct *tty);
        
        /*
         * The following routines are called from below.
@@ -129,6 +137,7 @@
                               char *fp, int count);
        int     (*receive_room)(struct tty_struct *);
        void    (*write_wakeup)(struct tty_struct *);
+       int     refcount;
 };
 
 #define TTY_LDISC_MAGIC        0x5403
diff -urN linux/include/linux/usb_ch9.h linux/include/linux/usb_ch9.h
--- linux/include/linux/usb_ch9.h       2004/08/14 18:39:03     1.2.2.2
+++ linux/include/linux/usb_ch9.h       2004/12/27 04:13:54     1.2.2.3
@@ -79,6 +79,7 @@
 #define USB_DEVICE_B_HNP_ENABLE                3       /* dev may initiate HNP 
*/
 #define USB_DEVICE_A_HNP_SUPPORT       4       /* RH port supports HNP */
 #define USB_DEVICE_A_ALT_HNP_SUPPORT   5       /* other RH port does */
+#define USB_DEVICE_DEBUG_MODE          6       /* (special devices only) */
 
 #define USB_ENDPOINT_HALT              0       /* IN/OUT will STALL */
 
@@ -323,6 +324,18 @@
 
 /*-------------------------------------------------------------------------*/
 
+/* USB_DT_DEBUG:  for special highspeed devices, replacing serial console */
+struct usb_debug_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       /* bulk endpoints with 8 byte maxpacket */
+       __u8  bDebugInEndpoint;
+       __u8  bDebugOutEndpoint;
+};
+
+/*-------------------------------------------------------------------------*/
+
 /* USB_DT_INTERFACE_ASSOCIATION: groups interfaces */
 struct usb_interface_assoc_descriptor {
        __u8  bLength;
diff -urN linux/include/linux/usb_gadget.h linux/include/linux/usb_gadget.h
--- linux/include/linux/usb_gadget.h    2004/08/14 18:39:03     1.5.2.4
+++ linux/include/linux/usb_gadget.h    2004/12/27 04:13:54     1.5.2.5
@@ -6,7 +6,7 @@
  * master many USB gadgets, but the gadgets are only slaved to one host.
  *
  *
- * (c) Copyright 2002-2003 by David Brownell
+ * (C) Copyright 2002-2004 by David Brownell
  * All Rights Reserved.
  *
  * This software is licensed under the GNU GPL version 2.
@@ -73,8 +73,6 @@
  */
        // NOTE this is analagous to 'struct urb' on the host side,
        // except that it's thinner and promotes more pre-allocation.
-       //
-       // ISSUE should this be allocated through the device?
 
 struct usb_request {
        void                    *buf;
@@ -116,8 +114,8 @@
                dma_addr_t *dma, int gfp_flags);
        void (*free_buffer) (struct usb_ep *ep, void *buf, dma_addr_t dma,
                unsigned bytes);
-       // NOTE:  on 2.5, drivers may also use dma_map() and
-       // dma_sync_single() to manage dma overhead. 
+       // NOTE:  on 2.6, drivers may also use dma_map() and
+       // dma_sync_single_*() to directly manage dma overhead. 
 
        int (*queue) (struct usb_ep *ep, struct usb_request *req,
                int gfp_flags);
@@ -453,7 +451,10 @@
 struct usb_gadget_ops {
        int     (*get_frame)(struct usb_gadget *);
        int     (*wakeup)(struct usb_gadget *);
-       int     (*set_selfpowered) (struct usb_gadget *, int value);
+       int     (*set_selfpowered) (struct usb_gadget *, int is_selfpowered);
+       int     (*vbus_session) (struct usb_gadget *, int is_active);
+       int     (*vbus_draw) (struct usb_gadget *, unsigned mA);
+       int     (*pullup) (struct usb_gadget *, int is_on);
        int     (*ioctl)(struct usb_gadget *,
                                unsigned code, unsigned long param);
 };
@@ -467,6 +468,17 @@
  * @speed: Speed of current connection to USB host.
  * @is_dualspeed: True if the controller supports both high and full speed
  *     operation.  If it does, the gadget driver must also support both.
+ * @is_otg: True if the USB device port uses a Mini-AB jack, so that the
+ *     gadget driver must provide a USB OTG descriptor.
+ * @is_a_peripheral: False unless is_otg, the "A" end of a USB cable
+ *     is in the Mini-AB jack, and HNP has been used to switch roles
+ *     so that the "A" device currently acts as A-Peripheral, not A-Host.
+ * @a_hnp_support: OTG device feature flag, indicating that the A-Host
+ *     supports HNP at this port.
+ * @a_alt_hnp_support: OTG device feature flag, indicating that the A-Host
+ *     only supports HNP on a different root port.
+ * @b_hnp_enable: OTG device feature flag, indicating that the A-Host
+ *     enabled HNP support.
  * @name: Identifies the controller hardware type.  Used in diagnostics
  *     and sometimes configuration.
  * @dev: Driver model state for this abstract device.
@@ -480,9 +492,14 @@
  *
  * Except for the driver data, all fields in this structure are
  * read-only to the gadget driver.  That driver data is part of the
- * "driver model" infrastructure in 2.5 (and later) kernels, and for
+ * "driver model" infrastructure in 2.6 (and later) kernels, and for
  * earlier systems is grouped in a similar structure that's not known
  * to the rest of the kernel.
+ *
+ * Values of the three OTG device feature flags are updated before the
+ * setup() call corresponding to USB_REQ_SET_CONFIGURATION, and before
+ * driver suspend() calls.  They are valid only when is_otg, and when the
+ * device is acting as a B-Peripheral (so is_a_peripheral is false).
  */
 struct usb_gadget {
        /* readonly to gadget driver */
@@ -491,6 +508,11 @@
        struct list_head                ep_list;        /* of usb_ep */
        enum usb_device_speed           speed;
        unsigned                        is_dualspeed:1;
+       unsigned                        is_otg:1;
+       unsigned                        is_a_peripheral:1;
+       unsigned                        b_hnp_enable:1;
+       unsigned                        a_hnp_support:1;
+       unsigned                        a_alt_hnp_support:1;
        const char                      *name;
 
        struct __gadget_device {
@@ -540,6 +562,10 @@
  * doesn't support such attempts, or its support has not been enabled
  * by the usb host.  Drivers must return device descriptors that report
  * their ability to support this, or hosts won't enable it.
+ *
+ * This may also try to use SRP to wake the host and start enumeration,
+ * even if OTG isn't otherwise in use.  OTG devices may also start
+ * remote wakeup even when hosts don't explicitly enable it.
  */
 static inline int usb_gadget_wakeup (struct usb_gadget *gadget)
 {
@@ -583,6 +609,107 @@
        return gadget->ops->set_selfpowered (gadget, 0);
 }
 
+/**
+ * usb_gadget_vbus_connect - Notify controller that VBUS is powered
+ * @gadget:The device which now has VBUS power.
+ *
+ * This call is used by a driver for an external transceiver (or GPIO)
+ * that detects a VBUS power session starting.  Common responses include
+ * resuming the controller, activating the D+ (or D-) pullup to let the
+ * host detect that a USB device is attached, and starting to draw power
+ * (8mA or possibly more, especially after SET_CONFIGURATION).
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_vbus_connect(struct usb_gadget *gadget)
+{
+       if (!gadget->ops->vbus_session)
+               return -EOPNOTSUPP;
+       return gadget->ops->vbus_session (gadget, 1);
+}
+
+/**
+ * usb_gadget_vbus_draw - constrain controller's VBUS power usage
+ * @gadget:The device whose VBUS usage is being described
+ * @mA:How much current to draw, in milliAmperes.  This should be twice
+ *     the value listed in the configuration descriptor bMaxPower field.
+ *
+ * This call is used by gadget drivers during SET_CONFIGURATION calls,
+ * reporting how much power the device may consume.  For example, this
+ * could affect how quickly batteries are recharged.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+       if (!gadget->ops->vbus_draw)
+               return -EOPNOTSUPP;
+       return gadget->ops->vbus_draw (gadget, mA);
+}
+
+/**
+ * usb_gadget_vbus_disconnect - notify controller about VBUS session end
+ * @gadget:the device whose VBUS supply is being described
+ *
+ * This call is used by a driver for an external transceiver (or GPIO)
+ * that detects a VBUS power session ending.  Common responses include
+ * reversing everything done in usb_gadget_vbus_connect().
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_vbus_disconnect(struct usb_gadget *gadget)
+{
+       if (!gadget->ops->vbus_session)
+               return -EOPNOTSUPP;
+       return gadget->ops->vbus_session (gadget, 0);
+}
+
+/**
+ * usb_gadget_connect - software-controlled connect to USB host
+ * @gadget:the peripheral being connected
+ *
+ * Enables the D+ (or potentially D-) pullup.  The host will start
+ * enumerating this gadget when the pullup is active and a VBUS session
+ * is active (the link is powered).  This pullup is always enabled unless
+ * usb_gadget_disconnect() has been used to disable it.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_connect (struct usb_gadget *gadget)
+{
+       if (!gadget->ops->pullup)
+               return -EOPNOTSUPP;
+       return gadget->ops->pullup (gadget, 1);
+}
+
+/**
+ * usb_gadget_disconnect - software-controlled disconnect from USB host
+ * @gadget:the peripheral being disconnected
+ *
+ * Disables the D+ (or potentially D-) pullup, which the host may see
+ * as a disconnect (when a VBUS session is active).  Not all systems
+ * support software pullup controls.
+ *
+ * This routine may be used during the gadget driver bind() call to prevent
+ * the peripheral from ever being visible to the USB host, unless later
+ * usb_gadget_connect() is called.  For example, user mode components may
+ * need to be activated before the system can talk to hosts.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_disconnect (struct usb_gadget *gadget)
+{
+       if (!gadget->ops->pullup)
+               return -EOPNOTSUPP;
+       return gadget->ops->pullup (gadget, 0);
+}
+
+
 
 /*-------------------------------------------------------------------------*/
 
@@ -610,11 +737,18 @@
  *     Called in a context that permits sleeping.
  * @suspend: Invoked on USB suspend.  May be called in_interrupt.
  * @resume: Invoked on USB resume.  May be called in_interrupt.
+ * @driver: Driver model state for this driver.
  *
  * Devices are disabled till a gadget driver successfully bind()s, which
  * means the driver will handle setup() requests needed to enumerate (and
  * meet "chapter 9" requirements) then do some useful work.
  *
+ * If gadget->is_otg is true, the gadget driver must provide an OTG
+ * descriptor during enumeration, or else fail the bind() call.  In such
+ * cases, no USB traffic may flow until both bind() returns without
+ * having called usb_gadget_disconnect(), and the USB host stack has
+ * initialized.
+ *
  * Drivers use hardware-specific knowledge to configure the usb hardware.
  * endpoint addressing is only one of several hardware characteristics that
  * are in descriptors the ep0 implementation returns from setup() calls.
diff -urN linux/include/net/ip_vs.h linux/include/net/ip_vs.h
--- linux/include/net/ip_vs.h   2004/11/19 00:28:51     1.3.2.3
+++ linux/include/net/ip_vs.h   2004/12/27 04:13:54     1.3.2.4
@@ -317,6 +317,7 @@
        NET_IPV4_VS_EXPIRE_NODEST_CONN=23,
        NET_IPV4_VS_SYNC_THRESHOLD=24,
        NET_IPV4_VS_NAT_ICMP_SEND=25,
+       NET_IPV4_VS_EXPIRE_QUIESCENT_TEMPLATE=26,
        NET_IPV4_VS_LAST
 };
 
@@ -700,6 +701,7 @@
  */
 extern int sysctl_ip_vs_cache_bypass;
 extern int sysctl_ip_vs_expire_nodest_conn;
+extern int sysctl_ip_vs_expire_quiescent_template;
 extern int sysctl_ip_vs_sync_threshold;
 extern int sysctl_ip_vs_nat_icmp_send;
 extern struct ip_vs_stats ip_vs_stats;
diff -urN linux/include/net/udp.h linux/include/net/udp.h
--- linux/include/net/udp.h     2001/06/13 17:28:17     1.7
+++ linux/include/net/udp.h     2004/12/27 04:13:54     1.7.2.1
@@ -23,6 +23,7 @@
 #define _UDP_H
 
 #include <linux/udp.h>
+#include <linux/poll.h>
 #include <net/sock.h>
 
 #define UDP_HTABLE_SIZE                128
@@ -68,6 +69,8 @@
 extern int     udp_rcv(struct sk_buff *skb);
 extern int     udp_ioctl(struct sock *sk, int cmd, unsigned long arg);
 extern int     udp_disconnect(struct sock *sk, int flags);
+extern unsigned int udp_poll(struct file *file, struct socket *sock,
+                            poll_table *wait);
 
 extern struct udp_mib udp_statistics[NR_CPUS*2];
 #define UDP_INC_STATS(field)           SNMP_INC_STATS(udp_statistics, field)
diff -urN linux/init/do_mounts.c linux/init/do_mounts.c
--- linux/init/do_mounts.c      2003/11/17 01:07:46     1.1.2.8
+++ linux/init/do_mounts.c      2004/12/27 04:13:54     1.1.2.9
@@ -348,6 +348,7 @@
 {
        char *fs_names = __getname();
        char *p;
+       int tries = 10;
 
        get_fs_names(fs_names);
 retry:
@@ -367,11 +368,18 @@
                 * Allow the user to distinguish between failed open
                 * and bad superblock on root device.
                 */
+               if (--tries) {
+                       printk ("VFS: Cannot open root device \"%s\" or %s, "
+                               "retrying in 1s.\n",
+                               root_device_name, kdevname (ROOT_DEV));
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       schedule_timeout(HZ);
+                       goto retry;
+               }
                printk ("VFS: Cannot open root device \"%s\" or %s\n",
                        root_device_name, kdevname (ROOT_DEV));
                printk ("Please append a correct \"root=\" boot option\n");
-               panic("VFS: Unable to mount root fs on %s",
-                       kdevname(ROOT_DEV));
+               break;
        }
        panic("VFS: Unable to mount root fs on %s", kdevname(ROOT_DEV));
 out:
diff -urN linux/kernel/fork.c linux/kernel/fork.c
--- linux/kernel/fork.c 2004/11/19 00:28:52     1.58.2.10
+++ linux/kernel/fork.c 2004/12/27 04:13:55     1.58.2.11
@@ -513,8 +513,17 @@
 
        for (i = open_files; i != 0; i--) {
                struct file *f = *old_fds++;
-               if (f)
+               if (f) {
                        get_file(f);
+               } else {
+                       /*
+                        * The fd may be claimed in the fd bitmap but not yet
+                        * instantiated in the files array if a sibling thread
+                        * is partway through open().  So make sure that this
+                        * fd is available to the new process.
+                        */
+                        FD_CLR(open_files - i, newf->open_fds);
+               }
                *new_fds++ = f;
        }
        read_unlock(&oldf->file_lock);
diff -urN linux/kernel/sysctl.c linux/kernel/sysctl.c
--- linux/kernel/sysctl.c       2004/11/29 17:47:18     1.46.2.10
+++ linux/kernel/sysctl.c       2004/12/27 04:13:55     1.46.2.11
@@ -379,6 +379,9 @@
                int old_len;
                if (!oldlenp || get_user(old_len, oldlenp))
                        return -EFAULT;
+               /* XXX: insufficient for SMP, but should be redundant anyway */
+               if ((ssize_t)old_len < 0)
+                       return -EINVAL;
        }
        tmp = &root_table_header.ctl_entry;
        do {
diff -urN linux/mm/mmap.c linux/mm/mmap.c
--- linux/mm/mmap.c     2004/01/20 15:10:34     1.49.2.7
+++ linux/mm/mmap.c     2004/12/27 04:13:55     1.49.2.8
@@ -650,7 +650,7 @@
 unsigned long get_unmapped_area(struct file *file, unsigned long addr, 
unsigned long len, unsigned long pgoff, unsigned long flags)
 {
        if (flags & MAP_FIXED) {
-               if (addr > TASK_SIZE - len)
+               if (addr > TASK_SIZE - len || addr >= TASK_SIZE)
                        return -ENOMEM;
                if (addr & ~PAGE_MASK)
                        return -EINVAL;
@@ -931,7 +931,7 @@
 {
        struct vm_area_struct *mpnt, *prev, **npp, *free, *extra;
 
-       if ((addr & ~PAGE_MASK) || addr > TASK_SIZE || len > TASK_SIZE-addr)
+       if ((addr & ~PAGE_MASK) || addr >= TASK_SIZE || len > TASK_SIZE-addr)
                return -EINVAL;
 
        if ((len = PAGE_ALIGN(len)) == 0)
@@ -1193,14 +1193,15 @@
        validate_mm(mm);
 }
 
-void insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma)
+int insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma)
 {
        struct vm_area_struct * __vma, * prev;
        rb_node_t ** rb_link, * rb_parent;
 
        __vma = find_vma_prepare(mm, vma->vm_start, &prev, &rb_link, 
&rb_parent);
        if (__vma && __vma->vm_start < vma->vm_end)
-               BUG();
+               return -ENOMEM;
        vma_link(mm, vma, prev, rb_link, rb_parent);
        validate_mm(mm);
+       return 0;
 }
diff -urN linux/mm/mremap.c linux/mm/mremap.c
--- linux/mm/mremap.c   2004/04/16 03:14:21     1.26.2.5
+++ linux/mm/mremap.c   2004/12/27 04:13:55     1.26.2.6
@@ -196,6 +196,7 @@
                        insert_vm_struct(current->mm, new_vma);
                }
 
+               /* XXX: possible errors masked, mapping might remain */
                do_munmap(current->mm, addr, old_len);
 
                current->mm->total_vm += new_len >> PAGE_SHIFT;
@@ -236,6 +237,12 @@
        old_len = PAGE_ALIGN(old_len);
        new_len = PAGE_ALIGN(new_len);
 
+       if (old_len > TASK_SIZE || addr > TASK_SIZE - old_len)
+               goto out;
+
+       if (addr >= TASK_SIZE)
+               goto out;
+
        /* new_addr is only valid if MREMAP_FIXED is specified */
        if (flags & MREMAP_FIXED) {
                if (new_addr & ~PAGE_MASK)
@@ -245,6 +252,10 @@
 
                if (new_len > TASK_SIZE || new_addr > TASK_SIZE - new_len)
                        goto out;
+
+               if (new_addr >= TASK_SIZE)
+                       goto out;
+
                /*
                 * Allow new_len == 0 only if new_addr == addr
                 * to preserve truncation in place (that was working
diff -urN linux/net/netsyms.c linux/net/netsyms.c
--- linux/net/Attic/netsyms.c   2004/11/19 00:28:52     1.53.2.12
+++ linux/net/Attic/netsyms.c   2004/12/27 04:13:55     1.53.2.13
@@ -327,6 +327,7 @@
 EXPORT_SYMBOL(tcp_listen_wlock);
 EXPORT_SYMBOL(udp_hash);
 EXPORT_SYMBOL(udp_hash_lock);
+EXPORT_SYMBOL(udp_poll);
 
 EXPORT_SYMBOL(tcp_destroy_sock);
 EXPORT_SYMBOL(ip_queue_xmit);
diff -urN linux/net/802/p8022.c linux/net/802/p8022.c
--- linux/net/802/p8022.c       2004/08/14 18:39:04     1.6.4.1
+++ linux/net/802/p8022.c       2004/12/27 04:13:55     1.6.4.2
@@ -97,7 +97,14 @@
        return 0;
 }
 
+static void __exit p8022_exit(void)
+{
+       dev_remove_pack(&p8022_packet_type);
+       return;
+}
+
 module_init(p8022_init);
+module_exit(p8022_exit);
 
 struct datalink_proto *register_8022_client(unsigned char type, int 
(*rcvfunc)(struct sk_buff *, struct net_device *, struct packet_type *))
 {
diff -urN linux/net/802/psnap.c linux/net/802/psnap.c
--- linux/net/802/psnap.c       2004/08/14 18:39:04     1.6.4.1
+++ linux/net/802/psnap.c       2004/12/27 04:13:55     1.6.4.2
@@ -96,7 +96,15 @@
                printk("SNAP - unable to register with 802.2\n");
        return 0;
 }
+
+static void __exit snap_exit(void)
+{
+       unregister_8022_client(0xAA);
+}
+
 module_init(snap_init);
+module_exit(snap_exit);
+
 
 /*
  *     Register SNAP clients. We don't yet use this for IP.
diff -urN linux/net/bluetooth/rfcomm/tty.c linux/net/bluetooth/rfcomm/tty.c
--- linux/net/bluetooth/rfcomm/tty.c    2004/08/14 18:39:04     1.5.2.6
+++ linux/net/bluetooth/rfcomm/tty.c    2004/12/27 04:13:55     1.5.2.7
@@ -532,10 +532,8 @@
 
        BT_DBG("dev %p tty %p", dev, tty);
 
-       if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && 
tty->ldisc.write_wakeup)
-                (tty->ldisc.write_wakeup)(tty);
+       tty_wakeup(tty);
 
-       wake_up_interruptible(&tty->write_wait);
 #ifdef SERIAL_HAVE_POLL_WAIT
        wake_up_interruptible(&tty->poll_wait);
 #endif
@@ -853,8 +851,7 @@
 
        skb_queue_purge(&dev->dlc->tx_queue);
 
-       if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && 
tty->ldisc.write_wakeup)
-               tty->ldisc.write_wakeup(tty);
+       tty_wakeup(tty);
 }
 
 static void rfcomm_tty_send_xchar(struct tty_struct *tty, char ch)
diff -urN linux/net/core/scm.c linux/net/core/scm.c
--- linux/net/core/scm.c        2001/12/29 05:38:26     1.13.4.1
+++ linux/net/core/scm.c        2004/12/27 04:13:55     1.13.4.2
@@ -124,9 +124,7 @@
                   for too short ancillary data object at all! Oops.
                   OK, let's add it...
                 */
-               if (cmsg->cmsg_len < sizeof(struct cmsghdr) ||
-                   (unsigned long)(((char*)cmsg - (char*)msg->msg_control)
-                                   + cmsg->cmsg_len) > msg->msg_controllen)
+               if (!CMSG_OK(msg, cmsg))
                        goto error;
 
                if (cmsg->cmsg_level != SOL_SOCKET)
diff -urN linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- linux/net/ipv4/af_inet.c    2004/08/14 18:39:04     1.38.2.5
+++ linux/net/ipv4/af_inet.c    2004/12/27 04:13:55     1.38.2.6
@@ -972,6 +972,27 @@
        socketpair:     sock_no_socketpair,
        accept:         sock_no_accept,
        getname:        inet_getname, 
+       poll:           udp_poll,
+       ioctl:          inet_ioctl,
+       listen:         sock_no_listen,
+       shutdown:       inet_shutdown,
+       setsockopt:     inet_setsockopt,
+       getsockopt:     inet_getsockopt,
+       sendmsg:        inet_sendmsg,
+       recvmsg:        inet_recvmsg,
+       mmap:           sock_no_mmap,
+       sendpage:       sock_no_sendpage,
+};
+
+struct proto_ops inet_sockraw_ops = {
+       family:         PF_INET,
+
+       release:        inet_release,
+       bind:           inet_bind,
+       connect:        inet_dgram_connect,
+       socketpair:     sock_no_socketpair,
+       accept:         sock_no_accept,
+       getname:        inet_getname, 
        poll:           datagram_poll,
        ioctl:          inet_ioctl,
        listen:         sock_no_listen,
@@ -1023,7 +1044,7 @@
                type:        SOCK_RAW,
                protocol:    IPPROTO_IP,        /* wild card */
                prot:        &raw_prot,
-               ops:         &inet_dgram_ops,
+               ops:         &inet_sockraw_ops,
                capability:  CAP_NET_RAW,
                no_check:    UDP_CSUM_DEFAULT,
                flags:       INET_PROTOSW_REUSE,
diff -urN linux/net/ipv4/igmp.c linux/net/ipv4/igmp.c
--- linux/net/ipv4/igmp.c       2004/08/14 18:39:04     1.22.2.10
+++ linux/net/ipv4/igmp.c       2004/12/27 04:13:55     1.22.2.11
@@ -1757,12 +1757,12 @@
                        goto done;
                rv = !0;
                for (i=0; i<psl->sl_count; i++) {
-                       rv = memcmp(&psl->sl_addr, &mreqs->imr_multiaddr,
+                       rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr,
                                sizeof(__u32));
-                       if (rv >= 0)
+                       if (rv == 0)
                                break;
                }
-               if (!rv)        /* source not found */
+               if (rv)         /* source not found */
                        goto done;
 
                /* update the interface filter */
@@ -1804,9 +1804,9 @@
        }
        rv = 1; /* > 0 for insert logic below if sl_count is 0 */
        for (i=0; i<psl->sl_count; i++) {
-               rv = memcmp(&psl->sl_addr, &mreqs->imr_multiaddr,
+               rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr,
                        sizeof(__u32));
-               if (rv >= 0)
+               if (rv == 0)
                        break;
        }
        if (rv == 0)            /* address already there is an error */
diff -urN linux/net/ipv4/ip_options.c linux/net/ipv4/ip_options.c
--- linux/net/ipv4/ip_options.c 2003/01/11 17:53:19     1.13.2.1
+++ linux/net/ipv4/ip_options.c 2004/12/27 04:13:56     1.13.2.2
@@ -514,6 +514,8 @@
                kfree(opt);
                return -EINVAL;
        }
+       if (*optp)
+               kfree(*optp);
        *optp = opt;
        return 0;
 }
diff -urN linux/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c
--- linux/net/ipv4/ip_sockglue.c        2004/08/14 18:39:04     1.25.2.3
+++ linux/net/ipv4/ip_sockglue.c        2004/12/27 04:13:56     1.25.2.4
@@ -143,11 +143,8 @@
        struct cmsghdr *cmsg;
 
        for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
-               if (cmsg->cmsg_len < sizeof(struct cmsghdr) ||
-                   (unsigned long)(((char*)cmsg - (char*)msg->msg_control)
-                                   + cmsg->cmsg_len) > msg->msg_controllen) {
+               if (!CMSG_OK(msg, cmsg))
                        return -EINVAL;
-               }
                if (cmsg->cmsg_level != SOL_IP)
                        continue;
                switch (cmsg->cmsg_type) {
diff -urN linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- linux/net/ipv4/tcp_input.c  2004/11/29 17:47:19     1.45.2.12
+++ linux/net/ipv4/tcp_input.c  2004/12/27 04:13:56     1.45.2.13
@@ -2908,8 +2908,8 @@
                                                        tp->snd_wscale = *(__u8 
*)ptr;
                                                        if(tp->snd_wscale > 14) 
{
                                                                
if(net_ratelimit())
-                                                                       
printk("tcp_parse_options: Illegal window "
-                                                                              
"scaling value %d >14 received.",
+                                                                       
printk(KERN_INFO "tcp_parse_options: Illegal window "
+                                                                              
"scaling value %d >14 received.\n",
                                                                               
tp->snd_wscale);
                                                                tp->snd_wscale 
= 14;
                                                        }
@@ -3145,7 +3145,7 @@
                        /* Only TCP_LISTEN and TCP_CLOSE are left, in these
                         * cases we should never reach this piece of code.
                         */
-                       printk("tcp_fin: Impossible, sk->state=%d\n", 
sk->state);
+                       printk(KERN_ERR "tcp_fin: Impossible, sk->state=%d\n", 
sk->state);
                        break;
        };
 
diff -urN linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- linux/net/ipv4/udp.c        2004/08/14 18:39:05     1.35.2.7
+++ linux/net/ipv4/udp.c        2004/12/27 04:13:56     1.35.2.8
@@ -371,7 +371,6 @@
        sock_put(sk);
 }
 
-
 static unsigned short udp_check(struct udphdr *uh, int len, unsigned long 
saddr, unsigned long daddr, unsigned long base)
 {
        return(csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base));
@@ -636,6 +635,55 @@
                __udp_checksum_complete(skb);
 }
 
+
+/**
+ *     udp_poll - wait for a UDP event.
+ *     @file - file struct
+ *     @sock - socket
+ *     @wait - poll table
+ *
+ *     This is same as datagram poll, except for the special case of 
+ *     blocking sockets. If application is using a blocking fd
+ *     and a packet with checksum error is in the queue;
+ *     then it could get return from select indicating data available
+ *     but then block when reading it. Add special case code
+ *     to work around these arguably broken applications.
+ */
+unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait)
+{
+       unsigned int mask = datagram_poll(file, sock, wait);
+       struct sock *sk = sock->sk;
+       
+       /* Check for false positives due to checksum errors */
+       if ( (mask & POLLRDNORM) &&
+            !(file->f_flags & O_NONBLOCK) &&
+            !(sk->shutdown & RCV_SHUTDOWN)){
+               struct sk_buff_head *rcvq = &sk->receive_queue;
+               struct sk_buff *skb;
+
+               spin_lock_irq(&rcvq->lock);
+               while ((skb = skb_peek(rcvq)) != NULL) {
+                       if (udp_checksum_complete(skb)) {
+                               UDP_INC_STATS_BH(UdpInErrors);
+                               IP_INC_STATS_BH(IpInDiscards);
+                               __skb_unlink(skb, rcvq);
+                               kfree_skb(skb);
+                       } else {
+                               skb->ip_summed = CHECKSUM_UNNECESSARY;
+                               break;
+                       }
+               }
+               spin_unlock_irq(&rcvq->lock);
+
+               /* nothing to see, move along */
+               if (skb == NULL)
+                       mask &= ~(POLLIN | POLLRDNORM);
+       }
+
+       return mask;
+       
+}
+
 /*
  *     This should be easy, if there is something there we
  *     return it, otherwise we block.
diff -urN linux/net/ipv4/ipvs/ip_vs_conn.c linux/net/ipv4/ipvs/ip_vs_conn.c
--- linux/net/ipv4/ipvs/ip_vs_conn.c    2004/04/16 03:14:22     1.5.2.2
+++ linux/net/ipv4/ipvs/ip_vs_conn.c    2004/12/27 04:13:56     1.5.2.3
@@ -1131,7 +1131,9 @@
         * Checking the dest server status.
         */
        if ((dest == NULL) ||
-           !(dest->flags & IP_VS_DEST_F_AVAILABLE)) {
+           !(dest->flags & IP_VS_DEST_F_AVAILABLE) || 
+           (sysctl_ip_vs_expire_quiescent_template && 
+            (atomic_read(&dest->weight) == 0))) {
                IP_VS_DBG(9, "check_template: dest not available for "
                          "protocol %s s:%u.%u.%u.%u:%d v:%u.%u.%u.%u:%d "
                          "-> d:%u.%u.%u.%u:%d\n",
diff -urN linux/net/ipv4/ipvs/ip_vs_ctl.c linux/net/ipv4/ipvs/ip_vs_ctl.c
--- linux/net/ipv4/ipvs/ip_vs_ctl.c     2004/04/16 03:14:22     1.6.2.2
+++ linux/net/ipv4/ipvs/ip_vs_ctl.c     2004/12/27 04:13:56     1.6.2.3
@@ -74,6 +74,7 @@
 static int sysctl_ip_vs_am_droprate = 10;
 int sysctl_ip_vs_cache_bypass = 0;
 int sysctl_ip_vs_expire_nodest_conn = 0;
+int sysctl_ip_vs_expire_quiescent_template = 0;
 int sysctl_ip_vs_sync_threshold = 3;
 int sysctl_ip_vs_nat_icmp_send = 0;
 
@@ -1440,6 +1441,9 @@
         {NET_IPV4_VS_NAT_ICMP_SEND, "nat_icmp_send",
          &sysctl_ip_vs_nat_icmp_send, sizeof(int), 0644, NULL,
          &proc_dointvec},
+        {NET_IPV4_VS_EXPIRE_QUIESCENT_TEMPLATE, "expire_quiescent_template",
+         &sysctl_ip_vs_expire_quiescent_template, sizeof(int), 0644, NULL,
+         &proc_dointvec},
         {0}},
        {{NET_IPV4_VS, "vs", NULL, 0, 0555, ipv4_vs_table.vs_vars},
         {0}},
diff -urN linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c
--- linux/net/ipv6/af_inet6.c   2004/11/19 00:29:04     1.32.2.6
+++ linux/net/ipv6/af_inet6.c   2004/12/27 04:13:57     1.32.2.7
@@ -497,6 +497,27 @@
        socketpair:     sock_no_socketpair,             /* a do nothing */
        accept:         sock_no_accept,                 /* a do nothing */
        getname:        inet6_getname, 
+       poll:           udp_poll,                       /* ok           */
+       ioctl:          inet6_ioctl,                    /* must change  */
+       listen:         sock_no_listen,                 /* ok           */
+       shutdown:       inet_shutdown,                  /* ok           */
+       setsockopt:     inet_setsockopt,                /* ok           */
+       getsockopt:     inet_getsockopt,                /* ok           */
+       sendmsg:        inet_sendmsg,                   /* ok           */
+       recvmsg:        inet_recvmsg,                   /* ok           */
+       mmap:           sock_no_mmap,
+       sendpage:       sock_no_sendpage,
+};
+
+struct proto_ops inet6_sockraw_ops = {
+       family:         PF_INET6,
+
+       release:        inet6_release,
+       bind:           inet6_bind,
+       connect:        inet_dgram_connect,             /* ok           */
+       socketpair:     sock_no_socketpair,             /* a do nothing */
+       accept:         sock_no_accept,                 /* a do nothing */
+       getname:        inet6_getname, 
        poll:           datagram_poll,                  /* ok           */
        ioctl:          inet6_ioctl,                    /* must change  */
        listen:         sock_no_listen,                 /* ok           */
@@ -532,7 +553,7 @@
        type:        SOCK_RAW,
        protocol:    IPPROTO_IP,        /* wild card */
        prot:        &rawv6_prot,
-       ops:         &inet6_dgram_ops,
+       ops:         &inet6_sockraw_ops,
        capability:  CAP_NET_RAW,
        no_check:    UDP_CSUM_DEFAULT,
        flags:       INET_PROTOSW_REUSE,
diff -urN linux/net/ipv6/datagram.c linux/net/ipv6/datagram.c
--- linux/net/ipv6/datagram.c   2004/11/19 00:29:04     1.13.2.3
+++ linux/net/ipv6/datagram.c   2004/12/27 04:13:57     1.13.2.4
@@ -260,9 +260,7 @@
 
        for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
 
-               if (cmsg->cmsg_len < sizeof(struct cmsghdr) ||
-                   (unsigned long)(((char*)cmsg - (char*)msg->msg_control)
-                                   + cmsg->cmsg_len) > msg->msg_controllen) {
+               if (!CMSG_OK(msg, cmsg)) {
                        err = -EINVAL;
                        goto exit_f;
                }
diff -urN linux/net/ipv6/mcast.c linux/net/ipv6/mcast.c
--- linux/net/ipv6/mcast.c      2004/11/19 00:29:04     1.22.2.11
+++ linux/net/ipv6/mcast.c      2004/12/27 04:13:57     1.22.2.12
@@ -386,12 +386,12 @@
                        goto done;
                rv = !0;
                for (i=0; i<psl->sl_count; i++) {
-                       rv = memcmp(&psl->sl_addr, group,
+                       rv = memcmp(&psl->sl_addr[i], source,
                                sizeof(struct in6_addr));
-                       if (rv >= 0)
+                       if (rv == 0)
                                break;
                }
-               if (!rv)        /* source not found */
+               if (rv)         /* source not found */
                        goto done;
 
                /* update the interface filter */
@@ -432,8 +432,8 @@
        }
        rv = 1; /* > 0 for insert logic below if sl_count is 0 */
        for (i=0; i<psl->sl_count; i++) {
-               rv = memcmp(&psl->sl_addr, group, sizeof(struct in6_addr));
-               if (rv >= 0)
+               rv = memcmp(&psl->sl_addr[i], source, sizeof(struct in6_addr));
+               if (rv == 0)
                        break;
        }
        if (rv == 0)            /* address already there is an error */
diff -urN linux/net/irda/ircomm/ircomm_tty.c linux/net/irda/ircomm/ircomm_tty.c
--- linux/net/irda/ircomm/ircomm_tty.c  2003/08/13 17:19:31     1.11.2.3
+++ linux/net/irda/ircomm/ircomm_tty.c  2004/12/27 04:13:57     1.11.2.4
@@ -566,8 +566,7 @@
 
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
 
        tty->closing = 0;
        self->tty = 0;
@@ -662,12 +661,7 @@
                ircomm_tty_do_event(self, IRCOMM_TTY_DATA_REQUEST, skb, NULL);
                
        /* Check if user (still) wants to be waken up */
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && 
-           tty->ldisc.write_wakeup)
-       {
-               (tty->ldisc.write_wakeup)(tty);
-       }
-       wake_up_interruptible(&tty->write_wait);
+       tty_wakeup(tty);
 }
 
 /*
diff -urN linux/net/sched/cls_tcindex.c linux/net/sched/cls_tcindex.c
--- linux/net/sched/cls_tcindex.c       2001/12/29 05:38:31     1.5.2.1
+++ linux/net/sched/cls_tcindex.c       2004/12/27 04:13:57     1.5.2.2
@@ -161,7 +161,8 @@
 }
 
 
-static int tcindex_delete(struct tcf_proto *tp, unsigned long arg)
+static int
+__tcindex_delete(struct tcf_proto *tp, unsigned long arg, int lock)
 {
        struct tcindex_data *p = PRIV(tp);
        struct tcindex_filter_result *r = (struct tcindex_filter_result *) arg;
@@ -184,9 +185,11 @@
 
 found:
                f = *walk;
-               tcf_tree_lock(tp); 
+               if (lock)
+                       tcf_tree_lock(tp);
                *walk = f->next;
-               tcf_tree_unlock(tp);
+               if (lock)
+                       tcf_tree_unlock(tp);
        }
        cl = __cls_set_class(&r->res.class,0);
        if (cl)
@@ -199,6 +202,10 @@
        return 0;
 }
 
+static int tcindex_delete(struct tcf_proto *tp, unsigned long arg)
+{
+       return __tcindex_delete(tp, arg, 1);
+}
 
 /*
  * There are no parameters for tcindex_init, so we overload tcindex_change
@@ -397,7 +404,7 @@
 static int tcindex_destroy_element(struct tcf_proto *tp,
     unsigned long arg, struct tcf_walker *walker)
 {
-       return tcindex_delete(tp,arg);
+       return __tcindex_delete(tp, arg, 0);
 }
 
 
diff -urN linux/net/sched/sch_netem.c linux/net/sched/sch_netem.c
--- linux/net/sched/sch_netem.c 2004/11/19 00:29:09     1.4.2.2
+++ linux/net/sched/sch_netem.c 2004/12/27 04:13:57     1.4.2.3
@@ -259,12 +259,13 @@
 {
        struct Qdisc *sch = (struct Qdisc *)arg;
        struct netem_sched_data *q = qdisc_priv(sch);
+       struct net_device *dev = sch->dev;
        struct sk_buff *skb;
        psched_time_t now;
 
        pr_debug("netem_watchdog: fired @%lu\n", jiffies);
 
-       spin_lock_bh(&sch->dev->queue_lock);
+       spin_lock_bh(&dev->queue_lock);
        PSCHED_GET_TIME(now);
 
        while ((skb = skb_peek(&q->delayed)) != NULL) {
@@ -284,8 +285,11 @@
 
                if (q->qdisc->enqueue(skb, q->qdisc))
                        sch->stats.drops++;
+               else
+                       sch->q.qlen++;
        }
-       spin_unlock_bh(&sch->dev->queue_lock);
+       qdisc_run(dev);
+       spin_unlock_bh(&dev->queue_lock);
 }
 
 static void netem_reset(struct Qdisc *sch)
@@ -505,7 +509,7 @@
        sch_tree_lock(sch);
        *old = xchg(&q->qdisc, new);
        qdisc_reset(*old);
-       sch->q.qlen = q->delayed.qlen;
+       sch->q.qlen = 0;
        sch_tree_unlock(sch);
 
        return 0;
diff -urN linux/net/sctp/socket.c linux/net/sctp/socket.c
--- linux/net/sctp/socket.c     2004/11/19 00:29:09     1.23.2.5
+++ linux/net/sctp/socket.c     2004/12/27 04:13:57     1.23.2.6
@@ -4090,12 +4090,8 @@
        for (cmsg = CMSG_FIRSTHDR(msg);
             cmsg != NULL;
             cmsg = CMSG_NXTHDR((struct msghdr*)msg, cmsg)) {
-               /* Check for minimum length.  The SCM code has this check.  */
-               if (cmsg->cmsg_len < sizeof(struct cmsghdr) ||
-                   (unsigned long)(((char*)cmsg - (char*)msg->msg_control)
-                                   + cmsg->cmsg_len) > msg->msg_controllen) {
+               if (!CMSG_OK(msg, cmsg))
                        return -EINVAL;
-               }
 
                /* Should we parse this header or ignore?  */
                if (cmsg->cmsg_level != IPPROTO_SCTP)

<Prev in Thread] Current Thread [Next in Thread>