# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	v2.6.0-test7 -> 1.1360 
#	fs/xfs/linux/xfs_lrw.c	1.32    -> 1.34   
#	drivers/i2c/chips/w83781d.c	1.16    -> 1.17   
#	drivers/net/8139too.c	1.72    -> 1.74   
#	      fs/jfs/inode.c	1.36    -> 1.37   
#	 drivers/net/defxx.c	1.21    -> 1.22   
#	arch/sparc64/kernel/smp.c	1.63    -> 1.64   
#	fs/jffs2/compr_zlib.c	1.8     -> 1.9    
#	  fs/jffs2/symlink.c	1.5     -> 1.6    
#	  fs/xfs/xfs_mount.h	1.23    -> 1.24   
#	drivers/i2c/chips/lm75.c	1.18    -> 1.19   
#	arch/i386/mm/fault.c	1.26    -> 1.27   
#	drivers/media/common/saa7146_vbi.c	1.6     -> 1.7    
#	fs/xfs/linux/xfs_sysctl.h	1.13    -> 1.14   
#	sound/pci/vx222/vx222_ops.c	1.1     -> 1.2    
#	net/ipv4/ipvs/ip_vs_core.c	1.6     -> 1.7    
#	drivers/media/dvb/frontends/tda1004x.c	1.2     -> 1.3    
#	fs/xfs/linux/xfs_linux.h	1.22    -> 1.23   
#	 fs/jffs2/pushpull.h	1.4     -> 1.5    
#	  net/ipx/ipx_proc.c	1.9     -> 1.10   
#	include/asm-i386/div64.h	1.3     -> 1.4    
#	fs/jffs2/background.c	1.19    -> 1.21   
#	drivers/media/dvb/ttpci/av7110.h	1.4     -> 1.5    
#	drivers/media/dvb/frontends/Makefile	1.9     -> 1.10   
#	drivers/acpi/hardware/hwacpi.c	1.16    -> 1.17   
#	drivers/acpi/sleep/main.c	1.35    -> 1.36   
#	drivers/char/n_tty.c	1.19    -> 1.20   
#	fs/xfs/linux/xfs_vfs.h	1.15    -> 1.16   
#	include/linux/jffs2_fs_sb.h	1.10    -> 1.11   
#	drivers/i2c/chips/adm1021.c	1.23    -> 1.24   
#	drivers/net/wan/cosa.c	1.27    -> 1.28   
#	drivers/media/dvb/frontends/cx24110.c	1.2     -> 1.3    
#	arch/arm/mach-integrator/lm.c	1.2     -> 1.3    
#	fs/xfs/xfs_buf_item.c	1.12    -> 1.13   
#	drivers/char/Kconfig	1.23    -> 1.24   
#	fs/jffs2/readinode.c	1.9     -> 1.10   
#	  arch/ia64/Makefile	1.60    -> 1.61   
#	fs/xfs/quota/xfs_qm.c	1.14    -> 1.15   
#	   fs/jffs2/malloc.c	1.7     -> 1.8    
#	arch/x86_64/kernel/setup.c	1.23    -> 1.24   
#	include/asm-i386/processor.h	1.55    -> 1.56   
#	           fs/open.c	1.52    -> 1.53   
#	arch/i386/kernel/cpu/cpufreq/longhaul.c	1.44    -> 1.48   
#	 kernel/power/disk.c	1.5     -> 1.6    
#	drivers/net/natsemi.c	1.55    -> 1.56   
#	net/ipv4/netfilter/ipt_limit.c	1.5     -> 1.6    
#	drivers/acpi/executer/exfield.c	1.18    -> 1.19   
#	   arch/ppc/Makefile	1.47    -> 1.48   
#	  sound/core/hwdep.c	1.17    -> 1.18   
#	drivers/usb/class/Kconfig	1.9     -> 1.10   
#	fs/xfs/xfs_trans_buf.c	1.9     -> 1.10   
#	          mm/mlock.c	1.6     -> 1.7    
#	 drivers/base/core.c	1.77    -> 1.78   
#	drivers/net/hamradio/Kconfig	1.7     -> 1.8    
#	fs/xfs/linux/xfs_lrw.h	1.14    -> 1.15   
#	arch/i386/kernel/irq.c	1.42    -> 1.44   
#	arch/arm/mach-sa1100/cpu-sa1100.c	1.16    -> 1.17   
#	drivers/usb/gadget/net2280.c	1.18    -> 1.19   
#	include/acpi/acexcep.h	1.15    -> 1.16   
#	include/media/saa7146_vv.h	1.5     -> 1.6    
#	drivers/media/dvb/frontends/mt312.c	1.4     -> 1.5    
#	drivers/usb/host/ohci-hcd.c	1.47    -> 1.48   
#	drivers/media/dvb/dvb-core/dvb_net.h	1.7     -> 1.9    
#	include/linux/nfs_page.h	1.10    -> 1.11   
#	    fs/jffs2/erase.c	1.11    -> 1.12   
#	  fs/xfs/xfs_dfrag.c	1.4     -> 1.5    
#	       kernel/fork.c	1.144   -> 1.145  
#	include/linux/sched.h	1.170   -> 1.173  
#	        kernel/sys.c	1.61.1.2 -> 1.66   
#	 drivers/net/Space.c	1.41    -> 1.42   
#	 fs/jffs2/os-linux.h	1.13    -> 1.14   
#	drivers/i2c/chips/via686a.c	1.12    -> 1.13   
#	include/asm-ia64/unistd.h	1.36    -> 1.37   
#	drivers/acpi/utilities/utglobal.c	1.28    -> 1.29   
#	drivers/acpi/executer/exstoren.c	1.17    -> 1.18   
#	drivers/media/dvb/frontends/alps_bsrv2.c	1.7     -> 1.8     drivers/media/dvb/frontends/ves1x93.c (moved)
#	include/asm-ia64/page.h	1.21    -> 1.22   
#	drivers/net/amd8111e.h	1.2     -> 1.3    
#	drivers/acpi/utilities/utalloc.c	1.15    -> 1.16   
#	arch/ia64/kernel/setup.c	1.59    -> 1.61   
#	drivers/media/dvb/frontends/grundig_29504-401.c	1.7     -> 1.8    
#	arch/ppc/mm/ppc_mmu.c	1.9     -> 1.10   
#	drivers/net/loopback.c	1.10    -> 1.11   
#	arch/x86_64/kernel/apic.c	1.24    -> 1.25   
#	include/acpi/actbl1.h	1.11    -> 1.12   
#	sound/isa/sb/emu8000_patch.c	1.2     -> 1.3    
#	drivers/media/dvb/frontends/Kconfig	1.9     -> 1.10   
#	   arch/i386/Kconfig	1.86.2.2 -> 1.91   
#	sound/core/rawmidi.c	1.29.1.1 -> 1.32   
#	sound/core/control.c	1.25    -> 1.26   
#	   fs/jfs/jfs_imap.c	1.28    -> 1.29   
#	fs/jfs/jfs_superblock.h	1.5     -> 1.6    
#	arch/i386/kernel/traps.c	1.60    -> 1.62   
#	   sound/core/init.c	1.20    -> 1.21   
#	 fs/jffs2/nodemgmt.c	1.9     -> 1.10   
#	 fs/xfs/xfs_ialloc.h	1.2     -> 1.3    
#	arch/ppc/kernel/cpu_setup_6xx.S	1.2     -> 1.3    
#	drivers/media/dvb/dvb-core/dvb_net.c	1.9     -> 1.11   
#	arch/i386/kernel/acpi/wakeup.S	1.15    -> 1.16   
#	drivers/acpi/executer/exprep.c	1.17    -> 1.18   
#	drivers/scsi/scsi_sysfs.c	1.33    -> 1.34   
#	 fs/xfs/xfs_vfsops.c	1.46    -> 1.49   
#	include/asm-ia64/sn/nodepda.h	1.9     -> 1.10   
#	include/linux/ioport.h	1.11    -> 1.12   
#	drivers/char/synclinkmp.c	1.23    -> 1.24   
#	drivers/media/dvb/frontends/alps_tdmb7.c	1.5     -> 1.6    
#	drivers/media/dvb/dvb-core/dvb_i2c.h	1.4     -> 1.5    
#	arch/x86_64/kernel/acpi/boot.c	1.5     -> 1.6    
#	drivers/block/Kconfig	1.14    -> 1.15   
#	    fs/xfs/xfs_dir.c	1.10    -> 1.11   
#	drivers/acpi/tables/tbinstal.c	1.20    -> 1.21   
#	drivers/acpi/executer/exresnte.c	1.20    -> 1.21   
#	  drivers/base/bus.c	1.51    -> 1.52   
#	  fs/xfs/xfs_types.h	1.12    -> 1.13   
#	  net/core/ethtool.c	1.8     -> 1.9    
#	include/linux/ethtool.h	1.22    -> 1.23   
#	drivers/media/dvb/frontends/alps_tdlb7.c	1.6     -> 1.7    
#	include/linux/suspend.h	1.24    -> 1.25   
#	kernel/power/swsusp.c	1.65    -> 1.67   
#	     fs/jffs2/wbuf.c	1.8     -> 1.9    
#	fs/jfs/jfs_metapage.c	1.23    -> 1.24   
#	net/bridge/netfilter/Kconfig	1.9     -> 1.10   
#	drivers/net/wireless/atmel.c	1.5     -> 1.6    
#	      kernel/futex.c	1.34    -> 1.36   
#	arch/ia64/sn/kernel/setup.c	1.19    -> 1.20   
#	arch/ppc/configs/TQM8260_defconfig	1.5     -> 1.6    
#	drivers/net/wan/syncppp.c	1.17    -> 1.18   
#	       fs/jffs2/gc.c	1.13    -> 1.14   
#	fs/xfs/xfs_ialloc_btree.h	1.2     -> 1.3    
#	include/net/syncppp.h	1.5     -> 1.6    
#	drivers/media/dvb/frontends/dvb_dummy_fe.c	1.3     -> 1.4    
#	arch/ppc/platforms/pmac_time.c	1.12    -> 1.13   
#	drivers/i2c/busses/i2c-sis630.c	1.4     -> 1.5    
#	include/asm-ia64/meminit.h	1.1     -> 1.3    
#	include/asm-ia64/pgtable.h	1.29    -> 1.30   
#	sound/usb/usbmixer.c	1.19    -> 1.20   
#	drivers/usb/serial/visor.c	1.71    -> 1.72   
#	        fs/dnotify.c	1.11    -> 1.12   
#	drivers/acpi/asus_acpi.c	1.5     -> 1.6    
#	include/asm-ia64/uaccess.h	1.12    -> 1.13   
#	drivers/usb/gadget/Kconfig	1.6     -> 1.7    
#	arch/ppc/boot/of1275/map.c	1.2     -> 1.3    
#	    fs/jffs2/compr.c	1.5     -> 1.6    
#	     fs/jffs2/read.c	1.7     -> 1.8    
#	drivers/acpi/executer/exfldio.c	1.23    -> 1.24   
#	drivers/net/wan/hdlc_cisco.c	1.8     -> 1.9    
#	fs/xfs/linux/xfs_iops.c	1.37    -> 1.38   
#	    fs/jffs2/super.c	1.27    -> 1.28   
#	arch/sparc64/kernel/unaligned.c	1.9     -> 1.10   
#	arch/sparc64/defconfig	1.102   -> 1.103  
#	arch/x86_64/kernel/cpufreq/Makefile	1.1     -> 1.2    
#	sound/core/pcm_native.c	1.40    -> 1.41   
#	arch/ia64/mm/contig.c	1.1     -> 1.3    
#	drivers/i2c/chips/lm85.c	1.5     -> 1.6    
#	fs/xfs/xfs_ialloc_btree.c	1.5     -> 1.6    
#	include/asm-ia64/numa.h	1.9     -> 1.11   
#	drivers/char/pcmcia/synclink_cs.c	1.27    -> 1.28   
#	  fs/xfs/xfs_mount.c	1.37    -> 1.39   
#	arch/arm/kernel/armksyms.c	1.22    -> 1.23   
#	   sound/pci/Kconfig	1.8.1.1 -> 1.10   
#	  arch/i386/Makefile	1.58    -> 1.59   
#	include/linux/nfs_fs.h	1.51    -> 1.52   
#	drivers/char/synclink.c	1.45    -> 1.46   
#	   arch/arm/Makefile	1.51    -> 1.52   
#	drivers/net/e1000/e1000_main.c	1.91    -> 1.92   
#	      fs/jfs/xattr.c	1.15    -> 1.16   
#	drivers/net/irda/sa1100_ir.c	1.13    -> 1.14   
#	           fs/exec.c	1.98    -> 1.99   
#	 drivers/net/hp100.c	1.21    -> 1.22   
#	sound/core/seq/seq_lock.c	1.5     -> 1.6    
#	   net/sunrpc/clnt.c	1.45    -> 1.46   
#	drivers/acpi/executer/exresolv.c	1.19    -> 1.20   
#	     kernel/signal.c	1.97    -> 1.98   
#	arch/arm/configs/lart_defconfig	1.11    -> 1.12   
#	drivers/acpi/tables/tbconvrt.c	1.24    -> 1.25   
#	drivers/pci/hotplug/Kconfig	1.11    -> 1.12   
#	sound/core/pcm_lib.c	1.23    -> 1.24   
#	include/asm-sparc64/uaccess.h	1.7     -> 1.8    
#	 arch/ia64/mm/init.c	1.48    -> 1.51   
#	   drivers/net/b44.c	1.12    -> 1.13   
#	drivers/mtd/devices/lart.c	1.3     -> 1.4    
#	       fs/jffs2/fs.c	1.18    -> 1.19   
#	 drivers/atm/Kconfig	1.9     -> 1.10   
#	     fs/binfmt_elf.c	1.58    -> 1.59   
#	drivers/net/hamradio/bpqether.c	1.17    -> 1.18   
#	      fs/jfs/super.c	1.44    -> 1.45   
#	  fs/xfs/xfs_trans.c	1.12    -> 1.13   
#	    fs/jffs2/write.c	1.11    -> 1.12   
#	arch/ppc/kernel/process.c	1.40    -> 1.42   
#	fs/xfs/support/move.h	1.4     -> 1.5    
#	drivers/usb/core/hcd-pci.c	1.22    -> 1.23   
#	drivers/video/aty/aty128fb.c	1.39    -> 1.40   
#	arch/ia64/kernel/acpi.c	1.52    -> 1.54   
#	drivers/video/imsttfb.c	1.28    -> 1.29   
#	  fs/jfs/jfs_xtree.c	1.11    -> 1.12   
#	   fs/nfs/nfs3proc.c	1.30    -> 1.31   
#	 fs/xfs/xfs_rename.c	1.12    -> 1.13   
#	 fs/jfs/jfs_filsys.h	1.4     -> 1.5    
#	drivers/usb/core/devio.c	1.53    -> 1.54   
#	drivers/net/wireless/atmel_cs.c	1.7     -> 1.8    
#	drivers/video/matrox/matroxfb_base.h	1.24    -> 1.25   
#	drivers/video/tridentfb.c	1.11    -> 1.12   
#	include/acpi/actbl.h	1.14    -> 1.15   
#	drivers/media/common/saa7146_fops.c	1.7     -> 1.8    
#	arch/x86_64/kernel/io_apic.c	1.15    -> 1.16   
#	arch/ppc/platforms/pmac_smp.c	1.14    -> 1.15   
#	    fs/jffs2/build.c	1.6     -> 1.7    
#	drivers/media/dvb/frontends/ves1820.c	1.9     -> 1.10   
#	arch/ia64/mm/hugetlbpage.c	1.14    -> 1.15   
#	fs/xfs/linux/xfs_file.c	1.17    -> 1.18   
#	arch/ppc/configs/est8260_defconfig	1.15    -> 1.16   
#	   fs/jffs2/writev.c	1.3     -> 1.4    
#	include/asm-x86_64/suspend.h	1.8     -> 1.9    
#	drivers/acpi/resources/rsaddr.c	1.14    -> 1.15   
#	arch/ppc/boot/openfirmware/coffmain.c	1.13    -> 1.14   
#	 fs/jfs/jfs_extent.c	1.9     -> 1.10   
#	fs/xfs/support/move.c	1.6     -> 1.7    
#	fs/xfs/xfs_log_recover.c	1.34    -> 1.37   
#	arch/m68k/sun3/sbus.c	1.4     -> 1.5    
#	 fs/jffs2/nodelist.c	1.9     -> 1.10   
#	       kernel/acct.c	1.25    -> 1.26   
#	arch/ppc/kernel/head.S	1.38    -> 1.39   
#	drivers/i2c/chips/Kconfig	1.14    -> 1.15   
#	fs/xfs/linux/xfs_iops.h	1.4     -> 1.5    
#	kernel/power/pmdisk.c	1.79    -> 1.80   
#	drivers/media/video/zoran_device.c	1.5     -> 1.6    
#	drivers/pcmcia/tcic.c	1.35    -> 1.36   
#	drivers/char/ipmi/ipmi_msghandler.c	1.6     -> 1.7    
#	        kernel/pid.c	1.12    -> 1.13   
#	drivers/media/video/zoran_card.c	1.7     -> 1.8    
#	          fs/Kconfig	1.37    -> 1.38   
#	 fs/xfs/xfs_ialloc.c	1.9     -> 1.11   
#	drivers/net/amd8111e.c	1.11    -> 1.12   
#	arch/arm/mach-clps7500/core.c	1.3     -> 1.4    
#	include/acpi/actypes.h	1.29    -> 1.30   
#	   fs/xfs/xfs_attr.c	1.10    -> 1.11   
#	drivers/char/tty_io.c	1.125   -> 1.126  
#	drivers/net/tulip/tulip_core.c	1.48    -> 1.49   
#	drivers/acpi/executer/exconfig.c	1.18    -> 1.19   
#	     fs/proc/array.c	1.53    -> 1.54   
#	 fs/jfs/jfs_txnmgr.c	1.48    -> 1.49   
#	arch/ia64/ia32/sys_ia32.c	1.79    -> 1.82   
#	include/acpi/actbl2.h	1.15    -> 1.16   
#	net/bridge/netfilter/Makefile	1.8     -> 1.9    
#	  sound/core/timer.c	1.21    -> 1.22   
#	Documentation/filesystems/jfs.txt	1.6     -> 1.7    
#	drivers/net/wan/sealevel.c	1.12    -> 1.13   
#	drivers/media/common/saa7146_video.c	1.11    -> 1.12   
#	 fs/xfs/xfs_dinode.h	1.5     -> 1.6    
#	drivers/media/dvb/ttpci/av7110.c	1.10    -> 1.12   
#	   kernel/resource.c	1.15    -> 1.16   
#	     fs/jfs/resize.c	1.10    -> 1.11   
#	fs/jffs2/compr_rtime.c	1.5     -> 1.6    
#	   fs/xfs/xfs_clnt.h	1.5     -> 1.6    
#	arch/i386/kernel/timers/timer_tsc.c	1.28    -> 1.29   
#	          fs/dquot.c	1.65    -> 1.66   
#	 mm/page-writeback.c	1.74    -> 1.75   
#	drivers/acpi/executer/exsystem.c	1.13    -> 1.14   
#	fs/xfs/xfs_inode_item.c	1.9     -> 1.10   
#	drivers/char/rocket.c	1.35    -> 1.36   
#	drivers/char/vt_ioctl.c	1.30    -> 1.31   
#	include/sound/pcm_oss.h	1.4     -> 1.5    
#	    net/sunrpc/xdr.c	1.14    -> 1.15   
#	  fs/jfs/jfs_dtree.c	1.24    -> 1.25   
#	drivers/char/ipmi/Kconfig	1.2     -> 1.3    
#	drivers/net/wan/hostess_sv11.c	1.9     -> 1.10   
#	drivers/media/dvb/frontends/nxt6000.c	1.3     -> 1.4    
#	include/asm-ia64/nodedata.h	1.5     -> 1.6    
#	include/asm-ppc/mpc10x.h	1.6     -> 1.7    
#	fs/xfs/xfs_buf_item.h	1.2     -> 1.3    
#	    fs/jffs2/ioctl.c	1.2     -> 1.3    
#	     kernel/module.c	1.93    -> 1.94   
#	include/linux/ipmi_msgdefs.h	1.1     -> 1.2    
#	sound/usb/usbaudio.c	1.47.1.1 -> 1.49   
#	  fs/xfs/xfs_inode.h	1.18    -> 1.20   
#	arch/ia64/sn/io/sn2/ml_SN_intr.c	1.6     -> 1.7    
#	  fs/xfs/xfs_trans.h	1.8     -> 1.9    
#	fs/proc/proc_devtree.c	1.2     -> 1.3    
#	arch/x86_64/mm/Makefile	1.9     -> 1.10   
#	   fs/nfs/nfs4proc.c	1.28    -> 1.30   
#	include/acpi/acconfig.h	1.44    -> 1.45   
#	include/asm-ppc/reg_booke.h	1.2     -> 1.3    
#	drivers/media/video/zoran_driver.c	1.5     -> 1.6    
#	include/asm-ia64/percpu.h	1.12    -> 1.13   
#	drivers/media/dvb/dvb-core/dvb_i2c.c	1.6     -> 1.7    
#	      fs/jfs/namei.c	1.33    -> 1.34   
#	fs/xfs/linux/xfs_ioctl.c	1.17    -> 1.18   
#	drivers/media/dvb/frontends/sp887x.c	1.2     -> 1.3    
#	arch/ia64/sn/io/machvec/pci_bus_cvlink.c	1.13    -> 1.14   
#	drivers/i2c/i2c-dev.c	1.37    -> 1.38   
#	drivers/i2c/chips/it87.c	1.14    -> 1.15   
#	           mm/slab.c	1.107   -> 1.109  
#	drivers/net/tulip/xircom_cb.c	1.17    -> 1.18   
#	    fs/xfs/xfsidbg.c	1.36    -> 1.37   
#	      kernel/sched.c	1.213.1.7 -> 1.220  
#	      fs/jffs2/dir.c	1.31    -> 1.32   
#	net/ipv6/netfilter/ip6t_owner.c	1.6     -> 1.7    
#	Documentation/filesystems/xfs.txt	1.4     -> 1.5    
#	include/asm-ppc/reg.h	1.4     -> 1.5    
#	drivers/media/dvb/frontends/grundig_29504-491.c	1.6     -> 1.7    
#	include/sound/rawmidi.h	1.4     -> 1.5    
#	drivers/i2c/chips/lm78.c	1.4     -> 1.5    
#	arch/sparc64/kernel/sparc64_ksyms.c	1.58    -> 1.59   
#	include/linux/nfs_xdr.h	1.38    -> 1.39   
#	      kernel/timer.c	1.68    -> 1.71   
#	 sound/pci/via82xx.c	1.42    -> 1.43   
#	drivers/usb/serial/visor.h	1.21    -> 1.22   
#	       fs/jfs/file.c	1.18    -> 1.19   
#	arch/ppc/mm/hashtable.S	1.15    -> 1.16   
#	drivers/net/pcmcia/pcnet_cs.c	1.25    -> 1.26   
#	   drivers/char/vt.c	1.55    -> 1.56   
#	drivers/net/hamradio/scc.c	1.24    -> 1.25   
#	drivers/media/dvb/frontends/at76c651.c	1.3     -> 1.4    
#	 drivers/net/Kconfig	1.55    -> 1.56   
#	drivers/i2c/busses/Kconfig	1.29    -> 1.31   
#	   fs/jfs/jfs_dmap.c	1.16    -> 1.17   
#	include/linux/jffs2.h	1.6     -> 1.7    
#	arch/ia64/mm/discontig.c	1.6     -> 1.8    
#	sound/core/oss/pcm_oss.c	1.29    -> 1.32   
#	arch/ia64/kernel/mca_asm.S	1.10    -> 1.11   
#	       kernel/exit.c	1.115   -> 1.117  
#	include/asm-x86_64/proto.h	1.14    -> 1.15   
#	drivers/usb/host/uhci-hcd.c	1.46    -> 1.47   
#	drivers/acpi/executer/exresop.c	1.21    -> 1.22   
#	     fs/nfs/direct.c	1.2     -> 1.4    
#	arch/ia64/kernel/unaligned.c	1.16    -> 1.17   
#	fs/xfs/linux/xfs_aops.c	1.48    -> 1.49   
#	net/ipv4/ipvs/ip_vs_ctl.c	1.10    -> 1.11   
#	sound/drivers/dummy.c	1.19    -> 1.20   
#	include/linux/device.h	1.109   -> 1.110  
#	fs/xfs/xfs_inode_item.h	1.4     -> 1.5    
#	net/8021q/vlan_dev.c	1.13    -> 1.14   
#	arch/ppc/kernel/ppc_ksyms.c	1.45    -> 1.47   
#	       lib/kobject.c	1.29    -> 1.31   
#	drivers/acpi/executer/exoparg1.c	1.22    -> 1.23   
#	   fs/nfs/pagelist.c	1.14    -> 1.15   
#	fs/xfs/linux/xfs_super.c	1.62    -> 1.63   
#	  drivers/usb/README	1.2     -> 1.3    
#	   fs/xfs/xfs_bmap.c	1.17    -> 1.18   
#	     fs/jffs2/scan.c	1.11    -> 1.13   
#	net/ipv4/netfilter/ipt_owner.c	1.11    -> 1.12   
#	          fs/locks.c	1.45    -> 1.46   
#	arch/ppc/8260_io/Kconfig	1.1     -> 1.2    
#	arch/ppc/kernel/setup.c	1.47.1.1 -> 1.49   
#	   fs/compat_ioctl.c	1.10    -> 1.11   
#	   arch/ia64/Kconfig	1.46    -> 1.47   
#	arch/sparc64/solaris/misc.c	1.19    -> 1.20   
#	drivers/usb/storage/Kconfig	1.5     -> 1.6    
#	drivers/char/ftape/lowlevel/ftape-proc.c	1.1     -> 1.2    
#	drivers/media/dvb/ttusb-dec/dec2000_frontend.c	1.2     -> 1.3    
#	drivers/usb/misc/Kconfig	1.9     -> 1.10   
#	drivers/net/sungem.c	1.46    -> 1.47   
#	  fs/xfs/xfs_inode.c	1.36    -> 1.38   
#	   fs/xfs/xfs_iget.c	1.17    -> 1.18   
#	arch/ppc/boot/common/ns16550.c	1.6     -> 1.7    
#	      net/atm/clip.c	1.26    -> 1.27   
#	drivers/serial/8250_acpi.c	1.4     -> 1.5    
#	sound/isa/sb/emu8000_pcm.c	1.5     -> 1.6    
#	     fs/xfs/xfs_rw.c	1.12    -> 1.13   
#	net/ipv4/ip_output.c	1.45    -> 1.46   
#	arch/arm/mach-sa1100/lart.c	1.5     -> 1.6    
#	Documentation/x86_64/boot-options.txt	1.1     -> 1.2    
#	drivers/acpi/resources/rsirq.c	1.15    -> 1.16   
#	    fs/nfs/nfs4xdr.c	1.28    -> 1.29   
#	     fs/jffs2/file.c	1.26    -> 1.27   
#	arch/ppc/syslib/of_device.c	1.5     -> 1.6    
#	arch/m68k/lib/checksum.c	1.5     -> 1.6    
#	drivers/media/dvb/frontends/stv0299.c	1.4     -> 1.5    
#	fs/xfs/linux/xfs_vnode.h	1.20    -> 1.21   
#	  drivers/net/slip.c	1.24    -> 1.25   
#	fs/xfs/xfs_vnodeops.c	1.45    -> 1.48   
#	drivers/macintosh/adbhid.c	1.15    -> 1.16   
#	     net/ipv4/ipip.c	1.34    -> 1.35   
#	include/asm-ia64/mmzone.h	1.5     -> 1.6    
#	 fs/jffs2/nodelist.h	1.9     -> 1.10   
#	   fs/xfs/xfs_dir2.c	1.9     -> 1.10   
#	               (new)	        -> 1.1     include/linux/netfilter_bridge/ebt_among.h
#	               (new)	        -> 1.1     net/bridge/netfilter/ebt_among.c
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/10/08	torvalds@home.osdl.org	1.1296.60.29
# Linux 2.6.0-test7
# --------------------------------------------
# 03/10/08	lord@jen.americas.sgi.com	1.1296.41.59
# [XFS] Match up minor formatting changes between SGI and Linus trees
# 
# --------------------------------------------
# 03/10/08	lord@jen.americas.sgi.com	1.1296.41.60
# Revert from using __kernel_fsid_t to fsid_t since ia64 now defines
# this correctly
# --------------------------------------------
# 03/10/08	lord@jen.americas.sgi.com	1.1296.41.61
# Change the way XFS implements the invisible I/O mechanism used by
# the online backup tools.
# --------------------------------------------
# 03/10/08	lord@jen.americas.sgi.com	1.1296.41.62
# More uio changes, add code attribution
# --------------------------------------------
# 03/10/08	len.brown@intel.com	1.1296.71.1
# Merge intel.com:/home/lenb/bk/linux-2.6.0
# into intel.com:/home/lenb/bk/linux-acpi-test-2.6.0
# --------------------------------------------
# 03/10/08	torvalds@home.osdl.org	1.1296.41.63
# Merge bk://kernel.bkbits.net/lord/xfs-2.6
# into home.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
# 03/10/08	len.brown@intel.com	1.1296.57.10
# Merge
# --------------------------------------------
# 03/10/08	bjorn.helgaas@com.rmk.(none)	1.1296.59.2
# [SERIAL] ACPI serial fix
# 
# Patch from Bjorn Helgaas
# 
# Intel 870 firmware reports an extra zero-length IO port range, which
# is bogus, as far as I can tell.  Ignore it.
# --------------------------------------------
# 03/10/08	shaggy@shaggy.austin.ibm.com	1.1296.60.30
# Merge jfs@jfs.bkbits.net:linux-2.5
# into shaggy.austin.ibm.com:/home/shaggy/bk/jfs-2.5
# --------------------------------------------
# 03/10/08	trini@kernel.crashing.org	1.1296.52.12
# PPC: Change how we export some Openfirmware device nodes.
# From Ethan Benson <erbenson@alaska.net>.
# --------------------------------------------
# 03/10/08	trini@kernel.crashing.org	1.1296.52.13
# PPC32: Fix the ns1655x uart driver in the bootwrapper.
# --------------------------------------------
# 03/10/08	mochel@kernel.bkbits.net	1.1296.58.6
# Merge kernel.bkbits.net:/home/repos/linux-2.5
# into kernel.bkbits.net:/home/mochel/linux-2.5-core
# --------------------------------------------
# 03/10/08	torvalds@home.osdl.org	1.1296.41.64
# Merge http://jfs.bkbits.net/linux-2.5
# into home.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
# 03/10/08	trini@kernel.crashing.org	1.1296.52.14
# PPC32: Update 'make help'.
# Mostly from Sam Ravnborg <sam@ravnborg.org>.
# --------------------------------------------
# 03/10/08	benh@kernel.crashing.org	1.1296.41.65
# [PATCH] add insert_resource() helper function
# 
# This allows PPC to insert resource descriptors later on after boot.
# --------------------------------------------
# 03/10/08	trini@kernel.crashing.org	1.1296.67.2
# Merge bk://ppc@ppc.bkbits.net/for-linus-ppc
# into kernel.crashing.org:/home/trini/work/kernel/pristine/for-linus-ppc
# --------------------------------------------
# 03/10/08	trini@kernel.crashing.org	1.1296.72.1
# Merge kernel.crashing.org:/home/trini/work/kernel/pristine/linux-2.6
# into kernel.crashing.org:/home/trini/work/kernel/pristine/for-linus-ppc
# --------------------------------------------
# 03/10/08	torvalds@home.osdl.org	1.1296.41.66
# Merge bk://bk.arm.linux.org.uk/linux-2.6-rmk
# into home.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
# 03/10/08	torvalds@home.osdl.org	1.1296.41.67
# Merge bk://bk.arm.linux.org.uk/linux-2.6-serial
# into home.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
# 03/10/08	ak@muc.de	1.1296.41.68
# [PATCH] APIC fixes for x86-64
# 
# Various APIC/ACPI fixes for x86-64. This brings us closer to working
# out of the box on the now popular VIA and NVidia Nforce3 based Athlon64
# and Opteron boards. To be really good we would need more ACPI changes
# (still waiting for that to be all merged through the usual channels).
# 
# With this we mostly work with acpi=off at least.
# 
# Also it syncs us up with bugfixes done in 2.4.
# 
#  - Disable IO-APIC by default on non SMP VIA/NVidia boards.  This is a
#    bit of a hack, but needed to work around ACPI bugs.  Can be
#    overwriten with "apic". 
#  - Add acpi=ht, meaning run ACPI boot setup, but do not enable the
#    interpreter.  Same as i386.
#  - Stop MADT parsing early when local APIC or IO-APIC are disabled
#  - Add more option parsing early enough to actually change the boot
#    process
#  - Update documentation for command line options
# --------------------------------------------
# 03/10/08	ak@muc.de	1.1296.41.69
# [PATCH] Fix x86-64 build with separate object tree
# 
# From Arnd Bergmann.
# --------------------------------------------
# 03/10/08	ak@muc.de	1.1296.41.70
# [PATCH] Disable non 64bit clean drivers for x86-64
# 
# This just disables some drivers which are clearly not 64bit clean from
# the configuration for CONFIG_64BIT hosts.
# 
# Partly from Arnd Bergmann.
# --------------------------------------------
# 03/10/08	mochel@kernel.bkbits.net	1.1311
# Merge bk://linux.bkbits.net/linux-2.5
# into kernel.bkbits.net:/home/mochel/linux-2.5-power
# --------------------------------------------
# 03/10/08	torvalds@home.osdl.org	1.1296.41.71
# Merge bk://kernel.bkbits.net//home/mochel/linux-2.5-core
# into home.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
# 03/10/08	torvalds@home.osdl.org	1.1312
# Merge bk://kernel.bkbits.net//home/mochel/linux-2.5-power
# into home.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
# 03/10/08	janetmor@us.ibm.com	1.1217.4.39
# [PATCH] ia64: sys_ia32.c fix for epoll
# 
# I ran into some bugs testing epoll in ia32-emulation mode on ia64.
# The attached patch fixes the problems and is well tested.
# Here is a summary of the changes:
# 
# Changes to sys32_epoll_ctl() and sys32_epoll_wait():
# - changed epoll_event32.data to an array (this is subjective, but seems
# to make the code more readable)
# 
# Changes to sys32_epoll_wait():
# - added call to __get_free_pages if kmalloc(epoll_event array) fails.  This
#   provides needed scalability and fixes the -ENOMEM failure during
# epoll-pipetest.
# - deleted copy-in of epoll_event array since this is not a user-inputsyscall
# - changed to check numevents > 0 as indicator of success on call to
#   sys_epoll_wait.
# - changed to loop on numevents not maxevents when copying out to userspace.
# --------------------------------------------
# 03/10/09	paulus@samba.org	1.1296.41.72
# Merge samba.org:/stuff/paulus/kernel/linux-2.5
# into samba.org:/stuff/paulus/kernel/for-linus-ppc
# --------------------------------------------
# 03/10/08	trond.myklebust@fys.uio.no	1.1313
# [PATCH] NFS: fix the synchronous READ/WRITE bugs
# 
#   - Use correct credentials in the NFSv4 synchronous read/write code.
#   - Return correct number of read bytes in the NFSv4 synchronous read code.
#   - SunRPC XDR fix: NFSv4 reads when caller requests a non-word aligned
#     number of bytes was broken.
# --------------------------------------------
# 03/10/08	trond.myklebust@fys.uio.no	1.1314
# [PATCH] NFS: remove broken O_DIRECT wait code
# 
# It is in any case no longer needed.
# --------------------------------------------
# 03/10/08	trond.myklebust@fys.uio.no	1.1315
# [PATCH] NFS: synchronous NFSv3/v4 COMMIT
# 
# Add support for synchronous calls to the NFSv3/v4 COMMIT functions.
# --------------------------------------------
# 03/10/08	trond.myklebust@fys.uio.no	1.1316
# [PATCH] NFS: Fix O_DIRECT code
# 
#   - Support synchronous directio only. Defer asynchronous directio until
#     it can be made safe.
#   - If read/write exits due to an error, return number of bytes read/written
#     prior to occurrence of the error.
#   - Make sure we mark read pages as dirty in case we're doing zero-copy tricks.
#     Export set_page_dirty_lock() for use by NFS directio.
#   - Ensure we revalidate stale attribute info.
# --------------------------------------------
# 03/10/08	trond.myklebust@fys.uio.no	1.1317
# [PATCH] NFS: Enable NFS_DIRECTIO support
# 
# Enable NFS_DIRECTIO support now that it has been fixed...
# --------------------------------------------
# 03/10/08	jamie@shareable.org	1.1318
# [PATCH] set sigio target to current->pid and only if not already set
# 
# 1. send_sigio() sends to a specific thread, _not_ a process.
#    (It can also send to a process group, but that's not relevant here).
#    This is useful, and should stay as it is.
# 
#    Therefore it makes _no sense_ to call f_setown() with current->tgid.
#    Presently the kernel is inconsistent about it, with some places using
#    current->pid and some others using current->tgid.
# 
#    This patch changes f_setown() calls to use current->pid.
# 
# 2. In some places, f_setown() is called not at the user's direct request,
#    but as a side effect of another function.  Specifically: dnotify and
#    file leases.
# 
#    It is good to allow a program the flexibility to specify a different
#    pid than the default, using F_SETOWN.  Presently they can do this after
#    the dnotify or lease call, but there is a small time window when it
#    will be temporarily set to current->tgid (which as pointed out above,
#    is not always right).
# 
#    The window is avoidable if the program can use F_SETOWN prior to the
#    dnotify or lease call.  This is exactly what the "force" argument to
#    f_setown() is for, and this patch changes it to zero in those callers.
# 
#    This change is not likely to affect any existing programs.
# --------------------------------------------
# 03/10/08	jamie@shareable.org	1.1319
# [PATCH] futex bug fixes
# 
# This fixes two serious bugs in the futex code.
# 
# One is a race condition which results in list corruption when
# FUTEX_REQUEUE is used.  It is due to the split locks change introduced
# in 2.6.0-test6, and oopses when triggered.
# 
# The other is a security hole.  A program can use FUTEX_FD to create
# futexes on mms or inodes which don't reference them, and when those
# structures are reused by a different mm or inode, the addresses match.
# The effect is that a malicious or flawed program can steal wakeups from
# completely unrelated tasks, causing them to block (or worse if they are
# counting on the token passing property).
# 
# These are the specific changes:
# 
#     1. Each futex_q retains a reference to its key mm or inode.
# 
#     2. The condition for a futex_q to indicate that it's woken can usually
#        be interrogated lock-free.
# 
#     3. futex_wait calls the hash function once instead of three times,
#        and usually takes the per-bucket lock once too.
# 
#     4. When a futex is woken, the per-bucket lock is not usually taken,
#        so that's one less cache line transfer during heavy SMP futex use.
# 
#     5. The wait condition and barriers in futex_wait are simpler.
# 
#     5. FUTEX_REQUEUE is fixed.  The per-bucket lock juggling is done
#        in such a way that there are no race conditions against the tests
#        for whether a futex is woken.
# 
# 
# This patch is an combination of patches previously sent to the list.  An
# equivalent patch has been in Andrew Morton's tree for a while, with no
# failure reports.  Also I have been running it on my own SMP box for a
# while.  Conversely, we have received an oops report for the 2.6.0-test6
# code, so the fix is needed.
# --------------------------------------------
# 03/10/08	torvalds@home.osdl.org	1.1320
# disable_irq() should synchronize with irq handler only if one exists.
# 
# Noted by Al Viro: if no handler exists (and we have IRQ_INPROGRESS set
# because of an earlier irq that got through), synchronize_irq() will
# end up waiting forever.
# --------------------------------------------
# 03/10/09	paulus@samba.org	1.1296.41.73
# PPC32: Export a couple of symbols (csum_partial and init_task).
# --------------------------------------------
# 03/10/09	paulus@samba.org	1.1321
# [PATCH] Fix compile on PPC
# 
# At the moment the aty128fb and matroxfb frame buffer drivers don't
# compile on PPC.  In both cases the error is pretty trivial.  This
# patch is the minimum change to fix the problems.
# 
# The _IOR() type problem fix in aty128fb.c depends on the fact that the
# size of a pointer is the same as "size_t", so we don't have to use
# _IOR_BAD() to keep the ioctl number the same.
# --------------------------------------------
# 03/10/09	torvalds@home.osdl.org	1.1322
# Merge bk://ppc.bkbits.net/for-linus-ppc
# into home.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
# 03/10/09	torvalds@home.osdl.org	1.1323
# Manual merge of sound config
# --------------------------------------------
# 03/10/09	trivial@rustcorp.com.au	1.1324
# [PATCH] Fix pcmcia_tcic.c if PCMCIA_DEBUG is defined.
# 
# From:  Stephen Hemminger <shemminger@osdl.org>
# 
#   Compile errors in the pcmcia/tcic driver if PCMCIA_DEBUG is defined.
#   Looks like simple debug code bitrot, this fixes it.
# --------------------------------------------
# 03/10/09	rusty@rustcorp.com.au	1.1325
# [PATCH] ipt_limit fix for HZ=1000
# 
# The range that the iptables limit extension can specify depends on HZ.
# This means that rules which worked i386 2.4 (100 HZ) won't work on
# 2.6.
# 
# The solution is to adjust the precision based on the HZ value (keeping
# the range of possible values the same).  For extra geek cred, this is
# done by calculating a power-of-two constant below the maximum
# multiplication factor, which gcc then turns into a simple shift.
# --------------------------------------------
# 03/10/09	rusty@rustcorp.com.au	1.1326
# [PATCH] More barriers in module code.
# 
# Paul McKenney convinced me that there's no *guarantee* that all archs
# will refuse the speculate the atomic ops above the state test, eg:
# 
# CPU0 (stopref_set_state)		CPU1 (stopref)
# 
#  atomic_set(&ack, 0);			if (state == XXX)
#  wmb();						atomic_inc(&ack);
#  state = XXX;
# 
# Certainly Alpha needs a rmb() inside stopref to guarantee it sees
# the same ordering.
# --------------------------------------------
# 03/10/09	ak@muc.de	1.1327
# [PATCH] Fix 64bit bug in trident frame buffer driver
# 
# Fix another 64bit bug, this time in the trident frame buffer driver
# 
# When storing the ioremap_nocache() return in a integer the variable must be
# long not int.
# --------------------------------------------
# 03/10/09	hunold@linuxtv.org	1.1328
# [PATCH] New DVB frontend driver ves1x93 (obsoletes alps_bsrv2)
# 
#  - replace alps_bsrv2 driver by generic ves1893 & ves1993 driver
#    (Andreas Oberritter)
# --------------------------------------------
# 03/10/09	hunold@linuxtv.org	1.1329
# [PATCH] Fix vbi handling in saa7146 core driver
# 
#  - add some debug and safety checks for video/vbi capture buffer
#    handling
#  - add new flag SAA7146_USE_PORT_B_FOR_VBI, so we can distinguish on
#    which video port to apply the vbi workaround
#  - add del_timer(...) for vbi capture queue and vbi_read timers,
#    prevents oopses on vbi usage
# --------------------------------------------
# 03/10/09	hunold@linuxtv.org	1.1330
# [PATCH] Add private data pointer to DVB frontends
# 
#  - allow private data to be associated with dvb frontend devices
#    (Andreas Oberritter)
#  - fixed fe_count countint in nxt6000 frontend driver (Andreas
#    Oberritter)
# --------------------------------------------
# 03/10/09	hunold@linuxtv.org	1.1331
# [PATCH] Fix DVB network device handling
# 
#  - simplify and sanitize add/del handling for dvb net devices
# --------------------------------------------
# 03/10/09	hunold@linuxtv.org	1.1332
# [PATCH] Misc. fixes for ALPS TDLB7 DVB frontend driver
# 
#  - applied latest changes by Juergen Peitz (great work!)
#   o as a workaround for the lockup problem the data valid signal is
#     checked after every channel switch.  If it is not set FEC parameters
#     are set again.
#   o disabled autoprobing if FEC settings are known (from sp887x). 
#   o added support for FE_READ_UNCORRECTED_BLOCKS (from sp887x).
#   o added support for FE_SLEEP (from sp887x).
#   o bit error rate is now not only read from register 0xC07 but also
#     from 0xC08 (from sp887x). 
#   o I2C feedthrough to the tuner is now only enabled when needed (from
#     sp887x).
#   o Added FE_CAN_QAM_AUTO and FE_CAN_HIERARCHY_AUTO to
#     dvb_frontend_info.
#   o Removed obsolete setting of default frontend parameters in
#     sp8870_init.
#   o Removed obsolete module parameter 'loadcode' because changes in the
#     saa7146 driver made firmware loading very fast.
# --------------------------------------------
# 03/10/09	hunold@linuxtv.org	1.1333
# [PATCH] Misc. fixes for AT76C651 DVB frontend driver
# 
#  - fixed some return values in device attach functions
#  - allow private data to be associated with frontend devices here, too
#  - misc bugfixes and performance improvements (endianess, function split up)
# --------------------------------------------
# 03/10/09	hunold@linuxtv.org	1.1334
# [PATCH] Update the AV7110 DVB driver
# 
#  - add vbi device handling for dvb-c cards with analog module
#  - fix error handling upon device initialization
#  - fix DD1_INIT handling of DVB-C w/ analog module installed.  (Jon
#    Burgess)
# --------------------------------------------
# 03/10/09	torvalds@home.osdl.org	1.1335
# Revert floppy driver dependence on CONFIG_ISA. The thing exists
# on lots of PCI-only setups that have no ISA anywhere.
# --------------------------------------------
# 03/10/09	mikpe@csd.uu.se	1.1336
# [PATCH] ftape linkage error
# 
# Since 2.6.0-test6, ftape can't be configured as a built-in driver.
# test6 changed ftape-init.c to call ftape_proc_destroy() also in
# the non-MODULE case; however, ftape_proc_destroy() is only defined
# when the driver is built as a module. The result is a linkage error.
# 
# This fixes this by deleting the #if MODULE around ftape_proc_destroy()'s
# definition.
# --------------------------------------------
# 03/10/09	cminyard@mvista.com	1.1337
# [PATCH] IPMI fixes for 2.6.0-test7
# 
# This fixes some problems with timing calculations (primarily for ia64)
# and adds an operation to send panic strings to the IPMI event log on a
# panic.
# --------------------------------------------
# 03/10/09	benh@kernel.crashing.org	1.1320.1.1
# Merge kernel.crashing.org:/home/benh/kernels/linux-2.5
# into kernel.crashing.org:/home/benh/kernels/for-linus-ppc
# --------------------------------------------
# 03/10/09	len.brown@intel.com	1.1338
# Merge intel.com:/home/lenb/bk/linux-2.6.0
# into intel.com:/home/lenb/bk/linux-acpi-test-2.6.0
# --------------------------------------------
# 03/10/09	david-b@pacbell.net	1.1337.1.1
# [PATCH] USB: minor net2280 cleanup
# 
# This holds minor net2280 cleanups:
# 
#   - Cleaner handling for cases where dma_alloc_coherent() must be
#     used instead of kmalloc().  (Kmalloc is more memory-efficient
#     for the "small buffers" case.)   Both MIPS cases should work,
#     as well as others.
# 
#   - Prefetch cachelines on PIO paths.
# 
# The first of those gets rid of one <linux/version.h> usage, no
# longer useful now that 2.4 and 2.6 versions have forked.
# --------------------------------------------
# 03/10/09	adobriyan@mail.ru	1.1337.1.2
# [PATCH] USB: Correct module names in drivers/usb/*/Kconfig
# 
# Module names in Kconfig help texts should match those in Makefiles. Please apply.
# --------------------------------------------
# 03/10/09	adobriyan@mail.ru	1.1337.1.3
# [PATCH] USB: Fix two typos in drivers/usb/README
# --------------------------------------------
# 03/10/09	paulus@samba.org	1.1337.1.4
# [PATCH] USB: Fix USB suspend in 2.6.0-test6
# 
# In drivers/usb/core/hcd-pci.c, the code forgets to set hcd->state to
# USB_STATE_SUSPENDED on suspend.  The effect is that on resume, the
# code refuses to wake the HCD up, and instead prints a message saying
# the interface hasn't been suspended.
# 
# The patch below fixes this.  It is against 2.6.0-test6.  With this
# patch I can suspend and resume my Apple PowerBook G4, and the USB
# works after resuming.
# --------------------------------------------
# 03/10/09	oliver@neukum.org	1.1337.1.5
# [PATCH] USB: remove stupid check for NULL in devio.c
# 
# usually this would be too trivial, but is so obviously stupid that
# people might think that there's some hidden trick in there.
# 
# We should not check for NULL _after_ following a pointer.
# Consider it a small tiny step towards cleaning up this code.
# --------------------------------------------
# 03/10/09	david-b@pacbell.net	1.1337.1.6
# [PATCH] USB: make more driver names match module names
# 
# This resolves a bug in osdl bugtraq (#1261) by making
# some more driver names match their module names.  Such
# mismatches are bad because scripts often need to add
# special cases, handling multiple names for drivers.
# --------------------------------------------
# 03/10/09	jbarnes@sgi.com	1.1296.73.1
# [PATCH] ia64: fix NUMA page table allocation to get memory from the right node
# 
# --------------------------------------------
# 03/10/09	ak@muc.de	1.1337.2.1
# [PATCH] Prefetch workaround for Athlon/Opteron
# 
# This is the latest iteration of the workaround for the Athlon/Opteron
# prefetch erratum.  Sometimes the CPU would incorrectly report an
# exception on prefetch.
# 
# This supercedes the previous dumb workaround of checking for AMD CPUs in
# prefetch().  That one bloated the kernel by several KB and lead to lots
# of unnecessary checks in hot paths. 
# 
# Also this one handles user space faults too, so the kernel can
# effectively isolte the user space from caring about this errata.
# 
# Instead it handles it in the slow path of the exception handler (the
# check is only done when the kernel would normally trigger seg fault or
# crash anyways)
# 
# All the serious criticisms to the previous patches have been addressed. 
# It checks segment bases now, handles vm86 mode and avoids deadlocks when
# the prefetch exception happened inside mmap_sem.
# 
# This includes review and fixes from Jamie Lokier and Andrew Morton.
# Opcode decoder based on code from Richard Brunner.
# --------------------------------------------
# 03/10/09	willy@debian.org	1.1337.2.2
# [PATCH] Build fixes for zoran on PA-RISC
# 
# The Zoran driver doesn't include <asm/io.h> and thus won't compile
# on architectures where that doesn't get implicitly included through
# some other path.
# 
# Add the proper includes.
# --------------------------------------------
# 03/10/09	lethal@linux-sh.org	1.1337.2.3
# [PATCH] net/sunrpc/clnt.c compile fix
# 
# net/sunrpc/clnt.c does not compile if RPC_DEBUG is not enabled, due to
# the fact that tk_pid is protected by RPC_DEBUG (which in turn depends on
# CONFIG_SYSCTL).
# 
# The printk's that use it don't actually need to print it out at all,
# the rpc_task tag isn't really interesting here.
# 
# Acked by Trond Myklebust.
# --------------------------------------------
# 03/10/09	Dax@GuruLabs.com	1.1337.1.7
# [PATCH] USB: Handspring Treo 600 id
# 
# I've got a new toy. This obviously correct 4 liner patches
# the two files:
# --------------------------------------------
# 03/10/09	noah@caltech.edu	1.1337.1.8
# [PATCH] USB: Make ISD-200 USB/ATA Bridge depend on BLK_DEV_IDE
# 
# This usb driver needs ide_fix_driveid from drivers/ide/ide-ops.c, which
# needs BLK_DEV_IDE ("Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy
# support") to get built.
# 
# Without this patch, you can configure an un-linkable kernel by doing make
# allnoconfig, make menuconfig, and setting CONFIG_PCI, CONFIG_USB,
# CONFIG_USB_STORAGE, and CONFIG_USB_STORAGE_ISD200 only.
# --------------------------------------------
# 03/10/09	noah@caltech.edu	1.1337.1.9
# [PATCH] USB: Make Ethernet Gadget depend on CONFIG_NET
# 
# Previously, one could configure a kernel that wouldn't link by doing a 'make
# allnoconfig' and then a 'make menuconfig' and enabling CONFIG_EXPERIMENTAL,
# CONFIG_PCI, CONFIG_USB_GADGET, and CONFIG_USB_ETH.
# --------------------------------------------
# 03/10/09	khali@linux-fr.org	1.1337.3.1
# [PATCH] I2C: Chip driver initialization fixes
# 
# fixes all chip drivers by moving the initialization before any sysfs
# entry is created.
# --------------------------------------------
# 03/10/09	khali@linux-fr.org	1.1337.3.2
# [PATCH] I2C: correct some errors in i2c/chips/Kconfig
# --------------------------------------------
# 03/10/09	jbarnes@sgi.com	1.1217.4.40
# [PATCH] ia64: fix SN2 code for GENERIC builds
# 
# Don't try to use the sn2 I/O code if we're not on sn2 or we may get into
# trouble.  Only makes a difference for generic kernels.
# --------------------------------------------
# 03/10/09	jbarnes@sgi.com	1.1217.4.41
# [PATCH] ia64: fix is_headless_node() for systems w/<64p
# 
# I didn't realize that any_online_cpu() wouldn't work for
# is_headless_node(), so this patch reverts the function back to using the
# node_to_cpu_mask[] array, fixing sn2 for systems with less than 64p.
# --------------------------------------------
# 03/10/09	jbarnes@sgi.com	1.1217.4.42
# [PATCH] ia64: early SN setup fix
# 
# Small fix to build early_sn_setup even if early printk is turned off.
# --------------------------------------------
# 03/10/09	jbarnes@sgi.com	1.1217.4.43
# [PATCH] ia64: deal with lack of SRAT in GENERIC kernels
# 
# n platforms without an SRAT (e.g. zx1), the cpu_to_node_map will get
# built incorrectly without this fix, making generic kernels fail when
# they try to alloc_pages_node() from a nodeid of -1.
# --------------------------------------------
# 03/10/09	torvalds@home.osdl.org	1.1337.2.4
# Revert the process group accessor functions. They are buggy, and
# cause NULL pointer references in /proc.
# 
# Moreover, it's questionable whether the whole thing makes sense at all. 
# Per-thread state is good.
# 
# Cset exclude: davem@nuts.ninka.net|ChangeSet|20031005193942|01097
# Cset exclude: akpm@osdl.org[torvalds]|ChangeSet|20031005180420|42200
# Cset exclude: akpm@osdl.org[torvalds]|ChangeSet|20031005180411|42211
# --------------------------------------------
# 03/10/09	kenneth.w.chen@intel.com	1.1217.4.44
# [PATCH] ia64: fix NUMA hugetlb support
# 
# Here is a patch that adds numa support for hugetlb page on ia64.  It is
# taken from x86 numa implementation.  The low level hugetlb page
# pre-allocation is done in round robin fashion on each numa node and
# allocation for user level code is node local aware.
# --------------------------------------------
# 03/10/09	davidm@tiger.hpl.hp.com	1.1296.73.2
# Merge tiger.hpl.hp.com:/data1/bk/vanilla/linux-2.5
# into tiger.hpl.hp.com:/data1/bk/lia64/to-linus-2.5
# --------------------------------------------
# 03/10/09	peterc@chubb.wattle.id.au	1.1296.73.3
# [PATCH] ia64: drop stale check for GAS_HAS_LOCAL_TAGS
# 
# GAS_HAS_LOCAL_TAGS was removed a long time ago, but uaccess.h never got
# updated.  Without this fix, bad syscall args may cause a SEGFAULT instead
# of failing gracefully.
# --------------------------------------------
# 03/10/09	arun.sharma@intel.com	1.1296.73.4
# [PATCH] ia64: fix ia32 epoll emulation warnings
# 
# --------------------------------------------
# 03/10/09	davem@nuts.ninka.net	1.1337.2.5
# [VLAN]: kfree(skb) --> kfree_skb(skb).
# --------------------------------------------
# 03/10/09	davem@nuts.ninka.net	1.1337.4.1
# [SPARC64]: Squelch bogus gcc warning in unaligned.c due to bad flow analysis.
# --------------------------------------------
# 03/10/09	khc@pc.waw.pl	1.1337.2.6
# [WAN]: Fix transmitted headers with generic HDLC + Cisco encap.
# --------------------------------------------
# 03/10/09	ak@muc.de	1.1337.2.7
# [ATM]: Mark unclean drivers as not-64BIT.
# --------------------------------------------
# 03/10/09	david@gibson.dropbear.id.au	1.1337.2.8
# [NET]: Fix initialization sequence in SunGEM driver.
# --------------------------------------------
# 03/10/10	shemminger@osdl.org	1.1337.2.9
# [IRDA]: Fix memory leak in sa1100_ir.c
# --------------------------------------------
# 03/10/10	shemminger@osdl.org	1.1337.2.10
# [WAN]: Incorrect comparison for register_netdev in cosa.c
# --------------------------------------------
# 03/10/10	davem@nuts.ninka.net	1.1337.2.11
# [NET]: Delete skb_shared() checks from loopback driver transmit.
# 
# This code is from ancient history when TCP did not used SKB cloning.
# --------------------------------------------
# 03/10/10	davem@nuts.ninka.net	1.1337.4.2
# [SPARC64]: Update defconfig.
# --------------------------------------------
# 03/10/10	davem@nuts.ninka.net	1.1337.4.3
# [SPARC64]: Fix __bzero_noasi declaration.
# --------------------------------------------
# 03/10/10	davem@nuts.ninka.net	1.1337.4.4
# [SPARC64]: Fix mixed declarations and code in flush_dcache_page_all.
# --------------------------------------------
# 03/10/10	torvalds@home.osdl.org	1.1337.2.12
# Merge bk://kernel.bkbits.net/davem/sparc-2.5
# into home.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
# 03/10/10	len.brown@intel.com	1.1339
# Merge intel.com:/home/lenb/bk/linux-2.6.0
# into intel.com:/home/lenb/bk/linux-acpi-test-2.6.0
# --------------------------------------------
# 03/10/10	benh@kernel.crashing.org	1.1337.5.1
# Merge bk://ppc@ppc.bkbits.net/for-linus-ppc
# into kernel.crashing.org:/home/benh/kernels/for-linus-ppc
# --------------------------------------------
# 03/10/10	davej@redhat.com	1.1296.64.16
# [CPUFREQ] Make VIA longhaul work on Samuel2 & Ezra again.
# These CPUs are actually only longhaul v1 compliant.
# This was catastrophic, as the MSRs moved between v1 and v2.
# There was also massive confusion in the documentation regarding Ezra.
# It's not another variant, so 'v2' never existed.
# Renamed v3 (Powersaver) to v2 as a result of this.
# 
# --------------------------------------------
# 03/10/10	davej@redhat.com	1.1296.64.17
# [CPUFREQ] refix EBLCR FSB only works on Samuel1.
# Now that longhaul=1 matches more than 1 CPU, this broke.
# --------------------------------------------
# 03/10/10	davej@redhat.com	1.1296.64.18
# [CPUFREQ] Fix longhauls speed calculations.
# We got half multipliers horribly wrong, which made us think we could
# clock the CPU much higher than we actually could.
# --------------------------------------------
# 03/10/10	arun.sharma@intel.com	1.1296.73.5
# [PATCH] ia64: Fix unaligned faults in IA-32 putstat64
# 
# This seems to be introduced by recent changes in 2.6.0-test series.
# --------------------------------------------
# 03/10/10	jbarnes@sgi.com	1.1296.73.6
# [PATCH] ia64: fix SN2 interrupt allocation
# 
# Patch from Christoph.  Fixes interrupt allocation code for sn2.
# --------------------------------------------
# 03/10/10	schwab@suse.de	1.1296.73.7
# [PATCH] ia64: fix misnamed syscalls
# 
# This fixes a misnomer of some syscalls in 2.6.0-test[567].  Glibc wants
# them without the sys_ infix.
# --------------------------------------------
# 03/10/10	amalysh@web.de	1.1337.3.3
# [PATCH] I2C: i2c-sis630 driver fixes
# 
# attached you can find a patch that should fix i2c-sis630 driver for
# 2.6.0-X kernel. With i2c-sis630 from stock 2.6.0-X we have oops and
# driver was not correct registered against i2c-core.
# 
# Changes:
# 	1) fixed a oops while modprobing
# 	2) added check for buffer overflow for i2c block data read transaction
# 	3) added 'force' modprobe parameter. It's allow more easily
# 	   testing for not yet supported SiS chips.
# --------------------------------------------
# 03/10/10	davej@redhat.com	1.1296.64.19
# [CPUFREQ] Kill longhaul warnings
# (Blah about unused variables).
# This code still won't be used, as its still not tested/debugged properly
# on a Nehemiah.
# --------------------------------------------
# 03/10/10	davej@wopr.codemonkey.org.uk	1.1320.2.1
# Merge wopr.codemonkey.org.uk:/mnt/nfs/sepia/bar/src/kernel/2.6/trees/bk-linus
# into wopr.codemonkey.org.uk:/mnt/nfs/sepia/bar/src/kernel/2.6/trees/cpufreq
# --------------------------------------------
# 03/10/10	greg@kroah.com	1.1337.3.4
# [PATCH] I2C: fix i2c-dev class release function bug.
# 
# There was no release function, that was the bug :)
# It caused bad messages to show up in the syslog whenever a i2c driver was removed, and could
# easily oops.
# --------------------------------------------
# 03/10/10	rmk@flint.arm.linux.org.uk	1.1296.68.5
# [ARM] Remove no_action function from CLPS7500 code.
# 
# no_action is implemented by generic code; no need for machine class
# code to implement it as well.
# --------------------------------------------
# 03/10/10	torvalds@home.osdl.org	1.1337.2.13
# Merge bk://linux-dj.bkbits.net/cpufreq
# into home.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
# 03/10/10	rmk@flint.arm.linux.org.uk	1.1296.68.6
# [ARM] Add missing exports for Integrator logic module drivers.
# 
# This adds a couple of missing symbol exports for
# lm_driver_register and lm_driver_unregister.
# --------------------------------------------
# 03/10/10	greg@kroah.com	1.1337.2.14
# Merge kroah.com:/home/greg/linux/BK/bleed-2.5
# into kroah.com:/home/greg/linux/BK/i2c-2.6
# --------------------------------------------
# 03/10/10	torvalds@home.osdl.org	1.1337.6.1
# Merge bk://bk.arm.linux.org.uk/linux-2.6-rmk
# into home.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
# 03/10/10	greg@kroah.com	1.1337.1.10
# Merge kroah.com:/home/greg/linux/BK/bleed-2.5
# into kroah.com:/home/greg/linux/BK/usb-2.6
# --------------------------------------------
# 03/10/10	jbarnes@sgi.com	1.1296.73.8
# [PATCH] ia64: 2nd step to fix GENERIC builds: split contig and discontig paging_init functions
# 
# --------------------------------------------
# 03/10/10	davidm@tiger.hpl.hp.com	1.1296.73.9
# ia64: Patch by Jesse Barnes:
# 
# This patch fixes the combination of CONFIG_DISCONTIGMEM and
# CONFIG_VIRTUAL_MEM_MAP so that generic kernels will work on all ia64
# platforms, including sn2, and also makes sn2 specific kernels work
# (which I think is a first).
# 
# I've cleaned this patch up heavily based on feedback from yourself,
# Christoph and others.  I've tested sn2, zx1, and dig (thanks Xavier!)
# specific configurations, as well as a generic configuration that allows
# the same binary to boot on zx1, dig, and sn2.
# --------------------------------------------
# 03/10/10	jbarnes@sgi.com	1.1296.73.10
# [PATCH] ia64: fix NUMA boot
# 
# Now that the ACPI table parsing stuff has been fixed we can move
# find_memory() back where it belongs--after the SRAT table has been
# parsed.
# --------------------------------------------
# 03/10/10	torvalds@home.osdl.org	1.1337.2.15
# Merge bk://kernel.bkbits.net/gregkh/linux/i2c-2.6
# into home.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
# 03/10/10	torvalds@home.osdl.org	1.1337.1.11
# Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
# into home.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
# 03/10/10	tony.luck@intel.com	1.1296.73.11
# [PATCH] ia64: fix register numbers in MCA save/restore
# 
# This corrects the save/restore code in mca_asm.S
# which was written long ago, before the assembler understood
# mnemonic names for 'cr' and 'ar' registers (in fact it
# appears to have been written pre-silicon, some of the
# control register numbers don't match with what actually
# got built).  There were other goofs too (like using
# 0, 1, 2, etc. for region register subscripts).
# --------------------------------------------
# 03/10/10	jbarnes@sgi.com	1.1296.73.12
# [PATCH] ia64: nable SN2 in generic builds
# 
# Now that it works, we can enable sn2 in generic builds.  This should not
# only allow generic kernels to work on sn2, but also fix the build
# problems people have been seeing with the qla1280 driver.  I tested a
# generic kernel built with this patch on zx1 and it worked.
# --------------------------------------------
# 03/10/11	benh@kernel.crashing.org	1.1337.1.12
# Merge kernel.crashing.org:/home/benh/kernels/linux-2.5
# into kernel.crashing.org:/home/benh/kernels/for-linus-ppc
# --------------------------------------------
# 03/10/11	benh@kernel.crashing.org	1.1337.1.13
# Fix call to Open Firmware "map" call, parameters were flipped causing
# the coff image to randomly fail
# --------------------------------------------
# 03/10/11	benh@kernel.crashing.org	1.1337.1.14
# coff images bootloader reserves more memory for the kernel, allow booting
# of "standard" configs on oldworld macs
# --------------------------------------------
# 03/10/11	benh@kernel.crashing.org	1.1337.1.15
# Export mol_trampoline and mmu_hash_lock for MOL
# (missing from a previous cset)
# --------------------------------------------
# 03/10/11	benh@kernel.crashing.org	1.1337.1.16
# Export init_mm, some modules need that
# --------------------------------------------
# 03/10/11	benh@kernel.crashing.org	1.1337.1.17
# The POWER4 support merged previously was incomplete, add the missing bits
# so that the kernel boots at least on POWER4 and G5 CPUs
# --------------------------------------------
# 03/10/11	benh@kernel.crashing.org	1.1337.1.18
# Fix RAMDAC detection on some IMS TwinTurbo video cards ("Mac" cards only),
# without this, you get no display on machines with those cards
# --------------------------------------------
# 03/10/11	benh@kernel.crashing.org	1.1337.1.19
# Move definition of TimeBase registers from reg_booke.h to reg.h, those
# registers exist on common CPUs and without those definitions, SMP won't
# build
# --------------------------------------------
# 03/10/11	benh@kernel.crashing.org	1.1337.1.20
# Fix timebase hardware sync on SMP PowerMacs (both oldworld dual 604s and
# core99 dual G4s).
# --------------------------------------------
# 03/10/11	benh@kernel.crashing.org	1.1337.1.21
# Fix VIA-based TB/Decrementer calibration , previously it wouldn't work
# properly with HZ != 100, causing tb_to_us to be wrong and gettimeofday()
# to return strangely "off" results
# --------------------------------------------
# 03/10/11	benh@kernel.crashing.org	1.1337.1.22
# Fix a crash on sleep in the OF platform core where we would
# use a NULL "driver" pointer and actually try to call it after
# casting it !
# --------------------------------------------
# 03/10/11	benh@kernel.crashing.org	1.1337.1.23
# Fix repeat delays in adbhit, they didn't make the transition to
# jiffies based values to ms. This fix crazy key repeat on ADB
# based PowerMacs
# --------------------------------------------
# 03/10/11	dwmw2@dwmw2.baythorne.internal	1.1337.7.1
# JFFS2 update; completed support for NAND flash.
# 
#  - Implement write-buffer flushing by garbage collection instead of padding.
#  - Implement selective write-buffer flushing on fsync(). 
#  - Implement error recovery on write-buffer flush.
#  - Fix remove_suid(). Writing to a suid file didn't previously mark the file non-suid.
#  - Fix handling of full file systems, to avoid unlink() returning -ENOSPC.
#  - Fix assorted memory leaks.
#  - Improve garbage collection efficiency by merging fewer pages.
# --------------------------------------------
# 03/10/11	dwmw2@dwmw2.baythorne.internal	1.1337.7.2
# Fix jffs2 memory leak on mount error
# --------------------------------------------
# 03/10/11	davem@nuts.ninka.net	1.1337.8.1
# Merge nuts.ninka.net:/disk1/davem/BK/sparcwork-2.5
# into nuts.ninka.net:/disk1/davem/BK/sparc-2.5
# --------------------------------------------
# 03/10/11	ja@ssi.bg	1.1337.9.1
# [IPV4]: ip_copy_metadata must copy the nfcache field.
# --------------------------------------------
# 03/10/11	shemminger@osdl.org	1.1337.9.2
# [WAN]: Fix register_netdev() return value check in hostess_sv11.c
# --------------------------------------------
# 03/10/11	shemminger@osdl.org	1.1337.9.3
# [NET]: Fix register_netdev() return value check in synclink_cs.c
# --------------------------------------------
# 03/10/11	noah@caltech.edu	1.1337.9.4
# [IPX]: ipx_proc.c needs linux/init.h even when PROC_FS is not enabled.
# --------------------------------------------
# 03/10/11	davem@nuts.ninka.net	1.1337.9.5
# [ATM]: Kill PROC_FS ifdef around includes.
# --------------------------------------------
# 03/10/11	mingo@elte.hu	1.1337.10.1
# [PATCH] SMP races in the timer code
# 
# This fixes two del_timer_sync() races that are still in the timer code. 
# 
# The first race was actually triggered in a 2.4 backport of the 2.6 timer
# code.  The second race was never triggered - it is mostly theoretical on
# a standalone kernel.  (It's more likely in any virtualized or otherwise
# preemptable environment.)
# 
# Both races happen when self-rearming timers are used.  One mainstream
# example is kernel/itimer.c.  The effect of the races is that
# del_timer_sync() lets a timer running instead of synchronizing with it,
# causing logic bugs (and crashes) in the affected kernel code.  One
# typical incarnation of the race is a double add_timer(). 
# 
# race #1:
# 
# this code in __run_timers() is running on CPU0:
# 
#                         list_del(&timer->entry);
#                         timer->base = NULL;
# 			[*]
#                         set_running_timer(base, timer);
#                         spin_unlock_irq(&base->lock);
# 			[**]
#                         fn(data);
#                         spin_lock_irq(&base->lock);
# 
# CPU0 gets stuck at the [*] code-point briefly - after the timer->base has
# been set to NULL, but before the base->running_timer pointer has been set
# up. This is a fundamentally volatile scenario, as there's _zero_ knowledge
# in the data structures that this timer is about to be executed!
# 
# Now CPU1 comes along and calls del_timer_sync(). It will find nothing -
# neither timer->base nor base->running_timer will cause it to synchronize.  
# It will return and report that the timer has been deleted - shortly
# afterwards CPU1 continues to execute the timer fn, which will cause
# crashes.
# 
# This particular race is easy to fix by reordering the timer->base
# clearing with set_running_timer(), and putting a wmb() between them, but
# there's more races:
# 
# race #2
# 
# The checking of del_timer_sync() for 'pending or running timer' is
# fundamentally unrobust. Eg. if CPU0 gets stuck at the [***] point below:
# 
#                 base = &per_cpu(tvec_bases, i);
#                 if (base->running_timer == timer) {
#                         while (base->running_timer == timer) {
#                                 cpu_relax();
#                                 preempt_check_resched();
#                         }
# 			[***]
#                         break;
#                 }
#         }
#         smp_rmb();
#         if (timer_pending(timer))
#                 goto del_again;
# 
# 
# then del_timer_sync() has already decided that this timer is not running
# (we just finished loop-waiting for it), but we have not done the
# timer_pending() check yet.
# 
# If the timer has re-armed itself, and if the timer expires on CPU1 (this
# needs a long delay on CPU0 but that's not hard to achieve eg.  in UML or
# with kernel preemption enabled), then CPU1 could start to expire the
# timer and gets to the [**] point in __run_timers (see above), then CPU1
# gets stalled and CPU0 is unstalled, then the timer_pending() check in
# del_timer_sync() will not notice the running timer, and del_timer_sync()
# returns - while CPU1 is just about to run the timer!
# 
# Fixing this second race is hard - it involves a heavy race-check
# operation that has to lock all bases, and has to re-check the
# base->running_timer value, and timer_pending condition atomically.
# 
# This fix also fixes the first race, due to forcing del_timer_sync() to
# always observe the timer state atomically, so the [*] code point will
# always synchronize with del_timer_sync(). 
# 
# The patch is ugly but safe, and it has fixed the crashes in the 2.4
# backport.  I tested the patch on 2.6.0-test7 with some heavy itimer use
# and it works fine.  Removing self-arming timers safely is the sole
# purpose of del_timer_sync(), so there's no way around this overhead i
# think.  I believe we should ultimately fix all major del_timer_sync()
# users to not use self-arming timers - having del_timer_sync() in the
# thread-exit path is now a considerable source of SMP overhead.  But this
# is out of the scope of current 2.6 fixes of course, and we have to
# support self-arming timers as well.
# --------------------------------------------
# 03/10/11	venkatesh.pallipadi@intel.com	1.1337.10.2
# [PATCH] Bug in timer_tsc cpufreq callback
# 
# There is a bug in cpufreq call back funtion in timer_tsc routines,
# that can result in system deadlock. The issue is: grabbing the
# write_lock on xtime_lock without disabling the interrupts. So,=20
# if we happen to get a timer interrupt while we are in this code,
# system will go into a deadlock.
# 
# This bug only effects the kernels that have CONFIG_CPU_FREQ enabled.
# --------------------------------------------
# 03/10/11	torvalds@home.osdl.org	1.1337.8.2
# Merge bk://kernel.bkbits.net/davem/sparc-2.5
# into home.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
# 03/10/11	torvalds@home.osdl.org	1.1337.8.3
# Merge bk://kernel.bkbits.net/davem/net-2.5
# into home.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
# 03/10/11	torvalds@home.osdl.org	1.1340
# Merge http://linux-acpi.bkbits.net/linux-acpi-release-2.6.0
# into home.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
# 03/10/12	rmk@flint.arm.linux.org.uk	1.1337.11.1
# [ARM] Add missing csum_partial export.
# --------------------------------------------
# 03/10/12	paulus@samba.org	1.1341
# Merge samba.org:/stuff/paulus/kernel/linux-2.5
# into samba.org:/stuff/paulus/kernel/for-linus-ppc
# --------------------------------------------
# 03/10/12	torvalds@home.osdl.org	1.1340.1.1
# Merge bk://bk.arm.linux.org.uk/linux-2.6-rmk
# into home.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
# 03/10/12	torvalds@home.osdl.org	1.1340.1.2
# Merge master.kernel.org:/home/dwmw2/BK/jffs2-forlinus-2.5
# into home.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
# 03/10/12	torvalds@home.osdl.org	1.1342
# Merge bk://ppc.bkbits.net/for-linus-ppc
# into home.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
# 03/10/12	torvalds@home.osdl.org	1.1343
# Merge http://lia64.bkbits.net/to-linus-2.5
# into home.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
# 03/10/12	torvalds@home.osdl.org	1.1344
# Make kernel stack dumps handle unaligned kernel stacks more gracefully.
# 
# They can happen on x86 as a result of interrupts in BIOS calls.
# 
# Noted by Manfred Spraul.
# --------------------------------------------
# 03/10/12	mdharm@one-eyed-alien.net	1.1345
# [PATCH] problems with USB memory pen
# 
# This fixes a bug which was introduced when the code was switched to use
# atomic_read()s.
# 
# The bug prevents hot-unplugging of SCSI (or emulated SCSI) devices from
# working. 
# 
# From Patrick Mansfield.
# --------------------------------------------
# 03/10/12	torvalds@home.osdl.org	1.1346
# Clear IRQ_INPROGRESS as part of "enable_irq()".
# 
# It can have gotten set by a stray interrupt if there were
# no handlers while the IRQ was disabled, and we shouldn't
# confuse other parts (ie this is another safety-net for the
# issues that Al Viro brought up about disable_irq() deadlocks
# when no handlers exist).
# --------------------------------------------
# 03/10/12	ak@muc.de	1.1347
# [PATCH] Fix software suspend compilation on x86-64
# 
# From Pavel Machek. Make software suspend compile again on x86-64
# --------------------------------------------
# 03/10/13	dwmw2@infradead.org	1.1348
# [PATCH] Kernel thread signal handling.
# 
#  - add disallow_signal() to complement allow_signal(), rather than
#    having different subsystems try to do it by hand.
# 
#  - add a version of dequeue_signal() which does the necessary locking on
#    its own, again to avoid having modules have to care.
# 
#  - let allow_signal() to actually allow signals other than
#    SIGKILL. Currently they get either converted to SIGKILL or
#    silently dropped, according to whether your kernel thread
#    happens to have sa_handler set for the signal in question.
# 
#    (Barf alert: we do this by just installing a dummy handler)
# 
#  - make jffs2 use the cleaned up infrastructure
# --------------------------------------------
# 03/10/13	geert@linux-m68k.org	1.1349
# [PATCH] M68k export csum_partial
# 
# M68k: Export missing symbol csum_partial
# --------------------------------------------
# 03/10/13	geert@linux-m68k.org	1.1350
# [PATCH] Sun-3 compile fix
# 
# Sun-3: Add missing include (needed because of __attribute_used__ in
# <linux/init.h>)
# --------------------------------------------
# 03/10/13	ak@colin2.muc.de	1.1351
# [PATCH] Fixing mlockall & PROT_NONE
# 
# This is the minimal change to make "mlockall()" not complain about
# the occasional PROT_NONE area.
# 
# PROT_NONE is commonly used on x86-64, and is no reason to not lock
# in the rest of the mappings into memory.
# --------------------------------------------
# 03/10/13	manfred@colorfullife.com	1.1352
# [PATCH] avoid crashes due to unaligned stacks
# 
# This fixes the stack end detection properly, and verifies that the
# stack content printing does not overflow into the next page even
# partially.
# 
# This is required especially for x86 BIOSes that misalign the stack,
# together with the page access debugging that unmaps unused kernel
# pages to check for valid accesses.
# 
# Architectures with special needs (eg HPPA with stacks that grow up)
# can override the kernel stack end test with __HAVE_ARCH_KSTACK_END
# if they ever enable the anal slab debugging code.
# --------------------------------------------
# 03/10/13	herbert@gondor.apana.org.au	1.1347.1.1
# [IPIP]: Decapsulate after checking policy.
# --------------------------------------------
# 03/10/13	wensong@linux-vs.org	1.1347.1.2
# [IPVS]: Fix IPVS sync state check.
# 
# Patch from Horms <horms@vergenet.net>
# 
# Since both the primay and the backup sync daemon can be started in a box
# at a time, we must just check if the MASTER bit is set in the sync state.
# --------------------------------------------
# 03/10/13	wensong@linux-vs.org	1.1347.1.3
# [IPVS]: Fix to set the statistics of dest zero when bound to a new service
# --------------------------------------------
# 03/10/13	shemminger@osdl.org	1.1347.1.4
# [NET]: Fix syncppp wan device regression.
# 
# In 2.6.0-test6, I put in a patch which fixed sealevel driver, but broke
# all the other wan devices because it got rid of one level of indirection.
# 
# This puts back the indirection, and hopefully prevents others from
# misreading it the same way. The SPPP drivers expect that
# netdev->priv points to device local structure whose first element
# is a pointer to the ppp device. 
# --------------------------------------------
# 03/10/13	shemminger@osdl.org	1.1347.1.5
# [NET]: Fix sealevel regression.
# 
# My earlier change broke the if_ptr assumption used by SPPP drivers.
# This makes sealevel driver do if_ptr like it used to.
# --------------------------------------------
# 03/10/13	bdschuym@pandora.be	1.1347.1.6
# [EBTABLES]: Add ebt_among match.
# --------------------------------------------
# 03/10/13	shemminger@osdl.org	1.1347.1.7
# [NET]: Resolve device probe difference.
# --------------------------------------------
# 03/10/13	davem@kernel.bkbits.net	1.1353
# Merge davem@nuts.ninka.net:/disk1/davem/BK/net-2.5
# into kernel.bkbits.net:/home/davem/net-2.5
# --------------------------------------------
# 03/10/13	torvalds@home.osdl.org	1.1354
# Revert recent SMP timer changes - they cause deadlocks
# 
# Cset exclude: mingo@elte.hu[torvalds]|ChangeSet|20031012025453|05000
# --------------------------------------------
# 03/10/13	torvalds@home.osdl.org	1.1355
# Mark timer as running in the timer base _before_ we clear the pending
# flag (and order it on SMP), so that del_timer_sync() always sees the
# timer either pending or running if it is active.
# --------------------------------------------
# 03/10/14	torvalds@home.osdl.org	1.1356
# Avoid unnecessary floating point usage in av7110 DVB driver
# --------------------------------------------
# 03/10/14	torvalds@home.osdl.org	1.1357
# Avoid unnecessary floating point calculations in amd8111e net driver
# --------------------------------------------
# 03/10/14	torvalds@home.osdl.org	1.1358
# Make x86 do_div() macro evaluate its "base" argument only once.
# --------------------------------------------
# 03/10/14	hunold@linuxtv.org	1.1359
# [PATCH] Fix dvb_net network subsystem usage
# 
# This restores the changes to the dvb_net code done by
# <shemminger@osdl.org>, which were wiped out by my last patchset.
# --------------------------------------------
# 03/10/14	shemminger@osdl.org	1.1355.1.1
# [netdrvr xircom_cb] fix race in statistics pointer setting
# by converting to use alloc_etherdev.
# --------------------------------------------
# 03/10/14	rmk+lkml@arm.linux.org.uk	1.1355.1.2
# [PATCH] Fix pcnet_cs network hotplug
# 
# pcnet_cs registers the network device too early.  The effect of this
# is that the networking hotplug scripts are unable to bring the device
# up automatically.
# 
# There are two issues:
# - we were registering the net device before we finished setting up
#   the device (eg, reading the MAC address.)
# - we were using DEV_CONFIG_PENDING to block the net device "open"
#   callback, and as we know the other methods may be called prior
#   to open.
# 
# My only concern with this patch is that we set info->node.dev_name
# after we register the net device, so use of cardctl during the
# hotplug scripts may give unexpected results.  However, I am not
# aware of anyone using cardctl to read the device name in network
# hotplug scripts.
# 
# Please review and merge.  Thanks.
# --------------------------------------------
# 03/10/14	scott.feldman@intel.com	1.1355.1.3
# [PATCH] ethtool_ops eeprom stuff
# 
# Finally got around to adding ethtool_ops to e100-3.0.x.  I found a bug
# with get_eeprom() and it seems to work best if we add get_eeprom_len() to
# the ops list.  Also moved check for offest + len < size into ethtool.c.
# 
# I was able to test [GS]EEPROM, PHYS_ID, GSTATS, GSTRINGS, and TEST, and
# everything looks good.
# 
# Should I send same for 2.4?
# --------------------------------------------
# 03/10/14	pe1rxq@amsat.org	1.1355.1.4
# [hamradio scc] fix probe function
# 
# fix for the probe function of the scc driver which now uses
# an uninitialised scc struct for requesting an io region.
# --------------------------------------------
# 03/10/14	pe1rxq@amsat.org	1.1355.1.5
# [hamradio bpqether] fix ancient debug line
# 
# removes a verry old debug line from the bpqethernet driver that
# only fills logs.
# --------------------------------------------
# 03/10/14	ak@muc.de	1.1355.1.6
# [PATCH] Mark non 64bit clean network drivers
# 
# This marks some net drivers which are clearly not 64bit (judging from
# the warnings) as !64BIT.
# 
# -Andi
# --------------------------------------------
# 03/10/14	ak@muc.de	1.1355.1.7
# [PATCH] Fix warnings in hp100
# 
# Fix some harmless integer/pointer size mismatch warnings in hp100.c
# on 64bit compiles
# --------------------------------------------
# 03/10/14	ak@muc.de	1.1355.1.8
# [PATCH] Fix warnings in defxx.c
# 
# Fix harmless 64bit warnings in defxx.c
# --------------------------------------------
# 03/10/14	scott.feldman@intel.com	1.1355.1.9
# [PATCH] hang on ZEROCOPY/TSO when hitting no-Tx-resources
# 
# * Critical bug fix: under heavy Tx stress using ZEROCOPY or TSO, if we
#   ran out of Tx descriptors, we didn't calculate for the context
#   descritor used as the first of the ZEROCOPY/TSO send, nor do we clean
#   up the context desriptor bits in the case where the send isn't going
#   to fit, where we need to undo the mappings.  This bug was introduced
#   with the 5.2.16 patch set which included a workaround for a hang
#   on 82544 over PCI-X.  This workaround cause the check for no-Tx-
#   rosource logic to change, and this bug slipped in.
# --------------------------------------------
# 03/10/14	jgarzik@redhat.com	1.1355.1.10
# [netdrvr 8139too] add pci id
# 
# contributed by "JaReK" and Donald Becker.
# --------------------------------------------
# 03/10/14	jgarzik@redhat.com	1.1355.1.11
# [netdrvr 8139too] another new PCI ID
# 
# Contributed by Josh Litherland, Donald Becker, and others.
# --------------------------------------------
# 03/10/14	simon@thekelleys.org.uk	1.1355.1.12
# [PATCH] - atmel wireless driver
# 
# 1) Remove "#include <linux/version.h>" which was not needed and added
#    bad extra compile dependencies.
# 
# 2) Fix typo in module description.
# 
# 3) Make card detection code cope with buggy SMC CIS entries.
# --------------------------------------------
# 03/10/14	jgarzik@redhat.com	1.1355.1.13
# [netdrvr tulip] add pci id
# 
# Contributed by Ken Zalewski.
# --------------------------------------------
# 03/10/14	manfred@colorfullife.com	1.1355.1.14
# [netdrvr natsemi] fix ring clean
# 
# Too much copy&paste in a call to pci_unmap_single.
# --------------------------------------------
# 03/10/14	pp@ee.oulu.fi	1.1355.1.15
# [PATCH] b44 enable interrupts after tx timeout (2.6-test version)
# 
# Resending the patch I sent some time ago for b44.c that nukes the
# 2.4 compatibility cruft as well.
# 
# I'll do one for 2.4.23pre6 ASAP, hopefully being able sync the driver fully
# with the one in 2.6 (free_netdev() etc.).
# --------------------------------------------
# 03/10/14	torvalds@home.osdl.org	1.1360
# Merge bk://kernel.bkbits.net/jgarzik/net-drivers-2.5
# into home.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
#
diff -Nru a/Documentation/filesystems/jfs.txt b/Documentation/filesystems/jfs.txt
--- a/Documentation/filesystems/jfs.txt	Wed Oct 15 00:46:37 2003
+++ b/Documentation/filesystems/jfs.txt	Wed Oct 15 00:46:37 2003
@@ -32,6 +32,10 @@
 		option to remount a volume where the nointegrity option was
 		previously specified in order to restore normal behavior.
 
+errors=continue		Keep going on a filesystem error.
+errors=remount-ro	Default. Remount the filesystem read-only on an error.
+errors=panic		Panic and halt the machine if an error occurs.
+
 JFS TODO list:
 
 Plans for our near term development items
diff -Nru a/Documentation/filesystems/xfs.txt b/Documentation/filesystems/xfs.txt
--- a/Documentation/filesystems/xfs.txt	Wed Oct 15 00:46:37 2003
+++ b/Documentation/filesystems/xfs.txt	Wed Oct 15 00:46:37 2003
@@ -29,6 +29,11 @@
 	The preferred buffered I/O size can also be altered on an
 	individual file basis using the ioctl(2) system call.
 
+  ikeep
+	When inode clusters are emptied of inodes, keep them around
+	on the disk, this is the old XFS behavior. Default is now to
+	return the inode cluster to the free space pool.
+
   logbufs=value
 	Set the number of in-memory log buffers.  Valid numbers range
 	from 2-8 inclusive.
diff -Nru a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt
--- a/Documentation/x86_64/boot-options.txt	Wed Oct 15 00:46:38 2003
+++ b/Documentation/x86_64/boot-options.txt	Wed Oct 15 00:46:38 2003
@@ -20,18 +20,15 @@
 
 APICs
 
-   nolocalapic   Don't use a local or IO-APIC. This should only
-   		 be needed if you have a buggy BIOS. The newer
-		 kernels already turn it off by default if the
-		 BIOS didn't enable the local APIC, so it will
-		 be hopefully not needed.
-		 Note this code path is not very well tested, you are on
-		 your own.
-
    apic		 Use IO-APIC. Default
+		 Unless you have an NVidia or VIA/Uniprocessor board.
+		Then it defaults to off.
 
    noapic	 Don't use the IO-APIC.
-		 Also only lightly tested.
+
+   disableapic	 Don't use the local APIC
+
+   nolapic	 Don't use the local APIC (alias for i386 compatibility)
 
    pirq=...	 See Documentation/i386/IO-APIC.txt
 
@@ -60,13 +57,16 @@
   Report when timer interrupts are lost because some code turned off
   interrupts for too long.
 
-  nmi_watchdog=NUMBER
+  nmi_watchdog=NUMBER[,panic]
   NUMBER can be:
   0 don't use an NMI watchdog
   1 use the IO-APIC timer for the NMI watchdog
   2 use the local APIC for the NMI watchdog using a performance counter. Note
   This will use one performance counter and the local APIC's performance
   vector.
+  When panic is specified panic when an NMI watchdog timeout occurs.
+  This is useful when you use a panic=... timeout and need the box
+  quickly up again.
 
 Idle loop
 
@@ -127,6 +127,9 @@
 ACPI
 
   acpi=off	Don't enable ACPI
+  acpi=ht	Use ACPI boot table parsing, but don't enable ACPI
+		interpreter
+  acpi=force	Force ACPI on (currently not needed)
 
 PCI
 
diff -Nru a/arch/arm/Makefile b/arch/arm/Makefile
--- a/arch/arm/Makefile	Wed Oct 15 00:46:36 2003
+++ b/arch/arm/Makefile	Wed Oct 15 00:46:36 2003
@@ -155,10 +155,8 @@
 zinstall install: vmlinux
 	$(Q)$(MAKE) $(build)=$(boot) $@
 
-MRPROPER_FILES	+= \
-	include/asm-arm/arch include/asm-arm/.arch \
-	include/asm-arm/constants.h* \
-	include/asm-arm/mach-types.h
+CLEAN_FILES += include/asm-arm/constants.h* include/asm-arm/mach-types.h
+MRPROPER_FILES += include/asm-arm/arch include/asm-arm/.arch
 
 # We use MRPROPER_FILES and CLEAN_FILES now
 archclean:
diff -Nru a/arch/arm/configs/lart_defconfig b/arch/arm/configs/lart_defconfig
--- a/arch/arm/configs/lart_defconfig	Wed Oct 15 00:46:36 2003
+++ b/arch/arm/configs/lart_defconfig	Wed Oct 15 00:46:36 2003
@@ -2,76 +2,107 @@
 # Automatically generated make config: don't edit
 #
 CONFIG_ARM=y
-# CONFIG_EISA is not set
-# CONFIG_SBUS is not set
-# CONFIG_MCA is not set
+CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-# CONFIG_OBSOLETE is not set
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
 
 #
 # Loadable module support
 #
 CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
 CONFIG_KMOD=y
 
 #
 # System Type
 #
+# CONFIG_ARCH_ADIFCC is not set
 # CONFIG_ARCH_ANAKIN is not set
-# CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
 # CONFIG_ARCH_L7200 is not set
 # CONFIG_ARCH_RPC is not set
 CONFIG_ARCH_SA1100=y
 # CONFIG_ARCH_SHARK is not set
 
 #
-# Archimedes/A5000 Implementations
+# CLPS711X/EP721X Implementations
 #
 
 #
-# Archimedes/A5000 Implementations (select only ONE)
+# Epxa10db
 #
-# CONFIG_ARCH_ARC is not set
-# CONFIG_ARCH_A5K is not set
 
 #
 # Footbridge Implementations
 #
-# CONFIG_ARCH_CATS is not set
-# CONFIG_ARCH_PERSONAL_SERVER is not set
-# CONFIG_ARCH_EBSA285_ADDIN is not set
-# CONFIG_ARCH_EBSA285_HOST is not set
-# CONFIG_ARCH_NETWINDER is not set
+
+#
+# IOP3xx Implementation Options
+#
+# CONFIG_ARCH_IOP310 is not set
+# CONFIG_ARCH_IOP321 is not set
+
+#
+# IOP3xx Chipset Features
+#
+
+#
+# Intel PXA250/210 Implementations
+#
 
 #
 # SA11x0 Implementations
 #
 # CONFIG_SA1100_ASSABET is not set
-# CONFIG_ASSABET_NEPONSET is not set
 # CONFIG_SA1100_ADSBITSY is not set
 # CONFIG_SA1100_BRUTUS is not set
 # CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_H3100 is not set
 # CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_H3800 is not set
 # CONFIG_SA1100_EXTENEX1 is not set
 # CONFIG_SA1100_FLEXANET is not set
 # CONFIG_SA1100_FREEBIRD is not set
 # CONFIG_SA1100_GRAPHICSCLIENT is not set
 # CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_BADGE4 is not set
 # CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_HACKKIT is not set
 # CONFIG_SA1100_HUW_WEBPANEL is not set
 # CONFIG_SA1100_ITSY is not set
 CONFIG_SA1100_LART=y
@@ -79,76 +110,72 @@
 # CONFIG_SA1100_OMNIMETER is not set
 # CONFIG_SA1100_PANGOLIN is not set
 # CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_PT_SYSTEM3 is not set
+# CONFIG_SA1100_SHANNON is not set
 # CONFIG_SA1100_SHERMAN is not set
 # CONFIG_SA1100_SIMPAD is not set
 # CONFIG_SA1100_PFS168 is not set
 # CONFIG_SA1100_VICTOR is not set
 # CONFIG_SA1100_XP860 is not set
 # CONFIG_SA1100_YOPY is not set
+# CONFIG_SA1100_STORK is not set
+# CONFIG_SA1100_SSP is not set
 CONFIG_SA1100_USB=m
 CONFIG_SA1100_USB_NETLINK=m
 CONFIG_SA1100_USB_CHAR=m
 
 #
-# CLPS711X/EP721X Implementations
+# Processor Type
 #
-# CONFIG_ARCH_CDB89712 is not set
-# CONFIG_ARCH_CLEP7312 is not set
-# CONFIG_ARCH_EDB7211 is not set
-# CONFIG_ARCH_P720T is not set
-# CONFIG_ARCH_EP7211 is not set
-# CONFIG_ARCH_EP7212 is not set
-# CONFIG_ARCH_ACORN is not set
-# CONFIG_FOOTBRIDGE is not set
-# CONFIG_FOOTBRIDGE_HOST is not set
-# CONFIG_FOOTBRIDGE_ADDIN is not set
 CONFIG_CPU_32=y
-# CONFIG_CPU_26 is not set
+CONFIG_CPU_SA1100=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4=y
+CONFIG_CPU_CACHE_V4WB=y
+CONFIG_CPU_TLB_V4WB=y
+CONFIG_CPU_MINICACHE=y
 
 #
-# Processor Type
+# Processor Features
 #
-# CONFIG_CPU_32v3 is not set
-CONFIG_CPU_32v4=y
-# CONFIG_CPU_ARM610 is not set
-# CONFIG_CPU_ARM710 is not set
-# CONFIG_CPU_ARM720T is not set
-# CONFIG_CPU_ARM920T is not set
-# CONFIG_CPU_ARM1020 is not set
-# CONFIG_CPU_SA110 is not set
-CONFIG_CPU_SA1100=y
-CONFIG_DISCONTIGMEM=y
-# CONFIG_CPU_BIG_ENDIAN is not set
 
 #
 # General setup
 #
-# CONFIG_PCI is not set
-# CONFIG_ISA is not set
-# CONFIG_ISA_DMA is not set
+CONFIG_DISCONTIGMEM=y
+CONFIG_ISA=y
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_SA1100=y
+# CONFIG_CPU_FREQ_PROC_INTF is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_24_API=y
 # CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
 
 #
 # At least one math emulation must be selected
 #
 CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
 # CONFIG_FPE_FASTFPE is not set
-CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
-CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
 # CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
 CONFIG_PM=y
+# CONFIG_PREEMPT is not set
 CONFIG_APM=m
 # CONFIG_ARTHUR is not set
 CONFIG_CMDLINE="console=ttySA0,9600 root=/dev/ram"
-# CONFIG_PFS168_CMDLINE is not set
 CONFIG_LEDS=y
 # CONFIG_LEDS_TIMER is not set
 CONFIG_LEDS_CPU=y
@@ -166,8 +193,9 @@
 CONFIG_MTD_DEBUG=y
 CONFIG_MTD_DEBUG_VERBOSE=1
 CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
 # CONFIG_MTD_REDBOOT_PARTS is not set
-# CONFIG_MTD_BOOTLDR_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
 # CONFIG_MTD_AFS_PARTS is not set
 
 #
@@ -177,51 +205,26 @@
 CONFIG_MTD_BLOCK=y
 # CONFIG_FTL is not set
 # CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
 
 #
 # RAM/ROM/Flash chip drivers
 #
 # CONFIG_MTD_CFI is not set
-# CONFIG_MTD_CFI_INTELEXT is not set
-# CONFIG_MTD_CFI_AMDSTD is not set
-# CONFIG_MTD_AMDSTD is not set
-# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDECPROBE is not set
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
-# CONFIG_MTD_JEDEC is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
 #
-# CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_SUN_UFLASH is not set
-# CONFIG_MTD_NORA is not set
-# CONFIG_MTD_PNC2000 is not set
-# CONFIG_MTD_RPXLITE is not set
-# CONFIG_MTD_TQM8XXL is not set
-# CONFIG_MTD_SC520CDP is not set
-# CONFIG_MTD_NETSC520 is not set
-# CONFIG_MTD_SBC_GXX is not set
-# CONFIG_MTD_ELAN_104NC is not set
-# CONFIG_MTD_DBOX2 is not set
-# CONFIG_MTD_CSTM_MIPS_IXX is not set
-# CONFIG_MTD_CFI_FLAGADM is not set
-# CONFIG_MTD_SOLUTIONENGINE is not set
-# CONFIG_MTD_MIXMEM is not set
-# CONFIG_MTD_OCTAGON is not set
-# CONFIG_MTD_VMAX is not set
-# CONFIG_MTD_OCELOT is not set
-# CONFIG_MTD_L440GX is not set
-# CONFIG_MTD_ARM_INTEGRATOR is not set
-# CONFIG_MTD_CDB89712 is not set
-# CONFIG_MTD_SA1100 is not set
-# CONFIG_MTD_DC21285 is not set
-# CONFIG_MTD_IQ80310 is not set
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
 
 #
 # Self-contained MTD device drivers
 #
-# CONFIG_MTD_PMC551 is not set
 # CONFIG_MTD_SLRAM is not set
 CONFIG_MTD_LART=y
 # CONFIG_MTD_MTDRAM is not set
@@ -230,10 +233,9 @@
 #
 # Disk-On-Chip Device Drivers
 #
-# CONFIG_MTD_DOC1000 is not set
 # CONFIG_MTD_DOC2000 is not set
 # CONFIG_MTD_DOC2001 is not set
-# CONFIG_MTD_DOCPROBE is not set
+# CONFIG_MTD_DOC2001PLUS is not set
 
 #
 # NAND Flash Device Drivers
@@ -241,21 +243,15 @@
 # CONFIG_MTD_NAND is not set
 
 #
-# Plug and Play configuration
+# Plug and Play support
 #
 # CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
 
 #
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 CONFIG_BLK_DEV_RAM=y
@@ -266,44 +262,49 @@
 # Multi-device support (RAID and LVM)
 #
 # CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
 
 #
 # Networking options
 #
 CONFIG_PACKET=m
 # CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
+# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
 # CONFIG_IP_PNP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
 CONFIG_INET_ECN=y
 CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
 # CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NETFILTER is not set
 
 #
-#  
+# SCTP Configuration (EXPERIMENTAL)
 #
+CONFIG_IPV6_SCTP__=y
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_LLC2 is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
-# CONFIG_LLC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -316,8 +317,9 @@
 # CONFIG_NET_SCHED is not set
 
 #
-# Network device support
+# Network testing
 #
+# CONFIG_NET_PKTGEN is not set
 CONFIG_NETDEVICES=y
 
 #
@@ -333,15 +335,14 @@
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
-# CONFIG_SUNLANCE is not set
-# CONFIG_SUNBMAC is not set
-# CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
-# CONFIG_SUNGEM is not set
+# CONFIG_MII is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
 # CONFIG_NET_ISA is not set
 # CONFIG_NET_PCI is not set
 # CONFIG_NET_POCKET is not set
@@ -349,16 +350,10 @@
 #
 # Ethernet (1000 Mbit)
 #
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
+
+#
+# Ethernet (10000 Mbit)
+#
 CONFIG_PPP=m
 # CONFIG_PPP_MULTILINK is not set
 # CONFIG_PPP_FILTER is not set
@@ -381,8 +376,6 @@
 # Token Ring devices
 #
 # CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
 # CONFIG_SHAPER is not set
 
 #
@@ -407,10 +400,9 @@
 CONFIG_IRNET=m
 CONFIG_IRCOMM=m
 # CONFIG_IRDA_ULTRA is not set
-CONFIG_IRDA_OPTIONS=y
 
 #
-#   IrDA options
+# IrDA options
 #
 CONFIG_IRDA_CACHE_LAST_LSAP=y
 # CONFIG_IRDA_FAST_RR is not set
@@ -424,132 +416,145 @@
 # SIR device drivers
 #
 # CONFIG_IRTTY_SIR is not set
-# CONFIG_IRPORT_SIR is not set
 
 #
 # Dongle support
 #
-# CONFIG_DONGLE is not set
+
+#
+# Old SIR device drivers
+#
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Old Serial dongle support
+#
 
 #
 # FIR device drivers
 #
-# CONFIG_USB_IRDA is not set
 # CONFIG_NSC_FIR is not set
 # CONFIG_WINBOND_FIR is not set
 # CONFIG_TOSHIBA_FIR is not set
 # CONFIG_SMC_IRCC_FIR is not set
 # CONFIG_ALI_FIR is not set
-# CONFIG_VLSI_FIR is not set
 CONFIG_SA1100_FIR=m
+# CONFIG_VIA_FIR is not set
 
 #
-# ATA/IDE/MFM/RLL support
+# Bluetooth support
 #
-CONFIG_IDE=m
+# CONFIG_BT is not set
 
 #
-# IDE, ATA and ATAPI Block devices
+# ATA/ATAPI/MFM/RLL support
 #
+CONFIG_IDE=m
 CONFIG_BLK_DEV_IDE=m
 
 #
 # Please see Documentation/ide.txt for help/info on IDE drives
 #
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=m
 # CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_IDEDISK_STROKE is not set
 CONFIG_BLK_DEV_IDECD=m
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
 
 #
 # IDE chipset support/bugfixes
 #
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_HD is not set
 
 #
-# SCSI support
+# SCSI device support
 #
 # CONFIG_SCSI is not set
 
 #
 # I2O device support
 #
-# CONFIG_I2O is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
 
 #
 # ISDN subsystem
 #
-# CONFIG_ISDN is not set
+# CONFIG_ISDN_BOOL is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
 
 #
-# Input core support
+# Userland interfaces
 #
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
 # CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_PS2_SYNAPTICS is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_INPORT is not set
+# CONFIG_MOUSE_LOGIBM is not set
+# CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
 
 #
 # Character devices
 #
-# CONFIG_VT is not set
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
 # Serial drivers
 #
-# CONFIG_SERIAL_ANAKIN is not set
-# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
-# CONFIG_SERIAL_AMBA is not set
-# CONFIG_SERIAL_AMBA_CONSOLE is not set
-# CONFIG_SERIAL_CLPS711X is not set
-# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
-# CONFIG_SERIAL_21285 is not set
-# CONFIG_SERIAL_21285_OLD is not set
-# CONFIG_SERIAL_21285_CONSOLE is not set
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
 CONFIG_SERIAL_SA1100=y
 CONFIG_SERIAL_SA1100_CONSOLE=y
-CONFIG_SA1100_DEFAULT_BAUDRATE=9600
-# CONFIG_SERIAL_8250 is not set
-# CONFIG_SERIAL_8250_CONSOLE is not set
-# CONFIG_SERIAL_8250_EXTENDED is not set
-# CONFIG_SERIAL_8250_MANY_PORTS is not set
-# CONFIG_SERIAL_8250_SHARE_IRQ is not set
-# CONFIG_SERIAL_8250_DETECT_IRQ is not set
-# CONFIG_SERIAL_8250_MULTIPORT is not set
-# CONFIG_SERIAL_8250_HUB6 is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-CONFIG_UCB1200=m
-CONFIG_TOUCHSCREEN_UCB1200=m
-CONFIG_AUDIO_UCB1200=m
-CONFIG_ADC_UCB1200=m
-# CONFIG_TOUCHSCREEN_H3600 is not set
-CONFIG_PROFILER=m
-# CONFIG_PFS168_SPI is not set
-# CONFIG_PFS168_DTMF is not set
-# CONFIG_PFS168_MISC is not set
 
 #
 # I2C support
@@ -557,55 +562,39 @@
 # CONFIG_I2C is not set
 
 #
-# L3 serial bus support
+# I2C Algorithms
 #
-# CONFIG_L3 is not set
-# CONFIG_L3_ALGOBIT is not set
-# CONFIG_L3_BIT_SA1100_GPIO is not set
 
 #
-# Other L3 adapters
+# I2C Hardware Bus support
 #
-# CONFIG_L3_SA1111 is not set
 
 #
-# L3 driver support
+# I2C Hardware Sensors Chip support
 #
-# CONFIG_L3_DRV_UDA1341 is not set
-# CONFIG_BIT_SA1100_GPIO is not set
+# CONFIG_I2C_SENSOR is not set
 
 #
 # Mice
 #
 # CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
+# CONFIG_QIC02_TAPE is not set
 
 #
-# Input core support is needed for joysticks
+# IPMI
 #
-# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-CONFIG_SA1100_RTC=m
+# CONFIG_GEN_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
-# CONFIG_SONYPI is not set
 
 #
 # Ftape, the floppy tape device driver
@@ -613,6 +602,7 @@
 # CONFIG_FTAPE is not set
 # CONFIG_AGP is not set
 # CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
 
 #
 # Multimedia devices
@@ -620,87 +610,104 @@
 # CONFIG_VIDEO_DEV is not set
 
 #
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
 # File systems
 #
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
 CONFIG_REISERFS_FS=m
 # CONFIG_REISERFS_CHECK is not set
 # CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=m
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_FAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
 # CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
-# CONFIG_CMS_FS is not set
-CONFIG_EXT3_FS=m
-CONFIG_JBD=m
-# CONFIG_JBD_DEBUG is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
 # CONFIG_EFS_FS is not set
 # CONFIG_JFFS_FS is not set
 CONFIG_JFFS2_FS=m
 CONFIG_JFFS2_FS_DEBUG=1
+# CONFIG_JFFS2_FS_NAND is not set
 CONFIG_CRAMFS=m
-CONFIG_TMPFS=y
-CONFIG_RAMFS=m
-CONFIG_ISO9660_FS=m
-CONFIG_JOLIET=y
-# CONFIG_MINIX_FS is not set
-# CONFIG_FREEVXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_DEBUG is not set
-# CONFIG_NTFS_RW is not set
+# CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
-CONFIG_UDF_FS=m
-# CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
 
 #
 # Network File Systems
 #
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=m
 CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
+# CONFIG_NFS_V4 is not set
 CONFIG_NFSD=m
 CONFIG_NFSD_V3=y
-CONFIG_SUNRPC=m
+# CONFIG_NFSD_V4 is not set
+# CONFIG_NFSD_TCP is not set
 CONFIG_LOCKD=m
 CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=m
+# CONFIG_SUNRPC_GSS is not set
 # CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+# CONFIG_AFS_FS is not set
 
 #
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
 CONFIG_NLS=y
 
 #
@@ -728,6 +735,7 @@
 # CONFIG_NLS_CODEPAGE_949 is not set
 # CONFIG_NLS_CODEPAGE_874 is not set
 # CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
 CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_ISO8859_2 is not set
@@ -745,149 +753,62 @@
 CONFIG_NLS_UTF8=m
 
 #
-# Sound
-#
-CONFIG_SOUND=m
-# CONFIG_SOUND_BT878 is not set
-# CONFIG_SOUND_CMPCI is not set
-# CONFIG_SOUND_EMU10K1 is not set
-# CONFIG_SOUND_FUSION is not set
-# CONFIG_SOUND_CS4281 is not set
-# CONFIG_SOUND_ES1370 is not set
-# CONFIG_SOUND_ES1371 is not set
-# CONFIG_SOUND_ESSSOLO1 is not set
-# CONFIG_SOUND_MAESTRO is not set
-# CONFIG_SOUND_MAESTRO3 is not set
-# CONFIG_SOUND_ICH is not set
-# CONFIG_SOUND_RME96XX is not set
-# CONFIG_SOUND_SONICVIBES is not set
-# CONFIG_SOUND_TRIDENT is not set
-# CONFIG_SOUND_MSNDCLAS is not set
-# CONFIG_SOUND_MSNDPIN is not set
-# CONFIG_SOUND_VIA82CXXX is not set
-# CONFIG_MIDI_VIA82CXXX is not set
-# CONFIG_SOUND_ASSABET_UDA1341 is not set
-# CONFIG_SOUND_H3600_UDA1341 is not set
-# CONFIG_SOUND_PANGOLIN_UDA1341 is not set
-# CONFIG_SOUND_SA1111_UDA1341 is not set
-CONFIG_SOUND_SA1100SSP=m
-# CONFIG_SOUND_OSS is not set
-# CONFIG_SOUND_WAVEARTIST is not set
-# CONFIG_SOUND_TVMIXER is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
+# Graphics support
 #
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
+# CONFIG_FB is not set
 
 #
-# USB Human Interface Devices (HID)
+# Console display driver support
 #
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
 
 #
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
+# Sound
 #
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
+CONFIG_SOUND=m
 
 #
-# USB Multimedia devices
+# Advanced Linux Sound Architecture
 #
+# CONFIG_SND is not set
 
 #
-#   Video4Linux support is needed for USB Multimedia device support
+# Open Sound System
 #
-# CONFIG_USB_DABUSB is not set
+# CONFIG_SOUND_PRIME is not set
 
 #
-# USB Network adaptors
+# Misc devices
 #
-# CONFIG_USB_PLUSB is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
 
 #
-# USB port drivers
+# USB support
 #
-# CONFIG_USB_USS720 is not set
+# CONFIG_USB_GADGET is not set
 
 #
-# USB Serial Converter support
+# Kernel hacking
 #
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_KERNEL is not set
 
 #
-# Miscellaneous USB drivers
+# Security options
 #
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_ID75 is not set
+# CONFIG_SECURITY is not set
 
 #
-# Bluetooth support
+# Cryptographic options
 #
-# CONFIG_BT is not set
+# CONFIG_CRYPTO is not set
 
 #
-# Kernel hacking
+# Library routines
 #
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_INFO is not set
-CONFIG_MAGIC_SYSRQ=y
-# CONFIG_NO_PGT_CACHE is not set
-CONFIG_DEBUG_LL=y
-# CONFIG_DEBUG_DC21285_PORT is not set
-# CONFIG_DEBUG_CLPS711X_UART2 is not set
+CONFIG_CRC32=m
+CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_DEFLATE=m
diff -Nru a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
--- a/arch/arm/kernel/armksyms.c	Wed Oct 15 00:46:36 2003
+++ b/arch/arm/kernel/armksyms.c	Wed Oct 15 00:46:36 2003
@@ -131,6 +131,7 @@
 EXPORT_SYMBOL(__machine_arch_type);
 
 	/* networking */
+EXPORT_SYMBOL(csum_partial);
 EXPORT_SYMBOL(csum_partial_copy_nocheck);
 EXPORT_SYMBOL(__csum_ipv6_magic);
 
diff -Nru a/arch/arm/mach-clps7500/core.c b/arch/arm/mach-clps7500/core.c
--- a/arch/arm/mach-clps7500/core.c	Wed Oct 15 00:46:37 2003
+++ b/arch/arm/mach-clps7500/core.c	Wed Oct 15 00:46:37 2003
@@ -187,10 +187,6 @@
 	.unmask	= cl7500_no_action,
 };
 
-static void no_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-}
-
 static struct irqaction irq_isa = { no_action, 0, 0, "isa", NULL, NULL };
 
 static void __init clps7500_init_irq(void)
diff -Nru a/arch/arm/mach-integrator/lm.c b/arch/arm/mach-integrator/lm.c
--- a/arch/arm/mach-integrator/lm.c	Wed Oct 15 00:46:35 2003
+++ b/arch/arm/mach-integrator/lm.c	Wed Oct 15 00:46:35 2003
@@ -7,6 +7,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/device.h>
 
@@ -90,3 +91,6 @@
 	}
 	return ret;
 }
+
+EXPORT_SYMBOL(lm_driver_register);
+EXPORT_SYMBOL(lm_driver_unregister);
diff -Nru a/arch/arm/mach-sa1100/cpu-sa1100.c b/arch/arm/mach-sa1100/cpu-sa1100.c
--- a/arch/arm/mach-sa1100/cpu-sa1100.c	Wed Oct 15 00:46:35 2003
+++ b/arch/arm/mach-sa1100/cpu-sa1100.c	Wed Oct 15 00:46:35 2003
@@ -194,7 +194,7 @@
 		new_ppcr = sa11x0_freq_to_ppcr(target_freq);
 		if ((sa11x0_ppcr_to_freq(new_ppcr) > target_freq) &&
 		    (sa11x0_ppcr_to_freq(new_ppcr - 1) >= policy->min))
-			mew_ppcr--;
+			new_ppcr--;
 		break;
 	}
 
diff -Nru a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c
--- a/arch/arm/mach-sa1100/lart.c	Wed Oct 15 00:46:38 2003
+++ b/arch/arm/mach-sa1100/lart.c	Wed Oct 15 00:46:38 2003
@@ -8,6 +8,7 @@
 
 #include <asm/hardware.h>
 #include <asm/setup.h>
+#include <asm/mach-types.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
diff -Nru a/arch/i386/kernel/acpi/wakeup.S b/arch/i386/kernel/acpi/wakeup.S
--- a/arch/i386/kernel/acpi/wakeup.S	Wed Oct 15 00:46:36 2003
+++ b/arch/i386/kernel/acpi/wakeup.S	Wed Oct 15 00:46:36 2003
@@ -172,14 +172,13 @@
 .org	0x1000
 
 wakeup_pmode_return:
-	movl	$__KERNEL_DS, %eax
-	movl	%eax, %ds
-	movw	$0x0e00 + 'u', %ds:(0xb8016)
-
-	# restore other segment registers
-	xorl	%eax, %eax
+	movw	$__KERNEL_DS, %ax
+	movw	%ax, %ss
+	movw	%ax, %ds
+	movw	%ax, %es
 	movw	%ax, %fs
 	movw	%ax, %gs
+	movw	$0x0e00 + 'u', 0xb8016
 
 	# reload the gdt, as we need the full 32 bit address
 	lgdt	saved_gdt
@@ -192,46 +191,30 @@
 	wbinvd
 
 	# and restore the stack ... but you need gdt for this to work
-	movl	$__KERNEL_DS, %eax
-	movw	%ax, %ss
-	movw	%ax, %ds
-	movw	%ax, %es
-	movw	%ax, %fs
-	movw	%ax, %gs
-	movl	saved_esp, %esp
+	movl	saved_context_esp, %esp
 
-	movw	$0x0e00 + 'W', %ds:(0xb8018)
-	movl	$(1024*1024*3), %ecx
-	movl	$0, %esi
-	rep	lodsb
-	movw	$0x0e00 + 'O', %ds:(0xb8018)
+	movw	$0x0e00 + 'W', 0xb8018
+	outl	%eax, $0x80
+	outl	%eax, $0x80
+	movw	$0x0e00 + 'O', 0xb8018
 
 	movl	%cs:saved_magic, %eax
 	cmpl	$0x12345678, %eax
 	jne	bogus_magic
 
-	# restore the other general registers
-	movl	saved_ebx, %ebx
-	movl	saved_edi, %edi
-	movl	saved_esi, %esi
-	movl	saved_ebp, %ebp
-
 	# jump to place where we left off
 	movl	saved_eip,%eax
-	movw	$0x0e00 + 'x', %ds:(0xb8018)
-	pushl	%eax
-	popl	%eax
-	movw	$0x0e00 + '!', %ds:(0xb801a)
+	movw	$0x0e00 + 'x', 0xb8018
+	outl	%eax, $0x80
+	outl	%eax, $0x80
+	movw	$0x0e00 + '!', 0xb801a
 	jmp	*%eax
 
 bogus_magic:
-	movw	$0x0e00 + 'B', %ds:(0xb8018)
-	jmp bogus_magic
+	movw	$0x0e00 + 'B', 0xb8018
+	jmp	bogus_magic
+
 
-bogus_magic2:
-	movw	$0x0e00 + '2', %ds:(0xb8018)
-	jmp bogus_magic2
-		
 ##
 # acpi_copy_wakeup_routine
 #
@@ -267,80 +250,45 @@
 
 .data
 ALIGN
-ENTRY(saved_ebp)	.long	0
-ENTRY(saved_esi)	.long	0
-ENTRY(saved_edi)	.long	0
-ENTRY(saved_ebx)	.long	0
-
-ENTRY(saved_eip)	.long	0
-ENTRY(saved_esp)	.long	0
-
 ENTRY(saved_magic)	.long	0
+ENTRY(saved_eip)	.long	0
 
-ENTRY(do_suspend_lowlevel)
-	cmpl $0,4(%esp)
-	jne ret_point
-	call save_processor_state
-
-	movl %esp, saved_context_esp
-	movl %eax, saved_context_eax
+save_registers:
+	leal	4(%esp), %eax
+	movl	%eax, saved_context_esp
 	movl %ebx, saved_context_ebx
-	movl %ecx, saved_context_ecx
-	movl %edx, saved_context_edx
 	movl %ebp, saved_context_ebp
 	movl %esi, saved_context_esi
 	movl %edi, saved_context_edi
 	pushfl ; popl saved_context_eflags
 
 	movl $ret_point,saved_eip
-	movl %esp,saved_esp
-	movl %ebp,saved_ebp
-	movl %ebx,saved_ebx
-	movl %edi,saved_edi
-	movl %esi,saved_esi
-
-	pushl $3
-	call acpi_enter_sleep_state
-	addl $4,%esp
 	ret
-	.p2align 4,,7
-ret_point:
-	movl $__KERNEL_DS,%eax
-	movw %ax, %ds
-	movl saved_context_esp, %esp
+
+
+restore_registers:
 	movl saved_context_ebp, %ebp
-	movl saved_context_eax, %eax
 	movl saved_context_ebx, %ebx
-	movl saved_context_ecx, %ecx
-	movl saved_context_edx, %edx
 	movl saved_context_esi, %esi
 	movl saved_context_edi, %edi
-	call restore_processor_state
 	pushl saved_context_eflags ; popfl
+	ret	
+
+ENTRY(do_suspend_lowlevel)
+	call	save_processor_state
+	call	save_registers
+	pushl	$3
+	call	acpi_enter_sleep_state
+	ret
+	.p2align 4,,7
+ret_point:
+	call	restore_registers
+	call	restore_processor_state
 	ret
 
 ENTRY(do_suspend_lowlevel_s4bios)
-	cmpl $0,4(%esp)
-	jne ret_point
 	call save_processor_state
-
-	movl %esp, saved_context_esp
-	movl %eax, saved_context_eax
-	movl %ebx, saved_context_ebx
-	movl %ecx, saved_context_ecx
-	movl %edx, saved_context_edx
-	movl %ebp, saved_context_ebp
-	movl %esi, saved_context_esi
-	movl %edi, saved_context_edi
-	pushfl ; popl saved_context_eflags
-
-	movl $ret_point,saved_eip
-	movl %esp,saved_esp
-	movl %ebp,saved_ebp
-	movl %ebx,saved_ebx
-	movl %edi,saved_edi
-	movl %esi,saved_esi
-
+	call save_registers
 	call acpi_enter_sleep_state_s4bios
 	ret
 
diff -Nru a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.c	Wed Oct 15 00:46:35 2003
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c	Wed Oct 15 00:46:35 2003
@@ -5,17 +5,14 @@
  *  Licensed under the terms of the GNU GPL License version 2.
  *  Based upon datasheets & sample CPUs kindly provided by VIA.
  *
- *  VIA have currently 3 different versions of Longhaul.
- *
- *  +---------------------+----------+---------------------------------+
- *  | Marketing name      | Codename | longhaul version / features.    |
- *  +---------------------+----------+---------------------------------+
- *  |  Samuel/CyrixIII    | C5A      | v1 : multipliers only           |
- *  |  Samuel2/C3         | C3E/C5B  | v1 : multiplier only            |
- *  |  Ezra               | C5C      | v2 : multipliers & voltage      |
- *  |  Ezra-T             | C5M      | v3 : multipliers, voltage & FSB |
- *  |  Nehemiah           | C5N      | v3 : multipliers, voltage & FSB |
- *  +---------------------+----------+---------------------------------+
+ *  VIA have currently 2 different versions of Longhaul.
+ *  Version 1 (Longhaul) uses the BCR2 MSR at 0x1147.
+ *   It is present only in Samuel 1, Samuel 2 and Ezra.
+ *  Version 2 (Powersaver) uses the POWERSAVER MSR at 0x110a.
+ *   It is present in Ezra-T, Nehemiah and above.
+ *   In addition to scaling multiplier, it can also scale voltage.
+ *   There is provision for scaling FSB too, but this doesn't work
+ *   too well in practice.
  *
  *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
  */
@@ -66,7 +63,11 @@
 
 static unsigned int calc_speed (int mult, int fsb)
 {
-	return ((mult/10)*fsb) + ((mult%10)*(fsb/2));
+	int mhz;
+	mhz = (mult/10)*fsb;
+	if (mult%10)
+		mhz += fsb/2;
+	return mhz;
 }
 
 
@@ -76,7 +77,7 @@
 
 	rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi);
 	invalue = (lo & (1<<22|1<<23|1<<24|1<<25)) >>22;
-	if (longhaul_version==3) {
+	if (longhaul_version==2) {
 		if (lo & (1<<27))
 			invalue+=16;
 	}
@@ -132,32 +133,15 @@
 		break;
 
 	/*
-	 * Longhaul v2. (Ezra [C5C])
+	 * Powersaver. (Ezra-T [C5M], Nehemiah [C5N])
 	 * We can scale voltage with this too, but that's currently
 	 * disabled until we come up with a decent 'match freq to voltage'
 	 * algorithm.
 	 * We also need to do the voltage/freq setting in order depending
 	 * on the direction of scaling (like we do in powernow-k7.c)
-	 */
-	case 2:
-		rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
-		longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf;
-		longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
-		longhaul.bits.EnableSoftBusRatio = 1;
-		/* We must program the revision key only with values we
-		 * know about, not blindly copy it from 0:3 */
-		longhaul.bits.RevisionKey = 1;
-		wrmsrl (MSR_VIA_LONGHAUL, longhaul.val);
-		__hlt();
-
-		break;
-
-	/*
-	 * Longhaul v3. (Ezra-T [C5M], Nehemiah [C5N])
-	 * This can also do voltage scaling, but see above.
 	 * Ezra-T was alleged to do FSB scaling too, but it never worked in practice.
 	 */
-	case 3:
+	case 2:
 		rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
 		longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf;
 		longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
@@ -214,6 +198,7 @@
 
 static int __init longhaul_get_ranges (void)
 {
+	struct cpuinfo_x86 *c = cpu_data;
 	unsigned long invalue;
 	unsigned int minmult=0, maxmult=0;
 	unsigned int multipliers[32]= {
@@ -232,10 +217,13 @@
 		maxmult = longhaul_get_cpu_mult();
 		rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi);
 		invalue = (lo & (1<<18|1<<19)) >>18;
-		fsb = eblcr_fsb_table[invalue];
+		if (c->x86_model==6)
+			fsb = eblcr_fsb_table[invalue];
+		else
+			fsb = guess_fsb(maxmult);
 		break;
 
-	case 2 ... 3:
+	case 2:
 		rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
 
 		invalue = longhaul.bits.MaxMHzBR;
@@ -378,10 +366,10 @@
 		break;
 
 	case 7:		/* C5B / C5C */
+		longhaul_version=1;
 		switch (c->x86_mask) {
 		case 0:
 			cpuname = "C3 'Samuel 2' [C5B]";
-			longhaul_version=1;
 			/* Note, this is not a typo, early Samuel2's had Samuel1 ratios. */
 			memcpy (clock_ratio, samuel1_clock_ratio, sizeof(samuel1_clock_ratio));
 			memcpy (eblcr_table, samuel2_eblcr, sizeof(samuel2_eblcr));
@@ -391,7 +379,6 @@
 				cpuname = "C3 'Samuel 2' [C5B]";
 			else
 				cpuname = "C3 'Ezra' [C5C]";
-			longhaul_version=2;
 			memcpy (clock_ratio, ezra_clock_ratio, sizeof(ezra_clock_ratio));
 			memcpy (eblcr_table, ezra_eblcr, sizeof(ezra_eblcr));
 			break;
@@ -399,20 +386,21 @@
 		break;
 
 	case 8:
-		cpuname = "C3 'Ezra-T [C5M]";
-		longhaul_version=3;
+		cpuname = "C3 'Ezra-T' [C5M]";
+		longhaul_version=2;
 		numscales=32;
 		memcpy (clock_ratio, ezrat_clock_ratio, sizeof(ezrat_clock_ratio));
 		memcpy (eblcr_table, ezrat_eblcr, sizeof(ezrat_eblcr));
 		break;
-	/*
+
 	case 9:
 		cpuname = "C3 'Nehemiah' [C5N]";
-		longhaul_version=3;
+		longhaul_version=2;
 		numscales=32;
 		memcpy (clock_ratio, nehemiah_clock_ratio, sizeof(nehemiah_clock_ratio));
 		memcpy (eblcr_table, nehemiah_eblcr, sizeof(nehemiah_eblcr));
-	*/
+		break;
+
 	default:
 		cpuname = "Unknown";
 		break;
@@ -421,7 +409,7 @@
 	printk (KERN_INFO PFX "VIA %s CPU detected. Longhaul v%d supported.\n",
 					cpuname, longhaul_version);
 
-	if ((longhaul_version==2 || longhaul_version==3) && (dont_scale_voltage==0))
+	if ((longhaul_version==2) && (dont_scale_voltage==0))
 		longhaul_setup_voltagescaling();
 
 	ret = longhaul_get_ranges();
diff -Nru a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
--- a/arch/i386/kernel/irq.c	Wed Oct 15 00:46:35 2003
+++ b/arch/i386/kernel/irq.c	Wed Oct 15 00:46:35 2003
@@ -355,8 +355,10 @@
  
 void disable_irq(unsigned int irq)
 {
+	irq_desc_t *desc = irq_desc + irq;
 	disable_irq_nosync(irq);
-	synchronize_irq(irq);
+	if (desc->action)
+		synchronize_irq(irq);
 }
 
 /**
@@ -378,7 +380,7 @@
 	spin_lock_irqsave(&desc->lock, flags);
 	switch (desc->depth) {
 	case 1: {
-		unsigned int status = desc->status & ~IRQ_DISABLED;
+		unsigned int status = desc->status & ~(IRQ_DISABLED | IRQ_INPROGRESS);
 		desc->status = status;
 		if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
 			desc->status = status | IRQ_REPLAY;
diff -Nru a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c
--- a/arch/i386/kernel/timers/timer_tsc.c	Wed Oct 15 00:46:37 2003
+++ b/arch/i386/kernel/timers/timer_tsc.c	Wed Oct 15 00:46:37 2003
@@ -321,7 +321,7 @@
 {
 	struct cpufreq_freqs *freq = data;
 
-	write_seqlock(&xtime_lock);
+	write_seqlock_irq(&xtime_lock);
 	if (!ref_freq) {
 		ref_freq = freq->old;
 		loops_per_jiffy_ref = cpu_data[freq->cpu].loops_per_jiffy;
@@ -342,7 +342,7 @@
 		}
 #endif
 	}
-	write_sequnlock(&xtime_lock);
+	write_sequnlock_irq(&xtime_lock);
 
 	return 0;
 }
diff -Nru a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
--- a/arch/i386/kernel/traps.c	Wed Oct 15 00:46:36 2003
+++ b/arch/i386/kernel/traps.c	Wed Oct 15 00:46:36 2003
@@ -104,7 +104,7 @@
 #ifdef CONFIG_KALLSYMS
 	printk("\n");
 #endif
-	while (((long) stack & (THREAD_SIZE-1)) != 0) {
+	while (!kstack_end(stack)) {
 		addr = *stack++;
 		if (kernel_text_address(addr)) {
 			printk(" [<%08lx>] ", addr);
@@ -138,7 +138,7 @@
 
 	stack = esp;
 	for(i = 0; i < kstack_depth_to_print; i++) {
-		if (((long) stack & (THREAD_SIZE-1)) == 0)
+		if (kstack_end(stack))
 			break;
 		if (i && ((i % 8) == 0))
 			printk("\n       ");
diff -Nru a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
--- a/arch/i386/mm/fault.c	Wed Oct 15 00:46:35 2003
+++ b/arch/i386/mm/fault.c	Wed Oct 15 00:46:35 2003
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/tty.h>
 #include <linux/vt_kern.h>		/* For unblank_screen() */
+#include <linux/highmem.h>
 #include <linux/module.h>
 
 #include <asm/system.h>
@@ -55,6 +56,147 @@
 	console_loglevel = loglevel_save;
 }
 
+/*
+ * Return EIP plus the CS segment base.  The segment limit is also
+ * adjusted, clamped to the kernel/user address space (whichever is
+ * appropriate), and returned in *eip_limit.
+ *
+ * The segment is checked, because it might have been changed by another
+ * task between the original faulting instruction and here.
+ *
+ * If CS is no longer a valid code segment, or if EIP is beyond the
+ * limit, or if it is a kernel address when CS is not a kernel segment,
+ * then the returned value will be greater than *eip_limit.
+ * 
+ * This is slow, but is very rarely executed.
+ */
+static inline unsigned long get_segment_eip(struct pt_regs *regs,
+					    unsigned long *eip_limit)
+{
+	unsigned long eip = regs->eip;
+	unsigned seg = regs->xcs & 0xffff;
+	u32 seg_ar, seg_limit, base, *desc;
+
+	/* The standard kernel/user address space limit. */
+	*eip_limit = (seg & 3) ? USER_DS.seg : KERNEL_DS.seg;
+
+	/* Unlikely, but must come before segment checks. */
+	if (unlikely((regs->eflags & VM_MASK) != 0))
+		return eip + (seg << 4);
+	
+	/* By far the most common cases. */
+	if (likely(seg == __USER_CS || seg == __KERNEL_CS))
+		return eip;
+
+	/* Check the segment exists, is within the current LDT/GDT size,
+	   that kernel/user (ring 0..3) has the appropriate privilege,
+	   that it's a code segment, and get the limit. */
+	__asm__ ("larl %3,%0; lsll %3,%1"
+		 : "=&r" (seg_ar), "=r" (seg_limit) : "0" (0), "rm" (seg));
+	if ((~seg_ar & 0x9800) || eip > seg_limit) {
+		*eip_limit = 0;
+		return 1;	 /* So that returned eip > *eip_limit. */
+	}
+
+	/* Get the GDT/LDT descriptor base. 
+	   When you look for races in this code remember that
+	   LDT and other horrors are only used in user space. */
+	if (seg & (1<<2)) {
+		/* Must lock the LDT while reading it. */
+		down(&current->mm->context.sem);
+		desc = current->mm->context.ldt;
+		desc = (void *)desc + (seg & ~7);
+	} else {
+		/* Must disable preemption while reading the GDT. */
+		desc = (u32 *)&cpu_gdt_table[get_cpu()];
+		desc = (void *)desc + (seg & ~7);
+	}
+
+	/* Decode the code segment base from the descriptor */
+	base =   (desc[0] >> 16) |
+		((desc[1] & 0xff) << 16) |
+		 (desc[1] & 0xff000000);
+
+	if (seg & (1<<2)) { 
+		up(&current->mm->context.sem);
+	} else
+		put_cpu();
+
+	/* Adjust EIP and segment limit, and clamp at the kernel limit.
+	   It's legitimate for segments to wrap at 0xffffffff. */
+	seg_limit += base;
+	if (seg_limit < *eip_limit && seg_limit >= base)
+		*eip_limit = seg_limit;
+	return eip + base;
+}
+
+/* 
+ * Sometimes AMD Athlon/Opteron CPUs report invalid exceptions on prefetch.
+ * Check that here and ignore it.
+ */
+static int __is_prefetch(struct pt_regs *regs, unsigned long addr)
+{ 
+	unsigned long limit;
+	unsigned long instr = get_segment_eip (regs, &limit);
+	int scan_more = 1;
+	int prefetch = 0; 
+	int i;
+
+	for (i = 0; scan_more && i < 15; i++) { 
+		unsigned char opcode;
+		unsigned char instr_hi;
+		unsigned char instr_lo;
+
+		if (instr > limit)
+			break;
+		if (__get_user(opcode, (unsigned char *) instr))
+			break; 
+
+		instr_hi = opcode & 0xf0; 
+		instr_lo = opcode & 0x0f; 
+		instr++;
+
+		switch (instr_hi) { 
+		case 0x20:
+		case 0x30:
+			/* Values 0x26,0x2E,0x36,0x3E are valid x86 prefixes. */
+			scan_more = ((instr_lo & 7) == 0x6);
+			break;
+			
+		case 0x60:
+			/* 0x64 thru 0x67 are valid prefixes in all modes. */
+			scan_more = (instr_lo & 0xC) == 0x4;
+			break;		
+		case 0xF0:
+			/* 0xF0, 0xF2, and 0xF3 are valid prefixes */
+			scan_more = !instr_lo || (instr_lo>>1) == 1;
+			break;			
+		case 0x00:
+			/* Prefetch instruction is 0x0F0D or 0x0F18 */
+			scan_more = 0;
+			if (instr > limit)
+				break;
+			if (__get_user(opcode, (unsigned char *) instr)) 
+				break;
+			prefetch = (instr_lo == 0xF) &&
+				(opcode == 0x0D || opcode == 0x18);
+			break;			
+		default:
+			scan_more = 0;
+			break;
+		} 
+	}
+	return prefetch;
+}
+
+static inline int is_prefetch(struct pt_regs *regs, unsigned long addr)
+{
+	if (unlikely(boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
+		     boot_cpu_data.x86 >= 6))
+		return __is_prefetch(regs, addr);
+	return 0;
+} 
+
 asmlinkage void do_invalid_op(struct pt_regs *, unsigned long);
 
 /*
@@ -86,6 +228,8 @@
 
 	tsk = current;
 
+	info.si_code = SEGV_MAPERR;
+
 	/*
 	 * We fault-in kernel-space virtual memory on-demand. The
 	 * 'reference' page table is init_mm.pgd.
@@ -99,18 +243,24 @@
 	 * (error_code & 4) == 0, and that the fault was not a
 	 * protection error (error_code & 1) == 0.
 	 */
-	if (address >= TASK_SIZE && !(error_code & 5))
-		goto vmalloc_fault;
+	if (unlikely(address >= TASK_SIZE)) { 
+		if (!(error_code & 5))
+			goto vmalloc_fault;
+		/* 
+		 * Don't take the mm semaphore here. If we fixup a prefetch
+		 * fault we could otherwise deadlock.
+		 */
+		goto bad_area_nosemaphore;
+	} 
 
 	mm = tsk->mm;
-	info.si_code = SEGV_MAPERR;
 
 	/*
 	 * If we're in an interrupt, have no user context or are running in an
 	 * atomic region then we must not take the fault..
 	 */
 	if (in_atomic() || !mm)
-		goto no_context;
+		goto bad_area_nosemaphore;
 
 	down_read(&mm->mmap_sem);
 
@@ -198,8 +348,16 @@
 bad_area:
 	up_read(&mm->mmap_sem);
 
+bad_area_nosemaphore:
 	/* User mode accesses just cause a SIGSEGV */
 	if (error_code & 4) {
+		/* 
+		 * Valid to do another page fault here because this one came 
+		 * from user space.
+		 */
+		if (is_prefetch(regs, address))
+			return;
+
 		tsk->thread.cr2 = address;
 		tsk->thread.error_code = error_code;
 		tsk->thread.trap_no = 14;
@@ -232,6 +390,14 @@
 	if (fixup_exception(regs))
 		return;
 
+	/* 
+	 * Valid to do another page fault here, because if this fault
+	 * had been triggered by is_prefetch fixup_exception would have 
+	 * handled it.
+	 */
+ 	if (is_prefetch(regs, address))
+ 		return;
+
 /*
  * Oops. The kernel tried to access some bad page. We'll have to
  * terminate things with extreme prejudice.
@@ -286,10 +452,14 @@
 do_sigbus:
 	up_read(&mm->mmap_sem);
 
-	/*
-	 * Send a sigbus, regardless of whether we were in kernel
-	 * or user mode.
-	 */
+	/* Kernel mode? Handle exceptions or die */
+	if (!(error_code & 4))
+		goto no_context;
+
+	/* User space => ok to do another page fault */
+	if (is_prefetch(regs, address))
+		return;
+
 	tsk->thread.cr2 = address;
 	tsk->thread.error_code = error_code;
 	tsk->thread.trap_no = 14;
@@ -298,10 +468,6 @@
 	info.si_code = BUS_ADRERR;
 	info.si_addr = (void *)address;
 	force_sig_info(SIGBUS, &info, tsk);
-
-	/* Kernel mode? Handle exceptions or die */
-	if (!(error_code & 4))
-		goto no_context;
 	return;
 
 vmalloc_fault:
diff -Nru a/arch/ia64/Kconfig b/arch/ia64/Kconfig
--- a/arch/ia64/Kconfig	Wed Oct 15 00:46:38 2003
+++ b/arch/ia64/Kconfig	Wed Oct 15 00:46:38 2003
@@ -220,24 +220,8 @@
 	  Access).  This option is for configuring high-end multiprocessor
 	  server systems.  If in doubt, say N.
 
-choice
-	prompt "Maximum Memory per NUMA Node" if NUMA && IA64_DIG
-	depends on NUMA && IA64_DIG
-	default IA64_NODESIZE_16GB
-
-config IA64_NODESIZE_16GB
-	bool "16GB"
-
-config IA64_NODESIZE_64GB
-	bool "64GB"
-
-config IA64_NODESIZE_256GB
-	bool "256GB"
-
-endchoice
-
 config DISCONTIGMEM
-	bool "Discontiguous memory support" if (IA64_DIG || IA64_SGI_SN2 || IA64_GENERIC) && NUMA
+	bool "Discontiguous memory support" if (IA64_DIG || IA64_SGI_SN2 || IA64_GENERIC) && NUMA && VIRTUAL_MEM_MAP
 	default y if (IA64_SGI_SN2 || IA64_GENERIC) && NUMA
 	help
 	  Say Y to support efficient handling of discontiguous physical memory,
@@ -250,14 +234,10 @@
 	default y if !IA64_HP_SIM
 	help
 	  Say Y to compile the kernel with support for a virtual mem map.
-	  This is an alternate method of supporting large holes in the
-	  physical address space on non NUMA machines. Since the DISCONTIGMEM
-	  option is not supported on machines with the ZX1 chipset, this is
-	  the only way of supporting more than 1 Gb of memory on those
-	  machines. This code also only takes effect if a memory hole of
-	  greater than 1 Gb is found during boot, so it is safe to enable
-	  unless you require the DISCONTIGMEM option for your machine. If you
-	  are unsure, say Y.
+	  This code also only takes effect if a memory hole of greater than
+	  1 Gb is found during boot.  You must turn this option on if you
+	  require the DISCONTIGMEM option for your machine. If you are
+	  unsure, say Y.
 
 config IA64_MCA
 	bool "Enable IA-64 Machine Check Abort"
diff -Nru a/arch/ia64/Makefile b/arch/ia64/Makefile
--- a/arch/ia64/Makefile	Wed Oct 15 00:46:35 2003
+++ b/arch/ia64/Makefile	Wed Oct 15 00:46:35 2003
@@ -64,7 +64,7 @@
 drivers-$(CONFIG_PCI)		+= arch/ia64/pci/
 drivers-$(CONFIG_IA64_HP_SIM)	+= arch/ia64/hp/sim/
 drivers-$(CONFIG_IA64_HP_ZX1)	+= arch/ia64/hp/common/ arch/ia64/hp/zx1/
-drivers-$(CONFIG_IA64_GENERIC)	+= arch/ia64/hp/common/ arch/ia64/hp/zx1/ arch/ia64/hp/sim/
+drivers-$(CONFIG_IA64_GENERIC)	+= arch/ia64/hp/common/ arch/ia64/hp/zx1/ arch/ia64/hp/sim/ arch/ia64/sn/
 drivers-$(CONFIG_OPROFILE)	+= arch/ia64/oprofile/
 
 boot := arch/ia64/hp/sim/boot
diff -Nru a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
--- a/arch/ia64/ia32/sys_ia32.c	Wed Oct 15 00:46:37 2003
+++ b/arch/ia64/ia32/sys_ia32.c	Wed Oct 15 00:46:37 2003
@@ -2486,11 +2486,14 @@
 putstat64 (struct stat64 *ubuf, struct kstat *kbuf)
 {
 	int err;
+	u64 hdev;
 
 	if (clear_user(ubuf, sizeof(*ubuf)))
 		return -EFAULT;
 
-	err  = __put_user(huge_encode_dev(kbuf->dev), &ubuf->st_dev);
+	hdev = huge_encode_dev(kbuf->dev);
+	err  = __put_user(hdev, (u32*)&ubuf->st_dev);
+	err |= __put_user(hdev >> 32, ((u32*)&ubuf->st_dev) + 1);
 	err |= __put_user(kbuf->ino, &ubuf->__st_ino);
 	err |= __put_user(kbuf->ino, &ubuf->st_ino_lo);
 	err |= __put_user(kbuf->ino >> 32, &ubuf->st_ino_hi);
@@ -2498,7 +2501,9 @@
 	err |= __put_user(kbuf->nlink, &ubuf->st_nlink);
 	err |= __put_user(kbuf->uid, &ubuf->st_uid);
 	err |= __put_user(kbuf->gid, &ubuf->st_gid);
-	err |= __put_user(huge_encode_dev(kbuf->rdev), &ubuf->st_rdev);
+	hdev = huge_encode_dev(kbuf->rdev);
+	err  = __put_user(hdev, (u32*)&ubuf->st_rdev);
+	err |= __put_user(hdev >> 32, ((u32*)&ubuf->st_rdev) + 1);
 	err |= __put_user(kbuf->size, &ubuf->st_size_lo);
 	err |= __put_user((kbuf->size >> 32), &ubuf->st_size_hi);
 	err |= __put_user(kbuf->atime.tv_sec, &ubuf->st_atime);
@@ -2724,8 +2729,8 @@
 struct epoll_event32
 {
 	u32 events;
-	u64 data;
-} __attribute__((packed));
+	u32 data[2];
+}; 
 
 asmlinkage long
 sys32_epoll_ctl(int epfd, int op, int fd, struct epoll_event32 *event)
@@ -2740,10 +2745,10 @@
 		return error;
 
 	__get_user(event64.events, &event->events);
-	__get_user(data_halfword, (u32*)(&event->data));
+	__get_user(data_halfword, &event->data[0]);
 	event64.data = data_halfword;
-	__get_user(data_halfword, ((u32*)(&event->data) + 1));
- 	event64.data |= ((u64)data_halfword) << 32;
+	__get_user(data_halfword, &event->data[1]);
+ 	event64.data |= (u64)data_halfword << 32;
 
 	set_fs(KERNEL_DS);
 	error = sys_epoll_ctl(epfd, op, fd, &event64);
@@ -2758,8 +2763,9 @@
 {
 	struct epoll_event *events64 = NULL;
 	mm_segment_t old_fs = get_fs();
-	int error;
+	int error, numevents, size;
 	int evt_idx;
+	int do_free_pages = 0;
 
 	if (maxevents <= 0) {
 		return -EINVAL;
@@ -2770,43 +2776,45 @@
 				 maxevents * sizeof(struct epoll_event32))))
 		return error;
 
-	/* Allocate the space needed for the intermediate copy */
-	events64 = kmalloc(maxevents * sizeof(struct epoll_event), GFP_KERNEL);
+	/* 
+ 	 * Allocate space for the intermediate copy.  If the space needed 
+	 * is large enough to cause kmalloc to fail, then try again with
+	 * __get_free_pages.
+	 */
+	size = maxevents * sizeof(struct epoll_event);
+	events64 = kmalloc(size, GFP_KERNEL);
 	if (events64 == NULL) {
-		return -ENOMEM;
-	}
-
-	/* Expand the 32-bit structures into the 64-bit structures */
-	for (evt_idx = 0; evt_idx < maxevents; evt_idx++) {
-		u32 data_halfword;
-		__get_user(events64[evt_idx].events, &events[evt_idx].events);
-		__get_user(data_halfword, (u32*)(&events[evt_idx].data));
-		events64[evt_idx].data = data_halfword;
-		__get_user(data_halfword, ((u32*)(&events[evt_idx].data) + 1));
-		events64[evt_idx].data |= ((u64)data_halfword) << 32;
+		events64 = (struct epoll_event *)
+				__get_free_pages(GFP_KERNEL, get_order(size));
+		if (events64 == NULL) 
+			return -ENOMEM;
+		do_free_pages = 1;
 	}
 
 	/* Do the system call */
 	set_fs(KERNEL_DS); /* copy_to/from_user should work on kernel mem*/
-	error = sys_epoll_wait(epfd, events64, maxevents, timeout);
+	numevents = sys_epoll_wait(epfd, events64, maxevents, timeout);
 	set_fs(old_fs);
 
 	/* Don't modify userspace memory if we're returning an error */
-	if (!error) {
+	if (numevents > 0) {
 		/* Translate the 64-bit structures back into the 32-bit
 		   structures */
-		for (evt_idx = 0; evt_idx < maxevents; evt_idx++) {
+		for (evt_idx = 0; evt_idx < numevents; evt_idx++) {
 			__put_user(events64[evt_idx].events,
 				   &events[evt_idx].events);
-			__put_user((u32)(events64[evt_idx].data),
-				   (u32*)(&events[evt_idx].data));
+			__put_user((u32)events64[evt_idx].data,
+				   &events[evt_idx].data[0]);
 			__put_user((u32)(events64[evt_idx].data >> 32),
-				   ((u32*)(&events[evt_idx].data) + 1));
+				   &events[evt_idx].data[1]);
 		}
 	}
 
-	kfree(events64);
-	return error;
+	if (do_free_pages)
+		free_pages((unsigned long) events64, get_order(size));
+	else
+		kfree(events64);
+	return numevents;
 }
 
 #ifdef	NOTYET  /* UNTESTED FOR IA64 FROM HERE DOWN */
diff -Nru a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
--- a/arch/ia64/kernel/acpi.c	Wed Oct 15 00:46:36 2003
+++ b/arch/ia64/kernel/acpi.c	Wed Oct 15 00:46:36 2003
@@ -380,7 +380,7 @@
 void __init
 acpi_numa_memory_affinity_init (struct acpi_table_memory_affinity *ma)
 {
-	unsigned long paddr, size, hole_size, min_hole_size;
+	unsigned long paddr, size;
 	u8 pxm;
 	struct node_memblk_s *p, *q, *pend;
 
@@ -402,34 +402,6 @@
 	if (!ma->flags.enabled)
 		return;
 
-	/*
-	 * When the chunk is not the first one in the node, check distance
-	 * from the other chunks. When the hole is too huge ignore the chunk.
-	 * This restriction should be removed when multiple chunks per node
-	 * is supported.
-	 */
-	pend = &node_memblk[num_memblks];
-	min_hole_size = 0;
-	for (p = &node_memblk[0]; p < pend; p++) {
-		if (p->nid != pxm)
-			continue;
-		if (p->start_paddr < paddr)
-			hole_size = paddr - (p->start_paddr + p->size);
-		else
-			hole_size = p->start_paddr - (paddr + size);
-
-		if (!min_hole_size || hole_size < min_hole_size)
-			min_hole_size = hole_size;
-	}
-
-	if (min_hole_size) {
-		if (min_hole_size > size) {
-			printk(KERN_ERR "Too huge memory hole. Ignoring %ld MBytes at %lx\n",
-			       size/(1024*1024), paddr);
-			return;
-		}
-	}
-
 	/* record this node in proximity bitmap */
 	pxm_bit_set(pxm);
 
@@ -454,6 +426,12 @@
 {
 	int i, j, node_from, node_to;
 
+	/* If there's no SRAT, fix the phys_id */
+	if (srat_num_cpus == 0) {
+		node_cpuid[0].phys_id = hard_smp_processor_id();
+		return;
+	}
+
 	/* calculate total number of nodes in system from PXM bitmap */
 	numnodes = 0;		/* init total nodes in system */
 
@@ -614,6 +592,12 @@
 
 	smp_build_cpu_map();
 # ifdef CONFIG_NUMA
+	if (srat_num_cpus == 0) {
+		int cpu, i = 1;
+		for (cpu = 0; cpu < smp_boot_data.cpu_count; cpu++)
+			if (smp_boot_data.cpu_phys_id[cpu] != hard_smp_processor_id())
+				node_cpuid[i++].phys_id = smp_boot_data.cpu_phys_id[cpu];
+	}
 	build_cpu_to_node_map();
 # endif
 #endif
diff -Nru a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S
--- a/arch/ia64/kernel/mca_asm.S	Wed Oct 15 00:46:37 2003
+++ b/arch/ia64/kernel/mca_asm.S	Wed Oct 15 00:46:37 2003
@@ -265,15 +265,15 @@
 	add		r4=8,r2                  // duplicate r2 in r4
 	add		r6=2*8,r2                // duplicate r2 in r4
 
-	mov		r3=cr0                      // cr.dcr
-	mov		r5=cr1                      // cr.itm
-	mov		r7=cr2;;                    // cr.iva
+	mov		r3=cr.dcr
+	mov		r5=cr.itm
+	mov		r7=cr.iva;;
 
 	st8		[r2]=r3,8*8
 	st8		[r4]=r5,3*8
 	st8		[r6]=r7,3*8;;            // 48 byte rements
 
-	mov		r3=cr8;;                    // cr.pta
+	mov		r3=cr.pta;;
 	st8		[r2]=r3,8*8;;            // 64 byte rements
 
 // if PSR.ic=0, reading interruption registers causes an illegal operation fault
@@ -286,23 +286,23 @@
 	add		r4=8,r2                  // duplicate r2 in r4
 	add		r6=2*8,r2                // duplicate r2 in r6
 
-	mov		r3=cr16                     // cr.ipsr
-	mov		r5=cr17                     // cr.isr
-        mov     r7=r0;;                     // cr.ida => cr18 (reserved)
+	mov		r3=cr.ipsr
+	mov		r5=cr.isr
+	mov		r7=r0;;
 	st8		[r2]=r3,3*8
 	st8		[r4]=r5,3*8
 	st8		[r6]=r7,3*8;;
 
-	mov		r3=cr19                     // cr.iip
-	mov		r5=cr20                     // cr.idtr
-	mov		r7=cr21;;                   // cr.iitr
+	mov		r3=cr.iip
+	mov		r5=cr.ifa
+	mov		r7=cr.itir;;
 	st8		[r2]=r3,3*8
 	st8		[r4]=r5,3*8
 	st8		[r6]=r7,3*8;;
 
-	mov		r3=cr22                     // cr.iipa
-	mov		r5=cr23                     // cr.ifs
-	mov		r7=cr24;;                   // cr.iim
+	mov		r3=cr.iipa
+	mov		r5=cr.ifs
+	mov		r7=cr.iim;;
 	st8		[r2]=r3,3*8
 	st8		[r4]=r5,3*8
 	st8		[r6]=r7,3*8;;
@@ -311,104 +311,101 @@
 	st8		[r2]=r3,160;;               // 160 byte rement
 
 SkipIntrRegs:
-	st8		[r2]=r0,168                 // another 168 byte .
+	st8		[r2]=r0,152;;               // another 152 byte .
 
-	mov		r3=cr66;;                   // cr.lid
-	st8		[r2]=r3,40                  // 40 byte rement
+	add		r4=8,r2                     // duplicate r2 in r4
+	add		r6=2*8,r2                   // duplicate r2 in r6
 
-	mov		r3=cr71;;                   // cr.ivr
-	st8		[r2]=r3,8
-
-	mov		r3=cr72;;                   // cr.tpr
-	st8		[r2]=r3,24                  // 24 byte increment
-
-	mov		r3=r0;;                     // cr.eoi => cr75
-	st8		[r2]=r3,168                 // 168 byte inc.
-
-	mov		r3=r0;;                     // cr.irr0 => cr96
-	st8		[r2]=r3,16               // 16 byte inc.
-
-	mov		r3=r0;;                     // cr.irr1 => cr98
-	st8		[r2]=r3,16               // 16 byte inc.
-
-	mov		r3=r0;;                     // cr.irr2 => cr100
-	st8		[r2]=r3,16               // 16 byte inc
-
-	mov		r3=r0;;                     // cr.irr3 => cr100
-	st8		[r2]=r3,16               // 16b inc.
-
-	mov		r3=r0;;                     // cr.itv => cr114
-	st8		[r2]=r3,16               // 16 byte inc.
+	mov		r3=cr.lid
+//	mov		r5=cr.ivr                     // cr.ivr, don't read it
+	mov		r7=cr.tpr;;
+	st8		[r2]=r3,3*8
+	st8		[r4]=r5,3*8
+	st8		[r6]=r7,3*8;;
 
-	mov		r3=r0;;                     // cr.pmv => cr116
-	st8		[r2]=r3,8
+	mov		r3=r0                       // cr.eoi => cr67
+	mov		r5=r0                       // cr.irr0 => cr68
+	mov		r7=r0;;                     // cr.irr1 => cr69
+	st8		[r2]=r3,3*8
+	st8		[r4]=r5,3*8
+	st8		[r6]=r7,3*8;;
 
-	mov		r3=r0;;                     // cr.lrr0 => cr117
-	st8		[r2]=r3,8
+	mov		r3=r0                       // cr.irr2 => cr70
+	mov		r5=r0                       // cr.irr3 => cr71
+	mov		r7=cr.itv;;
+	st8		[r2]=r3,3*8
+	st8		[r4]=r5,3*8
+	st8		[r6]=r7,3*8;;
 
-	mov		r3=r0;;                     // cr.lrr1 => cr118
-	st8		[r2]=r3,8
+	mov		r3=cr.pmv
+	mov		r5=cr.cmcv;;
+	st8		[r2]=r3,7*8
+	st8		[r4]=r5,7*8;;
+
+	mov		r3=r0                       // cr.lrr0 => cr80
+	mov		r5=r0;;                     // cr.lrr1 => cr81
+	st8		[r2]=r3,23*8
+	st8		[r4]=r5,23*8;;
 
-	mov		r3=r0;;                     // cr.cmcv => cr119
-	st8		[r2]=r3,8*10;;
+	adds		r2=25*8,r2;;
 
 cSaveARs:
 // save ARs
 	add		r4=8,r2                  // duplicate r2 in r4
 	add		r6=2*8,r2                // duplicate r2 in r6
 
-	mov		r3=ar0                      // ar.kro
-	mov		r5=ar1                      // ar.kr1
-	mov		r7=ar2;;                    // ar.kr2
+	mov		r3=ar.k0
+	mov		r5=ar.k1
+	mov		r7=ar.k2;;
 	st8		[r2]=r3,3*8
 	st8		[r4]=r5,3*8
 	st8		[r6]=r7,3*8;;
 
-	mov		r3=ar3                      // ar.kr3
-	mov		r5=ar4                      // ar.kr4
-	mov		r7=ar5;;                    // ar.kr5
+	mov		r3=ar.k3
+	mov		r5=ar.k4
+	mov		r7=ar.k5;;
 	st8		[r2]=r3,3*8
 	st8		[r4]=r5,3*8
 	st8		[r6]=r7,3*8;;
 
-	mov		r3=ar6                      // ar.kr6
-	mov		r5=ar7                      // ar.kr7
+	mov		r3=ar.k6
+	mov		r5=ar.k7
 	mov		r7=r0;;                     // ar.kr8
 	st8		[r2]=r3,10*8
 	st8		[r4]=r5,10*8
 	st8		[r6]=r7,10*8;;           // rement by 72 bytes
 
-	mov		r3=ar16                     // ar.rsc
-	mov		ar16=r0			    // put RSE in enforced lazy mode
-	mov		r5=ar17                     // ar.bsp
+	mov		r3=ar.rsc
+	mov		ar.rsc=r0			    // put RSE in enforced lazy mode
+	mov		r5=ar.bsp
 	;;
-	mov		r7=ar18;;                   // ar.bspstore
+	mov		r7=ar.bspstore;;
 	st8		[r2]=r3,3*8
 	st8		[r4]=r5,3*8
 	st8		[r6]=r7,3*8;;
 
-	mov		r3=ar19;;                   // ar.rnat
+	mov		r3=ar.rnat;;
 	st8		[r2]=r3,8*13             // increment by 13x8 bytes
 
-	mov		r3=ar32;;                   // ar.ccv
+	mov		r3=ar.ccv;;
 	st8		[r2]=r3,8*4
 
-	mov		r3=ar36;;                   // ar.unat
+	mov		r3=ar.unat;;
 	st8		[r2]=r3,8*4
 
-	mov		r3=ar40;;                   // ar.fpsr
+	mov		r3=ar.fpsr;;
 	st8		[r2]=r3,8*4
 
-	mov		r3=ar44;;                   // ar.itc
+	mov		r3=ar.itc;;
 	st8		[r2]=r3,160                 // 160
 
-	mov		r3=ar64;;                   // ar.pfs
+	mov		r3=ar.pfs;;
 	st8		[r2]=r3,8
 
-	mov		r3=ar65;;                   // ar.lc
+	mov		r3=ar.lc;;
 	st8		[r2]=r3,8
 
-	mov		r3=ar66;;                   // ar.ec
+	mov		r3=ar.ec;;
 	st8		[r2]=r3
 	add		r2=8*62,r2               //padding
 
@@ -417,7 +414,8 @@
 	movl		r4=0x00;;
 
 cStRR:
-	mov		r3=rr[r4];;
+	dep.z		r5=r4,61,3;;
+	mov		r3=rr[r5];;
 	st8		[r2]=r3,8
 	add		r4=1,r4
 	br.cloop.sptk.few	cStRR
@@ -501,12 +499,12 @@
 	ld8		r3=[r2],8*8
 	ld8		r5=[r4],3*8
 	ld8		r7=[r6],3*8;;            // 48 byte increments
-	mov		cr0=r3                      // cr.dcr
-	mov		cr1=r5                      // cr.itm
-	mov		cr2=r7;;                    // cr.iva
+	mov		cr.dcr=r3
+	mov		cr.itm=r5
+	mov		cr.iva=r7;;
 
 	ld8		r3=[r2],8*8;;            // 64 byte increments
-//      mov		cr8=r3                      // cr.pta
+//      mov		cr.pta=r3
 
 
 // if PSR.ic=1, reading interruption registers causes an illegal operation fault
@@ -523,64 +521,66 @@
 	ld8		r3=[r2],3*8
 	ld8		r5=[r4],3*8
 	ld8		r7=[r6],3*8;;
-	mov		cr16=r3                     // cr.ipsr
-	mov		cr17=r5                     // cr.isr is read only
-//      mov     cr18=r7;;                   // cr.ida (reserved - don't restore)
+	mov		cr.ipsr=r3
+//	mov		cr.isr=r5                   // cr.isr is read only
 
 	ld8		r3=[r2],3*8
 	ld8		r5=[r4],3*8
 	ld8		r7=[r6],3*8;;
-	mov		cr19=r3                     // cr.iip
-	mov		cr20=r5                     // cr.idtr
-	mov		cr21=r7;;                   // cr.iitr
+	mov		cr.iip=r3
+	mov		cr.ifa=r5
+	mov		cr.itir=r7;;
 
 	ld8		r3=[r2],3*8
 	ld8		r5=[r4],3*8
 	ld8		r7=[r6],3*8;;
-	mov		cr22=r3                     // cr.iipa
-	mov		cr23=r5                     // cr.ifs
-	mov		cr24=r7                     // cr.iim
+	mov		cr.iipa=r3
+	mov		cr.ifs=r5
+	mov		cr.iim=r7
 
 	ld8		r3=[r2],160;;               // 160 byte increment
-	mov		cr25=r3                     // cr.iha
+	mov		cr.iha=r3
 
 rSkipIntrRegs:
-	ld8		r3=[r2],168;;               // another 168 byte inc.
-
-	ld8		r3=[r2],40;;                // 40 byte increment
-	mov		cr66=r3                     // cr.lid
-
-	ld8		r3=[r2],8;;
-//      mov		cr71=r3                     // cr.ivr is read only
-	ld8		r3=[r2],24;;                // 24 byte increment
-	mov		cr72=r3                     // cr.tpr
-
-	ld8		r3=[r2],168;;               // 168 byte inc.
-//      mov		cr75=r3                     // cr.eoi
+	ld8		r3=[r2],152;;               // another 152 byte inc.
 
-	ld8		r3=[r2],16;;             // 16 byte inc.
-//      mov		cr96=r3                     // cr.irr0 is read only
+	add		r4=8,r2                     // duplicate r2 in r4
+	add		r6=2*8,r2;;                 // duplicate r2 in r6
 
-	ld8		r3=[r2],16;;             // 16 byte inc.
-//      mov		cr98=r3                     // cr.irr1 is read only
+	ld8		r3=[r2],8*3
+	ld8		r5=[r4],8*3
+	ld8		r7=[r6],8*3;;
+	mov		cr.lid=r3
+//	mov		cr.ivr=r5                   // cr.ivr is read only
+	mov		cr.tpr=r7;;
+
+	ld8		r3=[r2],8*3
+	ld8		r5=[r4],8*3
+	ld8		r7=[r6],8*3;;
+//	mov		cr.eoi=r3
+//	mov		cr.irr0=r5                  // cr.irr0 is read only
+//	mov		cr.irr1=r7;;                // cr.irr1 is read only
+
+	ld8		r3=[r2],8*3
+	ld8		r5=[r4],8*3
+	ld8		r7=[r6],8*3;;
+//	mov		cr.irr2=r3                  // cr.irr2 is read only
+//	mov		cr.irr3=r5                  // cr.irr3 is read only
+	mov		cr.itv=r7;;
+
+	ld8		r3=[r2],8*7
+	ld8		r5=[r4],8*7;;
+	mov		cr.pmv=r3
+	mov		cr.cmcv=r5;;
+
+	ld8		r3=[r2],8*23
+	ld8		r5=[r4],8*23;;
+	adds		r2=8*23,r2
+	adds		r4=8*23,r4;;
+//	mov		cr.lrr0=r3
+//	mov		cr.lrr1=r5
 
-	ld8		r3=[r2],16;;             // 16 byte inc
-//      mov		cr100=r3                    // cr.irr2 is read only
-
-	ld8		r3=[r2],16;;             // 16b inc.
-//      mov		cr102=r3                    // cr.irr3 is read only
-
-	ld8		r3=[r2],16;;             // 16 byte inc.
-//      mov		cr114=r3                    // cr.itv
-
-	ld8		r3=[r2],8;;
-//      mov		cr116=r3                    // cr.pmv
-	ld8		r3=[r2],8;;
-//      mov		cr117=r3                    // cr.lrr0
-	ld8		r3=[r2],8;;
-//      mov		cr118=r3                    // cr.lrr1
-	ld8		r3=[r2],8*10;;
-//      mov		cr119=r3                    // cr.cmcv
+	adds		r2=8*2,r2;;
 
 restore_ARs:
 	add		r4=8,r2                  // duplicate r2 in r4
@@ -589,67 +589,67 @@
 	ld8		r3=[r2],3*8
 	ld8		r5=[r4],3*8
 	ld8		r7=[r6],3*8;;
-	mov		ar0=r3                      // ar.kro
-	mov		ar1=r5                      // ar.kr1
-	mov		ar2=r7;;                    // ar.kr2
+	mov		ar.k0=r3
+	mov		ar.k1=r5
+	mov		ar.k2=r7;;
 
 	ld8		r3=[r2],3*8
 	ld8		r5=[r4],3*8
 	ld8		r7=[r6],3*8;;
-	mov		ar3=r3                      // ar.kr3
-	mov		ar4=r5                      // ar.kr4
-	mov		ar5=r7;;                    // ar.kr5
+	mov		ar.k3=r3
+	mov		ar.k4=r5
+	mov		ar.k5=r7;;
 
 	ld8		r3=[r2],10*8
 	ld8		r5=[r4],10*8
 	ld8		r7=[r6],10*8;;
-	mov		ar6=r3                      // ar.kr6
-	mov		ar7=r5                      // ar.kr7
-//      mov		ar8=r6                      // ar.kr8
+	mov		ar.k6=r3
+	mov		ar.k7=r5
 	;;
 
 	ld8		r3=[r2],3*8
 	ld8		r5=[r4],3*8
 	ld8		r7=[r6],3*8;;
-//      mov		ar16=r3                     // ar.rsc
-//      mov		ar17=r5                     // ar.bsp is read only
-	mov		ar16=r0			    // make sure that RSE is in enforced lazy mode
+//	mov		ar.rsc=r3
+//	mov		ar.bsp=r5                   // ar.bsp is read only
+	mov		ar.rsc=r0			    // make sure that RSE is in enforced lazy mode
 	;;
-	mov		ar18=r7;;                   // ar.bspstore
+	mov		ar.bspstore=r7;;
 
 	ld8		r9=[r2],8*13;;
-	mov		ar19=r9                     // ar.rnat
+	mov		ar.rnat=r9
 
-	mov		ar16=r3			    // ar.rsc
+	mov		ar.rsc=r3
 	ld8		r3=[r2],8*4;;
-	mov		ar32=r3                     // ar.ccv
+	mov		ar.ccv=r3
 
 	ld8		r3=[r2],8*4;;
-	mov		ar36=r3                     // ar.unat
+	mov		ar.unat=r3
 
 	ld8		r3=[r2],8*4;;
-	mov		ar40=r3                     // ar.fpsr
+	mov		ar.fpsr=r3
 
 	ld8		r3=[r2],160;;               // 160
-//      mov		ar44=r3                     // ar.itc
+//      mov		ar.itc=r3
 
 	ld8		r3=[r2],8;;
-	mov		ar64=r3                     // ar.pfs
+	mov		ar.pfs=r3
 
 	ld8		r3=[r2],8;;
-	mov		ar65=r3                     // ar.lc
+	mov		ar.lc=r3
 
 	ld8		r3=[r2];;
-	mov		ar66=r3                     // ar.ec
+	mov		ar.ec=r3
 	add		r2=8*62,r2;;             // padding
 
 restore_RRs:
 	mov		r5=ar.lc
 	mov		ar.lc=0x08-1
-	movl		r4=0x00
+	movl		r4=0x00;;
 cStRRr:
+	dep.z		r7=r4,61,3
 	ld8		r3=[r2],8;;
-//      mov		rr[r4]=r3                   // what are its access previledges?
+	mov		rr[r7]=r3                   // what are its access previledges?
 	add		r4=1,r4
 	br.cloop.sptk.few	cStRRr
 	;;
diff -Nru a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
--- a/arch/ia64/kernel/setup.c	Wed Oct 15 00:46:36 2003
+++ b/arch/ia64/kernel/setup.c	Wed Oct 15 00:46:36 2003
@@ -101,7 +101,7 @@
 filter_rsvd_memory (unsigned long start, unsigned long end, void *arg)
 {
 	unsigned long range_start, range_end, prev_start;
-	void (*func)(unsigned long, unsigned long);
+	void (*func)(unsigned long, unsigned long, int);
 	int i;
 
 #if IGNORE_PFN0
@@ -122,11 +122,7 @@
 		range_end   = min(end, rsvd_region[i].start);
 
 		if (range_start < range_end)
-#ifdef CONFIG_DISCONTIGMEM
-			call_pernode_memory(__pa(range_start), __pa(range_end), func);
-#else
-			(*func)(__pa(range_start), range_end - range_start);
-#endif
+			call_pernode_memory(__pa(range_start), range_end - range_start, func);
 
 		/* nothing more available in this segment */
 		if (range_end == end) return 0;
@@ -239,7 +235,6 @@
 	strlcpy(saved_command_line, *cmdline_p, sizeof(saved_command_line));
 
 	efi_init();
-	find_memory();
 
 #ifdef CONFIG_ACPI_BOOT
 	/* Initialize the ACPI boot-time table parser */
@@ -253,6 +248,8 @@
 # endif
 #endif /* CONFIG_APCI_BOOT */
 
+	find_memory();
+
 	/* process SAL system table: */
 	ia64_sal_init(efi.sal_systab);
 
@@ -544,28 +541,7 @@
 	struct cpuinfo_ia64 *cpu_info;
 	void *cpu_data;
 
-#ifdef CONFIG_SMP
-	int cpu;
-
-	/*
-	 * get_free_pages() cannot be used before cpu_init() done.  BSP allocates
-	 * "NR_CPUS" pages for all CPUs to avoid that AP calls get_zeroed_page().
-	 */
-	if (smp_processor_id() == 0) {
-		cpu_data = __alloc_bootmem(PERCPU_PAGE_SIZE * NR_CPUS, PERCPU_PAGE_SIZE,
-					   __pa(MAX_DMA_ADDRESS));
-		for (cpu = 0; cpu < NR_CPUS; cpu++) {
-			memcpy(cpu_data, __phys_per_cpu_start, __per_cpu_end - __per_cpu_start);
-			__per_cpu_offset[cpu] = (char *) cpu_data - __per_cpu_start;
-			cpu_data += PERCPU_PAGE_SIZE;
-
-			per_cpu(local_per_cpu_offset, cpu) = __per_cpu_offset[cpu];
-		}
-	}
-	cpu_data = __per_cpu_start + __per_cpu_offset[smp_processor_id()];
-#else /* !CONFIG_SMP */
-	cpu_data = __phys_per_cpu_start;
-#endif /* !CONFIG_SMP */
+	cpu_data = per_cpu_init();
 
 	get_max_cacheline_size();
 
@@ -576,9 +552,6 @@
 	 * accessing cpu_data() through the canonical per-CPU address.
 	 */
 	cpu_info = cpu_data + ((char *) &__ia64_per_cpu_var(cpu_info) - __per_cpu_start);
-#ifdef CONFIG_NUMA
-	cpu_info->node_data = get_node_data_ptr();
-#endif
 	identify_cpu(cpu_info);
 
 #ifdef CONFIG_MCKINLEY
diff -Nru a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c
--- a/arch/ia64/kernel/unaligned.c	Wed Oct 15 00:46:37 2003
+++ b/arch/ia64/kernel/unaligned.c	Wed Oct 15 00:46:37 2003
@@ -1347,7 +1347,7 @@
 			 * be holding locks...
 			 */
 			if (user_mode(regs))
-				tty_write_message(process_tty(current), buf);
+				tty_write_message(current->tty, buf);
 			buf[len-1] = '\0';	/* drop '\r' */
 			printk(KERN_WARNING "%s", buf);	/* watch for command names containing %s */
 		}
diff -Nru a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c
--- a/arch/ia64/mm/contig.c	Wed Oct 15 00:46:36 2003
+++ b/arch/ia64/mm/contig.c	Wed Oct 15 00:46:36 2003
@@ -25,6 +25,10 @@
 #include <asm/pgtable.h>
 #include <asm/sections.h>
 
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+static unsigned long num_dma_physpages;
+#endif
+
 /**
  * show_mem - display a memory statistics summary
  *
@@ -160,4 +164,134 @@
 	reserve_bootmem(bootmap_start, bootmap_size);
 
 	find_initrd();
+}
+
+#ifdef CONFIG_SMP
+/**
+ * per_cpu_init - setup per-cpu variables
+ *
+ * Allocate and setup per-cpu data areas.
+ */
+void *
+per_cpu_init (void)
+{
+	void *cpu_data;
+	int cpu;
+
+	/*
+	 * get_free_pages() cannot be used before cpu_init() done.  BSP
+	 * allocates "NR_CPUS" pages for all CPUs to avoid that AP calls
+	 * get_zeroed_page().
+	 */
+	if (smp_processor_id() == 0) {
+		cpu_data = __alloc_bootmem(PERCPU_PAGE_SIZE * NR_CPUS,
+					   PERCPU_PAGE_SIZE, __pa(MAX_DMA_ADDRESS));
+		for (cpu = 0; cpu < NR_CPUS; cpu++) {
+			memcpy(cpu_data, __phys_per_cpu_start, __per_cpu_end - __per_cpu_start);
+			__per_cpu_offset[cpu] = (char *) cpu_data - __per_cpu_start;
+			cpu_data += PERCPU_PAGE_SIZE;
+			per_cpu(local_per_cpu_offset, cpu) = __per_cpu_offset[cpu];
+		}
+	}
+	return __per_cpu_start + __per_cpu_offset[smp_processor_id()];
+}
+#endif /* CONFIG_SMP */
+
+static int
+count_pages (u64 start, u64 end, void *arg)
+{
+	unsigned long *count = arg;
+
+	*count += (end - start) >> PAGE_SHIFT;
+	return 0;
+}
+
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+static int
+count_dma_pages (u64 start, u64 end, void *arg)
+{
+	unsigned long *count = arg;
+
+	if (end <= MAX_DMA_ADDRESS)
+		*count += (end - start) >> PAGE_SHIFT;
+	return 0;
+}
+#endif
+
+/*
+ * Set up the page tables.
+ */
+
+void
+paging_init (void)
+{
+	unsigned long max_dma;
+	unsigned long zones_size[MAX_NR_ZONES];
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+	unsigned long zholes_size[MAX_NR_ZONES];
+	unsigned long max_gap;
+#endif
+
+	/* initialize mem_map[] */
+
+	memset(zones_size, 0, sizeof(zones_size));
+
+	num_physpages = 0;
+	efi_memmap_walk(count_pages, &num_physpages);
+
+	max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+	memset(zholes_size, 0, sizeof(zholes_size));
+
+	num_dma_physpages = 0;
+	efi_memmap_walk(count_dma_pages, &num_dma_physpages);
+
+	if (max_low_pfn < max_dma) {
+		zones_size[ZONE_DMA] = max_low_pfn;
+		zholes_size[ZONE_DMA] = max_low_pfn - num_dma_physpages;
+	} else {
+		zones_size[ZONE_DMA] = max_dma;
+		zholes_size[ZONE_DMA] = max_dma - num_dma_physpages;
+		if (num_physpages > num_dma_physpages) {
+			zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
+			zholes_size[ZONE_NORMAL] =
+				((max_low_pfn - max_dma) -
+				 (num_physpages - num_dma_physpages));
+		}
+	}
+
+	max_gap = 0;
+	efi_memmap_walk(find_largest_hole, (u64 *)&max_gap);
+	if (max_gap < LARGE_GAP) {
+		vmem_map = (struct page *) 0;
+		free_area_init_node(0, &contig_page_data, NULL, zones_size, 0,
+				    zholes_size);
+		mem_map = contig_page_data.node_mem_map;
+	} else {
+		unsigned long map_size;
+
+		/* allocate virtual_mem_map */
+
+		map_size = PAGE_ALIGN(max_low_pfn * sizeof(struct page));
+		vmalloc_end -= map_size;
+		vmem_map = (struct page *) vmalloc_end;
+		efi_memmap_walk(create_mem_map_page_table, 0);
+
+		free_area_init_node(0, &contig_page_data, vmem_map, zones_size,
+				    0, zholes_size);
+
+		mem_map = contig_page_data.node_mem_map;
+		printk("Virtual mem_map starts at 0x%p\n", mem_map);
+	}
+#else /* !CONFIG_VIRTUAL_MEM_MAP */
+	if (max_low_pfn < max_dma)
+		zones_size[ZONE_DMA] = max_low_pfn;
+	else {
+		zones_size[ZONE_DMA] = max_dma;
+		zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
+	}
+	free_area_init(zones_size);
+#endif /* !CONFIG_VIRTUAL_MEM_MAP */
+	zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page));
 }
diff -Nru a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
--- a/arch/ia64/mm/discontig.c	Wed Oct 15 00:46:37 2003
+++ b/arch/ia64/mm/discontig.c	Wed Oct 15 00:46:37 2003
@@ -17,72 +17,57 @@
 #include <linux/acpi.h>
 #include <linux/efi.h>
 #include <asm/pgalloc.h>
+#include <asm/tlb.h>
 #include <asm/meminit.h>
-
-
-/*
- * Round an address upward to the next multiple of GRANULE size.
- */
-#define GRANULEROUNDUP(n) (((n)+IA64_GRANULE_SIZE-1) & ~(IA64_GRANULE_SIZE-1))
-
-static struct ia64_node_data	*node_data[MAX_NUMNODES];
-static long			boot_pg_data[8*MAX_NUMNODES+sizeof(pg_data_t)]  __initdata;
-static pg_data_t		*pg_data_ptr[MAX_NUMNODES] __initdata;
-static bootmem_data_t		bdata[MAX_NUMNODES][NR_BANKS_PER_NODE+1] __initdata;
-/*
- * Return the compact node number of this cpu. Used prior to
- * setting up the cpu_data area.
- *	Note - not fast, intended for boot use only!!
- */
-int
-boot_get_local_nodeid(void)
-{
-	int	i;
-
-	for (i = 0; i < NR_CPUS; i++)
-		if (node_cpuid[i].phys_id == hard_smp_processor_id())
-			return node_cpuid[i].nid;
-
-	/* node info missing, so nid should be 0.. */
-	return 0;
-}
+#include <asm/numa.h>
+#include <asm/sections.h>
 
 /*
- * Return a pointer to the pg_data structure for a node.
- * This function is used ONLY in early boot before the cpu_data
- * structure is available.
+ * Track per-node information needed to setup the boot memory allocator, the
+ * per-node areas, and the real VM.
  */
-pg_data_t* __init
-boot_get_pg_data_ptr(long node)
-{
-	return pg_data_ptr[node];
-}
-
-
-/*
- * Return a pointer to the node data for the current node.
- *	(boottime initialization only)
+struct early_node_data {
+	struct ia64_node_data *node_data;
+	pg_data_t *pgdat;
+	unsigned long pernode_addr;
+	unsigned long pernode_size;
+	struct bootmem_data bootmem_data;
+	unsigned long num_physpages;
+	unsigned long num_dma_physpages;
+	unsigned long min_pfn;
+	unsigned long max_pfn;
+};
+
+static struct early_node_data mem_data[NR_NODES] __initdata;
+
+/*
+ * To prevent cache aliasing effects, align per-node structures so that they
+ * start at addresses that are strided by node number.
+ */
+#define NODEDATA_ALIGN(addr, node)						\
+	((((addr) + 1024*1024-1) & ~(1024*1024-1)) + (node)*PERCPU_PAGE_SIZE)
+
+/**
+ * build_node_maps - callback to setup bootmem structs for each node
+ * @start: physical start of range
+ * @len: length of range
+ * @node: node where this range resides
+ *
+ * We allocate a struct bootmem_data for each piece of memory that we wish to
+ * treat as a virtually contiguous block (i.e. each node). Each such block
+ * must start on an %IA64_GRANULE_SIZE boundary, so we round the address down
+ * if necessary.  Any non-existent pages will simply be part of the virtual
+ * memmap.  We also update min_low_pfn and max_low_pfn here as we receive
+ * memory ranges from the caller.
  */
-struct ia64_node_data *
-get_node_data_ptr(void)
+static int __init build_node_maps(unsigned long start, unsigned long len,
+				  int node)
 {
-	return node_data[boot_get_local_nodeid()];
-}
+	unsigned long cstart, epfn, end = start + len;
+	struct bootmem_data *bdp = &mem_data[node].bootmem_data;
 
-/*
- * We allocate one of the bootmem_data_t structs for each piece of memory
- * that we wish to treat as a contiguous block.  Each such block must start
- * on a BANKSIZE boundary.  Multiple banks per node is not supported.
- */
-static int __init
-build_maps(unsigned long pstart, unsigned long length, int node)
-{
-	bootmem_data_t	*bdp;
-	unsigned long cstart, epfn;
-
-	bdp = pg_data_ptr[node]->bdata;
-	epfn = GRANULEROUNDUP(pstart + length) >> PAGE_SHIFT;
-	cstart = pstart & ~(BANKSIZE - 1);
+	epfn = GRANULEROUNDUP(end) >> PAGE_SHIFT;
+	cstart = GRANULEROUNDDOWN(start);
 
 	if (!bdp->node_low_pfn) {
 		bdp->node_boot_start = cstart;
@@ -98,34 +83,143 @@
 	return 0;
 }
 
-/*
- * Find space on each node for the bootmem map.
+/**
+ * early_nr_cpus_node - return number of cpus on a given node
+ * @node: node to check
  *
- * Called by efi_memmap_walk to find boot memory on each node. Note that
- * only blocks that are free are passed to this routine (currently filtered by
- * free_available_memory).
+ * Count the number of cpus on @node.  We can't use nr_cpus_node() yet because
+ * acpi_boot_init() (which builds the node_to_cpu_mask array) hasn't been
+ * called yet.
  */
-static int __init
-find_bootmap_space(unsigned long pstart, unsigned long length, int node)
+static int early_nr_cpus_node(int node)
 {
-	unsigned long	mapsize, pages, epfn;
-	bootmem_data_t	*bdp;
+	int cpu, n = 0;
 
-	epfn = (pstart + length) >> PAGE_SHIFT;
-	bdp = &pg_data_ptr[node]->bdata[0];
+	for (cpu = 0; cpu < NR_CPUS; cpu++)
+		if (node == node_cpuid[cpu].nid)
+			n++;
+
+	return n;
+}
 
-	if (pstart < bdp->node_boot_start || epfn > bdp->node_low_pfn)
+/**
+ * find_pernode_space - allocate memory for memory map and per-node structures
+ * @start: physical start of range
+ * @len: length of range
+ * @node: node where this range resides
+ *
+ * This routine reserves space for the per-cpu data struct, the list of
+ * pg_data_ts and the per-node data struct.  Each node will have something like
+ * the following in the first chunk of addr. space large enough to hold it.
+ *
+ *    ________________________
+ *   |                        |
+ *   |~~~~~~~~~~~~~~~~~~~~~~~~| <-- NODEDATA_ALIGN(start, node) for the first
+ *   |    PERCPU_PAGE_SIZE *  |     start and length big enough
+ *   |        NR_CPUS         |
+ *   |------------------------|
+ *   |   local pg_data_t *    |
+ *   |------------------------|
+ *   |  local ia64_node_data  |
+ *   |------------------------|
+ *   |          ???           |
+ *   |________________________|
+ *
+ * Once this space has been set aside, the bootmem maps are initialized.  We
+ * could probably move the allocation of the per-cpu and ia64_node_data space
+ * outside of this function and use alloc_bootmem_node(), but doing it here
+ * is straightforward and we get the alignments we want so...
+ */
+static int __init find_pernode_space(unsigned long start, unsigned long len,
+				     int node)
+{
+	unsigned long epfn, cpu, cpus;
+	unsigned long pernodesize = 0, pernode;
+       	void *cpu_data;
+	struct bootmem_data *bdp = &mem_data[node].bootmem_data;
+
+	epfn = (start + len) >> PAGE_SHIFT;
+
+	/*
+	 * Make sure this memory falls within this node's usable memory
+	 * since we may have thrown some away in build_maps().
+	 */
+	if (start < bdp->node_boot_start ||
+	    epfn > bdp->node_low_pfn)
 		return 0;
 
-	if (!bdp->node_bootmem_map) {
-		pages = bdp->node_low_pfn - (bdp->node_boot_start>>PAGE_SHIFT);
+	/* Don't setup this node's local space twice... */
+	if (!mem_data[node].pernode_addr) {
+		/*
+		 * Calculate total size needed, incl. what's necessary
+		 * for good alignment and alias prevention.
+		 */
+		cpus = early_nr_cpus_node(node);
+		pernodesize += PERCPU_PAGE_SIZE * cpus;
+		pernodesize += L1_CACHE_ALIGN(sizeof(pg_data_t));
+		pernodesize += L1_CACHE_ALIGN(sizeof(struct ia64_node_data));
+		pernodesize = PAGE_ALIGN(pernodesize);
+		pernode = NODEDATA_ALIGN(start, node);
+
+		/* Is this range big enough for what we want to store here? */
+		if (start + len > (pernode + pernodesize)) {
+			mem_data[node].pernode_addr = pernode;
+			mem_data[node].pernode_size = pernodesize;
+			memset(__va(pernode), 0, pernodesize);
+
+			cpu_data = (void *)pernode;
+			pernode += PERCPU_PAGE_SIZE * cpus;
+
+			mem_data[node].pgdat = __va(pernode);
+			pernode += L1_CACHE_ALIGN(sizeof(pg_data_t));
+
+			mem_data[node].node_data = __va(pernode);
+			pernode += L1_CACHE_ALIGN(sizeof(struct ia64_node_data));
+
+			mem_data[node].pgdat->bdata = bdp;
+			pernode += L1_CACHE_ALIGN(sizeof(pg_data_t));
+
+			/*
+			 * Copy the static per-cpu data into the region we
+			 * just set aside and then setup __per_cpu_offset
+			 * for each CPU on this node.
+			 */
+			for (cpu = 0; cpu < NR_CPUS; cpu++) {
+				if (node == node_cpuid[cpu].nid) {
+					memcpy(cpu_data, __phys_per_cpu_start,
+					       __per_cpu_end-__per_cpu_start);
+					__per_cpu_offset[cpu] =
+						(char*)__va(cpu_data) -
+						__per_cpu_start;
+					cpu_data += PERCPU_PAGE_SIZE;
+				}
+			}
+		}
+	}
+
+	pernode = mem_data[node].pernode_addr;
+	pernodesize = mem_data[node].pernode_size;
+	if (pernode && !bdp->node_bootmem_map) {
+		unsigned long pages, mapsize, map = 0;
+
+		pages = bdp->node_low_pfn -
+			(bdp->node_boot_start >> PAGE_SHIFT);
 		mapsize = bootmem_bootmap_pages(pages) << PAGE_SHIFT;
-		if (length > mapsize) {
-			init_bootmem_node(
-				BOOT_NODE_DATA(node),
-				pstart>>PAGE_SHIFT, 
-				bdp->node_boot_start>>PAGE_SHIFT,
-				bdp->node_low_pfn);
+
+		/*
+		 * The map will either contain the pernode area or begin
+		 * after it.
+		 */
+		if (pernode - start > mapsize)
+			map = start;
+		else if (start + len - pernode - pernodesize > mapsize)
+			map = pernode + pernodesize;
+
+		if (map) {
+			init_bootmem_node(mem_data[node].pgdat,
+					  map>>PAGE_SHIFT,
+					  bdp->node_boot_start>>PAGE_SHIFT,
+					  bdp->node_low_pfn);
 		}
 
 	}
@@ -133,85 +227,93 @@
 	return 0;
 }
 
-
-/*
- * Free available memory to the bootmem allocator.
- *
- * Note that only blocks that are free are passed to this routine (currently 
- * filtered by free_available_memory).
+/**
+ * free_node_bootmem - free bootmem allocator memory for use
+ * @start: physical start of range
+ * @len: length of range
+ * @node: node where this range resides
  *
+ * Simply calls the bootmem allocator to free the specified ranged from
+ * the given pg_data_t's bdata struct.  After this function has been called
+ * for all the entries in the EFI memory map, the bootmem allocator will
+ * be ready to service allocation requests.
  */
-static int __init
-discontig_free_bootmem_node(unsigned long pstart, unsigned long length, int node)
+static int __init free_node_bootmem(unsigned long start, unsigned long len,
+				    int node)
 {
-	free_bootmem_node(BOOT_NODE_DATA(node), pstart, length);
+	free_bootmem_node(mem_data[node].pgdat, start, len);
 
 	return 0;
 }
 
-
-/*
- * Reserve the space used by the bootmem maps.
- */
-static void __init
-discontig_reserve_bootmem(void)
-{
-	int		node;
-	unsigned long	mapbase, mapsize, pages;
-	bootmem_data_t	*bdp;
+/**
+ * reserve_pernode_space - reserve memory for per-node space
+ *
+ * Reserve the space used by the bootmem maps & per-node space in the boot
+ * allocator so that when we actually create the real mem maps we don't
+ * use their memory.
+ */
+static void __init reserve_pernode_space(void)
+{
+	unsigned long base, size, pages;
+	struct bootmem_data *bdp;
+	int node;
 
 	for (node = 0; node < numnodes; node++) {
-		bdp = BOOT_NODE_DATA(node)->bdata;
+		pg_data_t *pdp = mem_data[node].pgdat;
 
+		bdp = pdp->bdata;
+
+		/* First the bootmem_map itself */
 		pages = bdp->node_low_pfn - (bdp->node_boot_start>>PAGE_SHIFT);
-		mapsize = bootmem_bootmap_pages(pages) << PAGE_SHIFT;
-		mapbase = __pa(bdp->node_bootmem_map);
-		reserve_bootmem_node(BOOT_NODE_DATA(node), mapbase, mapsize);
+		size = bootmem_bootmap_pages(pages) << PAGE_SHIFT;
+		base = __pa(bdp->node_bootmem_map);
+		reserve_bootmem_node(pdp, base, size);
+
+		/* Now the per-node space */
+		size = mem_data[node].pernode_size;
+		base = __pa(mem_data[node].pernode_addr);
+		reserve_bootmem_node(pdp, base, size);
 	}
 }
 
-/*
- * Allocate per node tables.
- * 	- the pg_data structure is allocated on each node. This minimizes offnode 
- *	  memory references
- *	- the node data is allocated & initialized. Portions of this structure is read-only (after 
- *	  boot) and contains node-local pointers to usefuls data structures located on
- *	  other nodes.
- *
- * We also switch to using the "real" pg_data structures at this point. Earlier in boot, we
- * use a different structure. The only use for pg_data prior to the point in boot is to get 
- * the pointer to the bdata for the node.
- */
-static void __init
-allocate_pernode_structures(void)
-{
-	pg_data_t	*pgdat=0, *new_pgdat_list=0;
-	int		node, mynode;
-
-	mynode = boot_get_local_nodeid();
-	for (node = numnodes - 1; node >= 0 ; node--) {
-		node_data[node] = alloc_bootmem_node(BOOT_NODE_DATA(node), sizeof (struct ia64_node_data));
-		pgdat = __alloc_bootmem_node(BOOT_NODE_DATA(node), sizeof(pg_data_t), SMP_CACHE_BYTES, 0);
-		pgdat->bdata = &(bdata[node][0]);
-		pg_data_ptr[node] = pgdat;
-		pgdat->pgdat_next = new_pgdat_list;
-		new_pgdat_list = pgdat;
-	}
+/**
+ * initialize_pernode_data - fixup per-cpu & per-node pointers
+ *
+ * Each node's per-node area has a copy of the global pg_data_t list, so
+ * we copy that to each node here, as well as setting the per-cpu pointer
+ * to the local node data structure.  The active_cpus field of the per-node
+ * structure gets setup by the platform_cpu_init() function later.
+ */
+static void __init initialize_pernode_data(void)
+{
+	int cpu, node;
+	pg_data_t *pgdat_list[NR_NODES];
 
-	memcpy(node_data[mynode]->pg_data_ptrs, pg_data_ptr, sizeof(pg_data_ptr));
-	memcpy(node_data[mynode]->node_data_ptrs, node_data, sizeof(node_data));
+	for (node = 0; node < numnodes; node++)
+		pgdat_list[node] = mem_data[node].pgdat;
 
-	pgdat_list = new_pgdat_list;
+	/* Copy the pg_data_t list to each node and init the node field */
+	for (node = 0; node < numnodes; node++) {
+		memcpy(mem_data[node].node_data->pg_data_ptrs, pgdat_list,
+		       sizeof(pgdat_list));
+	}
+
+	/* Set the node_data pointer for each per-cpu struct */
+	for (cpu = 0; cpu < NR_CPUS; cpu++) {
+		node = node_cpuid[cpu].nid;
+		per_cpu(cpu_info, cpu).node_data = mem_data[node].node_data;
+	}
 }
 
-/*
- * Called early in boot to setup the boot memory allocator, and to
- * allocate the node-local pg_data & node-directory data structures..
+/**
+ * find_memory - walk the EFI memory map and setup the bootmem allocator
+ *
+ * Called early in boot to setup the bootmem allocator, and to
+ * allocate the per-cpu and per-node structures.
  */
 void __init find_memory(void)
 {
-	int	node;
-
 	reserve_memory();
 
 	if (numnodes == 0) {
@@ -219,94 +321,48 @@
 		numnodes = 1;
 	}
 
-	for (node = 0; node < numnodes; node++) {
-		pg_data_ptr[node] = (pg_data_t*) &boot_pg_data[node];
-		pg_data_ptr[node]->bdata = &bdata[node][0];
-	}
-
 	min_low_pfn = -1;
 	max_low_pfn = 0;
 
-        efi_memmap_walk(filter_rsvd_memory, build_maps);
-        efi_memmap_walk(filter_rsvd_memory, find_bootmap_space);
-        efi_memmap_walk(filter_rsvd_memory, discontig_free_bootmem_node);
-	discontig_reserve_bootmem();
-	allocate_pernode_structures();
-
-	find_initrd();
-}
-
-/*
- * Initialize the paging system.
- *	- determine sizes of each node
- *	- initialize the paging system for the node
- *	- build the nodedir for the node. This contains pointers to
- *	  the per-bank mem_map entries.
- *	- fix the page struct "virtual" pointers. These are bank specific
- *	  values that the paging system doesn't understand.
- *	- replicate the nodedir structure to other nodes
- */
-
-void __init
-discontig_paging_init(void)
-{
-	int		node, mynode;
-	unsigned long	max_dma, zones_size[MAX_NR_ZONES];
-	unsigned long	kaddr, ekaddr, bid;
-	struct page	*page;
-	bootmem_data_t	*bdp;
-
-	max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+	/* These actually end up getting called by call_pernode_memory() */
+	efi_memmap_walk(filter_rsvd_memory, build_node_maps);
+	efi_memmap_walk(filter_rsvd_memory, find_pernode_space);
+	efi_memmap_walk(filter_rsvd_memory, free_node_bootmem);
 
-	mynode = boot_get_local_nodeid();
-	for (node = 0; node < numnodes; node++) {
-		long pfn, startpfn;
+	reserve_pernode_space();
+	initialize_pernode_data();
 
-		memset(zones_size, 0, sizeof(zones_size));
+	max_pfn = max_low_pfn;
 
-		startpfn = -1;
-		bdp = BOOT_NODE_DATA(node)->bdata;
-		pfn = bdp->node_boot_start >> PAGE_SHIFT;
-		if (startpfn == -1)
-			startpfn = pfn;
-		if (pfn > max_dma)
-			zones_size[ZONE_NORMAL] += (bdp->node_low_pfn - pfn);
-		else if (bdp->node_low_pfn < max_dma)
-			zones_size[ZONE_DMA] += (bdp->node_low_pfn - pfn);
-		else {
-			zones_size[ZONE_DMA] += (max_dma - pfn);
-			zones_size[ZONE_NORMAL] += (bdp->node_low_pfn - max_dma);
-		}
-
-		free_area_init_node(node, NODE_DATA(node), NULL, zones_size, startpfn, 0);
-
-		page = NODE_DATA(node)->node_mem_map;
+	find_initrd();
+}
 
-		bdp = BOOT_NODE_DATA(node)->bdata;
+/**
+ * per_cpu_init - setup per-cpu variables
+ *
+ * find_pernode_space() does most of this already, we just need to set
+ * local_per_cpu_offset
+ */
+void *per_cpu_init(void)
+{
+	int cpu;
 
-		kaddr = (unsigned long)__va(bdp->node_boot_start);
-		ekaddr = (unsigned long)__va(bdp->node_low_pfn << PAGE_SHIFT);
-		while (kaddr < ekaddr) {
-			if (paddr_to_nid(__pa(kaddr)) == node) {
-				bid = BANK_MEM_MAP_INDEX(kaddr);
-				node_data[mynode]->node_id_map[bid] = node;
-				node_data[mynode]->bank_mem_map_base[bid] = page;
-			}
-			kaddr += BANKSIZE;
-			page += BANKSIZE/PAGE_SIZE;
+	if (smp_processor_id() == 0) {
+		for (cpu = 0; cpu < NR_CPUS; cpu++) {
+			per_cpu(local_per_cpu_offset, cpu) =
+				__per_cpu_offset[cpu];
 		}
 	}
 
-	/*
-	 * Finish setting up the node data for this node, then copy it to the other nodes.
-	 */
-	for (node=0; node < numnodes; node++)
-		if (mynode != node) {
-			memcpy(node_data[node], node_data[mynode], sizeof(struct ia64_node_data));
-			node_data[node]->node = node;
-		}
+	return __per_cpu_start + __per_cpu_offset[smp_processor_id()];
 }
 
+/**
+ * show_mem - give short summary of memory stats
+ *
+ * Shows a simple page count of reserved and used pages in the system.
+ * For discontig machines, it does this on a per-pgdat basis.
+ */
 void show_mem(void)
 {
 	int i, reserved = 0;
@@ -335,7 +391,12 @@
 	printk("%d free buffer pages\n", nr_free_buffer_pages());
 }
 
-/*
+/**
+ * call_pernode_memory - use SRAT to call callback functions with node info
+ * @start: physical start of range
+ * @len: length of range
+ * @arg: function to call for each range
+ *
  * efi_memmap_walk() knows nothing about layout of memory across nodes. Find
  * out to which node a block of memory belongs.  Ignore memory that we cannot
  * identify, and split blocks that run across multiple nodes.
@@ -343,10 +404,10 @@
  * Take this opportunity to round the start address up and the end address
  * down to page boundaries.
  */
-void call_pernode_memory(unsigned long start, unsigned long end, void *arg)
+void call_pernode_memory(unsigned long start, unsigned long len, void *arg)
 {
-	unsigned long rs, re;
-	void (*func)(unsigned long, unsigned long, int, int);
+	unsigned long rs, re, end = start + len;
+	void (*func)(unsigned long, unsigned long, int);
 	int i;
 
 	start = PAGE_ALIGN(start);
@@ -357,21 +418,127 @@
 	func = arg;
 
 	if (!num_memblks) {
-		/*
-		 * This machine doesn't have SRAT, so call func with
-		 * nid=0, bank=0.
-		 */
+		/* No SRAT table, to assume one node (node 0) */
 		if (start < end)
-			(*func)(start, end - start, 0, 0);
+			(*func)(start, len, 0);
 		return;
 	}
 
 	for (i = 0; i < num_memblks; i++) {
 		rs = max(start, node_memblk[i].start_paddr);
-		re = min(end, node_memblk[i].start_paddr+node_memblk[i].size);
+		re = min(end, node_memblk[i].start_paddr +
+			 node_memblk[i].size);
 
 		if (rs < re)
-			(*func)(rs, re-rs, node_memblk[i].nid,
-				node_memblk[i].bank);
+			(*func)(rs, re - rs, node_memblk[i].nid);
+
+		if (re == end)
+			break;
+	}
+}
+
+/**
+ * count_node_pages - callback to build per-node memory info structures
+ * @start: physical start of range
+ * @len: length of range
+ * @node: node where this range resides
+ *
+ * Each node has it's own number of physical pages, DMAable pages, start, and
+ * end page frame number.  This routine will be called by call_pernode_memory()
+ * for each piece of usable memory and will setup these values for each node.
+ * Very similar to build_maps().
+ */
+static int count_node_pages(unsigned long start, unsigned long len, int node)
+{
+	unsigned long end = start + len;
+
+	mem_data[node].num_physpages += len >> PAGE_SHIFT;
+	if (start <= __pa(MAX_DMA_ADDRESS))
+		mem_data[node].num_dma_physpages +=
+			(min(end, __pa(MAX_DMA_ADDRESS)) - start) >>PAGE_SHIFT;
+	start = GRANULEROUNDDOWN(start);
+	start = ORDERROUNDDOWN(start);
+	end = GRANULEROUNDUP(end);
+	mem_data[node].max_pfn = max(mem_data[node].max_pfn,
+				     end >> PAGE_SHIFT);
+	mem_data[node].min_pfn = min(mem_data[node].min_pfn,
+				     start >> PAGE_SHIFT);
+
+	return 0;
+}
+
+/**
+ * paging_init - setup page tables
+ *
+ * paging_init() sets up the page tables for each node of the system and frees
+ * the bootmem allocator memory for general use.
+ */
+void paging_init(void)
+{
+	unsigned long max_dma;
+	unsigned long zones_size[MAX_NR_ZONES];
+	unsigned long zholes_size[MAX_NR_ZONES];
+	unsigned long max_gap, pfn_offset = 0;
+	int node;
+
+	max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+	max_gap = 0;
+	efi_memmap_walk(find_largest_hole, &max_gap);
+
+	/* so min() will work in count_node_pages */
+	for (node = 0; node < numnodes; node++)
+		mem_data[node].min_pfn = ~0UL;
+
+	efi_memmap_walk(filter_rsvd_memory, count_node_pages);
+
+	for (node = 0; node < numnodes; node++) {
+		memset(zones_size, 0, sizeof(zones_size));
+		memset(zholes_size, 0, sizeof(zholes_size));
+
+		num_physpages += mem_data[node].num_physpages;
+
+		if (mem_data[node].min_pfn >= max_dma) {
+			/* All of this node's memory is above ZONE_DMA */
+			zones_size[ZONE_NORMAL] = mem_data[node].max_pfn -
+				mem_data[node].min_pfn;
+			zholes_size[ZONE_NORMAL] = mem_data[node].max_pfn -
+				mem_data[node].min_pfn -
+				mem_data[node].num_physpages;
+		} else if (mem_data[node].max_pfn < max_dma) {
+			/* All of this node's memory is in ZONE_DMA */
+			zones_size[ZONE_DMA] = mem_data[node].max_pfn -
+				mem_data[node].min_pfn;
+			zholes_size[ZONE_DMA] = mem_data[node].max_pfn -
+				mem_data[node].min_pfn -
+				mem_data[node].num_dma_physpages;
+		} else {
+			/* This node has memory in both zones */
+			zones_size[ZONE_DMA] = max_dma -
+				mem_data[node].min_pfn;
+			zholes_size[ZONE_DMA] = zones_size[ZONE_DMA] -
+				mem_data[node].num_dma_physpages;
+			zones_size[ZONE_NORMAL] = mem_data[node].max_pfn -
+				max_dma;
+			zholes_size[ZONE_NORMAL] = zones_size[ZONE_NORMAL] -
+				(mem_data[node].num_physpages -
+				 mem_data[node].num_dma_physpages);
+		}
+
+		if (node == 0) {
+			vmalloc_end -=
+				PAGE_ALIGN(max_low_pfn * sizeof(struct page));
+			vmem_map = (struct page *) vmalloc_end;
+
+			efi_memmap_walk(create_mem_map_page_table, 0);
+			printk("Virtual mem_map starts at 0x%p\n", vmem_map);
+		}
+
+		pfn_offset = mem_data[node].min_pfn;
+
+		free_area_init_node(node, NODE_DATA(node),
+				    vmem_map + pfn_offset, zones_size,
+				    pfn_offset, zholes_size);
 	}
+
+	zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page));
 }
diff -Nru a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c
--- a/arch/ia64/mm/hugetlbpage.c	Wed Oct 15 00:46:36 2003
+++ b/arch/ia64/mm/hugetlbpage.c	Wed Oct 15 00:46:36 2003
@@ -20,13 +20,46 @@
 
 #define TASK_HPAGE_BASE (REGION_HPAGE << REGION_SHIFT)
 
-static long    htlbpagemem;
-int     htlbpage_max;
-static long    htlbzone_pages;
+static long	htlbpagemem;
+int		htlbpage_max;
+static long	htlbzone_pages;
 
-static LIST_HEAD(htlbpage_freelist);
+static struct list_head hugepage_freelists[MAX_NUMNODES];
 static spinlock_t htlbpage_lock = SPIN_LOCK_UNLOCKED;
 
+static void enqueue_huge_page(struct page *page)
+{
+	list_add(&page->list,
+		&hugepage_freelists[page_zone(page)->zone_pgdat->node_id]);
+}
+
+static struct page *dequeue_huge_page(void)
+{
+	int nid = numa_node_id();
+	struct page *page = NULL;
+
+	if (list_empty(&hugepage_freelists[nid])) {
+		for (nid = 0; nid < MAX_NUMNODES; ++nid)
+			if (!list_empty(&hugepage_freelists[nid]))
+				break;
+	}
+	if (nid >= 0 && nid < MAX_NUMNODES &&
+	    !list_empty(&hugepage_freelists[nid])) {
+		page = list_entry(hugepage_freelists[nid].next, struct page, list);
+		list_del(&page->list);
+	}
+	return page;
+}
+
+static struct page *alloc_fresh_huge_page(void)
+{
+	static int nid = 0;
+	struct page *page;
+	page = alloc_pages_node(nid, GFP_HIGHUSER, HUGETLB_PAGE_ORDER);
+	nid = (nid + 1) % numnodes;
+	return page;
+}
+
 void free_huge_page(struct page *page);
 
 static struct page *alloc_hugetlb_page(void)
@@ -35,13 +68,11 @@
 	struct page *page;
 
 	spin_lock(&htlbpage_lock);
-	if (list_empty(&htlbpage_freelist)) {
+	page = dequeue_huge_page();
+	if (!page) {
 		spin_unlock(&htlbpage_lock);
 		return NULL;
 	}
-
-	page = list_entry(htlbpage_freelist.next, struct page, list);
-	list_del(&page->list);
 	htlbpagemem--;
 	spin_unlock(&htlbpage_lock);
 	set_page_count(page, 1);
@@ -228,7 +259,7 @@
 	INIT_LIST_HEAD(&page->list);
 
 	spin_lock(&htlbpage_lock);
-	list_add(&page->list, &htlbpage_freelist);
+	enqueue_huge_page(page);
 	htlbpagemem++;
 	spin_unlock(&htlbpage_lock);
 }
@@ -371,7 +402,7 @@
 
 	map = NULL;
 	spin_lock(&htlbpage_lock);
-	list_for_each(p, &htlbpage_freelist) {
+	list_for_each(p, &hugepage_freelists[0]) {
 		if (map) {
 			list_del(&map->list);
 			update_and_free_page(map);
@@ -408,11 +439,11 @@
 		return (int)htlbzone_pages;
 	if (lcount > 0) {	/* Increase the mem size. */
 		while (lcount--) {
-			page = alloc_pages(__GFP_HIGHMEM, HUGETLB_PAGE_ORDER);
+			page = alloc_fresh_huge_page();
 			if (page == NULL)
 				break;
 			spin_lock(&htlbpage_lock);
-			list_add(&page->list, &htlbpage_freelist);
+			enqueue_huge_page(page);
 			htlbpagemem++;
 			htlbzone_pages++;
 			spin_unlock(&htlbpage_lock);
@@ -449,17 +480,18 @@
 
 static int __init hugetlb_init(void)
 {
-	int i, j;
+	int i;
 	struct page *page;
 
+	for (i = 0; i < MAX_NUMNODES; ++i)
+		INIT_LIST_HEAD(&hugepage_freelists[i]);
+
 	for (i = 0; i < htlbpage_max; ++i) {
-		page = alloc_pages(__GFP_HIGHMEM, HUGETLB_PAGE_ORDER);
+		page = alloc_fresh_huge_page();
 		if (!page)
 			break;
-		for (j = 0; j < HPAGE_SIZE/PAGE_SIZE; ++j)
-			SetPageReserved(&page[j]);
 		spin_lock(&htlbpage_lock);
-		list_add(&page->list, &htlbpage_freelist);
+		enqueue_huge_page(page);
 		spin_unlock(&htlbpage_lock);
 	}
 	htlbpage_max = htlbpagemem = htlbzone_pages = i;
diff -Nru a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
--- a/arch/ia64/mm/init.c	Wed Oct 15 00:46:36 2003
+++ b/arch/ia64/mm/init.c	Wed Oct 15 00:46:36 2003
@@ -24,6 +24,7 @@
 #include <asm/ia32.h>
 #include <asm/io.h>
 #include <asm/machvec.h>
+#include <asm/numa.h>
 #include <asm/patch.h>
 #include <asm/pgalloc.h>
 #include <asm/sal.h>
@@ -40,10 +41,8 @@
 unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL;
 
 #ifdef CONFIG_VIRTUAL_MEM_MAP
-# define LARGE_GAP	0x40000000	/* Use virtual mem map if hole is > than this */
   unsigned long vmalloc_end = VMALLOC_END_INIT;
-  static struct page *vmem_map;
-  static unsigned long num_dma_physpages;
+  struct page *vmem_map;
 #endif
 
 static int pgt_cache_water[2] = { 25, 50 };
@@ -337,11 +336,12 @@
 
 #ifdef CONFIG_VIRTUAL_MEM_MAP
 
-static int
+int
 create_mem_map_page_table (u64 start, u64 end, void *arg)
 {
 	unsigned long address, start_page, end_page;
 	struct page *map_start, *map_end;
+	int node;
 	pgd_t *pgd;
 	pmd_t *pmd;
 	pte_t *pte;
@@ -351,19 +351,20 @@
 
 	start_page = (unsigned long) map_start & PAGE_MASK;
 	end_page = PAGE_ALIGN((unsigned long) map_end);
+	node = paddr_to_nid(__pa(start));
 
 	for (address = start_page; address < end_page; address += PAGE_SIZE) {
 		pgd = pgd_offset_k(address);
 		if (pgd_none(*pgd))
-			pgd_populate(&init_mm, pgd, alloc_bootmem_pages(PAGE_SIZE));
+			pgd_populate(&init_mm, pgd, alloc_bootmem_pages_node(NODE_DATA(node), PAGE_SIZE));
 		pmd = pmd_offset(pgd, address);
 
 		if (pmd_none(*pmd))
-			pmd_populate_kernel(&init_mm, pmd, alloc_bootmem_pages(PAGE_SIZE));
+			pmd_populate_kernel(&init_mm, pmd, alloc_bootmem_pages_node(NODE_DATA(node), PAGE_SIZE));
 		pte = pte_offset_kernel(pmd, address);
 
 		if (pte_none(*pte))
-			set_pte(pte, pfn_pte(__pa(alloc_bootmem_pages(PAGE_SIZE)) >> PAGE_SHIFT,
+			set_pte(pte, pfn_pte(__pa(alloc_bootmem_pages_node(NODE_DATA(node), PAGE_SIZE)) >> PAGE_SHIFT,
 					     PAGE_KERNEL));
 	}
 	return 0;
@@ -433,17 +434,7 @@
 	return __get_user(byte, (char *) pfn_to_page(pfn)) == 0;
 }
 
-static int
-count_dma_pages (u64 start, u64 end, void *arg)
-{
-	unsigned long *count = arg;
-
-	if (end <= MAX_DMA_ADDRESS)
-		*count += (end - start) >> PAGE_SHIFT;
-	return 0;
-}
-
-static int
+int
 find_largest_hole (u64 start, u64 end, void *arg)
 {
 	u64 *max_gap = arg;
@@ -458,103 +449,6 @@
 	return 0;
 }
 #endif /* CONFIG_VIRTUAL_MEM_MAP */
-
-static int
-count_pages (u64 start, u64 end, void *arg)
-{
-	unsigned long *count = arg;
-
-	*count += (end - start) >> PAGE_SHIFT;
-	return 0;
-}
-
-/*
- * Set up the page tables.
- */
-
-#ifdef CONFIG_DISCONTIGMEM
-void
-paging_init (void)
-{
-	extern void discontig_paging_init(void);
-
-	discontig_paging_init();
-	efi_memmap_walk(count_pages, &num_physpages);
-	zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page));
-}
-#else /* !CONFIG_DISCONTIGMEM */
-void
-paging_init (void)
-{
-	unsigned long max_dma;
-	unsigned long zones_size[MAX_NR_ZONES];
-#  ifdef CONFIG_VIRTUAL_MEM_MAP
-	unsigned long zholes_size[MAX_NR_ZONES];
-	unsigned long max_gap;
-#  endif
-
-	/* initialize mem_map[] */
-
-	memset(zones_size, 0, sizeof(zones_size));
-
-	num_physpages = 0;
-	efi_memmap_walk(count_pages, &num_physpages);
-
-	max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
-
-#  ifdef CONFIG_VIRTUAL_MEM_MAP
-	memset(zholes_size, 0, sizeof(zholes_size));
-
-	num_dma_physpages = 0;
-	efi_memmap_walk(count_dma_pages, &num_dma_physpages);
-
-	if (max_low_pfn < max_dma) {
-		zones_size[ZONE_DMA] = max_low_pfn;
-		zholes_size[ZONE_DMA] = max_low_pfn - num_dma_physpages;
-	} else {
-		zones_size[ZONE_DMA] = max_dma;
-		zholes_size[ZONE_DMA] = max_dma - num_dma_physpages;
-		if (num_physpages > num_dma_physpages) {
-			zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
-			zholes_size[ZONE_NORMAL] = ((max_low_pfn - max_dma)
-						    - (num_physpages - num_dma_physpages));
-		}
-	}
-
-	max_gap = 0;
-	efi_memmap_walk(find_largest_hole, (u64 *)&max_gap);
-	if (max_gap < LARGE_GAP) {
-		vmem_map = (struct page *) 0;
-		free_area_init_node(0, &contig_page_data, NULL, zones_size, 0, zholes_size);
-		mem_map = contig_page_data.node_mem_map;
-	}
-	else {
-		unsigned long map_size;
-
-		/* allocate virtual_mem_map */
-
-		map_size = PAGE_ALIGN(max_low_pfn * sizeof(struct page));
-		vmalloc_end -= map_size;
-		vmem_map = (struct page *) vmalloc_end;
-		efi_memmap_walk(create_mem_map_page_table, 0);
-
-		free_area_init_node(0, &contig_page_data, vmem_map, zones_size, 0, zholes_size);
-
-		mem_map = contig_page_data.node_mem_map;
-		printk("Virtual mem_map starts at 0x%p\n", mem_map);
-	}
-#  else /* !CONFIG_VIRTUAL_MEM_MAP */
-	if (max_low_pfn < max_dma)
-		zones_size[ZONE_DMA] = max_low_pfn;
-	else {
-		zones_size[ZONE_DMA] = max_dma;
-		zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
-	}
-	free_area_init(zones_size);
-#  endif /* !CONFIG_VIRTUAL_MEM_MAP */
-	zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page));
-}
-#endif /* !CONFIG_DISCONTIGMEM */
 
 static int
 count_reserved_pages (u64 start, u64 end, void *arg)
diff -Nru a/arch/ia64/sn/io/machvec/pci_bus_cvlink.c b/arch/ia64/sn/io/machvec/pci_bus_cvlink.c
--- a/arch/ia64/sn/io/machvec/pci_bus_cvlink.c	Wed Oct 15 00:46:37 2003
+++ b/arch/ia64/sn/io/machvec/pci_bus_cvlink.c	Wed Oct 15 00:46:37 2003
@@ -867,6 +867,9 @@
 	int i = 0;
 	struct pci_controller *controller;
 
+	if (!ia64_platform_is("sn2"))
+	    return 0;
+
 	/*
 	 * set pci_raw_ops, etc.
 	 */
diff -Nru a/arch/ia64/sn/io/sn2/ml_SN_intr.c b/arch/ia64/sn/io/sn2/ml_SN_intr.c
--- a/arch/ia64/sn/io/sn2/ml_SN_intr.c	Wed Oct 15 00:46:37 2003
+++ b/arch/ia64/sn/io/sn2/ml_SN_intr.c	Wed Oct 15 00:46:37 2003
@@ -285,7 +285,6 @@
 cpuid_t intr_heuristic(vertex_hdl_t dev, int req_bit, int *resp_bit)
 {
 	cpuid_t		cpuid;
-	cpuid_t		candidate = CPU_NONE;
 	vertex_hdl_t	pconn_vhdl;
 	pcibr_soft_t	pcibr_soft;
 	int 		bit;
@@ -293,30 +292,32 @@
 	/* XXX: gross layering violation.. */
 	if (hwgraph_edge_get(dev, EDGE_LBL_PCI, &pconn_vhdl) == GRAPH_SUCCESS) {
 		pcibr_soft = pcibr_soft_get(pconn_vhdl);
-		if (pcibr_soft && pcibr_soft->bsi_err_intr)
-			candidate = ((hub_intr_t)pcibr_soft->bsi_err_intr)->i_cpuid;
-	}
-
-	if (candidate != CPU_NONE) {
-		/*
-		 * The cpu was chosen already when we assigned
-		 * the error interrupt.
-		 */
-		bit = intr_reserve_level(candidate, req_bit);
-		if (bit >= 0) {
-			*resp_bit = bit;
-			return candidate;
+		if (pcibr_soft && pcibr_soft->bsi_err_intr) {
+			/*
+			 * The cpu was chosen already when we assigned
+			 * the error interrupt.
+			 */
+			cpuid = ((hub_intr_t)pcibr_soft->bsi_err_intr)->i_cpuid;
+			goto done;
 		}
-
-		printk("Cannot target interrupt to target node (%ld).\n",candidate);
-		return CPU_NONE;
 	}
 
 	/*
 	 * Need to choose one.  Try the controlling c-brick first.
 	 */
 	cpuid = intr_cpu_choose_from_node(master_node_get(dev));
-	if (cpuid != CPU_NONE)
-		return cpuid;
-	return intr_cpu_choose_node();
+	if (cpuid == CPU_NONE)
+		cpuid = intr_cpu_choose_node();
+
+ done:
+	if (cpuid != CPU_NONE) {
+		bit = intr_reserve_level(cpuid, req_bit);
+		if (bit >= 0) {
+			*resp_bit = bit;
+			return cpuid;
+		}
+	}
+
+	printk("Cannot target interrupt to target cpu (%ld).\n", cpuid);
+	return CPU_NONE;
 }
diff -Nru a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c
--- a/arch/ia64/sn/kernel/setup.c	Wed Oct 15 00:46:36 2003
+++ b/arch/ia64/sn/kernel/setup.c	Wed Oct 15 00:46:36 2003
@@ -147,7 +147,6 @@
  * Sets up an initial console to aid debugging.  Intended primarily
  * for bringup.  See start_kernel() in init/main.c.
  */
-#if defined(CONFIG_IA64_EARLY_PRINTK_SGI_SN) || defined(CONFIG_IA64_SGI_SN_SIM)
 
 void __init
 early_sn_setup(void)
@@ -189,7 +188,6 @@
 		printk(KERN_DEBUG "early_sn_setup: setting master_node_bedrock_address to 0x%lx\n", master_node_bedrock_address);
 	}
 }
-#endif /* CONFIG_IA64_EARLY_PRINTK_SGI_SN */
 
 #ifdef CONFIG_IA64_MCA
 extern int platform_intr_list[];
diff -Nru a/arch/m68k/lib/checksum.c b/arch/m68k/lib/checksum.c
--- a/arch/m68k/lib/checksum.c	Wed Oct 15 00:46:38 2003
+++ b/arch/m68k/lib/checksum.c	Wed Oct 15 00:46:38 2003
@@ -125,6 +125,7 @@
 	return(sum);
 }
 
+EXPORT_SYMBOL(csum_partial);
 
 
 /*
diff -Nru a/arch/m68k/sun3/sbus.c b/arch/m68k/sun3/sbus.c
--- a/arch/m68k/sun3/sbus.c	Wed Oct 15 00:46:37 2003
+++ b/arch/m68k/sun3/sbus.c	Wed Oct 15 00:46:37 2003
@@ -10,6 +10,7 @@
  */
 
 #include <linux/types.h>
+#include <linux/compiler.h>
 #include <linux/init.h>
 
 int __init sbus_init(void)
diff -Nru a/arch/ppc/8260_io/Kconfig b/arch/ppc/8260_io/Kconfig
--- a/arch/ppc/8260_io/Kconfig	Wed Oct 15 00:46:37 2003
+++ b/arch/ppc/8260_io/Kconfig	Wed Oct 15 00:46:37 2003
@@ -57,14 +57,5 @@
 	bool "QS6612"
 
 endchoice
-
-comment "Generic MPC8260 Options"
-
-config DCACHE_DISABLE
-	bool "Disable data cache"
-	help
-	  This option allows you to run the kernel with data cache disabled.
-	  Say Y if you experience CPM lock-ups.
-
 endmenu
 
diff -Nru a/arch/ppc/Makefile b/arch/ppc/Makefile
--- a/arch/ppc/Makefile	Wed Oct 15 00:46:35 2003
+++ b/arch/ppc/Makefile	Wed Oct 15 00:46:35 2003
@@ -65,7 +65,13 @@
 	$(Q)$(MAKE) $(build)=$(boot)/images $(boot)/images/$@
 
 define archhelp
+  @echo '* zImage          - Compressed kernel image (arch/$(ARCH)/boot/images/zImage.*)'
   @echo '  uImage          - Create a bootable image for U-Boot / PPCBoot'
+  @echo '  install         - Install kernel using'
+  @echo '                    (your) ~/bin/installkernel or'
+  @echo '                    (distribution) /sbin/installkernel or'
+  @echo '                    install to $$(INSTALL_PATH) and run lilo'
+  @echo '  *_defconfig     - Select default config from arch/$(ARCH)/ppc/configs'
 endef
 
 archclean:
diff -Nru a/arch/ppc/boot/common/ns16550.c b/arch/ppc/boot/common/ns16550.c
--- a/arch/ppc/boot/common/ns16550.c	Wed Oct 15 00:46:38 2003
+++ b/arch/ppc/boot/common/ns16550.c	Wed Oct 15 00:46:38 2003
@@ -3,6 +3,8 @@
  */
 
 #include <linux/config.h>
+#include <linux/types.h>
+#include <linux/serial.h>
 #include <linux/serialP.h>
 #include <linux/serial_reg.h>
 #include <asm/serial.h>
diff -Nru a/arch/ppc/boot/of1275/map.c b/arch/ppc/boot/of1275/map.c
--- a/arch/ppc/boot/of1275/map.c	Wed Oct 15 00:46:36 2003
+++ b/arch/ppc/boot/of1275/map.c	Wed Oct 15 00:46:36 2003
@@ -23,11 +23,10 @@
 	char *method;
 	ihandle mmu_ihandle;
 	int misc;
-	unsigned int phys;
-	unsigned int virt;
 	unsigned int size;
+	unsigned int virt;
+	unsigned int phys;
 	int ret0;
-	int ret1;
     } args;
 
     if (of_prom_mmu == 0) {
@@ -36,10 +35,10 @@
     }
     args.service = "call-method";
     args.nargs = 6;
-    args.nret = 2;
+    args.nret = 1;
     args.method = "map";
     args.mmu_ihandle = of_prom_mmu;
-    args.misc = -1;
+    args.misc = 0;
     args.phys = phys;
     args.virt = virt;
     args.size = size;
diff -Nru a/arch/ppc/boot/openfirmware/coffmain.c b/arch/ppc/boot/openfirmware/coffmain.c
--- a/arch/ppc/boot/openfirmware/coffmain.c	Wed Oct 15 00:46:36 2003
+++ b/arch/ppc/boot/openfirmware/coffmain.c	Wed Oct 15 00:46:36 2003
@@ -38,9 +38,9 @@
 
 static unsigned long ram_start = 0;
 static unsigned long ram_end = 0x1000000;
-static unsigned long prog_start = 0x800000;
-static unsigned long prog_size = 0x800000;
 
+static unsigned long prog_start = 0x900000;
+static unsigned long prog_size = 0x700000;
 
 typedef void (*kernel_start_t)(int, int, void *);
 
diff -Nru a/arch/ppc/configs/TQM8260_defconfig b/arch/ppc/configs/TQM8260_defconfig
--- a/arch/ppc/configs/TQM8260_defconfig	Wed Oct 15 00:46:36 2003
+++ b/arch/ppc/configs/TQM8260_defconfig	Wed Oct 15 00:46:36 2003
@@ -469,11 +469,6 @@
 # CONFIG_FCC3_ENET is not set
 
 #
-# Generic MPC8260 Options
-#
-CONFIG_DCACHE_DISABLE=y
-
-#
 # USB support
 #
 # CONFIG_USB_GADGET is not set
diff -Nru a/arch/ppc/configs/est8260_defconfig b/arch/ppc/configs/est8260_defconfig
--- a/arch/ppc/configs/est8260_defconfig	Wed Oct 15 00:46:36 2003
+++ b/arch/ppc/configs/est8260_defconfig	Wed Oct 15 00:46:36 2003
@@ -461,11 +461,6 @@
 CONFIG_SCC_CONSOLE=y
 
 #
-# Generic MPC8260 Options
-#
-# CONFIG_DCACHE_DISABLE is not set
-
-#
 # USB support
 #
 # CONFIG_USB_GADGET is not set
diff -Nru a/arch/ppc/kernel/cpu_setup_6xx.S b/arch/ppc/kernel/cpu_setup_6xx.S
--- a/arch/ppc/kernel/cpu_setup_6xx.S	Wed Oct 15 00:46:36 2003
+++ b/arch/ppc/kernel/cpu_setup_6xx.S	Wed Oct 15 00:46:36 2003
@@ -75,11 +75,7 @@
 setup_common_caches:
 	mfspr	r11,HID0
 	andi.	r0,r11,HID0_DCE
-#ifdef CONFIG_DCACHE_DISABLE
-	ori	r11,r11,HID0_ICE
-#else
 	ori	r11,r11,HID0_ICE|HID0_DCE
-#endif
 	ori	r8,r11,HID0_ICFI
 	bne	1f			/* don't invalidate the D-cache */
 	ori	r8,r8,HID0_DCI		/* unless it wasn't enabled */
diff -Nru a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
--- a/arch/ppc/kernel/head.S	Wed Oct 15 00:46:37 2003
+++ b/arch/ppc/kernel/head.S	Wed Oct 15 00:46:37 2003
@@ -181,26 +181,8 @@
 	bl	setup_disp_bat
 #endif
 #else /* CONFIG_POWER4 */
-/*
- * Load up the SDR1 and segment register values now
- * since we don't have the BATs.
- * Also make sure we are running in 32-bit mode.
- */
 	bl	reloc_offset
-	addis	r14,r3,_SDR1@ha		/* get the value from _SDR1 */
-	lwz	r14,_SDR1@l(r14)	/* assume hash table below 4GB */
-	mtspr	SDR1,r14
-	slbia
-	lis	r4,0x2000		/* set pseudo-segment reg 12 */
-	ori	r5,r4,0x0ccc
-	mtsr	12,r5
-	ori	r4,r4,0x0888		/* set pseudo-segment reg 8 */
-	mtsr	8,r4			/* (for access to serial port) */
-	mfmsr	r0
-	clrldi	r0,r0,1
-	sync
-	mtmsr	r0
-	isync
+	bl	initial_mm_power4
 #endif /* CONFIG_POWER4 */
 
 /*
@@ -1637,6 +1619,34 @@
 #endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */
 
 #else /* CONFIG_POWER4 */
+/*
+ * Load up the SDR1 and segment register values now
+ * since we don't have the BATs.
+ * Also make sure we are running in 32-bit mode.
+ */
+
+initial_mm_power4:
+	addis	r14,r3,_SDR1@ha		/* get the value from _SDR1 */
+	lwz	r14,_SDR1@l(r14)	/* assume hash table below 4GB */
+	mtspr	SDR1,r14
+	slbia
+	lis	r4,0x2000		/* set pseudo-segment reg 12 */
+	ori	r5,r4,0x0ccc
+	mtsr	12,r5
+	ori	r5,r4,0x0888		/* set pseudo-segment reg 8 */
+	mtsr	8,r5			/* (for access to serial port) */
+	ori	r5,r4,0x0999		/* set pseudo-segment reg 8 */
+	mtsr	9,r5			/* (for access to screen) */
+	mfmsr	r0
+	clrldi	r0,r0,1
+	sync
+	mtmsr	r0
+	isync
+	blr
+
+/*
+ * On 970 (G5), we pre-set a few bits in HID0 & HID1
+ */
 ppc970_setup_hid:
 	li	r0,0
 	sync
diff -Nru a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
--- a/arch/ppc/kernel/ppc_ksyms.c	Wed Oct 15 00:46:37 2003
+++ b/arch/ppc/kernel/ppc_ksyms.c	Wed Oct 15 00:46:37 2003
@@ -123,7 +123,7 @@
 EXPORT_SYMBOL(strcasecmp);
 EXPORT_SYMBOL(__div64_32);
 
-/* EXPORT_SYMBOL(csum_partial); already in net/netsyms.c */
+EXPORT_SYMBOL(csum_partial);
 EXPORT_SYMBOL(csum_partial_copy_generic);
 EXPORT_SYMBOL(ip_fast_csum);
 EXPORT_SYMBOL(csum_tcpudp_magic);
@@ -367,11 +367,17 @@
 EXPORT_SYMBOL(set_context);
 EXPORT_SYMBOL(handle_mm_fault); /* For MOL */
 EXPORT_SYMBOL_NOVERS(disarm_decr);
+extern long mol_trampoline;
+EXPORT_SYMBOL(mol_trampoline); /* For MOL */
 #ifdef CONFIG_PPC_STD_MMU
 EXPORT_SYMBOL(flush_hash_pages); /* For MOL */
+#ifdef CONFIG_SMP
+extern int mmu_hash_lock;
+EXPORT_SYMBOL(mmu_hash_lock); /* For MOL */
+#endif /* CONFIG_SMP */
 extern long *intercept_table;
 EXPORT_SYMBOL(intercept_table);
-#endif
+#endif /* CONFIG_PPC_STD_MMU */
 EXPORT_SYMBOL(cur_cpu_spec);
 #ifdef CONFIG_PPC_PMAC
 extern unsigned long agp_special_page;
diff -Nru a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
--- a/arch/ppc/kernel/process.c	Wed Oct 15 00:46:36 2003
+++ b/arch/ppc/kernel/process.c	Wed Oct 15 00:46:36 2003
@@ -56,6 +56,7 @@
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
+EXPORT_SYMBOL(init_mm);
 
 /* this is 8kB-aligned so we can get to the thread_info struct
    at the base of it from the stack pointer with 1 integer instruction. */
@@ -65,6 +66,7 @@
 
 /* initial task structure */
 struct task_struct init_task = INIT_TASK(init_task);
+EXPORT_SYMBOL(init_task);
 
 /* only used to get secondary processor up */
 struct task_struct *current_set[NR_CPUS] = {&init_task, };
diff -Nru a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
--- a/arch/ppc/kernel/setup.c	Wed Oct 15 00:46:37 2003
+++ b/arch/ppc/kernel/setup.c	Wed Oct 15 00:46:37 2003
@@ -171,12 +171,12 @@
 		return 0;
 	pvr = cpu_data[i].pvr;
 	lpj = cpu_data[i].loops_per_jiffy;
-	seq_printf(m, "processor\t: %d\n", i);
 #else
 	pvr = mfspr(PVR);
 	lpj = loops_per_jiffy;
 #endif
 
+	seq_printf(m, "processor\t: %d\n", i);
 	seq_printf(m, "cpu\t\t: ");
 
 	if (cur_cpu_spec[i]->pvr_mask)
diff -Nru a/arch/ppc/mm/hashtable.S b/arch/ppc/mm/hashtable.S
--- a/arch/ppc/mm/hashtable.S	Wed Oct 15 00:46:37 2003
+++ b/arch/ppc/mm/hashtable.S	Wed Oct 15 00:46:37 2003
@@ -417,6 +417,21 @@
 	lwz	r6,next_slot@l(r4)
 	addi	r6,r6,PTE_SIZE
 	andi.	r6,r6,7*PTE_SIZE
+#ifdef CONFIG_POWER4
+	/*
+	 * Since we don't have BATs on POWER4, we rely on always having
+	 * PTEs in the hash table to map the hash table and the code
+	 * that manipulates it in virtual mode, namely flush_hash_page and
+	 * flush_hash_segments.  Otherwise we can get a DSI inside those
+	 * routines which leads to a deadlock on the hash_table_lock on
+	 * SMP machines.  We avoid this by never overwriting the first
+	 * PTE of each PTEG if it is already valid.
+	 *	-- paulus.
+	 */
+	bne	102f
+	li	r6,PTE_SIZE
+102:
+#endif /* CONFIG_POWER4 */
 	stw	r6,next_slot@l(r4)
 	add	r4,r3,r6
 
diff -Nru a/arch/ppc/mm/ppc_mmu.c b/arch/ppc/mm/ppc_mmu.c
--- a/arch/ppc/mm/ppc_mmu.c	Wed Oct 15 00:46:36 2003
+++ b/arch/ppc/mm/ppc_mmu.c	Wed Oct 15 00:46:36 2003
@@ -211,6 +211,17 @@
 #define MIN_N_HPTEG	1024		/* min 64kB hash table */
 #endif
 
+#ifdef CONFIG_POWER4
+	/* The hash table has already been allocated and initialized
+	   in prom.c */
+	n_hpteg = Hash_size >> LG_HPTEG_SIZE;
+	lg_n_hpteg = __ilog2(n_hpteg);
+
+	/* Remove the hash table from the available memory */
+	if (Hash)
+		reserve_phys_mem(__pa(Hash), Hash_size);
+
+#else /* CONFIG_POWER4 */
 	/*
 	 * Allow 1 HPTE (1/8 HPTEG) for each page of memory.
 	 * This is less than the recommended amount, but then
@@ -224,13 +235,7 @@
 		++lg_n_hpteg;		/* round up if not power of 2 */
 		n_hpteg = 1 << lg_n_hpteg;
 	}
-
 	Hash_size = n_hpteg << LG_HPTEG_SIZE;
-	Hash_mask = n_hpteg - 1;
-	hmask = Hash_mask >> (16 - LG_HPTEG_SIZE);
-	mb2 = mb = 32 - LG_HPTEG_SIZE - lg_n_hpteg;
-	if (lg_n_hpteg > 16)
-		mb2 = 16 - LG_HPTEG_SIZE;
 
 	/*
 	 * Find some memory for the hash table.
@@ -240,6 +245,7 @@
 	cacheable_memzero(Hash, Hash_size);
 	_SDR1 = __pa(Hash) | SDR1_LOW_BITS;
 	Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
+#endif /* CONFIG_POWER4 */
 
 	printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
 	       total_memory >> 20, Hash_size >> 10, Hash);
@@ -249,6 +255,12 @@
 	 * Patch up the instructions in hashtable.S:create_hpte
 	 */
 	if ( ppc_md.progress ) ppc_md.progress("hash:patch", 0x345);
+	Hash_mask = n_hpteg - 1;
+	hmask = Hash_mask >> (16 - LG_HPTEG_SIZE);
+	mb2 = mb = 32 - LG_HPTEG_SIZE - lg_n_hpteg;
+	if (lg_n_hpteg > 16)
+		mb2 = 16 - LG_HPTEG_SIZE;
+
 	hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff)
 		| ((unsigned int)(Hash) >> 16);
 	hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0) | (mb << 6);
diff -Nru a/arch/ppc/platforms/pmac_smp.c b/arch/ppc/platforms/pmac_smp.c
--- a/arch/ppc/platforms/pmac_smp.c	Wed Oct 15 00:46:36 2003
+++ b/arch/ppc/platforms/pmac_smp.c	Wed Oct 15 00:46:36 2003
@@ -51,6 +51,7 @@
 #include <asm/time.h>
 #include <asm/open_pic.h>
 #include <asm/cacheflush.h>
+#include <asm/keylargo.h>
 
 /*
  * Powersurge (old powermac SMP) support.
@@ -108,9 +109,16 @@
 /* what sort of powersurge board we have */
 static int psurge_type = PSURGE_NONE;
 
+/* L2 and L3 cache settings to pass from CPU0 to CPU1 */
 volatile static long int core99_l2_cache;
 volatile static long int core99_l3_cache;
 
+/* Timebase freeze GPIO */
+static unsigned int core99_tb_gpio;
+
+/* Sync flag for HW tb sync */
+static volatile int sec_tb_reset = 0;
+
 static void __init
 core99_init_caches(int cpu)
 {
@@ -380,7 +388,6 @@
  */
 static void __init psurge_dual_sync_tb(int cpu_nr)
 {
-	static volatile int sec_tb_reset = 0;
 	int t;
 
 	set_dec(tb_ticks_per_jiffy);
@@ -408,8 +415,15 @@
 {
 
 	if (cpu_nr == 0) {
-		if (num_online_cpus() < 2)
+		/* If we failed to start the second CPU, we should still
+		 * send it an IPI to start the timebase & DEC or we might
+		 * have them stuck.
+		 */
+		if (num_online_cpus() < 2) {
+			if (psurge_type == PSURGE_DUAL)
+				psurge_set_ipi(1);
 			return;
+		}
 		/* reset the entry point so if we get another intr we won't
 		 * try to startup again */
 		out_be32(psurge_start, 0x100);
@@ -421,19 +435,42 @@
 		psurge_dual_sync_tb(cpu_nr);
 }
 
+void __init
+smp_psurge_take_timebase(void)
+{
+	/* Dummy implementation */
+}
+
+void __init
+smp_psurge_give_timebase(void)
+{
+	/* Dummy implementation */
+}
+
 static int __init
 smp_core99_probe(void)
 {
+	extern int powersave_nap;
 	struct device_node *cpus;
 	int i, ncpus = 1;
-	extern int powersave_nap;
+	u32 *tbprop;
 
 	if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);
 	cpus = find_type_devices("cpu");
-	if (cpus)
-		while ((cpus = cpus->next) != NULL)
-			++ncpus;
+	if (cpus == NULL)
+		return 0;
+
+	tbprop = (u32 *)get_property(cpus, "timebase-enable", NULL);
+	if (tbprop)
+		core99_tb_gpio = *tbprop;
+	else
+		core99_tb_gpio = KL_GPIO_TB_ENABLE;
+
+       	while ((cpus = cpus->next) != NULL)
+	       	++ncpus;
+
 	printk("smp_core99_probe: found %d cpus\n", ncpus);
+
 	if (ncpus > 1) {
 		openpic_request_IPIs();
 		for (i = 1; i < ncpus; ++i)
@@ -517,14 +554,59 @@
 		if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349);
 }
 
+void __init
+smp_core99_take_timebase(void)
+{
+	/* Secondary processor "takes" the timebase by freezing
+	 * it, resetting its local TB and telling CPU 0 to go on
+	 */
+	pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4);
+	pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
+	mb();
+
+	set_dec(tb_ticks_per_jiffy);
+	set_tb(0, 0);
+	last_jiffy_stamp(smp_processor_id()) = 0;
+
+	mb();
+       	sec_tb_reset = 1;
+}
+
+void __init
+smp_core99_give_timebase(void)
+{
+	unsigned int t;
+
+	/* Primary processor waits for secondary to have frozen
+	 * the timebase, resets local TB, and kick timebase again
+	 */
+	/* wait for the secondary to have reset its TB before proceeding */
+	for (t = 1000; t > 0 && !sec_tb_reset; --t)
+		udelay(1000);
+	if (t == 0)
+		printk(KERN_WARNING "Timeout waiting sync on second CPU\n");
+
+       	set_dec(tb_ticks_per_jiffy);
+	set_tb(0, 0);
+	last_jiffy_stamp(smp_processor_id()) = 0;
+	mb();
+
+	/* Now, restart the timebase by leaving the GPIO to an open collector */
+       	pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0);
+        pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
+
+	smp_tb_synchronized = 1;
+}
+
+
 /* PowerSurge-style Macs */
 struct smp_ops_t psurge_smp_ops __pmacdata = {
 	.message_pass	= smp_psurge_message_pass,
 	.probe		= smp_psurge_probe,
 	.kick_cpu	= smp_psurge_kick_cpu,
 	.setup_cpu	= smp_psurge_setup_cpu,
-	.give_timebase	= smp_generic_give_timebase,
-	.take_timebase	= smp_generic_take_timebase,
+	.give_timebase	= smp_psurge_give_timebase,
+	.take_timebase	= smp_psurge_take_timebase,
 };
 
 /* Core99 Macs (dual G4s) */
@@ -533,6 +615,6 @@
 	.probe		= smp_core99_probe,
 	.kick_cpu	= smp_core99_kick_cpu,
 	.setup_cpu	= smp_core99_setup_cpu,
-	.give_timebase	= smp_generic_give_timebase,
-	.take_timebase	= smp_generic_take_timebase,
+	.give_timebase	= smp_core99_give_timebase,
+	.take_timebase	= smp_core99_take_timebase,
 };
diff -Nru a/arch/ppc/platforms/pmac_time.c b/arch/ppc/platforms/pmac_time.c
--- a/arch/ppc/platforms/pmac_time.c	Wed Oct 15 00:46:36 2003
+++ b/arch/ppc/platforms/pmac_time.c	Wed Oct 15 00:46:36 2003
@@ -166,7 +166,7 @@
 {
 	struct device_node *vias;
 	volatile unsigned char *via;
-	int count = VIA_TIMER_FREQ_6 / HZ;
+	int count = VIA_TIMER_FREQ_6 / 100;
 	unsigned int dstart, dend;
 
 	vias = find_devices("via-cuda");
@@ -196,7 +196,7 @@
 		;
 	dend = get_dec();
 
-	tb_ticks_per_jiffy = (dstart - dend) / 6;
+	tb_ticks_per_jiffy = (dstart - dend) / (6 * (HZ/100));
 	tb_to_us = mulhwu_scale_factor(dstart - dend, 60000);
 
 	printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n",
@@ -260,7 +260,9 @@
 	 * calibration. That's better since the VIA itself seems
 	 * to be slightly off. --BenH
 	 */
-	if (!machine_is_compatible("MacRISC2"))
+	if (!machine_is_compatible("MacRISC2") &&
+	    !machine_is_compatible("MacRISC3") &&
+	    !machine_is_compatible("MacRISC4"))
 		if (via_calibrate_decr())
 			return;
 
diff -Nru a/arch/ppc/syslib/of_device.c b/arch/ppc/syslib/of_device.c
--- a/arch/ppc/syslib/of_device.c	Wed Oct 15 00:46:38 2003
+++ b/arch/ppc/syslib/of_device.c	Wed Oct 15 00:46:38 2003
@@ -97,9 +97,9 @@
 static int of_device_remove(struct device *dev)
 {
 	struct of_device * of_dev = to_of_device(dev);
-	struct of_platform_driver * drv = to_of_platform_driver(of_dev->dev.driver);
+	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
 
-	if (drv && drv->remove)
+	if (dev->driver && drv->remove)
 		drv->remove(of_dev);
 	return 0;
 }
@@ -107,10 +107,10 @@
 static int of_device_suspend(struct device *dev, u32 state)
 {
 	struct of_device * of_dev = to_of_device(dev);
-	struct of_platform_driver * drv = to_of_platform_driver(of_dev->dev.driver);
+	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
 	int error = 0;
 
-	if (drv && drv->suspend)
+	if (dev->driver && drv->suspend)
 		error = drv->suspend(of_dev, state);
 	return error;
 }
@@ -118,10 +118,10 @@
 static int of_device_resume(struct device * dev)
 {
 	struct of_device * of_dev = to_of_device(dev);
-	struct of_platform_driver * drv = to_of_platform_driver(of_dev->dev.driver);
+	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
 	int error = 0;
 
-	if (drv && drv->resume)
+	if (dev->driver && drv->resume)
 		error = drv->resume(of_dev);
 	return error;
 }
diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig
--- a/arch/sparc64/defconfig	Wed Oct 15 00:46:36 2003
+++ b/arch/sparc64/defconfig	Wed Oct 15 00:46:36 2003
@@ -799,11 +799,9 @@
 # CONFIG_ATM_ENI is not set
 # CONFIG_ATM_FIRESTREAM is not set
 # CONFIG_ATM_ZATM is not set
-# CONFIG_ATM_NICSTAR is not set
 # CONFIG_ATM_IDT77252 is not set
 # CONFIG_ATM_AMBASSADOR is not set
 # CONFIG_ATM_HORIZON is not set
-# CONFIG_ATM_IA is not set
 CONFIG_ATM_FORE200E_MAYBE=m
 CONFIG_ATM_FORE200E_PCA=y
 CONFIG_ATM_FORE200E_PCA_DEFAULT_FW=y
@@ -835,7 +833,6 @@
 # CONFIG_BAYCOM_SER_FDX is not set
 # CONFIG_BAYCOM_SER_HDX is not set
 # CONFIG_BAYCOM_PAR is not set
-# CONFIG_BAYCOM_EPP is not set
 # CONFIG_YAM is not set
 
 #
@@ -1037,7 +1034,6 @@
 CONFIG_I2C_I810=m
 CONFIG_I2C_NFORCE2=m
 CONFIG_I2C_PHILIPSPAR=m
-CONFIG_I2C_PIIX4=m
 CONFIG_I2C_PROSAVAGE=m
 CONFIG_I2C_SAVAGE4=m
 CONFIG_SCx200_ACB=m
@@ -1148,6 +1144,7 @@
 CONFIG_NFS_FS=m
 CONFIG_NFS_V3=y
 CONFIG_NFS_V4=y
+CONFIG_NFS_DIRECTIO=y
 CONFIG_NFSD=m
 CONFIG_NFSD_V3=y
 CONFIG_NFSD_V4=y
@@ -1273,7 +1270,7 @@
 # Supported Frontend Modules
 #
 CONFIG_DVB_STV0299=m
-CONFIG_DVB_ALPS_BSRV2=m
+CONFIG_DVB_SP887X=m
 CONFIG_DVB_ALPS_TDLB7=m
 CONFIG_DVB_ALPS_TDMB7=m
 CONFIG_DVB_ATMEL_AT76C651=m
@@ -1282,6 +1279,7 @@
 CONFIG_DVB_GRUNDIG_29504_401=m
 CONFIG_DVB_MT312=m
 CONFIG_DVB_VES1820=m
+CONFIG_DVB_VES1X93=m
 
 #
 # Supported SAA7146 based PCI Adapters
@@ -1302,6 +1300,7 @@
 #
 CONFIG_DVB_B2C2_SKYSTAR=m
 CONFIG_VIDEO_SAA7146=m
+CONFIG_VIDEO_SAA7146_VV=m
 CONFIG_VIDEO_VIDEOBUF=m
 CONFIG_VIDEO_TUNER=m
 CONFIG_VIDEO_BUF=m
diff -Nru a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
--- a/arch/sparc64/kernel/smp.c	Wed Oct 15 00:46:35 2003
+++ b/arch/sparc64/kernel/smp.c	Wed Oct 15 00:46:35 2003
@@ -720,8 +720,9 @@
 void flush_dcache_page_all(struct mm_struct *mm, struct page *page)
 {
 	cpumask_t mask = cpu_online_map;
-	cpu_clear(smp_processor_id(), mask);
 	u64 data0;
+
+	cpu_clear(smp_processor_id(), mask);
 
 #ifdef CONFIG_DEBUG_DCFLUSH
 	atomic_inc(&dcpage_flushes);
diff -Nru a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
--- a/arch/sparc64/kernel/sparc64_ksyms.c	Wed Oct 15 00:46:37 2003
+++ b/arch/sparc64/kernel/sparc64_ksyms.c	Wed Oct 15 00:46:37 2003
@@ -68,7 +68,6 @@
 extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 void _sigpause_common (unsigned int set, struct pt_regs *);
 extern void *__bzero(void *, size_t);
-extern void *__bzero_noasi(void *, size_t);
 extern void *__memscan_zero(void *, size_t);
 extern void *__memscan_generic(void *, int, size_t);
 extern int __memcmp(const void *, const void *, __kernel_size_t);
diff -Nru a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c
--- a/arch/sparc64/kernel/unaligned.c	Wed Oct 15 00:46:36 2003
+++ b/arch/sparc64/kernel/unaligned.c	Wed Oct 15 00:46:36 2003
@@ -73,6 +73,14 @@
 	else {
 		printk("Impossible unaligned trap. insn=%08x\n", insn);
 		die_if_kernel("Byte sized unaligned access?!?!", current_thread_info()->kregs);
+
+		/* GCC should never warn that control reaches the end
+		 * of this function without returning a value because
+		 * die_if_kernel() is marked with attribute 'noreturn'.
+		 * Alas, some versions do...
+		 */
+
+		return 0;
 	}
 }
 
diff -Nru a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c
--- a/arch/sparc64/solaris/misc.c	Wed Oct 15 00:46:38 2003
+++ b/arch/sparc64/solaris/misc.c	Wed Oct 15 00:46:38 2003
@@ -402,7 +402,7 @@
 			   Solaris setpgrp and setsid? */
 			ret = sys_setpgid(0, 0);
 			if (ret) return ret;
-			current->signal->tty = NULL;
+			current->tty = NULL;
 			return process_group(current);
 		}
 	case 2: /* getsid */
diff -Nru a/arch/x86_64/kernel/acpi/boot.c b/arch/x86_64/kernel/acpi/boot.c
--- a/arch/x86_64/kernel/acpi/boot.c	Wed Oct 15 00:46:36 2003
+++ b/arch/x86_64/kernel/acpi/boot.c	Wed Oct 15 00:46:36 2003
@@ -46,10 +46,8 @@
 #include <asm/proto.h>
 #include <asm/tlbflush.h>
 
-extern int acpi_disabled;
 int acpi_lapic = 0;
 int acpi_ioapic = 0;
-extern int disable_apic;
 
 #define PREFIX			"ACPI: "
 
@@ -316,7 +314,7 @@
 {
 	int			result = 0;
 
-	if (acpi_disabled)
+	if (acpi_disabled && !acpi_ht)
 		return 1;
 
 	/*
@@ -339,9 +337,10 @@
 		return result;
 	}
 
-	extern int disable_apic;
-	if (disable_apic)
+	if (disable_apic) { 
+		printk(KERN_INFO PREFIX "Skipping MADT probe because local APIC is disabled\n");
 		return 0;
+	}
 
 #ifdef CONFIG_X86_LOCAL_APIC
 
@@ -423,7 +422,7 @@
 	/*
 	 * if "noapic" boot option, don't look for IO-APICs
 	 */
-	if (disable_apic) {
+	if (skip_ioapic_setup) {
 		printk(KERN_INFO PREFIX "Skipping IOAPIC probe "
 		       "due to 'noapic' option.\n");
 		return 1;
diff -Nru a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c
--- a/arch/x86_64/kernel/apic.c	Wed Oct 15 00:46:36 2003
+++ b/arch/x86_64/kernel/apic.c	Wed Oct 15 00:46:36 2003
@@ -1023,8 +1023,11 @@
 	return 0;
 } 
 
+/* dummy parsing: see setup.c */
+
 __setup("disableapic", setup_disableapic); 
 __setup("nolapic", setup_nolapic);  /* same as disableapic, for compatibility */
+
 __setup("noapictimer", setup_noapictimer); 
 
 /* no "lapic" flag - we only use the lapic when the BIOS tells us so. */
diff -Nru a/arch/x86_64/kernel/cpufreq/Makefile b/arch/x86_64/kernel/cpufreq/Makefile
--- a/arch/x86_64/kernel/cpufreq/Makefile	Wed Oct 15 00:46:36 2003
+++ b/arch/x86_64/kernel/cpufreq/Makefile	Wed Oct 15 00:46:36 2003
@@ -4,9 +4,4 @@
 
 obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o
 
-$(obj)/powernow-k8.c: $(obj)/powernow-k8.h
-	@ln -sf ../../../i386/kernel/cpu/cpufreq/powernow-k8.c $(obj)/powernow-k8.c
-$(obj)/powernow-k8.h:
-	@ln -sf ../../../i386/kernel/cpu/cpufreq/powernow-k8.h $(obj)/powernow-k8.h
-
-clean-files += powernow-k8.c powernow-k8.h
+powernow-k8-objs := ../../../i386/kernel/cpu/cpufreq/powernow-k8.o
diff -Nru a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
--- a/arch/x86_64/kernel/io_apic.c	Wed Oct 15 00:46:36 2003
+++ b/arch/x86_64/kernel/io_apic.c	Wed Oct 15 00:46:36 2003
@@ -176,14 +176,79 @@
 int pirq_entries [MAX_PIRQS];
 int pirqs_enabled;
 int skip_ioapic_setup;
+int ioapic_force;
 
-static int __init ioapic_setup(char *str)
+/* dummy parsing: see setup.c */
+
+static int __init disable_ioapic_setup(char *str)
 {
 	skip_ioapic_setup = 1;
 	return 1;
 }
 
-__setup("noapic", ioapic_setup);
+static int __init enable_ioapic_setup(char *str)
+{
+	ioapic_force = 1;
+	skip_ioapic_setup = 0;
+	return 1;
+}
+
+__setup("noapic", disable_ioapic_setup);
+__setup("apic", enable_ioapic_setup);
+
+#ifndef CONFIG_SMP
+#include <asm/pci-direct.h>
+#include <linux/pci_ids.h>
+#include <linux/pci.h>
+
+/* Temporary Hack. Nvidia and VIA boards currently only work with IO-APIC
+   off. Check for an Nvidia or VIA PCI bridge and turn it off.
+   Use pci direct infrastructure because this runs before the PCI subsystem. 
+
+   Can be overwritten with "apic" */
+void __init check_ioapic(void) 
+{ 
+	int num,slot,func; 
+	if (ioapic_force) 
+		return; 
+
+	/* Poor man's PCI discovery */
+	for (num = 0; num < 32; num++) { 
+		for (slot = 0; slot < 32; slot++) { 
+			for (func = 0; func < 8; func++) { 
+				u32 class;
+				u32 vendor;
+				class = read_pci_config(num,slot,func,
+							PCI_CLASS_REVISION);
+				if (class == 0xffffffff)
+					break; 
+
+		       		if ((class >> 16) != PCI_CLASS_BRIDGE_PCI)
+					continue; 
+
+				vendor = read_pci_config(num, slot, func, 
+							 PCI_VENDOR_ID);
+				vendor &= 0xffff;
+				switch (vendor) { 
+				case PCI_VENDOR_ID_NVIDIA: 
+				case PCI_VENDOR_ID_VIA:
+					printk(KERN_INFO 
+     "PCI bridge %02x:%02x from %x found. Setting \"noapic\". Overwrite with \"apic\"\n",
+					       num,slot,vendor); 
+					skip_ioapic_setup = 1;
+					return;
+				} 
+
+				/* No multi-function device? */
+				u8 type = read_pci_config_byte(num,slot,func,
+							       PCI_HEADER_TYPE);
+				if (!(type & 0x80))
+					break;
+			} 
+		}
+	}
+} 
+#endif
 
 static int __init ioapic_pirq_setup(char *str)
 {
diff -Nru a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
--- a/arch/x86_64/kernel/setup.c	Wed Oct 15 00:46:35 2003
+++ b/arch/x86_64/kernel/setup.c	Wed Oct 15 00:46:35 2003
@@ -65,6 +65,7 @@
 EXPORT_SYMBOL_GPL(mmu_cr4_features);
 
 int acpi_disabled = 0;
+int acpi_ht = 0;
 
 /* For PCI or other memory-mapped resources */
 unsigned long pci_mem_start = 0x10000000;
@@ -204,9 +205,24 @@
 			acpi_disabled = 0;
 		}
 
-		if (!memcmp(from, "disableapic", 11))
+		/* acpi=ht just means: do ACPI MADT parsing 
+		   at bootup, but don't enable the full ACPI interpreter */
+		if (!memcmp(from, "acpi=ht", 7)) { 
+			acpi_ht = 1; 
+		}
+
+		if (!memcmp(from, "nolapic", 7) ||
+		    !memcmp(from, "disableapic", 11))
 			disable_apic = 1;
 
+		if (!memcmp(from, "noapic", 6)) 
+			skip_ioapic_setup = 1;
+
+		if (!memcmp(from, "apic", 6)) { 
+			skip_ioapic_setup = 0;
+			ioapic_force = 1;
+		}
+			
 		if (!memcmp(from, "mem=", 4))
 			parse_memopt(from+4, &from); 
 
@@ -417,6 +433,13 @@
 #endif
 
 	paging_init();
+
+#ifndef CONFIG_SMP
+	/* Temporary hack: disable the IO-APIC for UP Nvidia and 
+	   This is until we sort out the ACPI problems. */
+	if (!acpi_disabled) 
+		check_ioapic();
+#endif
 #ifdef CONFIG_ACPI_BOOT
        /*
         * Initialize the ACPI boot-time table parser (gets the RSDP and SDT).
diff -Nru a/arch/x86_64/mm/Makefile b/arch/x86_64/mm/Makefile
--- a/arch/x86_64/mm/Makefile	Wed Oct 15 00:46:37 2003
+++ b/arch/x86_64/mm/Makefile	Wed Oct 15 00:46:37 2003
@@ -7,7 +7,4 @@
 obj-$(CONFIG_DISCONTIGMEM) += numa.o
 obj-$(CONFIG_K8_NUMA) += k8topology.o
 
-$(obj)/hugetlbpage.c: 
-	@ln -sf ../../i386/mm/hugetlbpage.c $(obj)/hugetlbpage.c
-
-clean-files += hugetlbpage.c
+hugetlbpage-y = ../../i386/mm/hugetlbpage.o
diff -Nru a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
--- a/drivers/acpi/asus_acpi.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/acpi/asus_acpi.c	Wed Oct 15 00:46:36 2003
@@ -33,7 +33,6 @@
  */
 
 #include <linux/config.h>
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
diff -Nru a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c
--- a/drivers/acpi/executer/exconfig.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/acpi/executer/exconfig.c	Wed Oct 15 00:46:37 2003
@@ -92,6 +92,9 @@
 
 	/* Install the new table into the local data structures */
 
+	ACPI_MEMSET (&table_info, 0, sizeof (struct acpi_table_desc));
+
+	table_info.type        = 5;
 	table_info.pointer     = table;
 	table_info.length      = (acpi_size) table->length;
 	table_info.allocation  = ACPI_MEM_ALLOCATED;
@@ -178,7 +181,7 @@
 			return_ACPI_STATUS (status);
 		}
 
-		/* Not found, return an Integer=0 and AE_OK */
+		/* Table not found, return an Integer=0 and AE_OK */
 
 		ddb_handle = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
 		if (!ddb_handle) {
@@ -248,9 +251,11 @@
 				 walk_state);
 		if (ACPI_FAILURE (status)) {
 			(void) acpi_ex_unload_table (ddb_handle);
+			return_ACPI_STATUS (status);
 		}
 	}
 
+	*return_desc = ddb_handle;
 	return_ACPI_STATUS  (status);
 }
 
@@ -417,7 +422,7 @@
 acpi_ex_unload_table (
 	union acpi_operand_object       *ddb_handle)
 {
-	acpi_status                     status = AE_NOT_IMPLEMENTED;
+	acpi_status                     status = AE_OK;
 	union acpi_operand_object       *table_desc = ddb_handle;
 	struct acpi_table_desc          *table_info;
 
diff -Nru a/drivers/acpi/executer/exfield.c b/drivers/acpi/executer/exfield.c
--- a/drivers/acpi/executer/exfield.c	Wed Oct 15 00:46:35 2003
+++ b/drivers/acpi/executer/exfield.c	Wed Oct 15 00:46:35 2003
@@ -160,10 +160,10 @@
 	}
 
 	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
-		"Obj=%p Type=%X Buf=%p Len=%X\n",
+		"field_read [TO]:  Obj %p, Type %X, Buf %p, byte_len %X\n",
 		obj_desc, ACPI_GET_OBJECT_TYPE (obj_desc), buffer, (u32) length));
 	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
-		"field_write: bit_len=%X bit_off=%X byte_off=%X\n",
+		"field_read [FROM]: bit_len %X, bit_off %X, byte_off %X\n",
 		obj_desc->common_field.bit_length,
 		obj_desc->common_field.start_field_bit_offset,
 		obj_desc->common_field.base_byte_offset));
@@ -335,10 +335,13 @@
 	}
 
 	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
-		"Obj=%p Type=%X Buf=%p Len=%X\n",
-		obj_desc, ACPI_GET_OBJECT_TYPE (obj_desc), buffer, length));
+		"field_write [FROM]: Obj %p (%s:%X), Buf %p, byte_len %X\n",
+		source_desc, acpi_ut_get_type_name (ACPI_GET_OBJECT_TYPE (source_desc)),
+		ACPI_GET_OBJECT_TYPE (source_desc), buffer, length));
 	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
-		"field_read: bit_len=%X bit_off=%X byte_off=%X\n",
+		"field_write [TO]:  Obj %p (%s:%X), bit_len %X, bit_off %X, byte_off %X\n",
+		obj_desc, acpi_ut_get_type_name (ACPI_GET_OBJECT_TYPE (obj_desc)),
+		ACPI_GET_OBJECT_TYPE (obj_desc),
 		obj_desc->common_field.bit_length,
 		obj_desc->common_field.start_field_bit_offset,
 		obj_desc->common_field.base_byte_offset));
diff -Nru a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c
--- a/drivers/acpi/executer/exfldio.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/acpi/executer/exfldio.c	Wed Oct 15 00:46:36 2003
@@ -64,7 +64,8 @@
  * RETURN:      Status
  *
  * DESCRIPTION: Common processing for acpi_ex_extract_from_field and
- *              acpi_ex_insert_into_field. Initialize the
+ *              acpi_ex_insert_into_field. Initialize the Region if necessary and
+ *              validate the request.
  *
  ******************************************************************************/
 
@@ -96,7 +97,7 @@
 	 * If the Region Address and Length have not been previously evaluated,
 	 * evaluate them now and save the results.
 	 */
-	if (!(rgn_desc->region.flags & AOPOBJ_DATA_VALID)) {
+	if (!(rgn_desc->common.flags & AOPOBJ_DATA_VALID)) {
 		status = acpi_ds_get_region_arguments (rgn_desc);
 		if (ACPI_FAILURE (status)) {
 			return_ACPI_STATUS (status);
@@ -109,6 +110,18 @@
 		return_ACPI_STATUS (AE_OK);
 	}
 
+#ifdef ACPI_UNDER_DEVELOPMENT
+	/*
+	 * If the Field access is any_acc, we can now compute the optimal
+	 * access (because we know know the length of the parent region)
+	 */
+	if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
+		if (ACPI_FAILURE (status)) {
+			return_ACPI_STATUS (status);
+		}
+	}
+#endif
+
 	/*
 	 * Validate the request.  The entire request from the byte offset for a
 	 * length of one field datum (access width) must fit within the region.
@@ -242,7 +255,7 @@
 	}
 
 	ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD,
-		" Region[%s-%X] Access %X Base:Off %X:%X at %8.8X%8.8X\n",
+		" Region [%s:%X], Width %X, byte_base %X, Offset %X at %8.8X%8.8X\n",
 		acpi_ut_get_region_name (rgn_desc->region.space_id),
 		rgn_desc->region.space_id,
 		obj_desc->common_field.access_byte_width,
@@ -365,10 +378,10 @@
 	/*
 	 * The four types of fields are:
 	 *
-	 * buffer_fields - Read/write from/to a Buffer
-	 * region_fields - Read/write from/to a Operation Region.
-	 * bank_fields  - Write to a Bank Register, then read/write from/to an op_region
-	 * index_fields - Write to an Index Register, then read/write from/to a Data Register
+	 * buffer_field - Read/write from/to a Buffer
+	 * region_field - Read/write from/to a Operation Region.
+	 * bank_field  - Write to a Bank Register, then read/write from/to an op_region
+	 * index_field - Write to an Index Register, then read/write from/to a Data Register
 	 */
 	switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
 	case ACPI_TYPE_BUFFER_FIELD:
@@ -458,24 +471,34 @@
 
 		/* Write the index value to the index_register (itself a region_field) */
 
+		field_datum_byte_offset += obj_desc->index_field.value;
+
+		ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+				"Write to Index Register: Value %8.8X\n",
+				field_datum_byte_offset));
+
 		status = acpi_ex_insert_into_field (obj_desc->index_field.index_obj,
-				 &obj_desc->index_field.value,
-				 sizeof (obj_desc->index_field.value));
+				 &field_datum_byte_offset,
+				 sizeof (field_datum_byte_offset));
 		if (ACPI_FAILURE (status)) {
 			return_ACPI_STATUS (status);
 		}
 
+		ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+				"I/O to Data Register: value_ptr %p\n",
+				value));
+
 		if (read_write == ACPI_READ) {
 			/* Read the datum from the data_register */
 
 			status = acpi_ex_extract_from_field (obj_desc->index_field.data_obj,
-					  value, obj_desc->common_field.access_byte_width);
+					  value, sizeof (acpi_integer));
 		}
 		else {
-			/* Write the datum to the Data register */
+			/* Write the datum to the data_register */
 
 			status = acpi_ex_insert_into_field (obj_desc->index_field.data_obj,
-					  value, obj_desc->common_field.access_byte_width);
+					  value, sizeof (acpi_integer));
 		}
 		break;
 
@@ -490,12 +513,14 @@
 
 	if (ACPI_SUCCESS (status)) {
 		if (read_write == ACPI_READ) {
-			ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read=%8.8X%8.8X\n",
-					   ACPI_HIDWORD (*value), ACPI_LODWORD (*value)));
+			ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read %8.8X%8.8X, Width %d\n",
+					   ACPI_HIDWORD (*value), ACPI_LODWORD (*value),
+					   obj_desc->common_field.access_byte_width));
 		}
 		else {
-			ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written=%8.8X%8.8X\n",
-					   ACPI_HIDWORD (*value), ACPI_LODWORD (*value)));
+			ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written %8.8X%8.8X, Width %d\n",
+					   ACPI_HIDWORD (*value), ACPI_LODWORD (*value),
+					   obj_desc->common_field.access_byte_width));
 		}
 	}
 
@@ -554,6 +579,10 @@
 				 */
 				status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset,
 						  &current_value, ACPI_READ);
+				if (ACPI_FAILURE (status)) {
+					return_ACPI_STATUS (status);
+				}
+
 				merged_value |= (current_value & ~mask);
 			}
 			break;
@@ -573,6 +602,7 @@
 			break;
 
 		default:
+
 			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
 				"write_with_update_rule: Unknown update_rule setting: %X\n",
 				(obj_desc->common_field.field_flags & AML_FIELD_UPDATE_RULE_MASK)));
@@ -580,18 +610,19 @@
 		}
 	}
 
-	/* Write the merged value */
-
-	status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset,
-			  &merged_value, ACPI_WRITE);
-
 	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
-		"Mask %8.8X%8.8X datum_offset %X Value %8.8X%8.8X, merged_value %8.8X%8.8X\n",
+		"Mask %8.8X%8.8X, datum_offset %X, Width %X, Value %8.8X%8.8X, merged_value %8.8X%8.8X\n",
 		ACPI_HIDWORD (mask), ACPI_LODWORD (mask),
 		field_datum_byte_offset,
+		obj_desc->common_field.access_byte_width,
 		ACPI_HIDWORD (field_value), ACPI_LODWORD (field_value),
 		ACPI_HIDWORD (merged_value),ACPI_LODWORD (merged_value)));
 
+	/* Write the merged value */
+
+	status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset,
+			  &merged_value, ACPI_WRITE);
+
 	return_ACPI_STATUS (status);
 }
 
@@ -625,7 +656,7 @@
 	u32                             index;
 
 
-	ACPI_FUNCTION_ENTRY ();
+	ACPI_FUNCTION_TRACE_U32 ("ex_get_buffer_datum", byte_granularity);
 
 
 	/* Get proper index into buffer (handles big/little endian) */
@@ -659,6 +690,8 @@
 		/* Should not get here */
 		break;
 	}
+
+	return_VOID;
 }
 
 
@@ -690,7 +723,8 @@
 {
 	u32                             index;
 
-	ACPI_FUNCTION_ENTRY ();
+
+	ACPI_FUNCTION_TRACE_U32 ("ex_set_buffer_datum", byte_granularity);
 
 
 	/* Get proper index into buffer (handles big/little endian) */
@@ -724,6 +758,8 @@
 		/* Should not get here */
 		break;
 	}
+
+	return_VOID;
 }
 
 
@@ -777,7 +813,7 @@
 			   obj_desc->common_field.access_byte_width);
 
 	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
-		"byte_len=%X, datum_len=%X, byte_gran=%X\n",
+		"byte_len %X, datum_len %X, byte_gran %X\n",
 		byte_field_length, datum_count,obj_desc->common_field.access_byte_width));
 
 	/*
@@ -942,20 +978,27 @@
 	 * larger than the field, this typically happens when an integer is
 	 * written to a field that is actually smaller than an integer.
 	 */
-	byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length);
+	byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES (
+			 obj_desc->common_field.bit_length);
 	if (buffer_length < byte_field_length) {
-		ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Buffer length %X too small for field %X\n",
+		ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+			"Buffer length %X too small for field %X\n",
 			buffer_length, byte_field_length));
 
 		return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
 	}
 
+	byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES (
+			 obj_desc->common_field.start_field_bit_offset +
+			 obj_desc->common_field.bit_length);
+
 	/* Convert byte count to datum count, round up if necessary */
 
-	datum_count = ACPI_ROUND_UP_TO (byte_field_length, obj_desc->common_field.access_byte_width);
+	datum_count = ACPI_ROUND_UP_TO (byte_field_length,
+			  obj_desc->common_field.access_byte_width);
 
 	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
-		"byte_len=%X, datum_len=%X, byte_gran=%X\n",
+		"Bytes %X, Datums %X, byte_gran %X\n",
 		byte_field_length, datum_count, obj_desc->common_field.access_byte_width));
 
 	/*
@@ -1006,6 +1049,10 @@
 		return_ACPI_STATUS (status);
 	}
 
+	/* We just wrote the first datum */
+
+	datum_offset++;
+
 	/* If the entire field fits within one datum, we are done. */
 
 	if ((datum_count == 1) &&
@@ -1025,7 +1072,6 @@
 	 * applied in Part3 below.
 	 */
 	while (datum_offset < datum_count) {
-		datum_offset++;
 		field_datum_byte_offset += obj_desc->common_field.access_byte_width;
 
 		/*
@@ -1057,33 +1103,34 @@
 		 * a datum boundary.  Update Rule must be applied to the bits outside
 		 * the field.
 		 */
-		if (datum_offset == datum_count) {
+		datum_offset++;
+		if ((datum_offset == datum_count) &&
+			(obj_desc->common_field.end_field_valid_bits)) {
 			/*
 			 * If there are dangling non-aligned bits, perform one more merged write
 			 * Else - field is aligned at the end, no need for any more writes
 			 */
-			if (obj_desc->common_field.end_field_valid_bits) {
-				/*
-				 * Part3:
-				 * This is the last datum and the field does not end on a datum boundary.
-				 * Build the partial datum and write with the update rule.
-				 *
-				 * Mask off the unused bits above (after) the end-of-field
-				 */
-				mask = ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_field_valid_bits);
-				merged_datum &= mask;
 
-				/* Write the last datum with the update rule */
+			/*
+			 * Part3:
+			 * This is the last datum and the field does not end on a datum boundary.
+			 * Build the partial datum and write with the update rule.
+			 *
+			 * Mask off the unused bits above (after) the end-of-field
+			 */
+			mask = ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_field_valid_bits);
+			merged_datum &= mask;
+
+			/* Write the last datum with the update rule */
 
-				status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum,
-						   field_datum_byte_offset);
-				if (ACPI_FAILURE (status)) {
-					return_ACPI_STATUS (status);
-				}
+			status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum,
+					   field_datum_byte_offset);
+			if (ACPI_FAILURE (status)) {
+				return_ACPI_STATUS (status);
 			}
 		}
 		else {
-			/* Normal case -- write the completed datum */
+			/* Normal (aligned) case -- write the completed datum */
 
 			status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset,
 					  &merged_datum, ACPI_WRITE);
diff -Nru a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c
--- a/drivers/acpi/executer/exoparg1.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/acpi/executer/exoparg1.c	Wed Oct 15 00:46:37 2003
@@ -524,7 +524,7 @@
 	acpi_integer                    value;
 
 
-	ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_0T_0R", acpi_ps_get_opcode_name (walk_state->opcode));
+	ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_0T_1R", acpi_ps_get_opcode_name (walk_state->opcode));
 
 
 	/* Examine the AML opcode */
diff -Nru a/drivers/acpi/executer/exprep.c b/drivers/acpi/executer/exprep.c
--- a/drivers/acpi/executer/exprep.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/acpi/executer/exprep.c	Wed Oct 15 00:46:36 2003
@@ -53,6 +53,133 @@
 	 ACPI_MODULE_NAME    ("exprep")
 
 
+#ifdef ACPI_UNDER_DEVELOPMENT
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ex_generate_access
+ *
+ * PARAMETERS:  field_bit_offset    - Start of field within parent region/buffer
+ *              field_bit_length    - Length of field in bits
+ *              region_length       - Length of parent in bytes
+ *
+ * RETURN:      Field granularity (8, 16, 32 or 64) and
+ *              byte_alignment (1, 2, 3, or 4)
+ *
+ * DESCRIPTION: Generate an optimal access width for fields defined with the
+ *              any_acc keyword.
+ *
+ * NOTE: Need to have the region_length in order to check for boundary
+ *       conditions (end-of-region).  However, the region_length is a deferred
+ *       operation.  Therefore, to complete this implementation, the generation
+ *       of this access width must be deferred until the region length has
+ *       been evaluated.
+ *
+ ******************************************************************************/
+
+static u32
+acpi_ex_generate_access (
+	u32                             field_bit_offset,
+	u32                             field_bit_length,
+	u32                             region_length)
+{
+	u32                             field_byte_length;
+	u32                             field_byte_offset;
+	u32                             field_byte_end_offset;
+	u32                             access_byte_width;
+	u32                             field_start_offset;
+	u32                             field_end_offset;
+	u32                             minimum_access_width = 0xFFFFFFFF;
+	u32                             minimum_accesses = 0xFFFFFFFF;
+	u32                             accesses;
+
+
+	ACPI_FUNCTION_TRACE ("ex_generate_access");
+
+
+	/* Round Field start offset and length to "minimal" byte boundaries */
+
+	field_byte_offset  = ACPI_DIV_8 (ACPI_ROUND_DOWN (field_bit_offset, 8));
+	field_byte_end_offset = ACPI_DIV_8 (ACPI_ROUND_UP (field_bit_length + field_bit_offset, 8));
+	field_byte_length  = field_byte_end_offset - field_byte_offset;
+
+	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+			"Bit length %d, Bit offset %d\n",
+			field_bit_length, field_bit_offset));
+	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+			"Byte Length %d, Byte Offset %d, End Offset %d\n",
+			field_byte_length, field_byte_offset, field_byte_end_offset));
+
+	/*
+	 * Iterative search for the maximum access width that is both aligned
+	 * and does not go beyond the end of the region
+	 *
+	 * Start at byte_acc and work upwards to qword_acc max. (1,2,4,8 bytes)
+	 */
+	for (access_byte_width = 1; access_byte_width <= 8; access_byte_width <<= 1) {
+		/*
+		 * 1) Round end offset up to next access boundary and make sure that this
+		 *    does not go beyond the end of the parent region.
+		 * 2) When the Access width is greater than the field_byte_length, we are done.
+		 *    (This does not optimize for the perfectly aligned case yet).
+		 */
+		if (ACPI_ROUND_UP (field_byte_end_offset, access_byte_width) <= region_length) {
+			field_start_offset = ACPI_ROUND_DOWN (field_byte_offset, access_byte_width) /
+					  access_byte_width;
+			field_end_offset = ACPI_ROUND_UP   ((field_byte_length + field_byte_offset),
+					  access_byte_width) / access_byte_width;
+			accesses         = field_end_offset - field_start_offset;
+
+			ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+					"access_width %d end is within region\n", access_byte_width));
+			ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+					"Field Start %d, Field End %d -- requires %d accesses\n",
+					field_start_offset, field_end_offset, accesses));
+
+			/* Single access is optimal */
+
+			if (accesses <= 1) {
+				ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+						"Entire field can be accessed with one operation of size %d\n",
+						access_byte_width));
+				return_VALUE (access_byte_width);
+			}
+
+			/*
+			 * Fits in the region, but requires more than one read/write.
+			 * try the next wider access on next iteration
+			 */
+			if (accesses < minimum_accesses) {
+				minimum_accesses   = accesses;
+				minimum_access_width = access_byte_width;
+			}
+		}
+		else {
+			ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+					"access_width %d end is NOT within region\n", access_byte_width));
+			if (access_byte_width == 1) {
+				ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+						"Field goes beyond end-of-region!\n"));
+				return_VALUE (0);     /* Field does not fit in the region at all */
+			}
+
+			/* This width goes beyond the end-of-region, back off to previous access */
+
+			ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+					"Backing off to previous optimal access width of %d\n",
+					minimum_access_width));
+			return_VALUE (minimum_access_width);
+		}
+	}
+
+	/* Could not read/write field with one operation, just use max access width */
+
+	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+			"Cannot access field in one operation, using width 8\n"));
+	return_VALUE (8);
+}
+#endif /* ACPI_UNDER_DEVELOPMENT */
+
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ex_decode_field_access
@@ -74,12 +201,11 @@
 	u32                             *return_byte_alignment)
 {
 	u32                             access;
-	u8                              byte_alignment;
-	u8                              bit_length;
-/*    u32                             Length; */
+	u32                             byte_alignment;
+	u32                             bit_length;
 
 
-	ACPI_FUNCTION_NAME ("ex_decode_field_access");
+	ACPI_FUNCTION_TRACE ("ex_decode_field_access");
 
 
 	access = (field_flags & AML_FIELD_ACCESS_TYPE_MASK);
@@ -87,41 +213,15 @@
 	switch (access) {
 	case AML_FIELD_ACCESS_ANY:
 
+#ifdef ACPI_UNDER_DEVELOPMENT
+		byte_alignment = acpi_ex_generate_access (obj_desc->common_field.start_field_bit_offset,
+				 obj_desc->common_field.bit_length,
+				 0xFFFFFFFF /* Temp until we pass region_length as param */);
+		bit_length = byte_alignment * 8;
+#endif
+
 		byte_alignment = 1;
 		bit_length = 8;
-
-#if 0
-		/*
-		 * TBD: optimize
-		 *
-		 * Any attempt to optimize the access size to the size of the field
-		 * must take into consideration the length of the region and take
-		 * care that an access to the field will not attempt to access
-		 * beyond the end of the region.
-		 */
-
-		/* Use the length to set the access type */
-
-		length = obj_desc->common_field.bit_length;
-
-		if (length <= 8) {
-			bit_length = 8;
-		}
-		else if (length <= 16) {
-			bit_length = 16;
-		}
-		else if (length <= 32) {
-			bit_length = 32;
-		}
-		else if (length <= 64) {
-			bit_length = 64;
-		}
-		else {
-			/* Larger than Qword - just use byte-size chunks */
-
-			bit_length = 8;
-		}
-#endif
 		break;
 
 	case AML_FIELD_ACCESS_BYTE:
@@ -151,7 +251,7 @@
 		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
 			"Unknown field access type %X\n",
 			access));
-		return (0);
+		return_VALUE (0);
 	}
 
 	if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_BUFFER_FIELD) {
@@ -164,7 +264,7 @@
 	}
 
 	*return_byte_alignment = byte_alignment;
-	return (bit_length);
+	return_VALUE (bit_length);
 }
 
 
@@ -336,7 +436,7 @@
 		type = acpi_ns_get_type (info->region_node);
 		if (type != ACPI_TYPE_REGION) {
 			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
-				"Needed Region, found type %X %s\n",
+				"Needed Region, found type %X (%s)\n",
 				type, acpi_ut_get_type_name (type)));
 
 			return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
@@ -372,7 +472,7 @@
 		acpi_ut_add_reference (obj_desc->field.region_obj);
 
 		ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
-			"region_field: Bitoff=%X Off=%X Gran=%X Region %p\n",
+			"region_field: bit_off %X, Off %X, Gran %X, Region %p\n",
 			obj_desc->field.start_field_bit_offset, obj_desc->field.base_byte_offset,
 			obj_desc->field.access_byte_width, obj_desc->field.region_obj));
 		break;
@@ -390,7 +490,7 @@
 		acpi_ut_add_reference (obj_desc->bank_field.bank_obj);
 
 		ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
-			"Bank Field: bit_off=%X Off=%X Gran=%X Region %p bank_reg %p\n",
+			"Bank Field: bit_off %X, Off %X, Gran %X, Region %p, bank_reg %p\n",
 			obj_desc->bank_field.start_field_bit_offset,
 			obj_desc->bank_field.base_byte_offset,
 			obj_desc->field.access_byte_width,
@@ -417,9 +517,10 @@
 		acpi_ut_add_reference (obj_desc->index_field.index_obj);
 
 		ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
-			"index_field: bitoff=%X off=%X gran=%X Index %p Data %p\n",
+			"index_field: bit_off %X, Off %X, Value %X, Gran %X, Index %p, Data %p\n",
 			obj_desc->index_field.start_field_bit_offset,
 			obj_desc->index_field.base_byte_offset,
+			obj_desc->index_field.value,
 			obj_desc->field.access_byte_width,
 			obj_desc->index_field.index_obj,
 			obj_desc->index_field.data_obj));
@@ -437,7 +538,7 @@
 	status = acpi_ns_attach_object (info->field_node, obj_desc,
 			  acpi_ns_get_type (info->field_node));
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "set named_obj %p (%4.4s) val = %p\n",
+	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Set named_obj %p [%4.4s], obj_desc %p\n",
 			info->field_node, info->field_node->name.ascii, obj_desc));
 
 	/* Remove local reference to the object */
diff -Nru a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c
--- a/drivers/acpi/executer/exresnte.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/acpi/executer/exresnte.c	Wed Oct 15 00:46:36 2003
@@ -47,6 +47,8 @@
 #include <acpi/acdispat.h>
 #include <acpi/acinterp.h>
 #include <acpi/acnamesp.h>
+#include <acpi/acparser.h>
+#include <acpi/amlcode.h>
 
 
 #define _COMPONENT          ACPI_EXECUTER
@@ -243,12 +245,26 @@
 
 	case ACPI_TYPE_LOCAL_REFERENCE:
 
-		/* No named references are allowed here */
+		switch (source_desc->reference.opcode) {
+		case AML_LOAD_OP:
 
-		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unsupported Reference opcode %X\n",
-			source_desc->reference.opcode));
+			/* This is a ddb_handle */
+			/* Return an additional reference to the object */
+
+			obj_desc = source_desc;
+			acpi_ut_add_reference (obj_desc);
+			break;
+
+		default:
+			/* No named references are allowed here */
 
-		return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unsupported Reference opcode %X (%s)\n",
+				source_desc->reference.opcode,
+				acpi_ps_get_opcode_name (source_desc->reference.opcode)));
+
+			return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+		}
+		break;
 
 
 	/* Default case is for unknown types */
diff -Nru a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c
--- a/drivers/acpi/executer/exresolv.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/acpi/executer/exresolv.c	Wed Oct 15 00:46:36 2003
@@ -48,6 +48,7 @@
 #include <acpi/acdispat.h>
 #include <acpi/acinterp.h>
 #include <acpi/acnamesp.h>
+#include <acpi/acparser.h>
 
 
 #define _COMPONENT          ACPI_EXECUTER
@@ -248,6 +249,7 @@
 
 		case AML_REF_OF_OP:
 		case AML_DEBUG_OP:
+		case AML_LOAD_OP:
 
 			/* Just leave the object as-is */
 
@@ -256,8 +258,8 @@
 
 		default:
 
-			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Reference opcode %X in %p\n",
-				opcode, stack_desc));
+			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Reference opcode %X (%s) in %p\n",
+				opcode, acpi_ps_get_opcode_name (opcode), stack_desc));
 			status = AE_AML_INTERNAL;
 			break;
 		}
diff -Nru a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c
--- a/drivers/acpi/executer/exresop.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/acpi/executer/exresop.c	Wed Oct 15 00:46:37 2003
@@ -224,6 +224,7 @@
 				case AML_REF_OF_OP:
 				case AML_ARG_OP:
 				case AML_LOCAL_OP:
+				case AML_LOAD_OP:   /* ddb_handle from LOAD_OP or LOAD_TABLE_OP */
 
 					ACPI_DEBUG_ONLY_MEMBERS (ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
 						"Reference Opcode: %s\n", op_info->name)));
@@ -231,8 +232,9 @@
 
 				default:
 					ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
-						"Unknown Reference Opcode %X\n",
-						obj_desc->reference.opcode));
+						"Unknown Reference Opcode %X [%s]\n",
+						obj_desc->reference.opcode,
+						(acpi_ps_get_opcode_info (obj_desc->reference.opcode))->name));
 
 					return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
 				}
@@ -376,6 +378,13 @@
 			/* Any operand type will do */
 
 			type_needed = ACPI_TYPE_ANY;
+			break;
+
+		case ARGI_DDBHANDLE:
+
+			/* Need an operand of type ACPI_TYPE_DDB_HANDLE */
+
+			type_needed = ACPI_TYPE_LOCAL_REFERENCE;
 			break;
 
 
diff -Nru a/drivers/acpi/executer/exstoren.c b/drivers/acpi/executer/exstoren.c
--- a/drivers/acpi/executer/exstoren.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/acpi/executer/exstoren.c	Wed Oct 15 00:46:36 2003
@@ -46,6 +46,7 @@
 
 #include <acpi/acpi.h>
 #include <acpi/acinterp.h>
+#include <acpi/amlcode.h>
 
 
 #define _COMPONENT          ACPI_EXECUTER
@@ -114,9 +115,10 @@
 		/*
 		 * Must have a Integer, Buffer, or String
 		 */
-		if ((ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_INTEGER)    &&
-			(ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_BUFFER)     &&
-			(ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_STRING)) {
+		if ((ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_INTEGER)   &&
+			(ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_BUFFER)    &&
+			(ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_STRING)    &&
+			!((ACPI_GET_OBJECT_TYPE (source_desc) == ACPI_TYPE_LOCAL_REFERENCE) && (source_desc->reference.opcode == AML_LOAD_OP))) {
 			/*
 			 * Conversion successful but still not a valid type
 			 */
diff -Nru a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c
--- a/drivers/acpi/executer/exsystem.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/acpi/executer/exsystem.c	Wed Oct 15 00:46:37 2003
@@ -129,18 +129,13 @@
 	ACPI_FUNCTION_ENTRY ();
 
 
-	if (how_long > 1000) /* 1 millisecond */ {
-		/* Since this thread will sleep, we must release the interpreter */
-
-		acpi_ex_exit_interpreter ();
-
-		acpi_os_sleep (0, (how_long / 1000) + 1);
-
-		/* And now we must get the interpreter again */
-
-		status = acpi_ex_enter_interpreter ();
+	if (how_long > 100) /* 100 microseconds */ {
+		/*
+		 * Longer than 100 usec, use sleep instead
+		 * (according to ACPI specification)
+		 */
+		status = acpi_ex_system_do_suspend ((how_long / 1000) + 1);
 	}
-
 	else {
 		acpi_os_stall (how_long);
 	}
diff -Nru a/drivers/acpi/hardware/hwacpi.c b/drivers/acpi/hardware/hwacpi.c
--- a/drivers/acpi/hardware/hwacpi.c	Wed Oct 15 00:46:35 2003
+++ b/drivers/acpi/hardware/hwacpi.c	Wed Oct 15 00:46:35 2003
@@ -208,6 +208,15 @@
 
 	ACPI_FUNCTION_TRACE ("hw_get_mode");
 
+
+	/*
+	 * ACPI 2.0 clarified that if SMI_CMD in FADT is zero,
+	 * system does not support mode transition.
+	 */
+	if (!acpi_gbl_FADT->smi_cmd) {
+		return_VALUE (ACPI_SYS_MODE_ACPI);
+	}
+
 	status = acpi_get_register (ACPI_BITREG_SCI_ENABLE, &value, ACPI_MTX_LOCK);
 	if (ACPI_FAILURE (status)) {
 		return_VALUE (ACPI_SYS_MODE_LEGACY);
diff -Nru a/drivers/acpi/resources/rsaddr.c b/drivers/acpi/resources/rsaddr.c
--- a/drivers/acpi/resources/rsaddr.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/acpi/resources/rsaddr.c	Wed Oct 15 00:46:36 2003
@@ -94,6 +94,12 @@
 	buffer += 1;
 	ACPI_MOVE_16_TO_16 (&temp16, buffer);
 
+	/* Validate minimum descriptor length */
+
+	if (temp16 < 13) {
+		return_ACPI_STATUS (AE_AML_BAD_RESOURCE_LENGTH);
+	}
+
 	*bytes_consumed = temp16 + 3;
 	output_struct->id = ACPI_RSTYPE_ADDRESS16;
 
@@ -199,8 +205,11 @@
 	 * pointer to where the null terminated string goes:
 	 * Each Interrupt takes 32-bits + the 5 bytes of the
 	 * stream that are default.
+	 *
+	 * Note: Some resource descriptors will have an additional null, so
+	 * we add 1 to the length.
 	 */
-	if (*bytes_consumed > 16) {
+	if (*bytes_consumed > (16 + 1)) {
 		/* Dereference the Index */
 
 		temp8 = *buffer;
@@ -401,7 +410,7 @@
 
 		/*
 		 * Buffer needs to be set to the length of the sting + one for the
-		 *  terminating null
+		 * terminating null
 		 */
 		buffer += (acpi_size)(ACPI_STRLEN (linked_list->data.address16.resource_source.string_ptr) + 1);
 	}
@@ -470,8 +479,14 @@
 	 */
 	buffer += 1;
 	ACPI_MOVE_16_TO_16 (&temp16, buffer);
-	*bytes_consumed = temp16 + 3;
 
+	/* Validate minimum descriptor length */
+
+	if (temp16 < 23) {
+		return_ACPI_STATUS (AE_AML_BAD_RESOURCE_LENGTH);
+	}
+
+	*bytes_consumed = temp16 + 3;
 	output_struct->id = ACPI_RSTYPE_ADDRESS32;
 
 	/*
@@ -578,8 +593,11 @@
 	 * This will leave us pointing to the Resource Source Index
 	 * If it is present, then save it off and calculate the
 	 * pointer to where the null terminated string goes:
+	 *
+	 * Note: Some resource descriptors will have an additional null, so
+	 * we add 1 to the length.
 	 */
-	if (*bytes_consumed > 26) {
+	if (*bytes_consumed > (26 + 1)) {
 		/* Dereference the Index */
 
 		temp8 = *buffer;
@@ -616,8 +634,8 @@
 
 		/*
 		 * In order for the struct_size to fall on a 32-bit boundary,
-		 *  calculate the length of the string and expand the
-		 *  struct_size to the next 32-bit boundary.
+		 * calculate the length of the string and expand the
+		 * struct_size to the next 32-bit boundary.
 		 */
 		temp8 = (u8) (index + 1);
 		struct_size += ACPI_ROUND_UP_to_32_bITS (temp8);
@@ -848,6 +866,12 @@
 	buffer += 1;
 	ACPI_MOVE_16_TO_16 (&temp16, buffer);
 
+	/* Validate minimum descriptor length */
+
+	if (temp16 < 43) {
+		return_ACPI_STATUS (AE_AML_BAD_RESOURCE_LENGTH);
+	}
+
 	*bytes_consumed = temp16 + 3;
 	output_struct->id = ACPI_RSTYPE_ADDRESS64;
 
@@ -958,8 +982,11 @@
 	 * pointer to where the null terminated string goes:
 	 * Each Interrupt takes 32-bits + the 5 bytes of the
 	 * stream that are default.
+	 *
+	 * Note: Some resource descriptors will have an additional null, so
+	 * we add 1 to the length.
 	 */
-	if (*bytes_consumed > 46) {
+	if (*bytes_consumed > (46 + 1)) {
 		/* Dereference the Index */
 
 		temp8 = *buffer;
@@ -992,7 +1019,6 @@
 		 * Add the terminating null
 		 */
 		*temp_ptr = 0x00;
-
 		output_struct->data.address64.resource_source.string_length = index + 1;
 
 		/*
@@ -1064,7 +1090,6 @@
 	/*
 	 * Set a pointer to the Length field - to be filled in later
 	 */
-
 	length_field = ACPI_CAST_PTR (u16, buffer);
 	buffer += 2;
 
@@ -1161,7 +1186,7 @@
 
 		/*
 		 * Buffer needs to be set to the length of the sting + one for the
-		 *  terminating null
+		 * terminating null
 		 */
 		buffer += (acpi_size)(ACPI_STRLEN (linked_list->data.address64.resource_source.string_ptr) + 1);
 	}
diff -Nru a/drivers/acpi/resources/rsirq.c b/drivers/acpi/resources/rsirq.c
--- a/drivers/acpi/resources/rsirq.c	Wed Oct 15 00:46:38 2003
+++ b/drivers/acpi/resources/rsirq.c	Wed Oct 15 00:46:38 2003
@@ -319,6 +319,12 @@
 	buffer += 1;
 	ACPI_MOVE_16_TO_16 (&temp16, buffer);
 
+	/* Validate minimum descriptor length */
+
+	if (temp16 < 6) {
+		return_ACPI_STATUS (AE_AML_BAD_RESOURCE_LENGTH);
+	}
+
 	*bytes_consumed = temp16 + 3;
 	output_struct->id = ACPI_RSTYPE_EXT_IRQ;
 
@@ -357,6 +363,12 @@
 	buffer += 1;
 	temp8 = *buffer;
 
+	/* Must have at least one IRQ */
+
+	if (temp8 < 1) {
+		return_ACPI_STATUS (AE_AML_BAD_RESOURCE_LENGTH);
+	}
+
 	output_struct->data.extended_irq.number_of_interrupts = temp8;
 
 	/*
@@ -388,9 +400,12 @@
 	 * pointer to where the null terminated string goes:
 	 * Each Interrupt takes 32-bits + the 5 bytes of the
 	 * stream that are default.
+	 *
+	 * Note: Some resource descriptors will have an additional null, so
+	 * we add 1 to the length.
 	 */
 	if (*bytes_consumed >
-		((acpi_size) output_struct->data.extended_irq.number_of_interrupts * 4) + 5) {
+		((acpi_size) output_struct->data.extended_irq.number_of_interrupts * 4) + (5 + 1)) {
 		/* Dereference the Index */
 
 		temp8 = *buffer;
diff -Nru a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
--- a/drivers/acpi/sleep/main.c	Wed Oct 15 00:46:35 2003
+++ b/drivers/acpi/sleep/main.c	Wed Oct 15 00:46:35 2003
@@ -20,8 +20,8 @@
 
 static struct pm_ops acpi_pm_ops;
 
-extern void do_suspend_lowlevel_s4bios(int);
-extern void do_suspend_lowlevel(int);
+extern void do_suspend_lowlevel_s4bios(void);
+extern void do_suspend_lowlevel(void);
 
 static u32 acpi_suspend_states[] = {
 	[PM_SUSPEND_ON]		= ACPI_STATE_S0,
@@ -95,14 +95,14 @@
 		break;
 
 	case PM_SUSPEND_MEM:
-		do_suspend_lowlevel(0);
+		do_suspend_lowlevel();
 		break;
 
 	case PM_SUSPEND_DISK:
 		if (acpi_pm_ops.pm_disk_mode == PM_DISK_PLATFORM)
 			status = acpi_enter_sleep_state(acpi_state);
 		else
-			do_suspend_lowlevel_s4bios(0);
+			do_suspend_lowlevel_s4bios();
 		break;
 	default:
 		return -EINVAL;
diff -Nru a/drivers/acpi/tables/tbconvrt.c b/drivers/acpi/tables/tbconvrt.c
--- a/drivers/acpi/tables/tbconvrt.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/acpi/tables/tbconvrt.c	Wed Oct 15 00:46:36 2003
@@ -131,7 +131,7 @@
 	/* Copy the header and set the length */
 
 	ACPI_MEMCPY (new_table, table_info->pointer, sizeof (struct acpi_table_header));
-	new_table->header.length = (u32) table_size;
+	new_table->length = (u32) table_size;
 
 	/* Copy the table pointers */
 
@@ -430,17 +430,17 @@
 	 * FADT length and version validation.  The table must be at least as
 	 * long as the version 1.0 FADT
 	 */
-	if (acpi_gbl_FADT->header.length < sizeof (struct fadt_descriptor_rev1)) {
-		ACPI_REPORT_ERROR (("Invalid FADT table length: 0x%X\n", acpi_gbl_FADT->header.length));
+	if (acpi_gbl_FADT->length < sizeof (struct fadt_descriptor_rev1)) {
+		ACPI_REPORT_ERROR (("Invalid FADT table length: 0x%X\n", acpi_gbl_FADT->length));
 		return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH);
 	}
 
-	if (acpi_gbl_FADT->header.revision >= FADT2_REVISION_ID) {
-		if (acpi_gbl_FADT->header.length < sizeof (struct fadt_descriptor_rev2)) {
+	if (acpi_gbl_FADT->revision >= FADT2_REVISION_ID) {
+		if (acpi_gbl_FADT->length < sizeof (struct fadt_descriptor_rev2)) {
 			/* Length is too short to be a V2.0 table */
 
 			ACPI_REPORT_WARNING (("Inconsistent FADT length (0x%X) and revision (0x%X), using FADT V1.0 portion of table\n",
-					 acpi_gbl_FADT->header.length, acpi_gbl_FADT->header.revision));
+					 acpi_gbl_FADT->length, acpi_gbl_FADT->revision));
 
 			acpi_tb_convert_fadt1 (local_fadt, (void *) acpi_gbl_FADT);
 		}
@@ -460,7 +460,7 @@
 	 * Global FADT pointer will point to the new common V2.0 FADT
 	 */
 	acpi_gbl_FADT = local_fadt;
-	acpi_gbl_FADT->header.length = sizeof (FADT_DESCRIPTOR);
+	acpi_gbl_FADT->length = sizeof (FADT_DESCRIPTOR);
 
 	/* Free the original table */
 
@@ -477,8 +477,8 @@
 
 	ACPI_DEBUG_PRINT ((ACPI_DB_TABLES,
 		"Hex dump of common internal FADT, size %d (%X)\n",
-		acpi_gbl_FADT->header.length, acpi_gbl_FADT->header.length));
-	ACPI_DUMP_BUFFER ((u8 *) (acpi_gbl_FADT), acpi_gbl_FADT->header.length);
+		acpi_gbl_FADT->length, acpi_gbl_FADT->length));
+	ACPI_DUMP_BUFFER ((u8 *) (acpi_gbl_FADT), acpi_gbl_FADT->length);
 
 	return_ACPI_STATUS (AE_OK);
 }
diff -Nru a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c
--- a/drivers/acpi/tables/tbinstal.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/acpi/tables/tbinstal.c	Wed Oct 15 00:46:36 2003
@@ -350,7 +350,7 @@
 void
 acpi_tb_delete_all_tables (void)
 {
-	acpi_table_type                     type;
+	acpi_table_type                 type;
 
 
 	/*
@@ -378,7 +378,7 @@
 
 void
 acpi_tb_delete_tables_by_type (
-	acpi_table_type                     type)
+	acpi_table_type                 type)
 {
 	struct acpi_table_desc          *table_desc;
 	u32                             count;
@@ -425,15 +425,16 @@
 		break;
 	}
 
-	/* Free the table */
-	/* Get the head of the list */
-
+	/*
+	 * Free the table
+	 * 1) Get the head of the list
+	 */
 	table_desc = acpi_gbl_table_lists[type].next;
 	count     = acpi_gbl_table_lists[type].count;
 
 	/*
-	 * Walk the entire list, deleting both the allocated tables
-	 * and the table descriptors
+	 * 2) Walk the entire list, deleting both the allocated tables
+	 *    and the table descriptors
 	 */
 	for (i = 0; i < count; i++) {
 		table_desc = acpi_tb_uninstall_table (table_desc);
diff -Nru a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c
--- a/drivers/acpi/utilities/utalloc.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/acpi/utilities/utalloc.c	Wed Oct 15 00:46:36 2003
@@ -795,7 +795,7 @@
 
 	ACPI_MEMSET (&allocation->user_space, 0xEA, allocation->size);
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Freeing size %X\n", allocation->size));
+	ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Freeing size 0%X\n", allocation->size));
 
 	status = acpi_ut_release_mutex (ACPI_MTX_MEMORY);
 	return_ACPI_STATUS (status);
diff -Nru a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
--- a/drivers/acpi/utilities/utglobal.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/acpi/utilities/utglobal.c	Wed Oct 15 00:46:36 2003
@@ -307,8 +307,8 @@
 	/***********    Name,   Signature, Global typed pointer     Signature size,      Type                  How many allowed?,    Contains valid AML? */
 
 	/* RSDP 0 */ {RSDP_NAME, RSDP_SIG, NULL,                    sizeof (RSDP_SIG)-1, ACPI_TABLE_ROOT     | ACPI_TABLE_SINGLE},
-	/* DSDT 1 */ {DSDT_SIG,  DSDT_SIG, (void *) &acpi_gbl_DSDT, sizeof (DSDT_SIG)-1, ACPI_TABLE_SECONDARY| ACPI_TABLE_SINGLE  | ACPI_TABLE_EXECUTABLE},
-	/* FADT 2 */ {FADT_SIG,  FADT_SIG, (void *) &acpi_gbl_FADT, sizeof (FADT_SIG)-1, ACPI_TABLE_PRIMARY | ACPI_TABLE_SINGLE},
+	/* DSDT 1 */ {DSDT_SIG,  DSDT_SIG, (void *) &acpi_gbl_DSDT, sizeof (DSDT_SIG)-1, ACPI_TABLE_SECONDARY| ACPI_TABLE_SINGLE   | ACPI_TABLE_EXECUTABLE},
+	/* FADT 2 */ {FADT_SIG,  FADT_SIG, (void *) &acpi_gbl_FADT, sizeof (FADT_SIG)-1, ACPI_TABLE_PRIMARY  | ACPI_TABLE_SINGLE},
 	/* FACS 3 */ {FACS_SIG,  FACS_SIG, (void *) &acpi_gbl_FACS, sizeof (FACS_SIG)-1, ACPI_TABLE_SECONDARY| ACPI_TABLE_SINGLE},
 	/* PSDT 4 */ {PSDT_SIG,  PSDT_SIG, NULL,                    sizeof (PSDT_SIG)-1, ACPI_TABLE_PRIMARY  | ACPI_TABLE_MULTIPLE | ACPI_TABLE_EXECUTABLE},
 	/* SSDT 5 */ {SSDT_SIG,  SSDT_SIG, NULL,                    sizeof (SSDT_SIG)-1, ACPI_TABLE_PRIMARY  | ACPI_TABLE_MULTIPLE | ACPI_TABLE_EXECUTABLE},
diff -Nru a/drivers/atm/Kconfig b/drivers/atm/Kconfig
--- a/drivers/atm/Kconfig	Wed Oct 15 00:46:36 2003
+++ b/drivers/atm/Kconfig	Wed Oct 15 00:46:36 2003
@@ -166,7 +166,7 @@
 #   fi
 config ATM_NICSTAR
 	tristate "IDT 77201 (NICStAR) (ForeRunnerLE)"
-	depends on PCI && ATM
+	depends on PCI && ATM && !64BIT
 	help
 	  The NICStAR chipset family is used in a large number of ATM NICs for
 	  25 and for 155 Mbps, including IDT cards and the Fore ForeRunnerLE
@@ -282,7 +282,7 @@
 
 config ATM_IA
 	tristate "Interphase ATM PCI x575/x525/x531"
-	depends on PCI && ATM
+	depends on PCI && ATM && !64BIT
 	---help---
 	  This is a driver for the Interphase (i)ChipSAR adapter cards
 	  which include a variety of variants in term of the size of the
diff -Nru a/drivers/base/bus.c b/drivers/base/bus.c
--- a/drivers/base/bus.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/base/bus.c	Wed Oct 15 00:46:36 2003
@@ -459,10 +459,6 @@
 		driver_attach(drv);
 		up_write(&bus->subsys.rwsem);
 
-		if (error) {
-			kobject_unregister(&drv->kobj);
-			put_bus(bus);
-		}
 	}
 	return error;
 }
diff -Nru a/drivers/base/core.c b/drivers/base/core.c
--- a/drivers/base/core.c	Wed Oct 15 00:46:35 2003
+++ b/drivers/base/core.c	Wed Oct 15 00:46:35 2003
@@ -76,6 +76,8 @@
 static void device_release(struct kobject * kobj)
 {
 	struct device * dev = to_dev(kobj);
+	struct completion * c = dev->complete;
+
 	if (dev->release)
 		dev->release(dev);
 	else {
@@ -84,6 +86,8 @@
 			dev->bus_id);
 		WARN_ON(1);
 	}
+	if (c)
+		complete(c);
 }
 
 static struct kobj_type ktype_device = {
@@ -349,6 +353,26 @@
 	put_device(dev);
 }
 
+
+/**
+ *	device_unregister_wait - Unregister device and wait for it to be freed.
+ *	@dev: Device to unregister.
+ *
+ *	For the cases where the caller needs to wait for all references to
+ *	be dropped from the device before continuing (e.g. modules with
+ *	statically allocated devices), this function uses a completion struct
+ *	to wait, along with a matching complete() in device_release() above.
+ */
+
+void device_unregister_wait(struct device * dev)
+{
+	struct completion c;
+	init_completion(&c);
+	dev->complete = &c;
+	device_unregister(dev);
+	wait_for_completion(&c);
+}
+
 /**
  *	device_for_each_child - device child iterator.
  *	@dev:	parent struct device.
@@ -389,6 +413,7 @@
 
 EXPORT_SYMBOL(device_del);
 EXPORT_SYMBOL(device_unregister);
+EXPORT_SYMBOL(device_unregister_wait);
 EXPORT_SYMBOL(get_device);
 EXPORT_SYMBOL(put_device);
 
diff -Nru a/drivers/block/Kconfig b/drivers/block/Kconfig
--- a/drivers/block/Kconfig	Wed Oct 15 00:46:36 2003
+++ b/drivers/block/Kconfig	Wed Oct 15 00:46:36 2003
@@ -6,7 +6,7 @@
 
 config BLK_DEV_FD
 	tristate "Normal floppy disk support"
-	depends on ISA || M68 || SPARC64
+	depends on !X86_PC9800 && !ARCH_S390
 	---help---
 	  If you want to use the floppy disk drive(s) of your PC under Linux,
 	  say Y. Information about this driver, especially important for IBM
diff -Nru a/drivers/char/Kconfig b/drivers/char/Kconfig
--- a/drivers/char/Kconfig	Wed Oct 15 00:46:35 2003
+++ b/drivers/char/Kconfig	Wed Oct 15 00:46:35 2003
@@ -851,7 +851,7 @@
 
 config SONYPI
 	tristate "Sony Vaio Programmable I/O Control Device support (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && X86 && PCI
+	depends on EXPERIMENTAL && X86 && PCI && !64BIT
 	---help---
 	  This driver enables access to the Sony Programmable I/O Control
 	  Device which can be found in many (all ?) Sony Vaio laptops.
diff -Nru a/drivers/char/ftape/lowlevel/ftape-proc.c b/drivers/char/ftape/lowlevel/ftape-proc.c
--- a/drivers/char/ftape/lowlevel/ftape-proc.c	Wed Oct 15 00:46:38 2003
+++ b/drivers/char/ftape/lowlevel/ftape-proc.c	Wed Oct 15 00:46:38 2003
@@ -207,11 +207,9 @@
 		ftape_read_proc, NULL) != NULL;
 }
 
-#ifdef MODULE
 void ftape_proc_destroy(void)
 {
 	remove_proc_entry("ftape", &proc_root);
 }
-#endif
 
 #endif /* defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS) */
diff -Nru a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig
--- a/drivers/char/ipmi/Kconfig	Wed Oct 15 00:46:37 2003
+++ b/drivers/char/ipmi/Kconfig	Wed Oct 15 00:46:37 2003
@@ -24,6 +24,18 @@
 	 generate an IPMI event describing the panic to each interface
 	 registered with the message handler.
 
+config IPMI_PANIC_STRING
+	bool 'Generate OEM events containing the panic string'
+	depends on IPMI_PANIC_EVENT
+	help
+	  When a panic occurs, this will cause the IPMI message handler to
+	  generate IPMI OEM type f0 events holding the IPMB address of the
+	  panic generator (byte 4 of the event), a sequence number for the
+	  string (byte 5 of the event) and part of the string (the rest of the
+	  event).  Bytes 1, 2, and 3 are the normal usage for an OEM event.
+	  You can fetch these events and use the sequence numbers to piece the
+	  string together.
+
 config IPMI_DEVICE_INTERFACE
        tristate 'Device interface for IPMI'
        depends on IPMI_HANDLER
diff -Nru a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
--- a/drivers/char/ipmi/ipmi_msghandler.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/char/ipmi/ipmi_msghandler.c	Wed Oct 15 00:46:37 2003
@@ -169,6 +169,19 @@
 	/* My LUN.  This should generally stay the SMS LUN, but just in
 	   case... */
 	unsigned char my_lun;
+
+	/* The event receiver for my BMC, only really used at panic
+	   shutdown as a place to store this. */
+	unsigned char event_receiver;
+	unsigned char event_receiver_lun;
+	unsigned char local_sel_device;
+	unsigned char local_event_generator;
+
+	/* A cheap hack, if this is non-null and a message to an
+	   interface comes in with a NULL user, call this routine with
+	   it.  Note that the message will still be freed by the
+	   caller.  This only works on the system interface. */
+	void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_smi_msg *msg);
 };
 
 int
@@ -1465,6 +1478,9 @@
 	}
 
 	if (!found) {
+		/* Special handling for NULL users. */
+		if (!recv_msg->user && intf->null_user_handler)
+			intf->null_user_handler(intf, msg);
 		/* The user for the message went away, so give up. */
 		ipmi_free_recv_msg(recv_msg);
 	} else {
@@ -1733,7 +1749,7 @@
 
 /* Call every 100 ms. */
 #define IPMI_TIMEOUT_TIME	100
-#define IPMI_TIMEOUT_JIFFIES	(IPMI_TIMEOUT_TIME/(1000/HZ))
+#define IPMI_TIMEOUT_JIFFIES	((IPMI_TIMEOUT_TIME * HZ)/1000)
 
 /* Request events from the queue every second.  Hopefully, in the
    future, IPMI will add a way to know immediately if an event is
@@ -1813,18 +1829,48 @@
 {
 }
 
-static void send_panic_events(void)
+#ifdef CONFIG_IPMI_PANIC_STRING
+static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
+{
+	if ((msg->rsp[0] == (IPMI_NETFN_SENSOR_EVENT_RESPONSE << 2))
+	    && (msg->rsp[1] == IPMI_GET_EVENT_RECEIVER_CMD)
+	    && (msg->rsp[2] == IPMI_CC_NO_ERROR))
+	{
+		/* A get event receiver command, save it. */
+		intf->event_receiver = msg->rsp[3];
+		intf->event_receiver_lun = msg->rsp[4] & 0x3;
+	}
+}
+
+static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
+{
+	if ((msg->rsp[0] == (IPMI_NETFN_APP_RESPONSE << 2))
+	    && (msg->rsp[1] == IPMI_GET_DEVICE_ID_CMD)
+	    && (msg->rsp[2] == IPMI_CC_NO_ERROR))
+	{
+		/* A get device id command, save if we are an event
+		   receiver or generator. */
+		intf->local_sel_device = (msg->rsp[8] >> 2) & 1;
+		intf->local_event_generator = (msg->rsp[8] >> 5) & 1;
+	}
+}
+#endif
+
+static void send_panic_events(char *str)
 {
 	struct ipmi_msg                   msg;
 	ipmi_smi_t                        intf;
-	unsigned char                     data[8];
+	unsigned char                     data[16];
 	int                               i;
-	struct ipmi_system_interface_addr addr;
+	struct ipmi_system_interface_addr *si;
+	struct ipmi_addr                  addr;
 	struct ipmi_smi_msg               smi_msg;
 	struct ipmi_recv_msg              recv_msg;
 
-	addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
-	addr.channel = IPMI_BMC_CHANNEL;
+	si = (struct ipmi_system_interface_addr *) &addr;
+	si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+	si->channel = IPMI_BMC_CHANNEL;
+	si->lun = 0;
 
 	/* Fill in an event telling that we have failed. */
 	msg.netfn = 0x04; /* Sensor or Event. */
@@ -1837,12 +1883,13 @@
 	data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */
 	data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */
 
-	/* These used to have the first three bytes of the panic string,
-	   but not only is that not terribly useful, it's not available
-	   any more. */
-	data[3] = 0;
-	data[6] = 0;
-	data[7] = 0;
+	/* Put a few breadcrumbs in.  Hopefully later we can add more things
+	   to make the panic events more useful. */
+	if (str) {
+		data[3] = str[0];
+		data[6] = str[1];
+		data[7] = str[2];
+	}
 
 	smi_msg.done = dummy_smi_done_handler;
 	recv_msg.done = dummy_recv_done_handler;
@@ -1853,10 +1900,11 @@
 		if (intf == NULL)
 			continue;
 
+		/* Send the event announcing the panic. */
 		intf->handlers->set_run_to_completion(intf->send_info, 1);
 		i_ipmi_request(NULL,
 			       intf,
-			       (struct ipmi_addr *) &addr,
+			       &addr,
 			       0,
 			       &msg,
 			       &smi_msg,
@@ -1865,6 +1913,130 @@
 			       intf->my_address,
 			       intf->my_lun);
 	}
+
+#ifdef CONFIG_IPMI_PANIC_STRING
+	/* On every interface, dump a bunch of OEM event holding the
+	   string. */
+	if (!str) 
+		return;
+
+	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+		char                  *p = str;
+		struct ipmi_ipmb_addr *ipmb;
+		int                   j;
+
+		intf = ipmi_interfaces[i];
+		if (intf == NULL)
+			continue;
+
+		/* First job here is to figure out where to send the
+		   OEM events.  There's no way in IPMI to send OEM
+		   events using an event send command, so we have to
+		   find the SEL to put them in and stick them in
+		   there. */
+
+		/* Get capabilities from the get device id. */
+		intf->local_sel_device = 0;
+		intf->local_event_generator = 0;
+		intf->event_receiver = 0;
+
+		/* Request the device info from the local MC. */
+		msg.netfn = IPMI_NETFN_APP_REQUEST;
+		msg.cmd = IPMI_GET_DEVICE_ID_CMD;
+		msg.data = NULL;
+		msg.data_len = 0;
+		intf->null_user_handler = device_id_fetcher;
+		i_ipmi_request(NULL,
+			       intf,
+			       &addr,
+			       0,
+			       &msg,
+			       &smi_msg,
+			       &recv_msg,
+			       0,
+			       intf->my_address,
+			       intf->my_lun);
+
+		if (intf->local_event_generator) {
+			/* Request the event receiver from the local MC. */
+			msg.netfn = IPMI_NETFN_SENSOR_EVENT_REQUEST;
+			msg.cmd = IPMI_GET_EVENT_RECEIVER_CMD;
+			msg.data = NULL;
+			msg.data_len = 0;
+			intf->null_user_handler = event_receiver_fetcher;
+			i_ipmi_request(NULL,
+				       intf,
+				       &addr,
+				       0,
+				       &msg,
+				       &smi_msg,
+				       &recv_msg,
+				       0,
+				       intf->my_address,
+				       intf->my_lun);
+		}
+		intf->null_user_handler = NULL;
+
+		/* Validate the event receiver.  The low bit must not
+		   be 1 (it must be a valid IPMB address), it cannot
+		   be zero, and it must not be my address. */
+                if (((intf->event_receiver & 1) == 0)
+		    && (intf->event_receiver != 0)
+		    && (intf->event_receiver != intf->my_address))
+		{
+			/* The event receiver is valid, send an IPMB
+			   message. */
+			ipmb = (struct ipmi_ipmb_addr *) &addr;
+			ipmb->addr_type = IPMI_IPMB_ADDR_TYPE;
+			ipmb->channel = 0; /* FIXME - is this right? */
+			ipmb->lun = intf->event_receiver_lun;
+			ipmb->slave_addr = intf->event_receiver;
+		} else if (intf->local_sel_device) {
+			/* The event receiver was not valid (or was
+			   me), but I am an SEL device, just dump it
+			   in my SEL. */
+			si = (struct ipmi_system_interface_addr *) &addr;
+			si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+			si->channel = IPMI_BMC_CHANNEL;
+			si->lun = 0;
+		} else
+			continue; /* No where to send the event. */
+
+		
+		msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */
+		msg.cmd = IPMI_ADD_SEL_ENTRY_CMD;
+		msg.data = data;
+		msg.data_len = 16;
+
+		j = 0;
+		while (*p) {
+			int size = strlen(p);
+
+			if (size > 11)
+				size = 11;
+			data[0] = 0;
+			data[1] = 0;
+			data[2] = 0xf0; /* OEM event without timestamp. */
+			data[3] = intf->my_address;
+			data[4] = j++; /* sequence # */
+			/* Always give 11 bytes, so strncpy will fill
+			   it with zeroes for me. */
+			strncpy(data+5, p, 11);
+			p += size;
+
+			i_ipmi_request(NULL,
+				       intf,
+				       &addr,
+				       0,
+				       &msg,
+				       &smi_msg,
+				       &recv_msg,
+				       0,
+				       intf->my_address,
+				       intf->my_lun);
+		}
+	}	
+#endif /* CONFIG_IPMI_PANIC_STRING */
 }
 #endif /* CONFIG_IPMI_PANIC_EVENT */
 
@@ -1891,7 +2063,7 @@
 	}
 
 #ifdef CONFIG_IPMI_PANIC_EVENT
-	send_panic_events();
+	send_panic_events(ptr);
 #endif
 
 	return NOTIFY_DONE;
diff -Nru a/drivers/char/n_tty.c b/drivers/char/n_tty.c
--- a/drivers/char/n_tty.c	Wed Oct 15 00:46:35 2003
+++ b/drivers/char/n_tty.c	Wed Oct 15 00:46:35 2003
@@ -974,8 +974,7 @@
 	/* NOTE: not yet done after every sleep pending a thorough
 	   check of the logic of this change. -- jlc */
 	/* don't stop on /dev/console */
-	if (file->f_op->write != redirected_tty_write &&
-			process_tty(current) == tty) {
+	if (file->f_op->write != redirected_tty_write && current->tty == tty) {
 		if (tty->pgrp <= 0)
 			printk("read_chan: tty->pgrp <= 0!\n");
 		else if (process_group(current) != tty->pgrp) {
diff -Nru a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
--- a/drivers/char/pcmcia/synclink_cs.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/char/pcmcia/synclink_cs.c	Wed Oct 15 00:46:36 2003
@@ -4232,7 +4232,7 @@
 	d->tx_timeout = mgslpc_sppp_tx_timeout;
 	d->watchdog_timeo = 10*HZ;
 
-	if (register_netdev(d) == -1) {
+	if (register_netdev(d)) {
 		printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
 		sppp_detach(info->netdev);
 		return;
diff -Nru a/drivers/char/rocket.c b/drivers/char/rocket.c
--- a/drivers/char/rocket.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/char/rocket.c	Wed Oct 15 00:46:37 2003
@@ -953,7 +953,7 @@
 	/*
 	 * Info->count is now 1; so it's safe to sleep now.
 	 */
-	info->session = process_session(current);
+	info->session = current->session;
 	info->pgrp = process_group(current);
 
 	if ((info->flags & ROCKET_INITIALIZED) == 0) {
diff -Nru a/drivers/char/synclink.c b/drivers/char/synclink.c
--- a/drivers/char/synclink.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/char/synclink.c	Wed Oct 15 00:46:36 2003
@@ -7847,7 +7847,7 @@
 	d->tx_timeout = mgsl_sppp_tx_timeout;
 	d->watchdog_timeo = 10*HZ;
 
-	if (register_netdev(d) == -1) {
+	if (register_netdev(d)) {
 		printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
 		sppp_detach(info->netdev);
 		return;
diff -Nru a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
--- a/drivers/char/synclinkmp.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/char/synclinkmp.c	Wed Oct 15 00:46:36 2003
@@ -1653,7 +1653,7 @@
 	d->tx_timeout = sppp_cb_tx_timeout;
 	d->watchdog_timeo = 10*HZ;
 
-	if (register_netdev(d) == -1) {
+	if (register_netdev(d)) {
 		printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
 		sppp_detach(info->netdev);
 		return;
diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c
--- a/drivers/char/tty_io.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/char/tty_io.c	Wed Oct 15 00:46:37 2003
@@ -316,7 +316,7 @@
  */
 int tty_check_change(struct tty_struct * tty)
 {
-	if (process_tty(current) != tty)
+	if (current->tty != tty)
 		return 0;
 	if (tty->pgrp <= 0) {
 		printk(KERN_WARNING "tty_check_change: tty->pgrp <= 0!\n");
@@ -483,14 +483,14 @@
 	if (tty->session > 0) {
 		struct list_head *l;
 		for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid) {
-			if (process_tty(p) == tty)
-				p->signal->tty = NULL;
-			if (!process_session_leader(p))
+			if (p->tty == tty)
+				p->tty = NULL;
+			if (!p->leader)
 				continue;
 			send_group_sig_info(SIGHUP, SEND_SIG_PRIV, p);
 			send_group_sig_info(SIGCONT, SEND_SIG_PRIV, p);
 			if (tty->pgrp > 0)
-				p->signal->tty_old_pgrp = tty->pgrp;
+				p->tty_old_pgrp = tty->pgrp;
 		}
 	}
 	read_unlock(&tasklist_lock);
@@ -567,15 +567,15 @@
 
 	lock_kernel();
 
-	tty = process_tty(current);
+	tty = current->tty;
 	if (tty) {
 		tty_pgrp = tty->pgrp;
 		if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
 			tty_vhangup(tty);
 	} else {
-		if (current->signal->tty_old_pgrp) {
-			kill_pg(current->signal->tty_old_pgrp, SIGHUP, on_exit);
-			kill_pg(current->signal->tty_old_pgrp, SIGCONT, on_exit);
+		if (current->tty_old_pgrp) {
+			kill_pg(current->tty_old_pgrp, SIGHUP, on_exit);
+			kill_pg(current->tty_old_pgrp, SIGCONT, on_exit);
 		}
 		unlock_kernel();	
 		return;
@@ -586,13 +586,13 @@
 			kill_pg(tty_pgrp, SIGCONT, on_exit);
 	}
 
-	current->signal->tty_old_pgrp = 0;
+	current->tty_old_pgrp = 0;
 	tty->session = 0;
 	tty->pgrp = -1;
 
 	read_lock(&tasklist_lock);
-	for_each_task_pid(process_session(current), PIDTYPE_SID, p, l, pid)
-		p->signal->tty = NULL;
+	for_each_task_pid(current->session, PIDTYPE_SID, p, l, pid)
+		p->tty = NULL;
 	read_unlock(&tasklist_lock);
 	unlock_kernel();
 }
@@ -1220,10 +1220,10 @@
 
 		read_lock(&tasklist_lock);
 		for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid)
-			p->signal->tty = NULL;
+			p->tty = NULL;
 		if (o_tty)
 			for_each_task_pid(o_tty->session, PIDTYPE_SID, p,l, pid)
-				p->signal->tty = NULL;
+				p->tty = NULL;
 		read_unlock(&tasklist_lock);
 	}
 
@@ -1294,10 +1294,10 @@
 retry_open:
 	noctty = filp->f_flags & O_NOCTTY;
 	if (device == MKDEV(TTYAUX_MAJOR,0)) {
-		if (!process_tty(current))
+		if (!current->tty)
 			return -ENXIO;
-		driver = process_tty(current)->driver;
-		index = process_tty(current)->index;
+		driver = current->tty->driver;
+		index = current->tty->index;
 		filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
 		/* noctty = 1; */
 		goto got_driver;
@@ -1391,13 +1391,15 @@
 			filp->f_op = &tty_fops;
 		goto retry_open;
 	}
-	if (!noctty && process_session_leader(current) &&
-			!process_tty(current) && tty->session == 0) {
+	if (!noctty &&
+	    current->leader &&
+	    !current->tty &&
+	    tty->session == 0) {
 	    	task_lock(current);
-		current->signal->tty = tty;
+		current->tty = tty;
 		task_unlock(current);
-		current->signal->tty_old_pgrp = 0;
-		tty->session = process_session(current);
+		current->tty_old_pgrp = 0;
+		tty->session = current->session;
 		tty->pgrp = process_group(current);
 	}
 	return 0;
@@ -1455,7 +1457,7 @@
 {
 	char ch, mbz = 0;
 
-	if ((process_tty(current) != tty) && !capable(CAP_SYS_ADMIN))
+	if ((current->tty != tty) && !capable(CAP_SYS_ADMIN))
 		return -EPERM;
 	if (get_user(ch, arg))
 		return -EFAULT;
@@ -1541,14 +1543,14 @@
 	struct pid *pid;
 	task_t *p;
 
-	if (process_session_leader(current) &&
-			(process_session(current) == tty->session))
+	if (current->leader &&
+	    (current->session == tty->session))
 		return 0;
 	/*
 	 * The process must be a session leader and
 	 * not have a controlling tty already.
 	 */
-	if (!process_session_leader(current) || process_tty(current))
+	if (!current->leader || current->tty)
 		return -EPERM;
 	if (tty->session > 0) {
 		/*
@@ -1562,16 +1564,16 @@
 
 			read_lock(&tasklist_lock);
 			for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid)
-				p->signal->tty = NULL;
+				p->tty = NULL;
 			read_unlock(&tasklist_lock);
 		} else
 			return -EPERM;
 	}
 	task_lock(current);
-	current->signal->tty = tty;
+	current->tty = tty;
 	task_unlock(current);
-	current->signal->tty_old_pgrp = 0;
-	tty->session = process_session(current);
+	current->tty_old_pgrp = 0;
+	tty->session = current->session;
 	tty->pgrp = process_group(current);
 	return 0;
 }
@@ -1582,13 +1584,12 @@
 	 * (tty == real_tty) is a cheap way of
 	 * testing if the tty is NOT a master pty.
 	 */
-	if (tty == real_tty && process_tty(current) != real_tty)
+	if (tty == real_tty && current->tty != real_tty)
 		return -ENOTTY;
 	return put_user(real_tty->pgrp, arg);
 }
 
-static int tiocspgrp(struct tty_struct *tty,
-			struct tty_struct *real_tty, pid_t *arg)
+static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t *arg)
 {
 	pid_t pgrp;
 	int retval = tty_check_change(real_tty);
@@ -1597,14 +1598,15 @@
 		return -ENOTTY;
 	if (retval)
 		return retval;
-	if (!process_tty(current) || (process_tty(current) != real_tty) ||
-			(real_tty->session != process_session(current)))
+	if (!current->tty ||
+	    (current->tty != real_tty) ||
+	    (real_tty->session != current->session))
 		return -ENOTTY;
 	if (get_user(pgrp, (pid_t *) arg))
 		return -EFAULT;
 	if (pgrp < 0)
 		return -EINVAL;
-	if (session_of_pgrp(pgrp) != process_session(current))
+	if (session_of_pgrp(pgrp) != current->session)
 		return -EPERM;
 	real_tty->pgrp = pgrp;
 	return 0;
@@ -1616,7 +1618,7 @@
 	 * (tty == real_tty) is a cheap way of
 	 * testing if the tty is NOT a master pty.
 	*/
-	if (tty == real_tty && process_tty(current) != real_tty)
+	if (tty == real_tty && current->tty != real_tty)
 		return -ENOTTY;
 	if (real_tty->session <= 0)
 		return -ENOTTY;
@@ -1774,12 +1776,12 @@
 			clear_bit(TTY_EXCLUSIVE, &tty->flags);
 			return 0;
 		case TIOCNOTTY:
-			if (process_tty(current) != tty)
+			if (current->tty != tty)
 				return -ENOTTY;
-			if (process_session_leader(current))
+			if (current->leader)
 				disassociate_ctty(0);
 			task_lock(current);
-			current->signal->tty = NULL;
+			current->tty = NULL;
 			task_unlock(current);
 			return 0;
 		case TIOCSCTTY:
@@ -1883,10 +1885,10 @@
 		tty->driver->flush_buffer(tty);
 	read_lock(&tasklist_lock);
 	for_each_task_pid(session, PIDTYPE_SID, p, l, pid) {
-		if (process_tty(p) == tty || session > 0) {
+		if (p->tty == tty || session > 0) {
 			printk(KERN_NOTICE "SAK: killed process %d"
-				" (%s): process_session(p)==tty->session\n",
-				p->pid, p->comm);
+			    " (%s): p->session==tty->session\n",
+			    p->pid, p->comm);
 			send_sig(SIGKILL, p, 1);
 			continue;
 		}
diff -Nru a/drivers/char/vt.c b/drivers/char/vt.c
--- a/drivers/char/vt.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/char/vt.c	Wed Oct 15 00:46:37 2003
@@ -2226,7 +2226,7 @@
 
 	if (tty->driver->type != TTY_DRIVER_TYPE_CONSOLE)
 		return -EINVAL;
-	if (process_tty(current) != tty && !capable(CAP_SYS_ADMIN))
+	if (current->tty != tty && !capable(CAP_SYS_ADMIN))
 		return -EPERM;
 	if (get_user(type, (char *)arg))
 		return -EFAULT;
diff -Nru a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
--- a/drivers/char/vt_ioctl.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/char/vt_ioctl.c	Wed Oct 15 00:46:37 2003
@@ -380,7 +380,7 @@
 	 * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
 	 */
 	perm = 0;
-	if (process_tty(current) == tty || capable(CAP_SYS_TTY_CONFIG))
+	if (current->tty == tty || capable(CAP_SYS_TTY_CONFIG))
 		perm = 1;
  
 	kbd = kbd_table + console;
@@ -1188,3 +1188,4 @@
 
 	complete_change_console(new_console);
 }
+
diff -Nru a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
--- a/drivers/i2c/busses/Kconfig	Wed Oct 15 00:46:37 2003
+++ b/drivers/i2c/busses/Kconfig	Wed Oct 15 00:46:37 2003
@@ -157,7 +157,7 @@
 
 config I2C_PIIX4
 	tristate "Intel PIIX4"
-	depends on I2C && PCI && EXPERIMENTAL
+	depends on I2C && PCI && EXPERIMENTAL && !64BIT
 	help
 	  If you say yes to this option, support will be included for the Intel
 	  PIIX4 family of mainboard I2C interfaces.  Specifically, the following
@@ -248,11 +248,11 @@
 	  will be called i2c-sis5595.
 
 config I2C_SIS630
-	tristate "SiS 630"
+	tristate "SiS 630/730"
 	depends on I2C && PCI && EXPERIMENTAL
 	help
 	  If you say yes to this option, support will be included for the 
-	  SiS630 SMBus (a subset of I2C) interface.
+	  SiS630 and SiS730 SMBus (a subset of I2C) interface.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-sis630.
diff -Nru a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c
--- a/drivers/i2c/busses/i2c-sis630.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/i2c/busses/i2c-sis630.c	Wed Oct 15 00:46:36 2003
@@ -25,10 +25,10 @@
    	Fixed the typo in sis630_access (Thanks to Mark M. Hoffman)
 	Changed sis630_transaction.(Thanks to Mark M. Hoffman)
    18.09.2002
-	Added SIS730 as supported
+	Added SIS730 as supported.
    21.09.2002
 	Added high_clock module option.If this option is set
-	used Host Master Clock 56KHz (default 14KHz).For now we are save old Host
+	used Host Master Clock 56KHz (default 14KHz).For now we save old Host
 	Master Clock and after transaction completed restore (otherwise
 	it's confuse BIOS and hung Machine).
    24.09.2002
@@ -95,12 +95,22 @@
 
 /* insmod parameters */
 static int high_clock = 0;
+static int force = 0;
 MODULE_PARM(high_clock, "i");
 MODULE_PARM_DESC(high_clock, "Set Host Master Clock to 56KHz (default 14KHz).");
+MODULE_PARM(force, "i");
+MODULE_PARM_DESC(force, "Forcibly enable the SIS630. DANGEROUS!");
 
-
+/* acpi base address */
 static unsigned short acpi_base = 0;
 
+/* supported chips */
+static int supported[] = {
+	PCI_DEVICE_ID_SI_630,
+	PCI_DEVICE_ID_SI_730,
+	0 /* terminates the list */
+};
+
 static inline u8 sis630_read(u8 reg)
 {
 	return inb(acpi_base + reg);
@@ -277,6 +287,10 @@
 			if (len == 0)
 				data->block[0] = sis630_read(SMB_COUNT);
 
+			/* just to be sure */
+			if (data->block[0] > 32)
+				data->block[0] = 32;
+
 			dev_dbg(&adap->dev, "block data read len=0x%x\n", data->block[0]);
 
 			for (i=0; i < 8 && len < data->block[0]; i++,len++) {
@@ -372,16 +386,26 @@
 		I2C_FUNC_SMBUS_BLOCK_DATA;
 }
 
-static int sis630_setup(struct pci_dev *dummy)
+static int sis630_setup(struct pci_dev *sis630_dev)
 {
 	unsigned char b;
-	struct pci_dev *sis630_dev = NULL;
-	int retval = -ENODEV;
+	struct pci_dev *dummy = NULL;
+	int retval = -ENODEV, i;
 
-	/* We need ISA bridge and not pci device passed in.  */
-	sis630_dev = pci_get_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, sis630_dev);
-	if (!sis630_dev) {
-		dev_err(&dummy->dev, "Error: Can't detect 85C503/5513 ISA bridge!\n");
+	/* check for supported SiS devices */
+	for (i=0; supported[i] > 0 ; i++) {
+		if ((dummy = pci_get_device(PCI_VENDOR_ID_SI, supported[i], dummy)))
+			break; /* found */
+	}
+
+	if (dummy) {
+		pci_dev_put(dummy);
+	}
+        else if (force > 0) {
+		dev_err(&sis630_dev->dev, "WARNING: Can't detect SIS630 compatible device, but "
+			"loading because of force option enabled\n");
+ 	}
+	else {
 		return -ENODEV;
 	}
 
@@ -389,19 +413,19 @@
 	   Enable ACPI first , so we can accsess reg 74-75
 	   in acpi io space and read acpi base addr
 	*/
-	if (!pci_read_config_byte(sis630_dev, SIS630_BIOS_CTL_REG,&b)) {
+	if (pci_read_config_byte(sis630_dev, SIS630_BIOS_CTL_REG,&b)) {
 		dev_err(&sis630_dev->dev, "Error: Can't read bios ctl reg\n");
 		goto exit;
 	}
-
 	/* if ACPI already enabled , do nothing */
 	if (!(b & 0x80) &&
-	    !pci_write_config_byte(sis630_dev, SIS630_BIOS_CTL_REG, b | 0x80)) {
+	    pci_write_config_byte(sis630_dev, SIS630_BIOS_CTL_REG, b | 0x80)) {
 		dev_err(&sis630_dev->dev, "Error: Can't enable ACPI\n");
 		goto exit;
 	}
+
 	/* Determine the ACPI base address */
-	if (!pci_read_config_word(sis630_dev,SIS630_ACPI_BASE_REG,&acpi_base)) {
+	if (pci_read_config_word(sis630_dev,SIS630_ACPI_BASE_REG,&acpi_base)) {
 		dev_err(&sis630_dev->dev, "Error: Can't determine ACPI base address\n");
 		goto exit;
 	}
@@ -418,7 +442,8 @@
 	retval = 0;
 
 exit:
-	pci_dev_put(sis630_dev);
+	if (retval)
+		acpi_base = 0;
 	return retval;
 }
 
@@ -432,19 +457,18 @@
 
 static struct i2c_adapter sis630_adapter = {
 	.owner		= THIS_MODULE,
+	.class		= I2C_ADAP_CLASS_SMBUS,
 	.name		= "unset",
 	.algo		= &smbus_algorithm,
 };
 
 static struct pci_device_id sis630_ids[] __devinitdata = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_730) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
 	{ 0, }
 };
 
 static int __devinit sis630_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
-
 	if (sis630_setup(dev)) {
 		dev_err(&dev->dev, "SIS630 comp. bus not detected, module not inserted.\n");
 		return -ENODEV;
@@ -461,7 +485,11 @@
 
 static void __devexit sis630_remove(struct pci_dev *dev)
 {
-	i2c_del_adapter(&sis630_adapter);
+	if (acpi_base) {
+		i2c_del_adapter(&sis630_adapter);
+		release_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION);
+		acpi_base = 0;
+	}
 }
 
 
@@ -481,7 +509,6 @@
 static void __exit i2c_sis630_exit(void)
 {
 	pci_unregister_driver(&sis630_driver);
-	release_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION);
 }
 
 
diff -Nru a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
--- a/drivers/i2c/chips/Kconfig	Wed Oct 15 00:46:37 2003
+++ b/drivers/i2c/chips/Kconfig	Wed Oct 15 00:46:37 2003
@@ -15,7 +15,7 @@
 	help
 	  If you say yes here you get support for Analog Devices ADM1021 
 	  and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A,
-	  Genesys Logic GL523SM, National Semi LM84, TI THMC10,
+	  Genesys Logic GL523SM, National Semiconductor LM84, TI THMC10,
 	  and the XEON processor built-in sensor.
 
 	  This driver can also be built as a module.  If so, the module
@@ -34,30 +34,30 @@
 	  will be called eeprom.
 
 config SENSORS_IT87
-	tristate "National Semiconductors IT87 and compatibles"
+	tristate "ITE IT87xx and compatibles"
 	depends on I2C && EXPERIMENTAL
 	select I2C_SENSOR
 	help
-	  If you say yes here you get support for National Semiconductor IT87
-	  sensor chips and clones: IT8705F, IT8712F and SiS960.
+	  If you say yes here you get support for ITE IT87xx sensor chips
+	  and clones: SiS960.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called it87.
 
 config SENSORS_LM75
-	tristate "National Semiconductors LM75 and compatibles"
+	tristate "National Semiconductor LM75 and compatibles"
 	depends on I2C && EXPERIMENTAL
 	select I2C_SENSOR
 	help
 	  If you say yes here you get support for National Semiconductor LM75
 	  sensor chips and clones: Dallas Semi DS75 and DS1775, TelCon
-	  TCN75, and National Semi LM77.
+	  TCN75, and National Semiconductor LM77.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called lm75.
 
 config SENSORS_LM78
-	tristate "National Semiconductors LM78 and compatibles"
+	tristate "National Semiconductor LM78 and compatibles"
 	depends on I2C && EXPERIMENTAL
 	select I2C_SENSOR
 	help
@@ -69,7 +69,7 @@
 	  will be called lm78.
 
 config SENSORS_LM85
-	tristate "National Semiconductors LM85 and compatibles"
+	tristate "National Semiconductor LM85 and compatibles"
 	depends on I2C && EXPERIMENTAL
 	select I2C_SENSOR
 	help
diff -Nru a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c
--- a/drivers/i2c/chips/adm1021.c	Wed Oct 15 00:46:35 2003
+++ b/drivers/i2c/chips/adm1021.c	Wed Oct 15 00:46:35 2003
@@ -322,6 +322,10 @@
 	if ((err = i2c_attach_client(new_client)))
 		goto error3;
 
+	/* Initialize the ADM1021 chip */
+	adm1021_init_client(new_client);
+
+	/* Register sysfs hooks */
 	device_create_file(&new_client->dev, &dev_attr_temp_max1);
 	device_create_file(&new_client->dev, &dev_attr_temp_min1);
 	device_create_file(&new_client->dev, &dev_attr_temp_input1);
@@ -332,8 +336,6 @@
 	if (data->type == adm1021)
 		device_create_file(&new_client->dev, &dev_attr_die_code);
 
-	/* Initialize the ADM1021 chip */
-	adm1021_init_client(new_client);
 	return 0;
 
 error3:
diff -Nru a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c
--- a/drivers/i2c/chips/it87.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/i2c/chips/it87.c	Wed Oct 15 00:46:37 2003
@@ -701,7 +701,10 @@
 	if ((err = i2c_attach_client(new_client)))
 		goto ERROR1;
 
-	/* register sysfs hooks */
+	/* Initialize the IT87 chip */
+	it87_init_client(new_client, data);
+
+	/* Register sysfs hooks */
 	device_create_file(&new_client->dev, &dev_attr_in_input0);
 	device_create_file(&new_client->dev, &dev_attr_in_input1);
 	device_create_file(&new_client->dev, &dev_attr_in_input2);
@@ -750,8 +753,6 @@
 	device_create_file(&new_client->dev, &dev_attr_fan_div3);
 	device_create_file(&new_client->dev, &dev_attr_alarm);
 
-	/* Initialize the IT87 chip */
-	it87_init_client(new_client, data);
 	return 0;
 
 ERROR1:
diff -Nru a/drivers/i2c/chips/lm75.c b/drivers/i2c/chips/lm75.c
--- a/drivers/i2c/chips/lm75.c	Wed Oct 15 00:46:35 2003
+++ b/drivers/i2c/chips/lm75.c	Wed Oct 15 00:46:35 2003
@@ -204,11 +204,14 @@
 	if ((err = i2c_attach_client(new_client)))
 		goto exit_free;
 
+	/* Initialize the LM75 chip */
+	lm75_init_client(new_client);
+	
+	/* Register sysfs hooks */
 	device_create_file(&new_client->dev, &dev_attr_temp_max);
 	device_create_file(&new_client->dev, &dev_attr_temp_min);
 	device_create_file(&new_client->dev, &dev_attr_temp_input);
 
-	lm75_init_client(new_client);
 	return 0;
 
 exit_free:
diff -Nru a/drivers/i2c/chips/lm78.c b/drivers/i2c/chips/lm78.c
--- a/drivers/i2c/chips/lm78.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/i2c/chips/lm78.c	Wed Oct 15 00:46:37 2003
@@ -648,7 +648,10 @@
 	if ((err = i2c_attach_client(new_client)))
 		goto ERROR2;
 
-	/* register sysfs hooks */
+	/* Initialize the LM78 chip */
+	lm78_init_client(new_client);
+
+	/* Register sysfs hooks */
 	device_create_file(&new_client->dev, &dev_attr_in_input0);
 	device_create_file(&new_client->dev, &dev_attr_in_min0);
 	device_create_file(&new_client->dev, &dev_attr_in_max0);
@@ -685,8 +688,6 @@
 	device_create_file(&new_client->dev, &dev_attr_alarms);
 	device_create_file(&new_client->dev, &dev_attr_vid);
 
-	/* Initialize the LM78 chip */
-	lm78_init_client(new_client);
 	return 0;
 
 ERROR2:
diff -Nru a/drivers/i2c/chips/lm85.c b/drivers/i2c/chips/lm85.c
--- a/drivers/i2c/chips/lm85.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/i2c/chips/lm85.c	Wed Oct 15 00:46:36 2003
@@ -888,6 +888,10 @@
 	/* Set the VRM version */
 	data->vrm = LM85_INIT_VRM ;
 
+	/* Initialize the LM85 chip */
+	lm85_init_client(new_client);
+
+	/* Register sysfs hooks */
 	device_create_file(&new_client->dev, &dev_attr_fan_input1);
 	device_create_file(&new_client->dev, &dev_attr_fan_input2);
 	device_create_file(&new_client->dev, &dev_attr_fan_input3);
@@ -930,8 +934,6 @@
 	device_create_file(&new_client->dev, &dev_attr_vid);
 	device_create_file(&new_client->dev, &dev_attr_alarms);
 
-	/* Initialize the LM85 chip */
-	lm85_init_client(new_client);
 	return 0;
 
 	/* Error out and cleanup code */
diff -Nru a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c
--- a/drivers/i2c/chips/via686a.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/i2c/chips/via686a.c	Wed Oct 15 00:46:36 2003
@@ -735,7 +735,10 @@
 	if ((err = i2c_attach_client(new_client)))
 		goto ERROR3;
 	
-	/* register sysfs hooks */
+	/* Initialize the VIA686A chip */
+	via686a_init_client(new_client);
+
+	/* Register sysfs hooks */
 	device_create_file(&new_client->dev, &dev_attr_in_input0);
 	device_create_file(&new_client->dev, &dev_attr_in_input1);
 	device_create_file(&new_client->dev, &dev_attr_in_input2);
@@ -768,8 +771,6 @@
 	device_create_file(&new_client->dev, &dev_attr_fan_div2);
 	device_create_file(&new_client->dev, &dev_attr_alarm);
 
-	/* Initialize the VIA686A chip */
-	via686a_init_client(new_client);
 	return 0;
 
       ERROR3:
diff -Nru a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c
--- a/drivers/i2c/chips/w83781d.c	Wed Oct 15 00:46:35 2003
+++ b/drivers/i2c/chips/w83781d.c	Wed Oct 15 00:46:35 2003
@@ -1346,6 +1346,10 @@
 		data->lm75[1] = NULL;
 	}
 
+	/* Initialize the chip */
+	w83781d_init_client(new_client);
+
+	/* Register sysfs hooks */
 	device_create_file_in(new_client, 0);
 	if (kind != w83783s && kind != w83697hf)
 		device_create_file_in(new_client, 1);
@@ -1408,8 +1412,6 @@
 	}
 #endif
 
-	/* Initialize the chip */
-	w83781d_init_client(new_client);
 	return 0;
 
 ERROR3:
diff -Nru a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
--- a/drivers/i2c/i2c-dev.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/i2c/i2c-dev.c	Wed Oct 15 00:46:37 2003
@@ -49,6 +49,7 @@
 	int minor;
 	struct i2c_adapter *adap;
 	struct class_device class_dev;
+	struct completion released;	/* FIXME, we need a class_device_unregister() */
 };
 #define to_i2c_dev(d) container_of(d, struct i2c_dev, class_dev)
 
@@ -112,7 +113,6 @@
 	spin_lock(&i2c_dev_array_lock);
 	i2c_dev_array[i2c_dev->minor] = NULL;
 	spin_unlock(&i2c_dev_array_lock);
-	kfree(i2c_dev);
 }
 
 static ssize_t show_dev(struct class_device *class_dev, char *buf)
@@ -421,8 +421,15 @@
 	.release	= i2cdev_release,
 };
 
+static void release_i2c_dev(struct class_device *dev)
+{
+	struct i2c_dev *i2c_dev = to_i2c_dev(dev);
+	complete(&i2c_dev->released);
+}
+
 static struct class i2c_dev_class = {
-	.name	= "i2c-dev",
+	.name		= "i2c-dev",
+	.release	= &release_i2c_dev,
 };
 
 static int i2cdev_attach_adapter(struct i2c_adapter *adap)
@@ -453,6 +460,7 @@
 	return 0;
 error:
 	return_i2c_dev(i2c_dev);
+	kfree(i2c_dev);
 	return retval;
 }
 
@@ -464,9 +472,12 @@
 	if (!i2c_dev)
 		return -ENODEV;
 
-	class_device_unregister(&i2c_dev->class_dev);
+	init_completion(&i2c_dev->released);
 	devfs_remove("i2c/%d", i2c_dev->minor);
 	return_i2c_dev(i2c_dev);
+	class_device_unregister(&i2c_dev->class_dev);
+	wait_for_completion(&i2c_dev->released);
+	kfree(i2c_dev);
 
 	dev_dbg(&adap->dev, "Adapter unregistered\n");
 	return 0;
diff -Nru a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
--- a/drivers/macintosh/adbhid.c	Wed Oct 15 00:46:38 2003
+++ b/drivers/macintosh/adbhid.c	Wed Oct 15 00:46:38 2003
@@ -611,8 +611,8 @@
 		/* HACK WARNING!! This should go away as soon there is an utility
 		 * to control that for event devices.
 		 */
-		adbhid[id]->input.rep[REP_DELAY] = HZ/2;   /* input layer default: HZ/4 */
-		adbhid[id]->input.rep[REP_PERIOD] = HZ/15; /* input layer default: HZ/33 */
+		adbhid[id]->input.rep[REP_DELAY] = 500;   /* input layer default: 250 */
+		adbhid[id]->input.rep[REP_PERIOD] = 66; /* input layer default: 33 */
 	}
 }
 
diff -Nru a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
--- a/drivers/media/common/saa7146_fops.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/media/common/saa7146_fops.c	Wed Oct 15 00:46:36 2003
@@ -61,8 +61,14 @@
 	}
 
 	DEB_EE(("dev:%p, dmaq:%p, state:%d\n", dev, q, state));
+	DEB_EE(("q->curr:%p\n",q->curr));
 
 	/* finish current buffer */
+	if (NULL == q->curr) {
+		DEB_D(("aiii. no current buffer\n"));
+		return;	
+	}
+			
 	q->curr->vb.state = state;
 	do_gettimeofday(&q->curr->vb.ts);
 	wake_up(&q->curr->vb.done);
@@ -221,9 +227,12 @@
 	fh->dev = dev;
 	fh->type = type;
 
-	saa7146_video_uops.open(dev,fh);
-	if( 0 != BOARD_CAN_DO_VBI(dev) ) {
+	if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+		DEB_S(("initializing vbi...\n"));
 		saa7146_vbi_uops.open(dev,fh);
+	} else {
+		DEB_S(("initializing video...\n"));
+		saa7146_video_uops.open(dev,fh);
 	}
 
 	result = 0;
@@ -245,9 +254,10 @@
 	if (down_interruptible(&saa7146_devices_lock))
 		return -ERESTARTSYS;
 
-	saa7146_video_uops.release(dev,fh,file);
-	if( 0 != BOARD_CAN_DO_VBI(dev) ) {
+	if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
 		saa7146_vbi_uops.release(dev,fh,file);
+	} else {
+		saa7146_video_uops.release(dev,fh,file);
 	}
 
 	module_put(dev->ext->module);
@@ -332,11 +342,11 @@
 
 	switch (fh->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
-		DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun", file, data, (unsigned long)count));
+//		DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun", file, data, (unsigned long)count));
 		return saa7146_video_uops.read(file,data,count,ppos);
 		}
 	case V4L2_BUF_TYPE_VBI_CAPTURE: {
-		DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n", file, data, (unsigned long)count));
+//		DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n", file, data, (unsigned long)count));
 		return saa7146_vbi_uops.read(file,data,count,ppos);
 		}
 		break;
@@ -443,7 +453,7 @@
 {
 	struct saa7146_vv *vv = dev->vv_data;
 
-	DEB_EE(("dev:%p, name:'%s'\n",dev,name));
+	DEB_EE(("dev:%p, name:'%s', type:%d\n",dev,name,type));
  
  	*vid = device_template;
 	strlcpy(vid->name, name, sizeof(vid->name));
@@ -451,7 +461,7 @@
 
 	// fixme: -1 should be an insmod parameter *for the extension* (like "video_nr");
 	if (video_register_device(vid,type,-1) < 0) {
-		ERR(("cannot register vbi v4l2 device. skipping.\n"));
+		ERR(("cannot register v4l2 device. skipping.\n"));
 		return -1;
 	}
 
diff -Nru a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c
--- a/drivers/media/common/saa7146_vbi.c	Wed Oct 15 00:46:35 2003
+++ b/drivers/media/common/saa7146_vbi.c	Wed Oct 15 00:46:35 2003
@@ -38,8 +38,14 @@
 		WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
 		/* BXO = 1h, BRS to outbound */
 		WRITE_RPS1(0xc000008c);   
-		/* wait for vbi_a */
+	/* wait for vbi_a or vbi_b*/
+	if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) {
+		DEB_D(("...using port b\n"));
+		WRITE_RPS1(CMD_PAUSE | MASK_09);
+	} else {
+		DEB_D(("...using port a\n"));
 		WRITE_RPS1(CMD_PAUSE | MASK_10);
+	}
 		/* upload brs */
 		WRITE_RPS1(CMD_UPLOAD | MASK_08);
 		/* load brs-control register */
@@ -106,7 +112,7 @@
 
 		if(signal_pending(current)) {
 		
-			DEB_VBI(("aborted.\n"));
+			DEB_VBI(("aborted (rps:0x%08x).\n",saa7146_read(dev,RPS_ADDR1)));
 
 			/* stop rps1 for sure */
 			saa7146_write(dev, MC1, MASK_29);
@@ -316,6 +322,11 @@
 	saa7146_write(dev, MC1, MASK_20);
 
 	vv->vbi_streaming = NULL;
+
+	del_timer(&vv->vbi_q.timeout);
+	del_timer(&fh->vbi_read_timeout);
+
+	DEB_VBI(("out\n"));
 	spin_unlock_irqrestore(&dev->slock, flags);
 }
 
@@ -371,7 +382,10 @@
 	fh->vbi_read_timeout.function = vbi_read_timeout;
 	fh->vbi_read_timeout.data = (unsigned long)fh;
 
+	/* fixme: enable this again, if the dvb-c w/ analog module work properly */
+/*
 	vbi_workaround(dev);
+*/
 }
 
 static void vbi_close(struct saa7146_dev *dev, struct saa7146_fh *fh, struct file *file)
diff -Nru a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
--- a/drivers/media/common/saa7146_video.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/media/common/saa7146_video.c	Wed Oct 15 00:46:37 2003
@@ -1319,7 +1319,7 @@
 			saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);
 		}
 		
-		err = videobuf_iolock(dev->pci,&buf->vb,NULL);
+		err = videobuf_iolock(dev->pci,&buf->vb, &vv->ov_fb);
 		if (err)
 			goto oops;
 		err = saa7146_pgtable_build(dev,buf);
diff -Nru a/drivers/media/dvb/dvb-core/dvb_i2c.c b/drivers/media/dvb/dvb-core/dvb_i2c.c
--- a/drivers/media/dvb/dvb-core/dvb_i2c.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/media/dvb/dvb-core/dvb_i2c.c	Wed Oct 15 00:46:37 2003
@@ -32,8 +32,9 @@
 struct dvb_i2c_device {
 	struct list_head list_head;
 	struct module *owner;
-	int (*attach) (struct dvb_i2c_bus *i2c);
-	void (*detach) (struct dvb_i2c_bus *i2c);
+	int (*attach) (struct dvb_i2c_bus *i2c, void **data);
+	void (*detach) (struct dvb_i2c_bus *i2c, void *data);
+	void *data;
 };
 
 LIST_HEAD(dvb_i2c_buslist);
@@ -66,7 +67,7 @@
 			return;
 	}
 
-	if (dev->attach (i2c) == 0) {
+	if (dev->attach (i2c, &dev->data) == 0) {
 		register_i2c_client (i2c, dev);
 	} else {
 		if (dev->owner)
@@ -77,7 +78,7 @@
 
 static void detach_device (struct dvb_i2c_bus *i2c, struct dvb_i2c_device *dev)
 {
-	dev->detach (i2c);
+	dev->detach (i2c, dev->data);
 
 	if (dev->owner)
 		module_put (dev->owner);
@@ -229,8 +230,8 @@
 
 
 int dvb_register_i2c_device (struct module *owner,
-			     int (*attach) (struct dvb_i2c_bus *i2c),
-			     void (*detach) (struct dvb_i2c_bus *i2c))
+			     int (*attach) (struct dvb_i2c_bus *i2c, void **data),
+			     void (*detach) (struct dvb_i2c_bus *i2c, void *data))
 {
 	struct dvb_i2c_device *entry;
 
@@ -256,7 +257,7 @@
 }
 
 
-int dvb_unregister_i2c_device (int (*attach) (struct dvb_i2c_bus *i2c))
+int dvb_unregister_i2c_device (int (*attach) (struct dvb_i2c_bus *i2c, void **data))
 {
 	struct list_head *entry, *n;
 
diff -Nru a/drivers/media/dvb/dvb-core/dvb_i2c.h b/drivers/media/dvb/dvb-core/dvb_i2c.h
--- a/drivers/media/dvb/dvb-core/dvb_i2c.h	Wed Oct 15 00:46:36 2003
+++ b/drivers/media/dvb/dvb-core/dvb_i2c.h	Wed Oct 15 00:46:36 2003
@@ -54,10 +54,10 @@
 
 
 extern int dvb_register_i2c_device (struct module *owner,
-				    int (*attach) (struct dvb_i2c_bus *i2c),
-				    void (*detach) (struct dvb_i2c_bus *i2c));
+				    int (*attach) (struct dvb_i2c_bus *i2c, void **data),
+				    void (*detach) (struct dvb_i2c_bus *i2c, void *data));
 
-extern int dvb_unregister_i2c_device (int (*attach) (struct dvb_i2c_bus *i2c));
+extern int dvb_unregister_i2c_device (int (*attach) (struct dvb_i2c_bus *i2c, void **data));
 
 #endif
 
diff -Nru a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
--- a/drivers/media/dvb/frontends/Kconfig	Wed Oct 15 00:46:36 2003
+++ b/drivers/media/dvb/frontends/Kconfig	Wed Oct 15 00:46:36 2003
@@ -16,16 +16,6 @@
 	  DVB adapter simply enable all supported frontends, the 
 	  right one will get autodetected.
 
-config DVB_ALPS_BSRV2
-	tristate "Alps BSRV2 (QPSK)"
-	depends on DVB_CORE
-	help
-	  A DVB-S tuner module. Say Y when you want to support this frontend.
-
-	  If you don't know what tuner module is soldered on your 
-	  DVB adapter simply enable all supported frontends, the 
-	  right one will get autodetected.
-
 config DVB_SP887X
  	tristate "Frontends with sp887x demodulators, e.g. Microtune DTF7072"
  	depends on DVB_CORE
@@ -120,6 +110,16 @@
 	  The VES1820 Demodulator is used on many DVB-C PCI cards and in some
 	  DVB-C SetTopBoxes. Say Y when you see this demodulator chip near your
 	  tuner module.
+
+	  If you don't know what tuner module is soldered on your 
+	  DVB adapter simply enable all supported frontends, the 
+	  right one will get autodetected.
+
+config DVB_VES1X93
+	tristate "Frontends with VES1893 or VES1993 demodulator (QPSK)"
+	depends on DVB_CORE
+	help
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
 
 	  If you don't know what tuner module is soldered on your 
 	  DVB adapter simply enable all supported frontends, the 
diff -Nru a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
--- a/drivers/media/dvb/frontends/Makefile	Wed Oct 15 00:46:35 2003
+++ b/drivers/media/dvb/frontends/Makefile	Wed Oct 15 00:46:35 2003
@@ -5,7 +5,6 @@
 EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
 
 obj-$(CONFIG_DVB_STV0299) += stv0299.o
-obj-$(CONFIG_DVB_ALPS_BSRV2) += alps_bsrv2.o
 obj-$(CONFIG_DVB_ALPS_TDLB7) += alps_tdlb7.o
 obj-$(CONFIG_DVB_ALPS_TDMB7) += alps_tdmb7.o
 obj-$(CONFIG_DVB_ATMEL_AT76C651) += at76c651.o
@@ -14,5 +13,6 @@
 obj-$(CONFIG_DVB_GRUNDIG_29504_401) += grundig_29504-401.o
 obj-$(CONFIG_DVB_MT312) += mt312.o
 obj-$(CONFIG_DVB_VES1820) += ves1820.o
+obj-$(CONFIG_DVB_VES1X93) += ves1x93.o
 obj-$(CONFIG_DVB_TDA1004X) += tda1004x.o
 obj-$(CONFIG_DVB_SP887X) += sp887x.o
diff -Nru a/drivers/media/dvb/frontends/alps_bsrv2.c b/drivers/media/dvb/frontends/alps_bsrv2.c
--- a/drivers/media/dvb/frontends/alps_bsrv2.c	Wed Oct 15 00:46:36 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,469 +0,0 @@
-/* 
-    Driver for Alps BSRV2 QPSK Frontend
-
-    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/    
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-
-static int debug = 0;
-#define dprintk	if (debug) printk
-
-
-static struct dvb_frontend_info bsrv2_info = {
-	.name 			= "Alps BSRV2",
-	.type 			= FE_QPSK,
-	.frequency_min 		= 950000,
-	.frequency_max 		= 2150000,
-	.frequency_stepsize 	= 250,           /* kHz for QPSK frontends */
-	.frequency_tolerance 	= 29500,
-	.symbol_rate_min	= 1000000,
-	.symbol_rate_max	= 45000000,
-/*     . symbol_rate_tolerance	= 	???,*/
-	.notifier_delay		= 50,                /* 1/20 s */
-	.caps = FE_CAN_INVERSION_AUTO |
-		FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-		FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-		FE_CAN_QPSK
-};
-
-
-
-static u8 init_1893_tab [] = {
-        0x01, 0xA4, 0x35, 0x81, 0x2A, 0x0d, 0x55, 0xC4,
-        0x09, 0x69, 0x00, 0x86, 0x4c, 0x28, 0x7F, 0x00,
-        0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	
-        0x80, 0x00, 0x31, 0xb0, 0x14, 0x00, 0xDC, 0x00,
-        0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x55, 0x00, 0x00, 0x7f, 0x00
-};
-
-
-static u8 init_1893_wtab[] =
-{
-        1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0,
-        0,1,0,0,0,0,0,0, 1,0,1,1,0,0,0,1,
-        1,1,1,0,0,0,0,0, 0,0,1,1,0,0,0,0,
-        1,1,1,0,1,1
-};
-
-
-static int ves1893_writereg (struct dvb_i2c_bus *i2c, u8 reg, u8 data)
-{
-        u8 buf [] = { 0x00, reg, data };
-	struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = buf, .len = 3 };
-	int err;
-
-        if ((err = i2c->xfer (i2c, &msg, 1)) != 1) {
-		dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data);
-		return -EREMOTEIO;
-	}
-
-        return 0;
-}
-
-
-static u8 ves1893_readreg (struct dvb_i2c_bus *i2c, u8 reg)
-{
-	int ret;
-	u8 b0 [] = { 0x00, reg };
-	u8 b1 [] = { 0 };
-	struct i2c_msg msg [] = { { .addr = 0x08, .flags = 0, .buf = b0, .len = 2 },
-			   { .addr = 0x08, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
-
-	ret = i2c->xfer (i2c, msg, 2);
-
-	if (ret != 2)
-		dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
-
-	return b1[0];
-}
-
-
-static int sp5659_write (struct dvb_i2c_bus *i2c, u8 data [4])
-{
-        int ret;
-        struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = 4 };
-
-        ret = i2c->xfer (i2c, &msg, 1);
-
-        if (ret != 1)
-                printk("%s: i/o error (ret == %i)\n", __FUNCTION__, ret);
-
-        return (ret != 1) ? -1 : 0;
-}
-
-
-
-/**
- *   set up the downconverter frequency divisor for a
- *   reference clock comparision frequency of 125 kHz.
- */
-static int sp5659_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, u8 pwr)
-{
-        u32 div = (freq + 479500) / 125;
-        u8 buf [4] = { (div >> 8) & 0x7f, div & 0xff, 0x95, (pwr << 5) | 0x30 };
-
-	return sp5659_write (i2c, buf);
-}
-
-
-static int ves1893_init (struct dvb_i2c_bus *i2c)
-{
-	int i;
-        
-	dprintk("%s: init chip\n", __FUNCTION__);
-
-	for (i=0; i<54; i++)
-		if (init_1893_wtab[i])
-			ves1893_writereg (i2c, i, init_1893_tab[i]);
-
-	return 0;
-}
-
-
-static int ves1893_clr_bit (struct dvb_i2c_bus *i2c)
-{
-        ves1893_writereg (i2c, 0, init_1893_tab[0] & 0xfe);
-        ves1893_writereg (i2c, 0, init_1893_tab[0]);
-        ves1893_writereg (i2c, 3, 0x00);
-        return ves1893_writereg (i2c, 3, init_1893_tab[3]);
-}
-
-
-static int ves1893_set_inversion (struct dvb_i2c_bus *i2c, fe_spectral_inversion_t inversion)
-{
-	u8 val;
-
-	/*
-	 * inversion on/off are interchanged because i and q seem to
-	 * be swapped on the hardware
-	 */
-
-	switch (inversion) {
-	case INVERSION_OFF:
-		val = 0xc0;
-		break;
-	case INVERSION_ON:
-		val = 0x80;
-		break;
-	case INVERSION_AUTO:
-		val = 0x00;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	/* needs to be saved for FE_GET_FRONTEND */
-	init_1893_tab[0x0c] = (init_1893_tab[0x0c] & 0x3f) | val;
-
-	return ves1893_writereg (i2c, 0x0c, init_1893_tab[0x0c]);
-}
-
-
-static int ves1893_set_fec (struct dvb_i2c_bus *i2c, fe_code_rate_t fec)
-{
-	if (fec == FEC_AUTO)
-		return ves1893_writereg (i2c, 0x0d, 0x08);
-	else if (fec < FEC_1_2 || fec > FEC_8_9)
-		return -EINVAL;
-	else
-		return ves1893_writereg (i2c, 0x0d, fec - FEC_1_2);
-}
-
-
-static fe_code_rate_t ves1893_get_fec (struct dvb_i2c_bus *i2c)
-{
-	return FEC_1_2 + ((ves1893_readreg (i2c, 0x0d) >> 4) & 0x7);
-}
-
-
-static int ves1893_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate)
-{
-	u32 BDR;
-        u32 ratio;
-	u8  ADCONF, FCONF, FNR;
-	u32 BDRI;
-	u32 tmp;
-
-	dprintk("%s: srate == %ud\n", __FUNCTION__, (unsigned int) srate);
-
-	if (srate > 90100000UL/2)
-		srate = 90100000UL/2;
-
-	if (srate < 500000)
-		srate = 500000;
-
-#define MUL (1UL<<26)
-#define FIN (90106000UL>>4)
-
-	tmp = srate << 6;
-	ratio = tmp / FIN;
-
-	tmp = (tmp % FIN) << 8;
-	ratio = (ratio << 8) + tmp / FIN;
-
-	tmp = (tmp % FIN) << 8;
-	ratio = (ratio << 8) + tmp / FIN;
-
-	FNR = 0xff;
-
-	if (ratio < MUL/3)           FNR = 0;
-	if (ratio < (MUL*11)/50)     FNR = 1;
-	if (ratio < MUL/6)           FNR = 2;
-	if (ratio < MUL/9)           FNR = 3;
-	if (ratio < MUL/12)          FNR = 4;
-	if (ratio < (MUL*11)/200)    FNR = 5;
-	if (ratio < MUL/24)          FNR = 6;
-	if (ratio < (MUL*27)/1000)   FNR = 7;
-	if (ratio < MUL/48)          FNR = 8;
-	if (ratio < (MUL*137)/10000) FNR = 9;
-
-	if (FNR == 0xff) {
-		ADCONF = 0x89;
-		FCONF  = 0x80;
-		FNR	= 0;
-	} else {
-		ADCONF = 0x81;
-		FCONF  = 0x88 | (FNR >> 1) | ((FNR & 0x01) << 5);
-	}
-
-	BDR = (( (ratio << (FNR >> 1)) >> 4) + 1) >> 1;
-	BDRI = ( ((FIN << 8) / ((srate << (FNR >> 1)) >> 2)) + 1) >> 1;
-
-        dprintk("FNR= %d\n", FNR);
-        dprintk("ratio= %08x\n", (unsigned int) ratio);
-        dprintk("BDR= %08x\n", (unsigned int) BDR);
-        dprintk("BDRI= %02x\n", (unsigned int) BDRI);
-
-	if (BDRI > 0xff)
-		BDRI = 0xff;
-
-	ves1893_writereg (i2c, 0x06, 0xff & BDR);
-	ves1893_writereg (i2c, 0x07, 0xff & (BDR >> 8));
-	ves1893_writereg (i2c, 0x08, 0x0f & (BDR >> 16));
-
-	ves1893_writereg (i2c, 0x09, BDRI);
-	ves1893_writereg (i2c, 0x20, ADCONF);
-	ves1893_writereg (i2c, 0x21, FCONF);
-
-	if (srate < 6000000) 
-		ves1893_writereg (i2c, 0x05, init_1893_tab[0x05] | 0x80);
-	else
-		ves1893_writereg (i2c, 0x05, init_1893_tab[0x05] & 0x7f);
-
-	ves1893_writereg (i2c, 0x00, 0x00);
-	ves1893_writereg (i2c, 0x00, 0x01);
-
-	ves1893_clr_bit (i2c);
-
-	return 0;
-}
-
-
-static int ves1893_set_voltage (struct dvb_i2c_bus *i2c, fe_sec_voltage_t voltage)
-{
-	switch (voltage) {
-	case SEC_VOLTAGE_13:
-		return ves1893_writereg (i2c, 0x1f, 0x20);
-	case SEC_VOLTAGE_18:
-		return ves1893_writereg (i2c, 0x1f, 0x30);
-	case SEC_VOLTAGE_OFF:
-		return ves1893_writereg (i2c, 0x1f, 0x00);
-	default:
-		return -EINVAL;
-	}
-}
-
-
-static int bsrv2_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
-{
-	struct dvb_i2c_bus *i2c = fe->i2c;
-                
-        switch (cmd) {
-        case FE_GET_INFO:
-		memcpy (arg, &bsrv2_info, sizeof(struct dvb_frontend_info));
-		break;
-
-        case FE_READ_STATUS:
-	{
-		fe_status_t *status = arg;
-		u8 sync = ves1893_readreg (i2c, 0x0e);
-
-		*status = 0;
-
-		if (sync & 1)
-			*status |= FE_HAS_SIGNAL;
-
-		if (sync & 2)
-			*status |= FE_HAS_CARRIER;
-
-		if (sync & 4)
-			*status |= FE_HAS_VITERBI;
-
-		if (sync & 8)
-			*status |= FE_HAS_SYNC;
-
-		if ((sync & 0x1f) == 0x1f)
-			*status |= FE_HAS_LOCK;
-
-		break;
-	}
-
-        case FE_READ_BER:
-	{
-		u32 *ber = (u32 *) arg;
-
-		*ber = ves1893_readreg (i2c, 0x15);
-                *ber |= (ves1893_readreg (i2c, 0x16) << 8);
-                *ber |= ((ves1893_readreg (i2c, 0x17) & 0x0f) << 16);
-		*ber *= 10;
-		break;
-	}
-
-        case FE_READ_SIGNAL_STRENGTH:
-	{
-		u8 signal = ~ves1893_readreg (i2c, 0x0b);
-		*((u16*) arg) = (signal << 8) | signal;
-		break;
-	}
-
-        case FE_READ_SNR:
-	{
-		u8 snr = ~ves1893_readreg (i2c, 0x1c);
-		*(u16*) arg = (snr << 8) | snr;
-		break;
-	}
-
-	case FE_READ_UNCORRECTED_BLOCKS: 
-	{
-		*(u32*) arg = ves1893_readreg (i2c, 0x18) & 0x7f;
-
-		if (*(u32*) arg == 0x7f)
-			*(u32*) arg = 0xffffffff;   /* counter overflow... */
-		
-		ves1893_writereg (i2c, 0x18, 0x00);  /* reset the counter */
-		ves1893_writereg (i2c, 0x18, 0x80);  /* dto. */
-		break;
-	}
-
-        case FE_SET_FRONTEND:
-        {
-		struct dvb_frontend_parameters *p = arg;
-
-		sp5659_set_tv_freq (i2c, p->frequency, 0);
-		ves1893_set_inversion (i2c, p->inversion);
-		ves1893_set_fec (i2c, p->u.qpsk.fec_inner);
-//		sp5659_set_tv_freq (i2c, p->frequency, 0);
-		ves1893_set_symbolrate (i2c, p->u.qpsk.symbol_rate);
-                break;
-        }
-
-	case FE_GET_FRONTEND:
-	{
-		struct dvb_frontend_parameters *p = arg;
-		int afc;
-
-		afc = ((int)((char)(ves1893_readreg (i2c, 0x0a) << 1)))/2;
-		afc = (afc * (int)(p->u.qpsk.symbol_rate/1000/8))/16;
-
-		p->frequency -= afc;
-
-		/*
-		 * inversion indicator is only valid
-		 * if auto inversion was used
-		 */
-		if (!(init_1893_tab[0x0c] & 0x80))
-		p->inversion = (ves1893_readreg (i2c, 0x0f) & 2) ? 
-					INVERSION_OFF : INVERSION_ON;
-		p->u.qpsk.fec_inner = ves1893_get_fec (i2c);
-	/*  XXX FIXME: timing offset !! */
-		break;
-	}
-
-        case FE_SLEEP:
-		ves1893_writereg (i2c, 0x1f, 0x00);    /*  LNB power off  */
-		return ves1893_writereg (i2c, 0x00, 0x08);
-
-        case FE_INIT:
-		return ves1893_init (i2c);
-
-	case FE_RESET:
-		return ves1893_clr_bit (i2c);
-
-	case FE_SET_TONE:
-		return -EOPNOTSUPP;  /* the ves1893 can generate the 22k */
-				     /* let's implement this when we have */
-				     /* a box that uses the 22K_0 pin... */
-	case FE_SET_VOLTAGE:
-		return ves1893_set_voltage (i2c, (fe_sec_voltage_t) arg);
-
-	default:
-		return -EOPNOTSUPP;
-        };
-        
-        return 0;
-} 
-
-
-static int bsrv2_attach (struct dvb_i2c_bus *i2c)
-{
-	if ((ves1893_readreg (i2c, 0x1e) & 0xf0) != 0xd0)
-		return -ENODEV;
-
-	dvb_register_frontend (bsrv2_ioctl, i2c, NULL, &bsrv2_info);
-
-	return 0;
-}
-
-
-static void bsrv2_detach (struct dvb_i2c_bus *i2c)
-{
-	dvb_unregister_frontend (bsrv2_ioctl, i2c);
-}
-
-
-static int __init init_bsrv2 (void)
-{
-	return dvb_register_i2c_device (THIS_MODULE, bsrv2_attach, bsrv2_detach);
-}
-
-
-static void __exit exit_bsrv2 (void)
-{
-	dvb_unregister_i2c_device (bsrv2_attach);
-}
-
-
-module_init(init_bsrv2);
-module_exit(exit_bsrv2);
-
-
-MODULE_DESCRIPTION("BSRV2 DVB-S Frontend");
-MODULE_AUTHOR("Ralph Metzler");
-MODULE_LICENSE("GPL");
-MODULE_PARM(debug,"i");
-
diff -Nru a/drivers/media/dvb/frontends/alps_tdlb7.c b/drivers/media/dvb/frontends/alps_tdlb7.c
--- a/drivers/media/dvb/frontends/alps_tdlb7.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/media/dvb/frontends/alps_tdlb7.c	Wed Oct 15 00:46:36 2003
@@ -1,7 +1,7 @@
 /*
     Driver for Alps TDLB7 Frontend
 
-    Copyright (C) 1999 Juergen Peitz <peitz@snafu.de>
+    Copyright (C) 1999 Juergen Peitz
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -22,23 +22,9 @@
 
 
 /* 
-    
-    Wrote this code mainly to get my own card running. It's working for me, but I
-    hope somebody who knows more about linux programming and the DVB driver can 
-    improve it.
-    
-    Reused a lot from the existing driver and tuner code.
-    Thanks to everybody who worked on it!
-    
-    This driver needs a copy of the microcode file 'Sc_main.mc' from the Haupauge 
-    windows driver in the 'usr/lib/DVB/driver/frontends' directory.  
-    You can also pass the complete file name with the module parameter 'mcfile'.
-    
-    The code only needs to be loaded once after a power on. Because loading the 
-    microcode to the card takes some time, you can use the 'loadcode=0' module 
-    parameter, if you only want to reload the dvb driver.      
-    
-    Juergen Peitz
+    This driver needs a copy of the firmware file 'Sc_main.mc' from the Haupauge
+    windows driver in the '/usr/lib/DVB/driver/frontends' directory.
+    You can also pass the complete file name with the module parameter 'firmware_file'.
     
 */  
 
@@ -50,49 +36,46 @@
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
 #include <linux/unistd.h>
+#include <linux/delay.h>
 
 #include "dvb_frontend.h"
+#include "dvb_functions.h"
 
-static int debug = 0;
-
-static int loadcode = 1;
+#ifndef CONFIG_ALPS_TDLB7_FIRMWARE_LOCATION
+#define CONFIG_ALPS_TDLB7_FIRMWARE_LOCATION "/usr/lib/DVB/driver/frontends/Sc_main.mc"
+#endif
 
-static char * mcfile = "/usr/lib/DVB/driver/frontends/Sc_main.mc";
+static char * firmware_file = CONFIG_ALPS_TDLB7_FIRMWARE_LOCATION;
+static int debug = 0;
 
 #define dprintk	if (debug) printk
 
-/* microcode size for sp8870 */
-#define SP8870_CODE_SIZE 16382
+/* firmware size for sp8870 */
+#define SP8870_FIRMWARE_SIZE 16382
 
-/* starting point for microcode in file 'Sc_main.mc' */
-#define SP8870_CODE_OFFSET 0x0A
+/* starting point for firmware in file 'Sc_main.mc' */
+#define SP8870_FIRMWARE_OFFSET 0x0A
 
 
 static int errno;
 
 static struct dvb_frontend_info tdlb7_info = {
-	.name			 = "Alps TDLB7",
-	.type			 = FE_OFDM,
-	.frequency_min		 = 470000000,
-	.frequency_max		 = 860000000,
-	.frequency_stepsize	 = 166666,
-#if 0
-    	.frequency_tolerance	 = ???,
-	.symbol_rate_min	 = ???,
-	.symbol_rate_max	 = ???,
-	.symbol_rate_tolerance	 = ???,
-	.notifier_delay	 = 0,
-#endif
-	.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+	name: "Alps TDLB7",
+	type: FE_OFDM,
+	frequency_min: 470000000,
+	frequency_max: 860000000,
+	frequency_stepsize: 166666,
+	caps: FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
 	      FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-	      FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64
+	      FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+	      FE_CAN_HIERARCHY_AUTO |  FE_CAN_RECOVER
 };
 
 
 static int sp8870_writereg (struct dvb_i2c_bus *i2c, u16 reg, u16 data)
 {
         u8 buf [] = { reg >> 8, reg & 0xff, data >> 8, data & 0xff };
-	struct i2c_msg msg = { .addr = 0x71, .flags = 0, .buf =  buf, .len = 4 };
+	struct i2c_msg msg = { addr: 0x71, flags: 0, buf: buf, len: 4 };
 	int err;
 
         if ((err = i2c->xfer (i2c, &msg, 1)) != 1) {
@@ -109,13 +92,15 @@
 	int ret;
 	u8 b0 [] = { reg >> 8 , reg & 0xff };
 	u8 b1 [] = { 0, 0 };
-	struct i2c_msg msg [] = { { .addr = 0x71, .flags = 0, .buf = b0, .len = 2 },
-			   { .addr = 0x71, .flags = I2C_M_RD, .buf = b1, .len = 2 } };
+	struct i2c_msg msg [] = { { addr: 0x71, flags: 0, buf: b0, len: 2 },
+			   { addr: 0x71, flags: I2C_M_RD, buf: b1, len: 2 } };
 
 	ret = i2c->xfer (i2c, msg, 2);
 
-	if (ret != 2)
+	if (ret != 2) {
 		dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+		return -1;
+	}
 
 	return (b1[0] << 8 | b1[1]);
 }
@@ -124,7 +109,7 @@
 static int sp5659_write (struct dvb_i2c_bus *i2c, u8 data [4])
 {
         int ret;
-        struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = 4 };
+        struct i2c_msg msg = { addr: 0x60, flags: 0, buf: data, len: 4 };
 
         ret = i2c->xfer (i2c, &msg, 1);
 
@@ -135,7 +120,7 @@
 }
 
 
-static int sp5659_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq)
+static void sp5659_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq)
 {
         u32 div = (freq + 36200000) / 166666;
         u8 buf [4];
@@ -151,102 +136,146 @@
 	buf[2] = 0x85;
 	buf[3] = pwr << 6;
 
-	return sp5659_write (i2c, buf);
+	/* open i2c gate for PLL message transmission... */
+	sp8870_writereg(i2c, 0x206, 0x001);
+	sp5659_write (i2c, buf);
+	sp8870_writereg(i2c, 0x206, 0x000);
 }
 
 
-static int sp8870_read_code(const char *fn, char **fp)
+static int sp8870_read_firmware_file (const char *fn, char **fp)
 {
         int fd;
-	loff_t l;
+	loff_t filesize;
 	char *dp;
 
 	fd = open(fn, 0, 0);
 	if (fd == -1) {
-                printk(KERN_INFO "%s: Unable to load '%s'.\n", __FUNCTION__, fn);
-		return -1;
+                printk("%s: unable to open '%s'.\n", __FUNCTION__, fn);
+		return -EIO;
 	}
-	l = lseek(fd, 0L, 2);
-	if (l <= 0 || l < SP8870_CODE_OFFSET+SP8870_CODE_SIZE) {
-	        printk(KERN_INFO "%s: code file too small '%s'\n", __FUNCTION__, fn);
+
+	filesize = lseek(fd, 0L, 2);
+	if (filesize <= 0 || filesize < SP8870_FIRMWARE_OFFSET + SP8870_FIRMWARE_SIZE) {
+	        printk("%s: firmware filesize to small '%s'\n", __FUNCTION__, fn);
 		sys_close(fd);
-		return -1;
+		return -EIO;
 	}
-	lseek(fd, SP8870_CODE_OFFSET, 0);
-	*fp= dp = vmalloc(SP8870_CODE_SIZE);
+
+	*fp= dp = vmalloc(SP8870_FIRMWARE_SIZE);
 	if (dp == NULL)	{
-		printk(KERN_INFO "%s: Out of memory loading '%s'.\n", __FUNCTION__, fn);
+		printk("%s: out of memory loading '%s'.\n", __FUNCTION__, fn);
 		sys_close(fd);
-		return -1;
+		return -EIO;
 	}
-	if (read(fd, dp, SP8870_CODE_SIZE) != SP8870_CODE_SIZE) {
-		printk(KERN_INFO "%s: Failed to read '%s'.\n",__FUNCTION__, fn);
+
+	lseek(fd, SP8870_FIRMWARE_OFFSET, 0);
+	if (read(fd, dp, SP8870_FIRMWARE_SIZE) != SP8870_FIRMWARE_SIZE) {
+		printk("%s: failed to read '%s'.\n",__FUNCTION__, fn);
 		vfree(dp);
 		sys_close(fd);
-		return -1;
+		return -EIO;
 	}
+
 	sys_close(fd);
 	*fp = dp;
+
 	return 0;
 }
 
 
-static int sp8870_load_code(struct dvb_i2c_bus *i2c)
+static int sp8870_firmware_upload (struct dvb_i2c_bus *i2c)
 {
-	/* this takes a long time. is there a way to do it faster? */
-	char *lcode;
 	struct i2c_msg msg;
-	unsigned char buf[255];
-	int err;
-	int p=0;
-	int c;
+	char *fw_buf = NULL;
+	int fw_pos;
+	u8 tx_buf[255];
+	int tx_len;
+	int err = 0;
 	mm_segment_t fs = get_fs();
 
+	dprintk ("%s: ...\n", __FUNCTION__);
+
 	// system controller stop 
 	sp8870_writereg(i2c,0x0F00,0x0000);
 
 	// instruction RAM register hiword
-	sp8870_writereg(i2c,0x8F08,((SP8870_CODE_SIZE/2) & 0xFFFF));
+	sp8870_writereg(i2c, 0x8F08, ((SP8870_FIRMWARE_SIZE / 2) & 0xFFFF));
 
 	// instruction RAM MWR
-	sp8870_writereg(i2c,0x8F0A,((SP8870_CODE_SIZE/2) >> 16));
+	sp8870_writereg(i2c, 0x8F0A, ((SP8870_FIRMWARE_SIZE / 2) >> 16));
 
+	// reading firmware file to buffer
 	set_fs(get_ds());
-        if (sp8870_read_code(mcfile,(char**) &lcode)<0) return -1;
+        err = sp8870_read_firmware_file(firmware_file, (char**) &fw_buf);
 	set_fs(fs);
-	while (p<SP8870_CODE_SIZE){
-		c = (p<=SP8870_CODE_SIZE-252) ? 252 : SP8870_CODE_SIZE-p;
-		buf[0]=0xCF;
-		buf[1]=0x0A;
-		memcpy(&buf[2],lcode+p,c);
-		c+=2;
+	if (err != 0) {
+		printk("%s: reading firmware file failed!\n", __FUNCTION__);
+		return err;
+	}
+
+	// do firmware upload
+	fw_pos = 0;
+	while (fw_pos < SP8870_FIRMWARE_SIZE){
+		tx_len = (fw_pos <= SP8870_FIRMWARE_SIZE - 252) ? 252 : SP8870_FIRMWARE_SIZE - fw_pos;
+		// write register 0xCF0A
+		tx_buf[0] = 0xCF;
+		tx_buf[1] = 0x0A;
+		memcpy(&tx_buf[2], fw_buf + fw_pos, tx_len);
 		msg.addr=0x71;
 		msg.flags=0;
-		msg.buf=buf;
-		msg.len=c;
+		msg.buf = tx_buf;
+		msg.len = tx_len + 2;
         	if ((err = i2c->xfer (i2c, &msg, 1)) != 1) {
-			dprintk ("%s: i2c error (err == %i)\n",
-				 __FUNCTION__, err);
-        		vfree(lcode);
-			return -EREMOTEIO;
+			printk("%s: firmware upload failed!\n", __FUNCTION__);
+			printk ("%s: i2c error (err == %i)\n", __FUNCTION__, err);
+        		vfree(fw_buf);
+			return err;
 		}
-
-		p+=252;
+		fw_pos += tx_len;
 	}
-        vfree(lcode);
+
+	vfree(fw_buf);
+
+	dprintk ("%s: done!\n", __FUNCTION__);
 	return 0;
 };
 
 
-static int sp8870_init (struct dvb_i2c_bus *i2c)
+static void sp8870_microcontroller_stop (struct dvb_i2c_bus *i2c)
+{
+	sp8870_writereg(i2c, 0x0F08, 0x000);
+	sp8870_writereg(i2c, 0x0F09, 0x000);
+
+	// microcontroller STOP
+	sp8870_writereg(i2c, 0x0F00, 0x000);
+}
+
+
+static void sp8870_microcontroller_start (struct dvb_i2c_bus *i2c)
 {
+	sp8870_writereg(i2c, 0x0F08, 0x000);
+	sp8870_writereg(i2c, 0x0F09, 0x000);
+
+	// microcontroller START
+	sp8870_writereg(i2c, 0x0F00, 0x001);
+	// not documented but if we don't read 0x0D01 out here
+	// we don't get a correct data valid signal
+	sp8870_readreg(i2c, 0x0D01);
+}
 
+
+static int sp8870_init (struct dvb_i2c_bus *i2c)
+{
 	dprintk ("%s\n", __FUNCTION__);
 
+	/* enable TS output and interface pins */
+	sp8870_writereg(i2c, 0xc18, 0x00d);
+
 	// system controller stop 
-	sp8870_writereg(i2c,0x0F00,0x0000);
+	sp8870_microcontroller_stop(i2c);
 
-	// ADC mode: 2 for MT8872, 3 for MT8870/8871 
+	// ADC mode
 	sp8870_writereg(i2c,0x0301,0x0003);
 
 	// Reed Solomon parity bytes passed to output
@@ -255,103 +284,214 @@
 	// MPEG clock is suppressed if no valid data
 	sp8870_writereg(i2c,0x0C14,0x0001);
 
-	// sample rate correction bit [23..17]
-	sp8870_writereg(i2c,0x0319,0x000A);
+	/* bit 0x010: enable data valid signal */
+	sp8870_writereg(i2c, 0x0D00, 0x010);
+	sp8870_writereg(i2c, 0x0D01, 0x000);
 
-	// sample rate correction bit [16..0]
-	sp8870_writereg(i2c,0x031A,0x0AAB);
+	return 0;
+}
 
-	// integer carrier offset
-	sp8870_writereg(i2c,0x0309,0x0400);
 
-	// fractional carrier offset
-	sp8870_writereg(i2c,0x030A,0x0000);
+static int sp8870_read_status (struct dvb_i2c_bus *i2c,  fe_status_t * fe_status)
+{
+	int status;
+	int signal;
 
-	// filter for 8 Mhz channel 
-	sp8870_writereg(i2c,0x0311,0x0000);
+	*fe_status = 0;
 
-	// scan order: 2k first = 0x0000, 8k first = 0x0001 
-	sp8870_writereg(i2c,0x0338,0x0000);
+	status = sp8870_readreg (i2c, 0x0200);
+	if (status < 0)
+		return -EIO;
+
+	signal = sp8870_readreg (i2c, 0x0303);
+	if (signal < 0)
+		return -EIO;
+
+	if (signal > 0x0F)
+		*fe_status |= FE_HAS_SIGNAL;
+	if (status & 0x08)
+		*fe_status |= FE_HAS_SYNC;
+	if (status & 0x04)
+		*fe_status |= FE_HAS_LOCK | FE_HAS_CARRIER | FE_HAS_VITERBI;
 
 	return 0;
 }
 
 
-static int tdlb7_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int sp8870_read_ber (struct dvb_i2c_bus *i2c, u32 * ber)
 {
-	struct dvb_i2c_bus *i2c = fe->i2c;
+	int ret;
+	u32 tmp;
 
-        switch (cmd) {
-        case FE_GET_INFO:
-		memcpy (arg, &tdlb7_info, sizeof(struct dvb_frontend_info));
-		break;
+	*ber = 0;
 
-        case FE_READ_STATUS:
-	{
-		fe_status_t *status = arg;
-		int sync = sp8870_readreg (i2c, 0x0200);
-		int signal = 0xff-sp8870_readreg (i2c, 0x303);
+	ret = sp8870_readreg(i2c, 0xC08);
+	if (ret < 0)
+		return -EIO;
 
-		*status=0;
-		if (signal>10) // FIXME: is 10 the right value ?
-			*status |= FE_HAS_SIGNAL;
+	tmp = ret & 0x3F;
 
-		if (sync&0x04) // FIXME: find criteria
-			*status |= FE_HAS_CARRIER;
+	ret = sp8870_readreg(i2c, 0xC07);
+	if (ret < 0)
+		return -EIO;
 
-		if (sync&0x04) // FIXME
-			*status |= FE_HAS_VITERBI;
+	 tmp = ret << 6;
 
-		if (sync&0x08) // FIXME
-			*status |= FE_HAS_SYNC;
+	if (tmp >= 0x3FFF0)
+		tmp = ~0;
 
-		if (sync&0x04)
-			*status |= FE_HAS_LOCK;
-		break;
+	*ber = tmp;
 
+	return 0;
 	}
 
-        case FE_READ_BER:
+
+static int sp8870_read_signal_strength (struct dvb_i2c_bus *i2c,  u16 * signal)
 	{
-		u32 *ber=(u32 *) arg;
-		// bit error rate before Viterbi
-		*ber=sp8870_readreg(i2c,0x0C07);
-		break;
+	int ret;
+	u16 tmp;
 
-	}
+	*signal = 0;
 
-        case FE_READ_SIGNAL_STRENGTH:		// FIXME: correct registers ?
-	{
-		*((u16*) arg) = 0xffff-((sp8870_readreg (i2c, 0x306) << 8) | sp8870_readreg (i2c, 0x303));
-		break;
+	ret = sp8870_readreg (i2c, 0x306);
+	if (ret < 0)
+		return -EIO;
+
+	tmp = ret << 8;
+
+	ret = sp8870_readreg (i2c, 0x303);
+	if (ret < 0)
+		return -EIO;
+
+	tmp |= ret;
+
+	if (tmp)
+		*signal = 0xFFFF - tmp;
+
+	return 0;
 	}
 
-        case FE_READ_SNR:			// not supported by hardware?
+
+static int sp8870_read_snr(struct dvb_i2c_bus *i2c, u32* snr)
 	{
-		s32 *snr=(s32 *) arg;
                 *snr=0;  
 		return -EOPNOTSUPP;
 	}
 
-	case FE_READ_UNCORRECTED_BLOCKS: 	// not supported by hardware?
+
+static int sp8870_read_uncorrected_blocks (struct dvb_i2c_bus *i2c, u32* ublocks)
 	{
-		u32 *ublocks=(u32 *) arg;
+		int ret;
+
 		*ublocks=0;  
-		return -EOPNOTSUPP;
+
+		ret = sp8870_readreg(i2c, 0xC0C);
+		if (ret < 0)
+			return -EIO;
+
+		if (ret == 0xFFFF)
+			ret = ~0;
+
+		*ublocks = ret;
+
+		return 0;
 	}
 
-        case FE_SET_FRONTEND:
+
+static int sp8870_read_data_valid_signal(struct dvb_i2c_bus *i2c)
+{
+	return (sp8870_readreg(i2c, 0x0D02) > 0);
+}
+
+
+static
+int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05)
+{
+	int known_parameters = 1;
+
+	*reg0xc05 = 0x000;
+
+	switch (p->u.ofdm.constellation) {
+	case QPSK:
+		break;
+	case QAM_16:
+		*reg0xc05 |= (1 << 10);
+		break;
+	case QAM_64:
+		*reg0xc05 |= (2 << 10);
+		break;
+	case QAM_AUTO:
+		known_parameters = 0;
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	switch (p->u.ofdm.hierarchy_information) {
+	case HIERARCHY_NONE:
+		break;
+	case HIERARCHY_1:
+		*reg0xc05 |= (1 << 7);
+		break;
+	case HIERARCHY_2:
+		*reg0xc05 |= (2 << 7);
+		break;
+	case HIERARCHY_4:
+		*reg0xc05 |= (3 << 7);
+		break;
+	case HIERARCHY_AUTO:
+		known_parameters = 0;
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	switch (p->u.ofdm.code_rate_HP) {
+	case FEC_1_2:
+		break;
+	case FEC_2_3:
+		*reg0xc05 |= (1 << 3);
+		break;
+	case FEC_3_4:
+		*reg0xc05 |= (2 << 3);
+		break;
+	case FEC_5_6:
+		*reg0xc05 |= (3 << 3);
+		break;
+	case FEC_7_8:
+		*reg0xc05 |= (4 << 3);
+		break;
+	case FEC_AUTO:
+		known_parameters = 0;
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	if (known_parameters)
+		*reg0xc05 |= (2 << 1);	/* use specified parameters */
+	else
+		*reg0xc05 |= (1 << 1);	/* enable autoprobing */
+
+	return 0;
+}
+
+
+static int sp8870_set_frontend_parameters (struct dvb_i2c_bus *i2c,
+				      struct dvb_frontend_parameters *p)
         {
-		struct dvb_frontend_parameters *p = arg;
+	int  err;
+	u16 reg0xc05;
+
+	if ((err = configure_reg0xc05(p, &reg0xc05)))
+		return err;
 
 		// system controller stop 
-		sp8870_writereg(i2c,0x0F00,0x0000);
+	sp8870_microcontroller_stop(i2c);
 
+	// set tuner parameters
 		sp5659_set_tv_freq (i2c, p->frequency);
 
-		// read status reg in order to clear pending irqs
-		sp8870_readreg(i2c, 0x200);
-
 		// sample rate correction bit [23..17]
 		sp8870_writereg(i2c,0x0319,0x000A);
 		
@@ -378,28 +518,141 @@
 		else
 			sp8870_writereg(i2c,0x0338,0x0001);
 
-		// instruction RAM register loword
-		sp8870_writereg(i2c,0x0F09,0x0000);
+	sp8870_writereg(i2c, 0xc05, reg0xc05);
 
-		// instruction RAM register hiword
-		sp8870_writereg(i2c,0x0F08,0x0000);
+	// read status reg in order to clear pending irqs
+	sp8870_readreg(i2c, 0x200);
 
 		// system controller start
-		sp8870_writereg(i2c,0x0F00,0x0001);
+	sp8870_microcontroller_start(i2c);
 
-		break;
+	return 0;
         }
 
-	case FE_GET_FRONTEND:  // FIXME: read known values back from Hardware...
+
+// number of trials to recover from lockup
+#define MAXTRIALS 5
+// maximum checks for data valid signal
+#define MAXCHECKS 100
+
+// only for debugging: counter for detected lockups
+static int lockups = 0;
+// only for debugging: counter for channel switches
+static int switches = 0;
+
+static int sp8870_set_frontend (struct dvb_i2c_bus *i2c, struct dvb_frontend_parameters *p)
 	{
+	/*
+	    The firmware of the sp8870 sometimes locks up after setting frontend parameters.
+	    We try to detect this by checking the data valid signal.
+	    If it is not set after MAXCHECKS we try to recover the lockup by setting
+	    the frontend parameters again.
+	*/
+
+	int err = 0;
+	int valid = 0;
+	int trials = 0;
+	int check_count = 0;
+
+	dprintk("%s: frequency = %i\n", __FUNCTION__, p->frequency);
+
+	for (trials = 1; trials <= MAXTRIALS; trials++) {
+
+		if ((err = sp8870_set_frontend_parameters(i2c, p)))
+			return err;
+
+		for (check_count = 0; check_count < MAXCHECKS; check_count++) {
+//			valid = ((sp8870_readreg(i2c, 0x0200) & 4) == 0);
+			valid = sp8870_read_data_valid_signal(i2c);
+			if (valid) {
+				dprintk("%s: delay = %i usec\n",
+					__FUNCTION__, check_count * 10);
+				break;
+			}
+			udelay(10);
+		}
+		if (valid)
 		break;
 	}
 
-        case FE_SLEEP:			// is this supported by hardware?
+	if (!valid) {
+		printk("%s: firmware crash!!!!!!\n", __FUNCTION__);
+		return -EIO;
+	}
+
+	if (debug) {
+		if (valid) {
+			if (trials > 1) {
+				printk("%s: firmware lockup!!!\n", __FUNCTION__);
+				printk("%s: recovered after %i trial(s))\n",  __FUNCTION__, trials - 1);
+				lockups++;
+			}
+		}
+		switches++;
+		printk("%s: switches = %i lockups = %i\n", __FUNCTION__, switches, lockups);
+	}
+
+	return 0;
+}
+
+
+static int sp8870_sleep(struct dvb_i2c_bus *i2c)
+{
+	// tristate TS output and disable interface pins
+	return sp8870_writereg(i2c, 0xC18, 0x000);
+}
+
+
+static int sp8870_wake_up(struct dvb_i2c_bus *i2c)
+{
+	// enable TS output and interface pins
+	return sp8870_writereg(i2c, 0xC18, 0x00D);
+}
+
+
+static int tdlb7_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+{
+	struct dvb_i2c_bus *i2c = fe->i2c;
+
+        switch (cmd) {
+        case FE_GET_INFO:
+		memcpy (arg, &tdlb7_info, sizeof(struct dvb_frontend_info));
+		break;
+
+        case FE_READ_STATUS:
+		return sp8870_read_status(i2c, (fe_status_t *) arg);
+
+        case FE_READ_BER:
+		return sp8870_read_ber(i2c, (u32 *) arg);
+
+        case FE_READ_SIGNAL_STRENGTH:
+		return sp8870_read_signal_strength(i2c, (u16 *) arg);
+
+        case FE_READ_SNR:				// not supported by hardware?
+		return sp8870_read_snr(i2c, (u32 *) arg);
+
+	case FE_READ_UNCORRECTED_BLOCKS:
+		return sp8870_read_uncorrected_blocks(i2c, (u32 *) arg);
+
+        case FE_SET_FRONTEND:
+		return sp8870_set_frontend(i2c, (struct dvb_frontend_parameters*) arg);
+
+	case FE_RESET:
 		return -EOPNOTSUPP;
 
+	case FE_GET_FRONTEND:			 // FIXME: read known values back from Hardware...
+		return -EOPNOTSUPP;
+
+        case FE_SLEEP:
+		return sp8870_sleep(i2c);
+
         case FE_INIT:
-		return sp8870_init (i2c);
+		sp8870_wake_up(i2c);
+		if (fe->data == NULL) {		// first time initialisation...
+			fe->data = (void*) ~0;
+			sp8870_init (i2c);
+		}
+		break;
 
 	default:
 		return -EOPNOTSUPP;
@@ -409,31 +662,22 @@
 }
 
 
-static int tdlb7_attach (struct dvb_i2c_bus *i2c)
+static int tdlb7_attach (struct dvb_i2c_bus *i2c, void **data)
 {
-
-	struct i2c_msg msg = { .addr = 0x71, .flags = 0, .buf = NULL, .len = 0 };
+	struct i2c_msg msg = { addr: 0x71, flags: 0, buf: NULL, len: 0 };
 
 	dprintk ("%s\n", __FUNCTION__);
 
 	if (i2c->xfer (i2c, &msg, 1) != 1)
                 return -ENODEV;
 
-	if (loadcode) {
-		dprintk("%s: loading mcfile '%s' !\n", __FUNCTION__, mcfile);
-		if (sp8870_load_code(i2c)==0)
-		    dprintk("%s: microcode loaded!\n", __FUNCTION__);
-	}else{
-		dprintk("%s: without loading mcfile!\n", __FUNCTION__);
-	}
-
-	dvb_register_frontend (tdlb7_ioctl, i2c, NULL, &tdlb7_info);
+	sp8870_firmware_upload(i2c);
 
-	return 0;
+	return dvb_register_frontend (tdlb7_ioctl, i2c, NULL, &tdlb7_info);
 }
 
 
-static void tdlb7_detach (struct dvb_i2c_bus *i2c)
+static void tdlb7_detach (struct dvb_i2c_bus *i2c, void *data)
 {
 	dprintk ("%s\n", __FUNCTION__);
 
@@ -464,11 +708,8 @@
 MODULE_PARM(debug,"i");
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
-MODULE_PARM(loadcode,"i");
-MODULE_PARM_DESC(loadcode, "load tuner microcode");
-
-MODULE_PARM(mcfile,"s");
-MODULE_PARM_DESC(mcfile, "where to find the microcode file");
+MODULE_PARM(firmware_file,"s");
+MODULE_PARM_DESC(firmware_file, "where to find the firmware file");
 
 MODULE_DESCRIPTION("TDLB7 DVB-T Frontend");
 MODULE_AUTHOR("Juergen Peitz");
diff -Nru a/drivers/media/dvb/frontends/alps_tdmb7.c b/drivers/media/dvb/frontends/alps_tdmb7.c
--- a/drivers/media/dvb/frontends/alps_tdmb7.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/media/dvb/frontends/alps_tdmb7.c	Wed Oct 15 00:46:36 2003
@@ -402,7 +402,7 @@
 
 
 
-static int tdmb7_attach (struct dvb_i2c_bus *i2c)
+static int tdmb7_attach (struct dvb_i2c_bus *i2c, void **data)
 {
 	struct i2c_msg msg = { .addr = 0x43, .flags = 0, .buf = NULL,. len = 0 };
 
@@ -411,13 +411,11 @@
 	if (i2c->xfer (i2c, &msg, 1) != 1)
                 return -ENODEV;
 
-	dvb_register_frontend (tdmb7_ioctl, i2c, NULL, &tdmb7_info);
-
-	return 0;
+	return dvb_register_frontend (tdmb7_ioctl, i2c, NULL, &tdmb7_info);
 }
 
 
-static void tdmb7_detach (struct dvb_i2c_bus *i2c)
+static void tdmb7_detach (struct dvb_i2c_bus *i2c, void *data)
 {
 	dprintk ("%s\n", __FUNCTION__);
 
diff -Nru a/drivers/media/dvb/frontends/at76c651.c b/drivers/media/dvb/frontends/at76c651.c
--- a/drivers/media/dvb/frontends/at76c651.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/media/dvb/frontends/at76c651.c	Wed Oct 15 00:46:37 2003
@@ -37,6 +37,8 @@
 #include "dvb_functions.h"
 
 static int debug = 0;
+static u8 at76c651_qam;
+static u8 at76c651_revision;
 
 #define dprintk	if (debug) printk
 
@@ -53,7 +55,7 @@
 
 static struct dvb_frontend_info at76c651_info = {
 
-	.name = "Atmel AT76c651(B) with DAT7021",
+	.name = "Atmel AT76C651(B) with DAT7021",
 	.type = FE_QAM,
 	.frequency_min = 48250000,
 	.frequency_max = 863250000,
@@ -126,46 +128,70 @@
 
 }
 
+static int at76c651_reset(struct dvb_i2c_bus *i2c)
+{
+
+	return at76c651_writereg(i2c, 0x07, 0x01);
+
+}
+
+static int at76c651_disable_interrupts(struct dvb_i2c_bus *i2c)
+{
+
+	return at76c651_writereg(i2c, 0x0b, 0x00);
+
+}
+
 static int at76c651_set_auto_config(struct dvb_i2c_bus *i2c)
 {
 
+	/*
+	 * Autoconfig
+	 */
+
 	at76c651_writereg(i2c, 0x06, 0x01);
 
 	/*
-	 * performance optimizations 
+	 * Performance optimizations, should be done after autoconfig
 	 */
 
 	at76c651_writereg(i2c, 0x10, 0x06);
-	at76c651_writereg(i2c, 0x11, 0x10);
+	at76c651_writereg(i2c, 0x11, ((at76c651_qam == 5) || (at76c651_qam == 7)) ? 0x12 : 0x10);
 	at76c651_writereg(i2c, 0x15, 0x28);
 	at76c651_writereg(i2c, 0x20, 0x09);
-	at76c651_writereg(i2c, 0x24, 0x90);
+	at76c651_writereg(i2c, 0x24, ((at76c651_qam == 5) || (at76c651_qam == 7)) ? 0xC0 : 0x90);
+	at76c651_writereg(i2c, 0x30, 0x90);
+	if (at76c651_qam == 5)
+		at76c651_writereg(i2c, 0x35, 0x2A);
 
-	return 0;
+	/*
+	 * Initialize A/D-converter
+	 */
 
+	if (at76c651_revision == 0x11) {
+		at76c651_writereg(i2c, 0x2E, 0x38);
+		at76c651_writereg(i2c, 0x2F, 0x13);
 }
 
-static int at76c651_set_bbfreq(struct dvb_i2c_bus *i2c)
-{
+	at76c651_disable_interrupts(i2c);
 
-	at76c651_writereg(i2c, 0x04, 0x3f);
-	at76c651_writereg(i2c, 0x05, 0xee);
+	/*
+	 * Restart operation
+	 */
+
+	at76c651_reset(i2c);
 
 	return 0;
 
 }
 
-static int at76c651_reset(struct dvb_i2c_bus *i2c)
+static int at76c651_set_bbfreq(struct dvb_i2c_bus *i2c)
 {
 
-	return at76c651_writereg(i2c, 0x07, 0x01);
-
-}
-
-static int at76c651_disable_interrupts(struct dvb_i2c_bus *i2c)
-{
+	at76c651_writereg(i2c, 0x04, 0x3f);
+	at76c651_writereg(i2c, 0x05, 0xee);
 
-	return at76c651_writereg(i2c, 0x0b, 0x00);
+	return 0;
 
 }
 
@@ -186,6 +212,10 @@
 	struct i2c_msg msg =
 	    { .addr = 0xc2 >> 1, .flags = 0, .buf = (u8 *) & tw, .len = sizeof (tw) };
 
+#ifdef __LITTLE_ENDIAN
+	tw = __cpu_to_be32(tw);
+#endif
+
 	at76c651_switch_tuner_i2c(i2c, 1);
 
 	ret = i2c->xfer(i2c, &msg, 1);
@@ -236,7 +266,7 @@
 	u32 mantissa;
 
 	if (symbolrate > 9360000)
-		return -1;
+		return -EINVAL;
 
 	/*
 	 * FREF = 57800 kHz
@@ -258,34 +288,31 @@
 static int at76c651_set_qam(struct dvb_i2c_bus *i2c, fe_modulation_t qam)
 {
 
-	u8 qamsel = 0;
-
 	switch (qam) {
-
 	case QPSK:
-		qamsel = 0x02;
+		at76c651_qam = 0x02;
 		break;
 	case QAM_16:
-		qamsel = 0x04;
+		at76c651_qam = 0x04;
 		break;
 	case QAM_32:
-		qamsel = 0x05;
+		at76c651_qam = 0x05;
 		break;
 	case QAM_64:
-		qamsel = 0x06;
+		at76c651_qam = 0x06;
 		break;
 	case QAM_128:
-		qamsel = 0x07;
+		at76c651_qam = 0x07;
 		break;
 	case QAM_256:
-		qamsel = 0x08;
+		at76c651_qam = 0x08;
 		break;
 #if 0
 	case QAM_512:
-		qamsel = 0x09;
+		at76c651_qam = 0x09;
 		break;
 	case QAM_1024:
-		qamsel = 0x0A;
+		at76c651_qam = 0x0A;
 		break;
 #endif
 	default:
@@ -293,7 +320,7 @@
 
 	}
 
-	return at76c651_writereg(i2c, 0x03, qamsel);
+	return at76c651_writereg(i2c, 0x03, at76c651_qam);
 
 }
 
@@ -345,7 +372,6 @@
 	at76c651_set_qam(i2c, QAM_64);
 	at76c651_set_bbfreq(i2c);
 	at76c651_set_auto_config(i2c);
-	at76c651_disable_interrupts(i2c);
 
 	return 0;
 
@@ -408,13 +434,12 @@
 		{
 			u8 gain = ~at76c651_readreg(fe->i2c, 0x91);
 
-			*(s32 *) arg = (gain << 8) | gain;
-			*(s32 *) arg = 0x0FFF;
+			*(u16 *) arg = (gain << 8) | gain;
 			break;
 		}
 
 	case FE_READ_SNR:
-		*(s32 *) arg =
+		*(u16 *) arg =
 		    0xFFFF -
 		    ((at76c651_readreg(fe->i2c, 0x8F) << 8) |
 		     at76c651_readreg(fe->i2c, 0x90));
@@ -440,59 +465,44 @@
 		return at76c651_reset(fe->i2c);
 
 	default:
-		return -ENOSYS;
+		return -ENOIOCTLCMD;
 	}
 
 	return 0;
 
 }
 
-static int at76c651_attach(struct dvb_i2c_bus *i2c)
+static int at76c651_attach(struct dvb_i2c_bus *i2c, void **data)
+{
+	if ( (at76c651_readreg(i2c, 0x0E) != 0x65) ||
+	     ( ( (at76c651_revision = at76c651_readreg(i2c, 0x0F)) & 0xFE) != 0x10) )
 {
-
-	if (at76c651_readreg(i2c, 0x0e) != 0x65) {
-
 		dprintk("no AT76C651(B) found\n");
-
 		return -ENODEV;
-
 	}
 
-	if (at76c651_readreg(i2c, 0x0F) != 0x10) {
-
-		if (at76c651_readreg(i2c, 0x0F) == 0x11) {
-
-			dprintk("AT76C651B found\n");
-
-		} else {
-
-			dprintk("no AT76C651(B) found\n");
-
-			return -ENODEV;
-
+	if (at76c651_revision == 0x10)
+	{
+		dprintk("AT76C651A found\n");
+		strcpy(at76c651_info.name,"Atmel AT76C651A with DAT7021");
 		}
-
-	} else {
-
+	else
+	{
+		strcpy(at76c651_info.name,"Atmel AT76C651B with DAT7021");
 		dprintk("AT76C651B found\n");
-
 	}
 
 	at76c651_set_defaults(i2c);
 
-	dvb_register_frontend(at76c651_ioctl, i2c, NULL, &at76c651_info);
-
-	return 0;
+	return dvb_register_frontend(at76c651_ioctl, i2c, NULL, &at76c651_info);
 
 }
 
-static void at76c651_detach(struct dvb_i2c_bus *i2c)
+static void at76c651_detach(struct dvb_i2c_bus *i2c, void *data)
 {
 
 	dvb_unregister_frontend(at76c651_ioctl, i2c);
 
-	at76c651_disable_interrupts(i2c);
-
 }
 
 static int __init at76c651_init(void)
@@ -513,11 +523,7 @@
 module_init(at76c651_init);
 module_exit(at76c651_exit);
 
-#ifdef MODULE
 MODULE_DESCRIPTION("at76c651/dat7021 dvb-c frontend driver");
 MODULE_AUTHOR("Andreas Oberritter <andreas@oberritter.de>");
-#ifdef MODULE_LICENSE
 MODULE_LICENSE("GPL");
-#endif
 MODULE_PARM(debug, "i");
-#endif
diff -Nru a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
--- a/drivers/media/dvb/frontends/cx24110.c	Wed Oct 15 00:46:35 2003
+++ b/drivers/media/dvb/frontends/cx24110.c	Wed Oct 15 00:46:35 2003
@@ -643,7 +643,7 @@
 }
 
 
-static int cx24110_attach (struct dvb_i2c_bus *i2c)
+static int cx24110_attach (struct dvb_i2c_bus *i2c, void **data)
 {
 	u8 sig;
 
@@ -651,13 +651,11 @@
 	if ( sig != 0x5a && sig != 0x69 )
 		return -ENODEV;
 
-	dvb_register_frontend (cx24110_ioctl, i2c, NULL, &cx24110_info);
-
-	return 0;
+	return dvb_register_frontend (cx24110_ioctl, i2c, NULL, &cx24110_info);
 }
 
 
-static void cx24110_detach (struct dvb_i2c_bus *i2c)
+static void cx24110_detach (struct dvb_i2c_bus *i2c, void *data)
 {
 	dvb_unregister_frontend (cx24110_ioctl, i2c);
 }
diff -Nru a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c
--- a/drivers/media/dvb/frontends/dvb_dummy_fe.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c	Wed Oct 15 00:46:36 2003
@@ -173,14 +173,13 @@
 } 
 
 
-static int dvbdummyfe_attach (struct dvb_i2c_bus *i2c)
+static int dvbdummyfe_attach (struct dvb_i2c_bus *i2c, void **data)
 {
-	dvb_register_frontend (dvbdummyfe_ioctl, i2c, NULL, frontend_info());
-	return 0;
+	return dvb_register_frontend (dvbdummyfe_ioctl, i2c, NULL, frontend_info());
 }
 
 
-static void dvbdummyfe_detach (struct dvb_i2c_bus *i2c)
+static void dvbdummyfe_detach (struct dvb_i2c_bus *i2c, void *data)
 {
 	dvb_unregister_frontend (dvbdummyfe_ioctl, i2c);
 }
@@ -191,14 +190,12 @@
 	return dvb_register_i2c_device (THIS_MODULE,
 					dvbdummyfe_attach, 
 					dvbdummyfe_detach);
-	return 0;
 }
 
 
 static void __exit exit_dvbdummyfe (void)
 {
 	dvb_unregister_i2c_device (dvbdummyfe_attach);
-	return;
 }
 
 
diff -Nru a/drivers/media/dvb/frontends/grundig_29504-401.c b/drivers/media/dvb/frontends/grundig_29504-401.c
--- a/drivers/media/dvb/frontends/grundig_29504-401.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/media/dvb/frontends/grundig_29504-401.c	Wed Oct 15 00:46:36 2003
@@ -415,7 +415,7 @@
 } 
 
 
-static int l64781_attach (struct dvb_i2c_bus *i2c)
+static int l64781_attach (struct dvb_i2c_bus *i2c, void **data)
 {
 	u8 reg0x3e;
 	u8 b0 [] = { 0x1a };
@@ -465,9 +465,8 @@
 	        goto bailout;
 	}
 
-	dvb_register_frontend (grundig_29504_401_ioctl, i2c, NULL,
+	return dvb_register_frontend (grundig_29504_401_ioctl, i2c, NULL,
 			       &grundig_29504_401_info);
-	return 0;
 
  bailout:
 	l64781_writereg (i2c, 0x3e, reg0x3e);  /* restore reg 0x3e */
@@ -475,7 +474,8 @@
 }
 
 
-static void l64781_detach (struct dvb_i2c_bus *i2c)
+
+static void l64781_detach (struct dvb_i2c_bus *i2c, void *data)
 {
 	dvb_unregister_frontend (grundig_29504_401_ioctl, i2c);
 }
diff -Nru a/drivers/media/dvb/frontends/grundig_29504-491.c b/drivers/media/dvb/frontends/grundig_29504-491.c
--- a/drivers/media/dvb/frontends/grundig_29504-491.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/media/dvb/frontends/grundig_29504-491.c	Wed Oct 15 00:46:37 2003
@@ -433,19 +433,17 @@
 } 
 
 
-static int tda8083_attach (struct dvb_i2c_bus *i2c)
+static int tda8083_attach (struct dvb_i2c_bus *i2c, void **data)
 {
 	if ((tda8083_readreg (i2c, 0x00)) != 0x05)
 		return -ENODEV;
 
-	dvb_register_frontend (grundig_29504_491_ioctl, i2c, NULL,
+	return dvb_register_frontend (grundig_29504_491_ioctl, i2c, NULL,
 			       &grundig_29504_491_info);
-
-	return 0;
 }
 
 
-static void tda8083_detach (struct dvb_i2c_bus *i2c)
+static void tda8083_detach (struct dvb_i2c_bus *i2c, void *data)
 {
 	dvb_unregister_frontend (grundig_29504_491_ioctl, i2c);
 }
diff -Nru a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c
--- a/drivers/media/dvb/frontends/mt312.c	Wed Oct 15 00:46:35 2003
+++ b/drivers/media/dvb/frontends/mt312.c	Wed Oct 15 00:46:35 2003
@@ -714,7 +714,7 @@
 	return 0;
 }
 
-static int mt312_attach(struct dvb_i2c_bus *i2c)
+static int mt312_attach(struct dvb_i2c_bus *i2c, void **data)
 {
 	int ret;
 	u8 id;
@@ -734,7 +734,7 @@
 	return 0;
 }
 
-static void mt312_detach(struct dvb_i2c_bus *i2c)
+static void mt312_detach(struct dvb_i2c_bus *i2c, void *data)
 {
 	dvb_unregister_frontend(mt312_ioctl, i2c);
 
diff -Nru a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c
--- a/drivers/media/dvb/frontends/nxt6000.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/media/dvb/frontends/nxt6000.c	Wed Oct 15 00:46:37 2003
@@ -829,7 +829,7 @@
 
 static u8 demod_addr_tbl[] = {0x14, 0x18, 0x24, 0x28};
 
-static int nxt6000_attach(struct dvb_i2c_bus *i2c)
+static int nxt6000_attach(struct dvb_i2c_bus *i2c, void **data)
 {
 
 	u8 addr_nr;
@@ -881,13 +881,14 @@
 	
 		dvb_register_frontend(nxt6000_ioctl, i2c, (void *)(*((u32 *)&nxt)), &nxt6000_info);
 		
+		fe_count++;
 	}
 	
 	return (fe_count > 0) ? 0 : -ENODEV;
 	
 }
 
-static void nxt6000_detach(struct dvb_i2c_bus *i2c)
+static void nxt6000_detach(struct dvb_i2c_bus *i2c, void *data)
 {
 
 	dprintk("nxt6000: detach\n");
diff -Nru a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c
--- a/drivers/media/dvb/frontends/sp887x.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/media/dvb/frontends/sp887x.c	Wed Oct 15 00:46:37 2003
@@ -561,7 +561,7 @@
 
 
 static
-int sp887x_attach (struct dvb_i2c_bus *i2c)
+int sp887x_attach (struct dvb_i2c_bus *i2c, void **data)
 {
 	struct i2c_msg msg = { addr: 0x70, flags: 0, buf: NULL, len: 0 };
 
@@ -570,14 +570,12 @@
 	if (i2c->xfer (i2c, &msg, 1) != 1)
                 return -ENODEV;
 
-	dvb_register_frontend (sp887x_ioctl, i2c, NULL, &sp887x_info);
-
-	return 0;
+	return dvb_register_frontend (sp887x_ioctl, i2c, NULL, &sp887x_info);
 }
 
 
 static
-void sp887x_detach (struct dvb_i2c_bus *i2c)
+void sp887x_detach (struct dvb_i2c_bus *i2c, void *data)
 {
 	dprintk ("%s\n", __FUNCTION__);
 	dvb_unregister_frontend (sp887x_ioctl, i2c);
diff -Nru a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
--- a/drivers/media/dvb/frontends/stv0299.c	Wed Oct 15 00:46:38 2003
+++ b/drivers/media/dvb/frontends/stv0299.c	Wed Oct 15 00:46:38 2003
@@ -910,7 +910,7 @@
 }
 
 
-static int uni0299_attach (struct dvb_i2c_bus *i2c)
+static int uni0299_attach (struct dvb_i2c_bus *i2c, void **data)
 {
         long tuner_type;
 	u8 id;
@@ -928,17 +928,14 @@
 	if ((tuner_type = probe_tuner(i2c)) < 0)
 		return -ENODEV;
 
-	dvb_register_frontend (uni0299_ioctl, i2c, (void*) tuner_type, 
+	return dvb_register_frontend (uni0299_ioctl, i2c, (void*) tuner_type, 
 			       &uni0299_info);
-
-	return 0;
 }
 
 
-static void uni0299_detach (struct dvb_i2c_bus *i2c)
+static void uni0299_detach (struct dvb_i2c_bus *i2c, void *data)
 {
 	dprintk ("%s\n", __FUNCTION__);
-
 	dvb_unregister_frontend (uni0299_ioctl, i2c);
 }
 
diff -Nru a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
--- a/drivers/media/dvb/frontends/tda1004x.c	Wed Oct 15 00:46:35 2003
+++ b/drivers/media/dvb/frontends/tda1004x.c	Wed Oct 15 00:46:35 2003
@@ -1055,7 +1055,7 @@
 }
 
 
-static int tda1004x_attach(struct dvb_i2c_bus *i2c)
+static int tda1004x_attach(struct dvb_i2c_bus *i2c, void **data)
 {
         int tda1004x_address = -1;
 	int tuner_address = -1;
@@ -1113,17 +1113,15 @@
 	// register
         switch(tda_state.tda1004x_address) {
         case TDA10045H_ADDRESS:
-        	dvb_register_frontend(tda1004x_ioctl, i2c, (void *)(*((u32*) &tda_state)), &tda10045h_info);
-                break;
+        	return dvb_register_frontend(tda1004x_ioctl, i2c, (void *)(*((u32*) &tda_state)), &tda10045h_info);
+	default:
+		return -ENODEV;
         }
-
-	// success
-	return 0;
 }
 
 
 static
-void tda1004x_detach(struct dvb_i2c_bus *i2c)
+void tda1004x_detach(struct dvb_i2c_bus *i2c, void *data)
 {
 	dprintk("%s\n", __FUNCTION__);
 
diff -Nru a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c
--- a/drivers/media/dvb/frontends/ves1820.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/media/dvb/frontends/ves1820.c	Wed Oct 15 00:46:36 2003
@@ -507,9 +507,9 @@
 }
 
 
-static int ves1820_attach (struct dvb_i2c_bus *i2c)
+static int ves1820_attach (struct dvb_i2c_bus *i2c, void **data)
 {
-	void *data = NULL;
+	void *priv = NULL;
 	long demod_addr;
 	long tuner_type;
 
@@ -522,21 +522,19 @@
 	if ((i2c->adapter->num < MAX_UNITS) && pwm[i2c->adapter->num] != -1) {
 		printk("DVB: VES1820(%d): pwm=0x%02x (user specified)\n",
 				i2c->adapter->num, pwm[i2c->adapter->num]);
-		SET_PWM(data, pwm[i2c->adapter->num]);
+		SET_PWM(priv, pwm[i2c->adapter->num]);
 	}
 	else
-	SET_PWM(data, read_pwm(i2c));
-	SET_REG0(data, ves1820_inittab[0]);
-	SET_TUNER(data, tuner_type);
-	SET_DEMOD_ADDR(data, demod_addr);
+		SET_PWM(priv, read_pwm(i2c));
+	SET_REG0(priv, ves1820_inittab[0]);
+	SET_TUNER(priv, tuner_type);
+	SET_DEMOD_ADDR(priv, demod_addr);
 
-	dvb_register_frontend (ves1820_ioctl, i2c, data, &ves1820_info);
-
-        return 0;
+	return dvb_register_frontend (ves1820_ioctl, i2c, priv, &ves1820_info);
 }
 
 
-static void ves1820_detach (struct dvb_i2c_bus *i2c)
+static void ves1820_detach (struct dvb_i2c_bus *i2c, void *data)
 {
 	dvb_unregister_frontend (ves1820_ioctl, i2c);
 }
diff -Nru a/drivers/media/dvb/frontends/ves1x93.c b/drivers/media/dvb/frontends/ves1x93.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/media/dvb/frontends/ves1x93.c	Wed Oct 15 00:46:36 2003
@@ -0,0 +1,619 @@
+/* 
+    Driver for VES1893 and VES1993 QPSK Frontends
+
+    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
+    Copyright (C) 2001 Ronny Strutz <3des@tuxbox.org>
+    Copyright (C) 2002 Dennis Noermann <dennis.noermann@noernet.de>
+    Copyright (C) 2002-2003 Andreas Oberritter <obi@tuxbox.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/    
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+
+static int debug = 0;
+#define dprintk	if (debug) printk
+
+static int board_type = 0;
+#define BOARD_SIEMENS_PCI	0
+#define BOARD_NOKIA_DBOX2	1
+#define BOARD_SAGEM_DBOX2	2
+
+static int demod_type = 0;
+#define DEMOD_VES1893		0
+#define DEMOD_VES1993		1
+
+static struct dvb_frontend_info ves1x93_info = {
+	.name			= "VES1x93",
+	.type			= FE_QPSK,
+	.frequency_min		= 950000,
+	.frequency_max		= 2150000,
+	.frequency_stepsize	= 250,           /* kHz for QPSK frontends */
+	.frequency_tolerance	= 29500,
+	.symbol_rate_min	= 1000000,
+	.symbol_rate_max	= 45000000,
+/*      .symbol_rate_tolerance	=	???,*/
+	.notifier_delay		= 50,                /* 1/20 s */
+	.caps = FE_CAN_INVERSION_AUTO |
+		FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+		FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+		FE_CAN_QPSK
+};
+
+
+/**
+ * nokia dbox2 (ves1893) and sagem dbox2 (ves1993)
+ * need bit AGCR[PWMS] set to 1
+ */
+
+static u8 init_1893_tab [] = {
+	0x01, 0xa4, 0x35, 0x81, 0x2a, 0x0d, 0x55, 0xc4,
+	0x09, 0x69, 0x00, 0x86, 0x4c, 0x28, 0x7f, 0x00,
+	0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x80, 0x00, 0x31, 0xb0, 0x14, 0x00, 0xdc, 0x00,
+	0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x55, 0x00, 0x00, 0x7f, 0x00
+};
+
+
+static u8 init_1993_tab [] = {
+	0x00, 0x9c, 0x35, 0x80, 0x6a, 0x09, 0x72, 0x8c,
+	0x09, 0x6b, 0x00, 0x00, 0x4c, 0x08, 0x00, 0x00,
+	0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x80, 0x40, 0x21, 0xb0, 0x00, 0x00, 0x00, 0x10,
+	0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x55, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03,
+	0x00, 0x00, 0x0e, 0x80, 0x00
+};
+
+
+static u8 * init_1x93_tab;
+
+
+static u8 init_1893_wtab[] =
+{
+        1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0,
+        0,1,0,0,0,0,0,0, 1,0,1,1,0,0,0,1,
+        1,1,1,0,0,0,0,0, 0,0,1,1,0,0,0,0,
+        1,1,1,0,1,1
+};
+
+
+static u8 init_1993_wtab[] =
+{
+	1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0,
+	0,1,0,0,0,0,0,0, 1,1,1,1,0,0,0,1,
+	1,1,1,0,0,0,0,0, 0,0,1,1,0,0,0,0,
+	1,1,1,0,1,1,1,1, 1,1,1,1,1
+};
+
+
+static int ves1x93_writereg (struct dvb_i2c_bus *i2c, u8 reg, u8 data)
+{
+        u8 buf [] = { 0x00, reg, data };
+	struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = buf, .len = 3 };
+	int err;
+
+        if ((err = i2c->xfer (i2c, &msg, 1)) != 1) {
+		dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data);
+		return -EREMOTEIO;
+	}
+
+        return 0;
+}
+
+
+static u8 ves1x93_readreg (struct dvb_i2c_bus *i2c, u8 reg)
+{
+	int ret;
+	u8 b0 [] = { 0x00, reg };
+	u8 b1 [] = { 0 };
+	struct i2c_msg msg [] = { { .addr = 0x08, .flags = 0, .buf = b0, .len = 2 },
+			   { .addr = 0x08, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+
+	ret = i2c->xfer (i2c, msg, 2);
+
+	if (ret != 2)
+		dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+
+	return b1[0];
+}
+
+
+static int tuner_write (struct dvb_i2c_bus *i2c, u8 *data, u8 len)
+{
+        int ret;
+        struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = len };
+
+	ves1x93_writereg(i2c, 0x00, 0x11);
+        ret = i2c->xfer (i2c, &msg, 1);
+	ves1x93_writereg(i2c, 0x00, 0x01);
+
+        if (ret != 1)
+                printk("%s: i/o error (ret == %i)\n", __FUNCTION__, ret);
+
+        return (ret != 1) ? -1 : 0;
+}
+
+
+
+/**
+ *   set up the downconverter frequency divisor for a
+ *   reference clock comparision frequency of 125 kHz.
+ */
+static int sp5659_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, u8 pwr)
+{
+        u32 div = (freq + 479500) / 125;
+	u8 buf [4] = { (div >> 8) & 0x7f, div & 0xff, 0x95, (pwr << 5) | 0x30 };
+
+	return tuner_write (i2c, buf, sizeof(buf));
+}
+
+
+static int tsa5059_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq)
+{
+	int ret;
+	u8 buf [2];
+
+	freq /= 1000;
+
+	buf[0] = (freq >> 8) & 0x7F;
+	buf[1] = freq & 0xFF;
+
+	ret = tuner_write(i2c, buf, sizeof(buf));
+
+	return ret;
+}
+
+
+static int tuner_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, u8 pwr)
+{
+	if ((demod_type == DEMOD_VES1893) && (board_type == BOARD_SIEMENS_PCI))
+		return sp5659_set_tv_freq (i2c, freq, pwr);
+	else if (demod_type == DEMOD_VES1993)
+		return tsa5059_set_tv_freq (i2c, freq);
+
+	return -EINVAL;
+}
+
+
+static int ves1x93_init (struct dvb_i2c_bus *i2c)
+{
+	int i;
+	int size;
+	u8 *init_1x93_wtab;
+ 
+	dprintk("%s: init chip\n", __FUNCTION__);
+
+	switch (demod_type) {
+	case DEMOD_VES1893:
+		init_1x93_tab = init_1893_tab;
+		init_1x93_wtab = init_1893_wtab;
+		size = sizeof(init_1893_tab);
+		if (board_type == BOARD_NOKIA_DBOX2)
+			init_1x93_tab[0x05] |= 0x20; /* invert PWM */
+		break;
+
+	case DEMOD_VES1993:
+		init_1x93_tab = init_1993_tab;
+		init_1x93_wtab = init_1993_wtab;
+		size = sizeof(init_1993_tab);
+		if (board_type == BOARD_SAGEM_DBOX2)
+			init_1x93_tab[0x05] |= 0x20; /* invert PWM */
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	for (i = 0; i < size; i++)
+		if (init_1x93_wtab[i])
+			ves1x93_writereg (i2c, i, init_1x93_tab[i]);
+
+	if (demod_type == DEMOD_VES1993) {
+		if (board_type == BOARD_NOKIA_DBOX2)
+			tuner_write(i2c, "\x06\x5c\x83\x60", 4);
+		else if (board_type == BOARD_SAGEM_DBOX2)
+			tuner_write(i2c, "\x25\x70\x92\x40", 4);
+	}
+
+	return 0;
+}
+
+
+static int ves1x93_clr_bit (struct dvb_i2c_bus *i2c)
+{
+        ves1x93_writereg (i2c, 0, init_1x93_tab[0] & 0xfe);
+        ves1x93_writereg (i2c, 0, init_1x93_tab[0]);
+        ves1x93_writereg (i2c, 3, 0x00);
+        return ves1x93_writereg (i2c, 3, init_1x93_tab[3]);
+}
+
+
+static int ves1x93_set_inversion (struct dvb_i2c_bus *i2c, fe_spectral_inversion_t inversion)
+{
+	u8 val;
+
+	/*
+	 * inversion on/off are interchanged because i and q seem to
+	 * be swapped on the hardware
+	 */
+
+	switch (inversion) {
+	case INVERSION_OFF:
+		val = 0xc0;
+		break;
+	case INVERSION_ON:
+		val = 0x80;
+		break;
+	case INVERSION_AUTO:
+		val = 0x00;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* needs to be saved for FE_GET_FRONTEND */
+	init_1x93_tab[0x0c] = (init_1x93_tab[0x0c] & 0x3f) | val;
+
+	return ves1x93_writereg (i2c, 0x0c, init_1x93_tab[0x0c]);
+}
+
+
+static int ves1x93_set_fec (struct dvb_i2c_bus *i2c, fe_code_rate_t fec)
+{
+	if (fec == FEC_AUTO)
+		return ves1x93_writereg (i2c, 0x0d, 0x08);
+	else if (fec < FEC_1_2 || fec > FEC_8_9)
+		return -EINVAL;
+	else
+		return ves1x93_writereg (i2c, 0x0d, fec - FEC_1_2);
+}
+
+
+static fe_code_rate_t ves1x93_get_fec (struct dvb_i2c_bus *i2c)
+{
+	return FEC_1_2 + ((ves1x93_readreg (i2c, 0x0d) >> 4) & 0x7);
+}
+
+
+static int ves1x93_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate)
+{
+	u32 BDR;
+        u32 ratio;
+	u8  ADCONF, FCONF, FNR;
+	u32 BDRI;
+	u32 tmp;
+	u32 XIN, FIN;
+
+	dprintk("%s: srate == %d\n", __FUNCTION__, (unsigned int) srate);
+
+	switch (board_type) {
+	case BOARD_SIEMENS_PCI:
+		XIN = 90100000UL;
+		break;
+	case BOARD_NOKIA_DBOX2:
+		if (demod_type == DEMOD_VES1893)
+			XIN = 91000000UL;
+		else if (demod_type == DEMOD_VES1993)
+			XIN = 96000000UL;
+		else
+			return -EINVAL;
+		break;
+	case BOARD_SAGEM_DBOX2:
+		XIN = 92160000UL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (srate > XIN/2)
+		srate = XIN/2;
+
+	if (srate < 500000)
+		srate = 500000;
+
+#define MUL (1UL<<26)
+
+	FIN = (XIN + 6000) >> 4;
+
+	tmp = srate << 6;
+	ratio = tmp / FIN;
+
+	tmp = (tmp % FIN) << 8;
+	ratio = (ratio << 8) + tmp / FIN;
+
+	tmp = (tmp % FIN) << 8;
+	ratio = (ratio << 8) + tmp / FIN;
+
+	FNR = 0xff;
+
+	if (ratio < MUL/3)           FNR = 0;
+	if (ratio < (MUL*11)/50)     FNR = 1;
+	if (ratio < MUL/6)           FNR = 2;
+	if (ratio < MUL/9)           FNR = 3;
+	if (ratio < MUL/12)          FNR = 4;
+	if (ratio < (MUL*11)/200)    FNR = 5;
+	if (ratio < MUL/24)          FNR = 6;
+	if (ratio < (MUL*27)/1000)   FNR = 7;
+	if (ratio < MUL/48)          FNR = 8;
+	if (ratio < (MUL*137)/10000) FNR = 9;
+
+	if (FNR == 0xff) {
+		ADCONF = 0x89;
+		FCONF  = 0x80;
+		FNR	= 0;
+	} else {
+		ADCONF = 0x81;
+		FCONF  = 0x88 | (FNR >> 1) | ((FNR & 0x01) << 5);
+		/*FCONF  = 0x80 | ((FNR & 0x01) << 5) | (((FNR > 1) & 0x03) << 3) | ((FNR >> 1) & 0x07);*/
+	}
+
+	BDR = (( (ratio << (FNR >> 1)) >> 4) + 1) >> 1;
+	BDRI = ( ((FIN << 8) / ((srate << (FNR >> 1)) >> 2)) + 1) >> 1;
+
+        dprintk("FNR= %d\n", FNR);
+        dprintk("ratio= %08x\n", (unsigned int) ratio);
+        dprintk("BDR= %08x\n", (unsigned int) BDR);
+        dprintk("BDRI= %02x\n", (unsigned int) BDRI);
+
+	if (BDRI > 0xff)
+		BDRI = 0xff;
+
+	ves1x93_writereg (i2c, 0x06, 0xff & BDR);
+	ves1x93_writereg (i2c, 0x07, 0xff & (BDR >> 8));
+	ves1x93_writereg (i2c, 0x08, 0x0f & (BDR >> 16));
+
+	ves1x93_writereg (i2c, 0x09, BDRI);
+	ves1x93_writereg (i2c, 0x20, ADCONF);
+	ves1x93_writereg (i2c, 0x21, FCONF);
+
+	if (srate < 6000000) 
+		ves1x93_writereg (i2c, 0x05, init_1x93_tab[0x05] | 0x80);
+	else
+		ves1x93_writereg (i2c, 0x05, init_1x93_tab[0x05] & 0x7f);
+
+	ves1x93_writereg (i2c, 0x00, 0x00);
+	ves1x93_writereg (i2c, 0x00, 0x01);
+
+	/* ves1993 hates this, will lose lock */
+	if (demod_type != DEMOD_VES1993)
+		ves1x93_clr_bit (i2c);
+
+	return 0;
+}
+
+
+static int ves1x93_set_voltage (struct dvb_i2c_bus *i2c, fe_sec_voltage_t voltage)
+{
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		return ves1x93_writereg (i2c, 0x1f, 0x20);
+	case SEC_VOLTAGE_18:
+		return ves1x93_writereg (i2c, 0x1f, 0x30);
+	case SEC_VOLTAGE_OFF:
+		return ves1x93_writereg (i2c, 0x1f, 0x00);
+	default:
+		return -EINVAL;
+	}
+}
+
+
+static int ves1x93_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+{
+	struct dvb_i2c_bus *i2c = fe->i2c;
+
+        switch (cmd) {
+        case FE_GET_INFO:
+		memcpy (arg, &ves1x93_info, sizeof(struct dvb_frontend_info));
+		break;
+
+        case FE_READ_STATUS:
+	{
+		fe_status_t *status = arg;
+		u8 sync = ves1x93_readreg (i2c, 0x0e);
+
+		*status = 0;
+
+		if (sync & 1)
+			*status |= FE_HAS_SIGNAL;
+
+		if (sync & 2)
+			*status |= FE_HAS_CARRIER;
+
+		if (sync & 4)
+			*status |= FE_HAS_VITERBI;
+
+		if (sync & 8)
+			*status |= FE_HAS_SYNC;
+
+		if ((sync & 0x1f) == 0x1f)
+			*status |= FE_HAS_LOCK;
+
+		break;
+	}
+
+        case FE_READ_BER:
+	{
+		u32 *ber = (u32 *) arg;
+
+		*ber = ves1x93_readreg (i2c, 0x15);
+                *ber |= (ves1x93_readreg (i2c, 0x16) << 8);
+                *ber |= ((ves1x93_readreg (i2c, 0x17) & 0x0F) << 16);
+		*ber *= 10;
+		break;
+	}
+
+        case FE_READ_SIGNAL_STRENGTH:
+	{
+		u8 signal = ~ves1x93_readreg (i2c, 0x0b);
+		*((u16*) arg) = (signal << 8) | signal;
+		break;
+	}
+
+        case FE_READ_SNR:
+	{
+		u8 snr = ~ves1x93_readreg (i2c, 0x1c);
+		*(u16*) arg = (snr << 8) | snr;
+		break;
+	}
+
+	case FE_READ_UNCORRECTED_BLOCKS: 
+	{
+		*(u32*) arg = ves1x93_readreg (i2c, 0x18) & 0x7f;
+
+		if (*(u32*) arg == 0x7f)
+			*(u32*) arg = 0xffffffff;   /* counter overflow... */
+		
+		ves1x93_writereg (i2c, 0x18, 0x00);  /* reset the counter */
+		ves1x93_writereg (i2c, 0x18, 0x80);  /* dto. */
+		break;
+	}
+
+        case FE_SET_FRONTEND:
+        {
+		struct dvb_frontend_parameters *p = arg;
+
+		tuner_set_tv_freq (i2c, p->frequency, 0);
+		ves1x93_set_inversion (i2c, p->inversion);
+		ves1x93_set_fec (i2c, p->u.qpsk.fec_inner);
+		ves1x93_set_symbolrate (i2c, p->u.qpsk.symbol_rate);
+                break;
+        }
+
+	case FE_GET_FRONTEND:
+	{
+		struct dvb_frontend_parameters *p = arg;
+		int afc;
+
+		afc = ((int)((char)(ves1x93_readreg (i2c, 0x0a) << 1)))/2;
+		afc = (afc * (int)(p->u.qpsk.symbol_rate/1000/8))/16;
+
+		p->frequency -= afc;
+
+		/*
+		 * inversion indicator is only valid
+		 * if auto inversion was used
+		 */
+		if (!(init_1x93_tab[0x0c] & 0x80))
+			p->inversion = (ves1x93_readreg (i2c, 0x0f) & 2) ? 
+					INVERSION_OFF : INVERSION_ON;
+		p->u.qpsk.fec_inner = ves1x93_get_fec (i2c);
+	/*  XXX FIXME: timing offset !! */
+		break;
+	}
+
+        case FE_SLEEP:
+		if (board_type == BOARD_SIEMENS_PCI)
+			ves1x93_writereg (i2c, 0x1f, 0x00);    /*  LNB power off  */
+		return ves1x93_writereg (i2c, 0x00, 0x08);
+
+        case FE_INIT:
+		return ves1x93_init (i2c);
+
+	case FE_RESET:
+		return ves1x93_clr_bit (i2c);
+
+	case FE_SET_TONE:
+		return -EOPNOTSUPP;  /* the ves1893 can generate the 22k */
+		                     /* let's implement this when we have */
+		                     /* a box that uses the 22K_0 pin... */
+
+	case FE_SET_VOLTAGE:
+		return ves1x93_set_voltage (i2c, (fe_sec_voltage_t) arg);
+
+	default:
+		return -EOPNOTSUPP;
+        };
+        
+        return 0;
+} 
+
+
+static int ves1x93_attach (struct dvb_i2c_bus *i2c, void **data)
+{
+	u8 identity = ves1x93_readreg(i2c, 0x1e);
+
+	switch (identity) {
+	case 0xdc: /* VES1893A rev1 */
+	case 0xdd: /* VES1893A rev2 */
+		demod_type = DEMOD_VES1893;
+		ves1x93_info.name[4] = '8';
+		break;
+	case 0xde: /* VES1993 */
+		demod_type = DEMOD_VES1993;
+		ves1x93_info.name[4] = '9';
+		break;
+	default:
+		dprintk("VES1x93 not found (identity %02x)\n", identity);
+		return -ENODEV;
+	}
+
+	return dvb_register_frontend (ves1x93_ioctl, i2c, NULL, &ves1x93_info);
+}
+
+
+static void ves1x93_detach (struct dvb_i2c_bus *i2c, void *data)
+{
+	dvb_unregister_frontend (ves1x93_ioctl, i2c);
+}
+
+
+static int __init init_ves1x93 (void)
+{
+	switch (board_type) {
+	case BOARD_NOKIA_DBOX2:
+		dprintk("%s: NOKIA_DBOX2\n", __FILE__);
+		break;
+	case BOARD_SAGEM_DBOX2:
+		dprintk("%s: SAGEM_DBOX2\n", __FILE__);
+		break;
+	case BOARD_SIEMENS_PCI:
+		dprintk("%s: SIEMENS_PCI\n", __FILE__);
+		break;
+	default:
+		return -EIO;
+	}
+
+	return dvb_register_i2c_device (THIS_MODULE, ves1x93_attach, ves1x93_detach);
+}
+
+
+static void __exit exit_ves1x93 (void)
+{
+	dvb_unregister_i2c_device (ves1x93_attach);
+}
+
+
+module_init(init_ves1x93);
+module_exit(exit_ves1x93);
+
+
+MODULE_DESCRIPTION("VES1x93 DVB-S Frontend");
+MODULE_AUTHOR("Ralph Metzler");
+MODULE_LICENSE("GPL");
+MODULE_PARM(debug,"i");
+MODULE_PARM(board_type,"i");
+
diff -Nru a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
--- a/drivers/media/dvb/ttpci/av7110.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/media/dvb/ttpci/av7110.c	Wed Oct 15 00:46:37 2003
@@ -55,8 +55,10 @@
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/pci.h>
+#include <linux/init.h>
 #include <linux/vmalloc.h>
 #include <linux/netdevice.h>
 #include <linux/inetdevice.h>
@@ -2704,9 +2706,9 @@
 	buf[1] = div & 0xff;
 	buf[2] = 0x8e;
 
-	if (freq < 16*168.25 ) 
+	if (freq < (u32) (16*168.25) ) 
 		config = 0xa0;
-	else if (freq < 16*447.25) 
+	else if (freq < (u32) (16*447.25)) 
 		config = 0x90;
 	else
 		config = 0x30;
@@ -4520,28 +4522,6 @@
 
 	DEB_EE(("dev: %p, av7110: %p\n",dev,av7110));
 
-	/* special case DVB-C: these cards have an analog tuner
-	   plus need some special handling, so we have separate
-	   saa7146_ext_vv data for these... */
-	if (dev->pci->subsystem_vendor == 0x110a) {
-		ret = saa7146_vv_init(dev, &av7110_vv_data_c);
-	} else {
-		ret = saa7146_vv_init(dev, &av7110_vv_data_st);
-	}
-	
-	if ( 0 != ret) {
-		ERR(("cannot init capture device. skipping.\n"));
-		kfree(av7110);
-		return -1;
-	}
-
-	if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) {
-		ERR(("cannot register capture device. skipping.\n"));
-		saa7146_vv_release(dev);
-		kfree(av7110);
-		return -1;
-	}
-
 	av7110->dev=(struct saa7146_dev *)dev;
 	dvb_register_adapter(&av7110->dvb_adapter, av7110->card_name);
 
@@ -4555,8 +4535,6 @@
 						av7110->dvb_adapter, 0);
 
 	if (!av7110->i2c_bus) {
-		saa7146_unregister_device(&av7110->v4l_dev, dev);
-		saa7146_vv_release(dev);
 		dvb_unregister_adapter (av7110->dvb_adapter);
 		kfree(av7110);
 		return -ENOMEM;
@@ -4727,7 +4705,7 @@
 		memcpy(standard,dvb_standard,sizeof(struct saa7146_standard)*2);
 		/* set dd1 stream a & b */
       		saa7146_write(dev, DD1_STREAM_B, 0x00000000);
-		saa7146_write(dev, DD1_INIT, 0x0200700);
+		saa7146_write(dev, DD1_INIT, 0x02000700);
 		saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
 	}
 	else if (dev->pci->subsystem_vendor == 0x110a) {
@@ -4754,17 +4732,52 @@
 	av7110_setup_irc_config (av7110, 0);
 	av7110_register(av7110);
 	
+	/* special case DVB-C: these cards have an analog tuner
+	   plus need some special handling, so we have separate
+	   saa7146_ext_vv data for these... */
+	if (0 != av7110->has_analog_tuner) {
+		ret = saa7146_vv_init(dev, &av7110_vv_data_c);
+	} else {
+		ret = saa7146_vv_init(dev, &av7110_vv_data_st);
+	}
+	
+	if ( 0 != ret) {
+		ERR(("cannot init capture device. skipping.\n"));
+		ret = -ENODEV;
+		goto err;
+	}
+
+	if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) {
+		ERR(("cannot register capture device. skipping.\n"));
+		ret = -ENODEV;
+		goto video_err;
+	}
+	
+	if (0 != av7110->has_analog_tuner) {
+		if( 0 != saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) {
+			ERR(("cannot register vbi v4l2 device. skipping.\n"));
+		}
+		/* we use this to remember that this dvb-c card cannot do vbi */
+		av7110->has_analog_tuner = 2;
+	}	
+
 	printk(KERN_INFO "av7110: found av7110-%d.\n",av7110_num);
 	av7110_num++;
         return 0;
 
+video_err:
+	saa7146_vv_release(dev);
+
 err:
-	if (av7110 )
+	if (NULL != av7110 ) {
 		kfree(av7110);
-
-	/* FIXME: error handling is pretty bogus: memory does not get freed...*/
-	saa7146_unregister_device(&av7110->v4l_dev, dev);
-	saa7146_vv_release(dev);
+	}
+	if (NULL != av7110->debi_virt) {
+		pci_free_consistent(dev->pci, 8192, av7110->debi_virt, av7110->debi_bus);
+	}
+	if (NULL != av7110->iobuf) {
+		vfree(av7110->iobuf);
+	}
 
 	dvb_unregister_i2c_bus (master_xfer,av7110->i2c_bus->adapter,
 				av7110->i2c_bus->id);
@@ -4780,6 +4793,9 @@
 	DEB_EE(("av7110: %p\n",av7110));
 
 	saa7146_unregister_device(&av7110->v4l_dev, saa);
+	if (2 == av7110->has_analog_tuner) {
+		saa7146_unregister_device(&av7110->vbi_dev, saa);
+	}	
 
 	av7110->arm_rmmod=1;
 	wake_up_interruptible(&av7110->arm_wait);
@@ -4948,8 +4964,8 @@
 static struct saa7146_ext_vv av7110_vv_data_c = {
 	.inputs		= 1,
 	.audios 	= 1,
-	.capabilities	= V4L2_CAP_TUNER,
-	.flags		= 0,
+	.capabilities	= V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,
+	.flags		= SAA7146_USE_PORT_B_FOR_VBI,
 
 	.stds		= &standard[0],
 	.num_stds	= sizeof(standard)/sizeof(struct saa7146_standard),
diff -Nru a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
--- a/drivers/media/dvb/ttpci/av7110.h	Wed Oct 15 00:46:35 2003
+++ b/drivers/media/dvb/ttpci/av7110.h	Wed Oct 15 00:46:35 2003
@@ -399,7 +399,9 @@
 
         struct dvb_device       dvb_dev;
         struct dvb_net               dvb_net;
+
 	struct video_device	v4l_dev;
+	struct video_device	vbi_dev;
 
         struct saa7146_dev	*dev;
 
diff -Nru a/drivers/media/dvb/ttusb-dec/dec2000_frontend.c b/drivers/media/dvb/ttusb-dec/dec2000_frontend.c
--- a/drivers/media/dvb/ttusb-dec/dec2000_frontend.c	Wed Oct 15 00:46:38 2003
+++ b/drivers/media/dvb/ttusb-dec/dec2000_frontend.c	Wed Oct 15 00:46:38 2003
@@ -140,17 +140,15 @@
 	return 0;
 }
 
-static int dec2000_frontend_attach(struct dvb_i2c_bus *i2c)
+static int dec2000_frontend_attach(struct dvb_i2c_bus *i2c, void **data)
 {
 	dprintk("%s\n", __FUNCTION__);
 
-	dvb_register_frontend(dec2000_frontend_ioctl, i2c, NULL,
+	return dvb_register_frontend(dec2000_frontend_ioctl, i2c, NULL,
 			      &dec2000_frontend_info);
-
-	return 0;
 }
 
-static void dec2000_frontend_detach(struct dvb_i2c_bus *i2c)
+static void dec2000_frontend_detach(struct dvb_i2c_bus *i2c, void *data)
 {
 	dprintk("%s\n", __FUNCTION__);
 
diff -Nru a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c
--- a/drivers/media/video/zoran_card.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/media/video/zoran_card.c	Wed Oct 15 00:46:37 2003
@@ -47,6 +47,8 @@
 #include <linux/video_decoder.h>
 #include <linux/video_encoder.h>
 
+#include <asm/io.h>
+
 #include "videocodec.h"
 #include "zoran.h"
 #include "zoran_card.h"
diff -Nru a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c
--- a/drivers/media/video/zoran_device.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/media/video/zoran_device.c	Wed Oct 15 00:46:37 2003
@@ -46,6 +46,8 @@
 #include <linux/video_encoder.h>
 #include <linux/delay.h>
 
+#include <asm/io.h>
+
 #include "videocodec.h"
 #include "zoran.h"
 #include "zoran_device.h"
diff -Nru a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
--- a/drivers/media/video/zoran_driver.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/media/video/zoran_driver.c	Wed Oct 15 00:46:37 2003
@@ -73,6 +73,7 @@
 #include <linux/videodev.h>
 #include "videocodec.h"
 
+#include <asm/io.h>
 #include <asm/uaccess.h>
 #include <linux/proc_fs.h>
 
diff -Nru a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c
--- a/drivers/mtd/devices/lart.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/mtd/devices/lart.c	Wed Oct 15 00:46:36 2003
@@ -42,6 +42,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/types.h>
+#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/mtd/mtd.h>
 #ifdef HAVE_PARTITIONS
diff -Nru a/drivers/net/8139too.c b/drivers/net/8139too.c
--- a/drivers/net/8139too.c	Wed Oct 15 00:46:35 2003
+++ b/drivers/net/8139too.c	Wed Oct 15 00:46:35 2003
@@ -248,6 +248,8 @@
 	{0x14ea, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
 	{0x14ea, 0xab07, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
 	{0x11db, 0x1234, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+	{0x1432, 0x9130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+	{0x02ac, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
 
 #ifdef CONFIG_SH_SECUREEDGE5410
 	/* Bogus 8139 silicon reports 8129 without external PROM :-( */
diff -Nru a/drivers/net/Kconfig b/drivers/net/Kconfig
--- a/drivers/net/Kconfig	Wed Oct 15 00:46:37 2003
+++ b/drivers/net/Kconfig	Wed Oct 15 00:46:37 2003
@@ -1616,7 +1616,7 @@
 
 config TLAN
 	tristate "TI ThunderLAN support"
-	depends on NET_PCI && (PCI || EISA)
+	depends on NET_PCI && (PCI || EISA) && !64BIT
 	---help---
 	  If you have a PCI Ethernet network card based on the ThunderLAN chip
 	  which is supported by this driver, say Y and read the
@@ -2412,7 +2412,7 @@
 
 config RCPCI
 	tristate "Red Creek Hardware VPN (EXPERIMENTAL)"
-	depends on NETDEVICES && EXPERIMENTAL && PCI
+	depends on NETDEVICES && EXPERIMENTAL && PCI && !64BIT
 	help
 	  This is a driver for hardware which provides a Virtual Private
 	  Network (VPN). Say Y if you have it.
diff -Nru a/drivers/net/Space.c b/drivers/net/Space.c
--- a/drivers/net/Space.c	Wed Oct 15 00:46:35 2003
+++ b/drivers/net/Space.c	Wed Oct 15 00:46:36 2003
@@ -433,17 +433,15 @@
 	
 #ifdef CONFIG_SBNI
 	for (num = 0; num < 8; ++num)
-		if (sbni_probe(num))
-			break;
+		sbni_probe(num);
 #endif
 #ifdef CONFIG_TR
 	for (num = 0; num < 8; ++num)
-		if (trif_probe(num))
-			break;
+		trif_probe(num);
 #endif
 	for (num = 0; num < 8; ++num)
-		if (ethif_probe(num))
-			break;
+		ethif_probe(num);
+
 #ifdef CONFIG_COPS
 	cops_probe(0);
 	cops_probe(1);
diff -Nru a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
--- a/drivers/net/amd8111e.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/net/amd8111e.c	Wed Oct 15 00:46:37 2003
@@ -1698,7 +1698,7 @@
 	/* Restart ipg timer */
 	if(lp->options & OPTION_DYN_IPG_ENABLE)	        
 		mod_timer(&lp->ipg_data.ipg_timer, 
-				jiffies + (IPG_CONVERGE_TIME * HZ));
+				jiffies + IPG_CONVERGE_JIFFIES);
 	spin_unlock_irq(&lp->lock);
 
 	return 0;
@@ -1772,7 +1772,7 @@
 		writew((u32)tmp_ipg, mmio + IPG); 
 		writew((u32)(tmp_ipg - IFS1_DELTA), mmio + IFS1); 
 	}
-	 mod_timer(&lp->ipg_data.ipg_timer, jiffies + (IPG_CONVERGE_TIME * HZ));
+	 mod_timer(&lp->ipg_data.ipg_timer, jiffies + IPG_CONVERGE_JIFFIES);
 	return;
 
 }
@@ -1909,7 +1909,7 @@
 		lp->ipg_data.ipg_timer.data = (unsigned long) dev;
 		lp->ipg_data.ipg_timer.function = (void *)&amd8111e_config_ipg;
 		lp->ipg_data.ipg_timer.expires = jiffies + 
-						 IPG_CONVERGE_TIME * HZ;
+						 IPG_CONVERGE_JIFFIES;
 		lp->ipg_data.ipg = DEFAULT_IPG;
 		lp->ipg_data.ipg_state = CSTATE;
 	};
diff -Nru a/drivers/net/amd8111e.h b/drivers/net/amd8111e.h
--- a/drivers/net/amd8111e.h	Wed Oct 15 00:46:36 2003
+++ b/drivers/net/amd8111e.h	Wed Oct 15 00:46:36 2003
@@ -606,7 +606,7 @@
 /* ipg parameters */
 #define DEFAULT_IPG			0x60
 #define IFS1_DELTA			36
-#define	IPG_CONVERGE_TIME 0.5
+#define	IPG_CONVERGE_JIFFIES	(HZ / 2)
 #define	IPG_STABLE_TIME	5
 #define	MIN_IPG	96
 #define	MAX_IPG	255
diff -Nru a/drivers/net/b44.c b/drivers/net/b44.c
--- a/drivers/net/b44.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/net/b44.c	Wed Oct 15 00:46:36 2003
@@ -25,8 +25,8 @@
 
 #define DRV_MODULE_NAME		"b44"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"0.9"
-#define DRV_MODULE_RELDATE	"Jul 14, 2003"
+#define DRV_MODULE_VERSION	"0.91"
+#define DRV_MODULE_RELDATE	"Oct 3, 2003"
 
 #define B44_DEF_MSG_ENABLE	  \
 	(NETIF_MSG_DRV		| \
@@ -80,15 +80,6 @@
 
 static int b44_debug = -1;	/* -1 == use B44_DEF_MSG_ENABLE as value */
 
-#ifndef PCI_DEVICE_ID_BCM4401
-#define PCI_DEVICE_ID_BCM4401      0x4401
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#define IRQ_RETVAL(x) 
-#define irqreturn_t void
-#endif
-
 static struct pci_device_id b44_pci_tbl[] = {
 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
@@ -869,6 +860,8 @@
 	b44_init_hw(bp);
 
 	spin_unlock_irq(&bp->lock);
+
+	b44_enable_ints(bp);
 
 	netif_wake_queue(dev);
 }
diff -Nru a/drivers/net/defxx.c b/drivers/net/defxx.c
--- a/drivers/net/defxx.c	Wed Oct 15 00:46:35 2003
+++ b/drivers/net/defxx.c	Wed Oct 15 00:46:35 2003
@@ -2664,8 +2664,8 @@
  
 static void my_skb_align(struct sk_buff *skb, int n)
 {
-	u32 x=(u32)skb->data;	/* We only want the low bits .. */
-	u32 v;
+	unsigned long x=(unsigned long)skb->data;	
+	unsigned long v;
 	
 	v=(x+n-1)&~(n-1);	/* Where we want to be */
 	
diff -Nru a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
--- a/drivers/net/e1000/e1000_main.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/net/e1000/e1000_main.c	Wed Oct 15 00:46:36 2003
@@ -30,7 +30,7 @@
 
 /* Change Log
  *
- * 5.2.18	9/13/03
+ * 5.2.20	9/30/03
  *   o Bug fix: SERDES devices might be connected to a back-plane
  *     switch that doesn't support auto-neg, so add the capability
  *     to force 1000/Full.
@@ -39,6 +39,9 @@
  *     Jumbo Frames or with the reduced FIFO in 82547.
  *   o Better propagation of error codes. [Janice Girouard 
  *     (janiceg@us.ibm.com)].
+ *   o Bug fix: hang under heavy Tx stress when running out of Tx
+ *     descriptors; wasn't clearing context descriptor when backing
+ *     out of send because of no-resource condition.
  *
  * 5.2.16	8/8/03
  *   o Added support for new controllers: 82545GM, 82546GB, 82541/7_B1
@@ -61,7 +64,7 @@
 
 char e1000_driver_name[] = "e1000";
 char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
-char e1000_driver_version[] = "5.2.19-k1";
+char e1000_driver_version[] = "5.2.20-k1";
 char e1000_copyright[] = "Copyright (c) 1999-2003 Intel Corporation.";
 
 /* e1000_pci_tbl - PCI Device ID Table
@@ -1545,6 +1548,7 @@
 	unsigned int first)
 {
 	struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
+	struct e1000_tx_desc *tx_desc;
 	struct e1000_buffer *buffer_info;
 	unsigned int len = skb->len, max_per_txd = E1000_MAX_DATA_PER_TXD;
 	unsigned int offset = 0, size, count = 0, i;
@@ -1640,17 +1644,29 @@
 		}
 	}
 
-	if(E1000_DESC_UNUSED(&adapter->tx_ring) < count) {
+	if(E1000_DESC_UNUSED(&adapter->tx_ring) < count + 2) {
 
 		/* There aren't enough descriptors available to queue up
-		 * this send, so undo the mapping and abort the send. 
-		 * We could have done the check before we mapped the skb,
-		 * but because of all the workarounds (above), it's too
-		 * difficult to predict how many we're going to need.*/
-		i = first;
+		 * this send (need: count + 1 context desc + 1 desc gap
+		 * to keep tail from touching head), so undo the mapping
+		 * and abort the send.  We could have done the check before
+		 * we mapped the skb, but because of all the workarounds
+		 * (above), it's too difficult to predict how many we're
+		 * going to need.*/
+		i = adapter->tx_ring.next_to_use;
+
+		if(i == first) {
+			/* Cleanup after e1000_tx_[csum|tso] scribbling
+			 * on descriptors. */
+			tx_desc = E1000_TX_DESC(*tx_ring, first);
+			tx_desc->buffer_addr = 0;
+			tx_desc->lower.data = 0;
+			tx_desc->upper.data = 0;
+		}
 
 		while(count--) {
 			buffer_info = &tx_ring->buffer_info[i];
+
 			if(buffer_info->dma) {
 				pci_unmap_page(adapter->pdev,
 					       buffer_info->dma,
@@ -1658,8 +1674,11 @@
 					       PCI_DMA_TODEVICE);
 				buffer_info->dma = 0;
 			}
+
 			if(++i == tx_ring->count) i = 0;
 		}
+
+		adapter->tx_ring.next_to_use = first;
 
 		return 0;
 	}
diff -Nru a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig
--- a/drivers/net/hamradio/Kconfig	Wed Oct 15 00:46:35 2003
+++ b/drivers/net/hamradio/Kconfig	Wed Oct 15 00:46:35 2003
@@ -159,7 +159,7 @@
 
 config BAYCOM_EPP
 	tristate "BAYCOM epp driver for AX.25"
-	depends on PARPORT && AX25
+	depends on PARPORT && AX25 && !64BIT
 	---help---
 	  This is a driver for Baycom style simple amateur radio modems that
 	  connect to a parallel interface. The driver supports the EPP
diff -Nru a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
--- a/drivers/net/hamradio/bpqether.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/net/hamradio/bpqether.c	Wed Oct 15 00:46:36 2003
@@ -196,12 +196,8 @@
 	eth = (struct ethhdr *)skb->mac.raw;
 
 	if (!(bpq->acpt_addr[0] & 0x01) &&
-	    memcmp(eth->h_source, bpq->acpt_addr, ETH_ALEN)) {
-		if (net_ratelimit())
-			printk(KERN_DEBUG "bpqether: wrong dest %s\n",
-			       bpq_print_ethaddr(eth->h_source));
+	    memcmp(eth->h_source, bpq->acpt_addr, ETH_ALEN))
 		goto drop_unlock;
-	}
 
 	if (skb_cow(skb, sizeof(struct ethhdr)))
 		goto drop_unlock;
diff -Nru a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
--- a/drivers/net/hamradio/scc.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/net/hamradio/scc.c	Wed Oct 15 00:46:37 2003
@@ -1762,7 +1762,7 @@
 
 #ifndef SCC_DONT_CHECK
 
-			if(request_region(scc->ctrl, 1, "scc-probe"))
+			if(request_region(hwcfg.ctrl_a, 1, "scc-probe"))
 			{
 				disable_irq(hwcfg.irq);
 				Outb(hwcfg.ctrl_a, 0);
@@ -1774,7 +1774,7 @@
 				if (InReg(hwcfg.ctrl_a,R13) != 0x55)
 					found = 0;
 				enable_irq(hwcfg.irq);
-				release_region(scc->ctrl, 1);
+				release_region(hwcfg.ctrl_a, 1);
 			}
 			else
 				found = 0;
diff -Nru a/drivers/net/hp100.c b/drivers/net/hp100.c
--- a/drivers/net/hp100.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/net/hp100.c	Wed Oct 15 00:46:36 2003
@@ -1265,9 +1265,9 @@
 {
 	/* pdlptr is starting address for this pdl */
 
-	if (0 != (((unsigned) pdlptr) & 0xf))
-		printk("hp100: %s: Init rxpdl: Unaligned pdlptr 0x%x.\n",
-		       dev->name, (unsigned) pdlptr);
+	if (0 != (((unsigned long) pdlptr) & 0xf))
+		printk("hp100: %s: Init rxpdl: Unaligned pdlptr 0x%lx.\n",
+		       dev->name, (unsigned long) pdlptr);
 
 	ringptr->pdl = pdlptr + 1;
 	ringptr->pdl_paddr = virt_to_whatever(dev, pdlptr + 1);
@@ -1292,8 +1292,8 @@
 			    register hp100_ring_t * ringptr,
 			    register u32 * pdlptr)
 {
-	if (0 != (((unsigned) pdlptr) & 0xf))
-		printk("hp100: %s: Init txpdl: Unaligned pdlptr 0x%x.\n", dev->name, (unsigned) pdlptr);
+	if (0 != (((unsigned long) pdlptr) & 0xf))
+		printk("hp100: %s: Init txpdl: Unaligned pdlptr 0x%lx.\n", dev->name, (unsigned long) pdlptr);
 
 	ringptr->pdl = pdlptr;	/* +1; */
 	ringptr->pdl_paddr = virt_to_whatever(dev, pdlptr);	/* +1 */
diff -Nru a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
--- a/drivers/net/irda/sa1100_ir.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/net/irda/sa1100_ir.c	Wed Oct 15 00:46:36 2003
@@ -1132,12 +1132,8 @@
 	release_mem_region(__PREG(Ser2HSCR0), 0x1c);
 	release_mem_region(__PREG(Ser2UTCR0), 0x24);
 
-	/*
-	 * We now know that the netdevice is no longer in use, and all
-	 * references to our driver have been removed.  The only structure
-	 * which may still be present is the netdevice, which will get
-	 * cleaned up by net/core/dev.c
-	 */
+	if(dev)
+		free_netdev(dev);
 }
 
 static int __init sa1100ir_setup(char *line)
diff -Nru a/drivers/net/loopback.c b/drivers/net/loopback.c
--- a/drivers/net/loopback.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/net/loopback.c	Wed Oct 15 00:46:36 2003
@@ -125,19 +125,7 @@
 {
 	struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
 
-	/*
-	 *	Optimise so buffers with skb->free=1 are not copied but
-	 *	instead are lobbed from tx queue to rx queue 
-	 */
-
-	if (skb_shared(skb)) {
-	  	struct sk_buff *skb2=skb;
-	  	skb=skb_clone(skb, GFP_ATOMIC);		/* Clone the buffer */
-		kfree_skb(skb2);
-	  	if (unlikely(skb==NULL))
-			return 0;
-	} else
-		skb_orphan(skb);
+	skb_orphan(skb);
 
 	skb->protocol=eth_type_trans(skb,dev);
 	skb->dev=dev;
diff -Nru a/drivers/net/natsemi.c b/drivers/net/natsemi.c
--- a/drivers/net/natsemi.c	Wed Oct 15 00:46:35 2003
+++ b/drivers/net/natsemi.c	Wed Oct 15 00:46:35 2003
@@ -1530,7 +1530,7 @@
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		if (np->tx_skbuff[i]) {
 			pci_unmap_single(np->pci_dev,
-				np->rx_dma[i], np->rx_skbuff[i]->len,
+				np->tx_dma[i], np->tx_skbuff[i]->len,
 				PCI_DMA_TODEVICE);
 			dev_kfree_skb(np->tx_skbuff[i]);
 			np->stats.tx_dropped++;
diff -Nru a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
--- a/drivers/net/pcmcia/pcnet_cs.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/net/pcmcia/pcnet_cs.c	Wed Oct 15 00:46:37 2003
@@ -681,10 +681,6 @@
     } else {
 	dev->if_port = 0;
     }
-    if (register_netdev(dev) != 0) {
-	printk(KERN_NOTICE "pcnet_cs: register_netdev() failed\n");
-	goto failed;
-    }
 
     hw_info = get_hwinfo(link);
     if (hw_info == NULL)
@@ -699,7 +695,6 @@
     if (hw_info == NULL) {
 	printk(KERN_NOTICE "pcnet_cs: unable to read hardware net"
 	       " address for io base %#3lx\n", dev->base_addr);
-	unregister_netdev(dev);
 	goto failed;
     }
 
@@ -733,8 +728,6 @@
     ei_status.word16 = 1;
     ei_status.reset_8390 = &pcnet_reset_8390;
 
-    strcpy(info->node.dev_name, dev->name);
-    link->dev = &info->node;
     SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 
     if (info->flags & (IS_DL10019|IS_DL10022)) {
@@ -743,6 +736,21 @@
 	mii_phy_probe(dev);
 	if ((id == 0x30) && !info->pna_phy && (info->eth_phy == 4))
 	    info->eth_phy = 0;
+    }
+
+    link->dev = &info->node;
+    link->state &= ~DEV_CONFIG_PENDING;
+
+    if (register_netdev(dev) != 0) {
+	printk(KERN_NOTICE "pcnet_cs: register_netdev() failed\n");
+	link->dev = NULL;
+	goto failed;
+    }
+
+    strcpy(info->node.dev_name, dev->name);
+
+    if (info->flags & (IS_DL10019|IS_DL10022)) {
+	u_char id = inb(dev->base_addr + 0x1a);
 	printk(KERN_INFO "%s: NE2000 (DL100%d rev %02x): ",
 	       dev->name, ((info->flags & IS_DL10022) ? 22 : 19), id);
 	if (info->pna_phy)
@@ -758,7 +766,6 @@
     printk(" hw_addr ");
     for (i = 0; i < 6; i++)
 	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
-    link->state &= ~DEV_CONFIG_PENDING;
     return;
 
 cs_failed:
diff -Nru a/drivers/net/slip.c b/drivers/net/slip.c
--- a/drivers/net/slip.c	Wed Oct 15 00:46:38 2003
+++ b/drivers/net/slip.c	Wed Oct 15 00:46:38 2003
@@ -1307,7 +1307,7 @@
 		/* Resolve race condition, when ioctl'ing hanged up 
 		   and opened by another process device.
 		 */
-		if (sl->tty != process_tty(current) && sl->pid != current->pid) {
+		if (sl->tty != current->tty && sl->pid != current->pid) {
 			spin_unlock_bh(&sl->lock);
 			return -EPERM;
 		}
diff -Nru a/drivers/net/sungem.c b/drivers/net/sungem.c
--- a/drivers/net/sungem.c	Wed Oct 15 00:46:38 2003
+++ b/drivers/net/sungem.c	Wed Oct 15 00:46:38 2003
@@ -2731,6 +2731,19 @@
 	if (gem_get_device_address(gp))
 		goto err_out_free_consistent;
 
+	dev->open = gem_open;
+	dev->stop = gem_close;
+	dev->hard_start_xmit = gem_start_xmit;
+	dev->get_stats = gem_get_stats;
+	dev->set_multicast_list = gem_set_multicast;
+	dev->do_ioctl = gem_ioctl;
+	dev->ethtool_ops = &gem_ethtool_ops;
+	dev->tx_timeout = gem_tx_timeout;
+	dev->watchdog_timeo = 5 * HZ;
+	dev->change_mtu = gem_change_mtu;
+	dev->irq = pdev->irq;
+	dev->dma = 0;
+
 	if (register_netdev(dev)) {
 		printk(KERN_ERR PFX "Cannot register net device, "
 		       "aborting.\n");
@@ -2758,19 +2771,6 @@
 			gp->phy_mii.def ? gp->phy_mii.def->name : "no");
 
 	pci_set_drvdata(pdev, dev);
-
-	dev->open = gem_open;
-	dev->stop = gem_close;
-	dev->hard_start_xmit = gem_start_xmit;
-	dev->get_stats = gem_get_stats;
-	dev->set_multicast_list = gem_set_multicast;
-	dev->do_ioctl = gem_ioctl;
-	dev->ethtool_ops = &gem_ethtool_ops;
-	dev->tx_timeout = gem_tx_timeout;
-	dev->watchdog_timeo = 5 * HZ;
-	dev->change_mtu = gem_change_mtu;
-	dev->irq = pdev->irq;
-	dev->dma = 0;
 
 	/* GEM can do it all... */
 	dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
diff -Nru a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
--- a/drivers/net/tulip/tulip_core.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/net/tulip/tulip_core.c	Wed Oct 15 00:46:37 2003
@@ -224,6 +224,7 @@
 	{ 0x1186, 0x1561, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x1626, 0x8410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x1737, 0xAB09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+	{ 0x1737, 0xAB08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x17B3, 0xAB08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
  	{ 0x10b9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X },	/* ALi 1563 integrated ethernet */
 	{ 0x10b7, 0x9300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* 3Com 3CSOHO100B-TX */
diff -Nru a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
--- a/drivers/net/tulip/xircom_cb.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/net/tulip/xircom_cb.c	Wed Oct 15 00:46:37 2003
@@ -230,7 +230,8 @@
 	   This way, we can fail gracefully if not enough memory
 	   is available. 
 	 */
-	if ((dev = init_etherdev(NULL, sizeof(struct xircom_private))) == NULL) {
+	dev = alloc_etherdev(sizeof(struct xircom_private));
+	if (!dev) {
 		printk(KERN_ERR "xircom_probe: failed to allocate etherdev\n");
 		goto device_fail;
 	}
@@ -250,7 +251,7 @@
 
 	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
-	printk(KERN_INFO "%s: Xircom cardbus revision %i at irq %i \n", dev->name, chip_rev, pdev->irq);
+
 
 	private->dev = dev;
 	private->pdev = pdev;
@@ -259,7 +260,6 @@
 	dev->irq = pdev->irq;
 	dev->base_addr = private->io_port;
 	
-	
 	initialize_card(private);
 	read_mac_address(private);
 	setup_descriptors(private);
@@ -272,7 +272,12 @@
 	SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 	pci_set_drvdata(pdev, dev);
 
-	
+	if (register_netdev(dev)) {
+		printk(KERN_ERR "xircom_probe: netdevice registration failed.\n");
+		goto reg_fail;
+	}
+		
+	printk(KERN_INFO "%s: Xircom cardbus revision %i at irq %i \n", dev->name, chip_rev, pdev->irq);
 	/* start the transmitter to get a heartbeat */
 	/* TODO: send 2 dummy packets here */
 	transceiver_voodoo(private);
@@ -287,10 +292,12 @@
 	leave("xircom_probe");
 	return 0;
 
+reg_fail:
+	kfree(private->tx_buffer);
 tx_buf_fail:
 	kfree(private->rx_buffer);
 rx_buf_fail:
-	kfree(dev);
+	free_netdev(dev);
 device_fail:
 	return -ENODEV;
 }
@@ -305,22 +312,16 @@
 static void __devexit xircom_remove(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct xircom_private *card;
+	struct xircom_private *card = dev->priv;
+
 	enter("xircom_remove");
-	if (dev!=NULL) {
-		card=dev->priv;
-		if (card!=NULL) {	
-			if (card->rx_buffer!=NULL)
-				pci_free_consistent(pdev,8192,card->rx_buffer,card->rx_dma_handle);
-			card->rx_buffer = NULL;
-			if (card->tx_buffer!=NULL)
-				pci_free_consistent(pdev,8192,card->tx_buffer,card->tx_dma_handle);
-			card->tx_buffer = NULL;			
-		}
-	}
+	pci_free_consistent(pdev,8192,card->rx_buffer,card->rx_dma_handle);
+	pci_free_consistent(pdev,8192,card->tx_buffer,card->tx_dma_handle);
+
 	release_region(dev->base_addr, 128);
 	unregister_netdev(dev);
 	free_netdev(dev);
+	pci_set_drvdata(pdev, NULL);
 	leave("xircom_remove");
 } 
 
diff -Nru a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
--- a/drivers/net/wan/cosa.c	Wed Oct 15 00:46:35 2003
+++ b/drivers/net/wan/cosa.c	Wed Oct 15 00:46:35 2003
@@ -615,7 +615,7 @@
 	d->get_stats = cosa_net_stats;
 	d->tx_timeout = cosa_sppp_timeout;
 	d->watchdog_timeo = TX_TIMEOUT;
-	if (register_netdev(d) == -1) {
+	if (register_netdev(d)) {
 		printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
 		sppp_detach(chan->pppdev.dev);
 		free_netdev(chan->pppdev.dev);
diff -Nru a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
--- a/drivers/net/wan/hdlc_cisco.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/net/wan/hdlc_cisco.c	Wed Oct 15 00:46:36 2003
@@ -311,7 +311,9 @@
 		hdlc->proto.id = IF_PROTO_CISCO;
 		dev->hard_start_xmit = hdlc->xmit;
 		dev->hard_header = cisco_hard_header;
+		dev->hard_header_cache = NULL;
 		dev->type = ARPHRD_CISCO;
+		dev->flags = IFF_POINTOPOINT | IFF_NOARP;
 		dev->addr_len = 0;
 		return 0;
 	}
diff -Nru a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c
--- a/drivers/net/wan/hostess_sv11.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/net/wan/hostess_sv11.c	Wed Oct 15 00:46:37 2003
@@ -337,7 +337,7 @@
 		d->neigh_setup = hostess_neigh_setup_dev;
 		d->set_mac_address = NULL;
 		
-		if(register_netdev(d)==-1)
+		if(register_netdev(d))
 		{
 			printk(KERN_ERR "%s: unable to register device.\n",
 				d->name);
diff -Nru a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c
--- a/drivers/net/wan/sealevel.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/net/wan/sealevel.c	Wed Oct 15 00:46:37 2003
@@ -31,6 +31,7 @@
 
 struct slvl_device
 {
+	void *if_ptr;	/* General purpose pointer (used by SPPP) */
 	struct z8530_channel *chan;
 	struct ppp_device pppdev;
 	int channel;
@@ -238,6 +239,7 @@
 		return NULL;
 
 	sv = d->priv;
+	sv->if_ptr = &sv->pppdev;
 	sv->pppdev.dev = d;
 	d->base_addr = iobase;
 	d->irq = irq;
diff -Nru a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c
--- a/drivers/net/wan/syncppp.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/net/wan/syncppp.c	Wed Oct 15 00:46:36 2003
@@ -1069,6 +1069,9 @@
 	struct sppp *sp = &pd->sppp;
 	unsigned long flags;
 
+	/* Make sure embedding is safe for sppp_of */
+	BUG_ON(sppp_of(dev) != sp);
+
 	spin_lock_irqsave(&spppq_lock, flags);
 	/* Initialize keepalive handler. */
 	if (! spppq)
diff -Nru a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
--- a/drivers/net/wireless/atmel.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/net/wireless/atmel.c	Wed Oct 15 00:46:36 2003
@@ -37,7 +37,6 @@
 ******************************************************************************/
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/init.h>
 
 #include <linux/kernel.h>
diff -Nru a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c
--- a/drivers/net/wireless/atmel_cs.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/net/wireless/atmel_cs.c	Wed Oct 15 00:46:36 2003
@@ -84,7 +84,7 @@
 static int irq_list[4] = { -1 };
 
 MODULE_AUTHOR("Simon Kelley");
-MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethnet cards.");
+MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards.");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("Atmel at76c50x PCMCIA cards");
 MODULE_PARM(irq_mask, "i");
@@ -404,9 +404,12 @@
 					goto mismatch;
 				for (k = 0; k < j; k++) {
 					while ((*p != '\0') && (*p != '/')) p++;
-					if (*p == '\0')
-						goto mismatch;
-					p++;
+					if (*p == '\0') {
+						if (*q != '\0')
+							goto mismatch;
+					} else {
+						p++;
+					}
 				}
 				while((*q != '\0') && (*p != '\0') && 
 				      (*p != '/') && (*p == *q)) p++, q++;
diff -Nru a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
--- a/drivers/pci/hotplug/Kconfig	Wed Oct 15 00:46:36 2003
+++ b/drivers/pci/hotplug/Kconfig	Wed Oct 15 00:46:36 2003
@@ -44,7 +44,7 @@
 
 config HOTPLUG_PCI_COMPAQ
 	tristate "Compaq PCI Hotplug driver"
-	depends on HOTPLUG_PCI && X86
+	depends on HOTPLUG_PCI && X86 && PCI_BIOS
 	help
 	  Say Y here if you have a motherboard with a Compaq PCI Hotplug
 	  controller.
@@ -66,7 +66,7 @@
 
 config HOTPLUG_PCI_IBM
 	tristate "IBM PCI Hotplug driver"
-	depends on HOTPLUG_PCI && X86_IO_APIC && X86
+	depends on HOTPLUG_PCI && X86_IO_APIC && X86 && PCI_BIOS
 	help
 	  Say Y here if you have a motherboard with a IBM PCI Hotplug
 	  controller.
diff -Nru a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
--- a/drivers/pcmcia/tcic.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/pcmcia/tcic.c	Wed Oct 15 00:46:37 2003
@@ -643,7 +643,7 @@
     reg = tcic_getb(TCIC_PWR);
     if (reg & (TCIC_PWR_VCC(psock)|TCIC_PWR_VPP(psock)))
 	*value |= SS_POWERON;
-    DEBUG(1, "tcic: GetStatus(%d) = %#2.2x\n", lsock, *value);
+    DEBUG(1, "tcic: GetStatus(%d) = %#2.2x\n", psock, *value);
     return 0;
 } /* tcic_get_status */
   
@@ -695,7 +695,7 @@
     }
 
     DEBUG(1, "tcic: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, "
-	  "io_irq %d, csc_mask %#2.2x\n", lsock, state->flags,
+	  "io_irq %d, csc_mask %#2.2x\n", psock, state->flags,
 	  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
     return 0;
 } /* tcic_get_socket */
@@ -709,7 +709,7 @@
     u_short scf1, scf2;
 
     DEBUG(1, "tcic: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
-	  "io_irq %d, csc_mask %#2.2x)\n", lsock, state->flags,
+	  "io_irq %d, csc_mask %#2.2x)\n", psock, state->flags,
 	  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
     tcic_setw(TCIC_ADDR+2, (psock << TCIC_SS_SHFT) | TCIC_ADR2_INDREG);
 
@@ -784,7 +784,7 @@
     u_short base, len, ioctl;
     
     DEBUG(1, "tcic: SetIOMap(%d, %d, %#2.2x, %d ns, "
-	  "%#4.4x-%#4.4x)\n", lsock, io->map, io->flags,
+	  "%#4.4x-%#4.4x)\n", psock, io->map, io->flags,
 	  io->speed, io->start, io->stop);
     if ((io->map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
 	(io->stop < io->start)) return -EINVAL;
@@ -821,7 +821,7 @@
     u_long base, len, mmap;
 
     DEBUG(1, "tcic: SetMemMap(%d, %d, %#2.2x, %d ns, "
-	  "%#5.5lx-%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags,
+	  "%#5.5lx-%#5.5lx, %#5.5x)\n", psock, mem->map, mem->flags,
 	  mem->speed, mem->sys_start, mem->sys_stop, mem->card_start);
     if ((mem->map > 3) || (mem->card_start > 0x3ffffff) ||
 	(mem->sys_start > 0xffffff) || (mem->sys_stop > 0xffffff) ||
diff -Nru a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
--- a/drivers/scsi/scsi_sysfs.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/scsi/scsi_sysfs.c	Wed Oct 15 00:46:36 2003
@@ -412,7 +412,7 @@
 		set_bit(SDEV_DEL, &sdev->sdev_state);
 		if (sdev->host->hostt->slave_destroy)
 			sdev->host->hostt->slave_destroy(sdev);
-		if (atomic_read(&sdev->access_count))
+		if (!atomic_read(&sdev->access_count))
 			device_del(&sdev->sdev_gendev);
 		up_write(&class->subsys.rwsem);
 	}
diff -Nru a/drivers/serial/8250_acpi.c b/drivers/serial/8250_acpi.c
--- a/drivers/serial/8250_acpi.c	Wed Oct 15 00:46:38 2003
+++ b/drivers/serial/8250_acpi.c	Wed Oct 15 00:46:38 2003
@@ -38,8 +38,11 @@
 static acpi_status acpi_serial_port(struct serial_struct *req,
 				    struct acpi_resource_io *io)
 {
-	req->port = io->min_base_address;
-	req->io_type = SERIAL_IO_PORT;
+	if (io->range_length) {
+		req->port = io->min_base_address;
+		req->io_type = SERIAL_IO_PORT;
+	} else
+		printk(KERN_ERR "%s: zero-length IO port range?\n", __FUNCTION__);
 	return AE_OK;
 }
 
diff -Nru a/drivers/usb/README b/drivers/usb/README
--- a/drivers/usb/README	Wed Oct 15 00:46:37 2003
+++ b/drivers/usb/README	Wed Oct 15 00:46:37 2003
@@ -8,7 +8,7 @@
 		  includes UHCI, OHCI, EHCI, and any others that might
 		  be created in the future.
 
-device/		- This is for all of the USB device controller drivers. 
+gadget/		- This is for all of the USB device controller drivers. 
 
 
 Individual USB driver directories.  A new driver should be added to the
@@ -16,7 +16,7 @@
 
 image/		- This is for still image drivers, like scanners or
 		  digital cameras.
-input/		- This if for any driver that uses the input subsystem,
+input/		- This is for any driver that uses the input subsystem,
 		  like keyboard, mice, touchscreens, tablets, etc.
 media/		- This is for multimedia drivers, like video cameras,
 		  radios, and any other drivers that talk to the v4l
@@ -29,5 +29,3 @@
 		  of USB Class specified devices. 
 misc/		- This is for all USB device drivers that do not fit
 		  into any of the above categories.
-	  
-
diff -Nru a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig
--- a/drivers/usb/class/Kconfig	Wed Oct 15 00:46:35 2003
+++ b/drivers/usb/class/Kconfig	Wed Oct 15 00:46:35 2003
@@ -71,7 +71,7 @@
 	  driver.
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called acm.
+	  module will be called cdc-acm.
 
 config USB_PRINTER
 	tristate "USB Printer support"
diff -Nru a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
--- a/drivers/usb/core/devio.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/usb/core/devio.c	Wed Oct 15 00:46:36 2003
@@ -384,7 +384,7 @@
 	err = -EINVAL;
 	dev = ps->dev;
 	down(&dev->serialize);
-	if (dev && test_and_clear_bit(intf, &ps->ifclaimed)) {
+	if (test_and_clear_bit(intf, &ps->ifclaimed)) {
 		iface = dev->actconfig->interface[intf];
 		usb_driver_release_interface(&usbdevfs_driver, iface);
 		err = 0;
diff -Nru a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
--- a/drivers/usb/core/hcd-pci.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/usb/core/hcd-pci.c	Wed Oct 15 00:46:36 2003
@@ -295,6 +295,8 @@
 		if (retval)
 			dev_dbg (hcd->controller, "suspend fail, retval %d\n",
 					retval);
+		else
+			hcd->state = USB_STATE_SUSPENDED;
 	}
 
  	pci_set_power_state (dev, state);
diff -Nru a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
--- a/drivers/usb/gadget/Kconfig	Wed Oct 15 00:46:36 2003
+++ b/drivers/usb/gadget/Kconfig	Wed Oct 15 00:46:36 2003
@@ -110,7 +110,7 @@
 
 config USB_ETH
 	tristate "Ethernet Gadget"
-	depends on USB_GADGET && (USB_DUMMY_HCD || USB_NET2280 || USB_PXA2XX || USB_SA1100)
+	depends on USB_GADGET && NET && (USB_DUMMY_HCD || USB_NET2280 || USB_PXA2XX || USB_SA1100)
 	help
 	  This driver implements Ethernet style communication, in either
 	  of two ways:
diff -Nru a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
--- a/drivers/usb/gadget/net2280.c	Wed Oct 15 00:46:35 2003
+++ b/drivers/usb/gadget/net2280.c	Wed Oct 15 00:46:35 2003
@@ -50,7 +50,6 @@
 #define DEBUG	1
 // #define	VERBOSE		/* extra debug messages (success too) */
 
-#include <linux/version.h>
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/pci.h>
@@ -431,6 +430,9 @@
 #elif	defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE)
 #define USE_KMALLOC
 
+#elif	defined(CONFIG_MIPS) && !defined(CONFIG_NONCOHERENT_IO)
+#define USE_KMALLOC
+
 /* FIXME there are other cases, including an x86-64 one ...  */
 #endif
 
@@ -452,31 +454,23 @@
 	ep = container_of (_ep, struct net2280_ep, ep);
 	if (!_ep)
 		return 0;
-
 	*dma = DMA_ADDR_INVALID;
-	if (ep->dma) {
-#if	defined(USE_KMALLOC)
-		retval = kmalloc (bytes, gfp_flags);
-		if (retval)
-			*dma = virt_to_phys (retval);
 
-#elif	LINUX_VERSION_CODE > KERNEL_VERSION(2,5,58)
-#warning Using dma_alloc_consistent even with sub-page allocations
+#if	defined(USE_KMALLOC)
+	retval = kmalloc(bytes, gfp_flags);
+	if (retval)
+		*dma = virt_to_phys(retval);
+#else
+	if (ep->dma) {
 		/* the main problem with this call is that it wastes memory
 		 * on typical 1/N page allocations: it allocates 1-N pages.
 		 */
-		retval = dma_alloc_coherent (&ep->dev->pdev->dev,
+#warning Using dma_alloc_coherent even with buffers smaller than a page.
+		retval = dma_alloc_coherent(&ep->dev->pdev->dev,
 				bytes, dma, gfp_flags);
-#else
-#error No dma-coherent memory allocator is available
-		/* pci_alloc_consistent works, but pci_free_consistent()
-		 * isn't safe in_interrupt().  plus, in addition to the
-		 * 1/Nth page weakness, it doesn't understand gfp_flags.
-		 */
-#endif
 	} else
-		retval = kmalloc (bytes, gfp_flags);
-
+		retval = kmalloc(bytes, gfp_flags);
+#endif
 	return retval;
 }
 
@@ -489,9 +483,14 @@
 ) {
 	/* free memory into the right allocator */
 #ifndef	USE_KMALLOC
-	if (dma != DMA_ADDR_INVALID)
-		dma_free_coherent (ep->dev->pdev, bytes, dma);
-	else
+	if (dma != DMA_ADDR_INVALID) {
+		struct net2280_ep	*ep;
+
+		ep = container_of(_ep, struct net2280_ep, ep);
+		if (!_ep)
+			return;
+		dma_free_coherent(&ep->dev->pdev->dev, bytes, buf, dma);
+	} else
 #endif
 		kfree (buf);
 }
@@ -516,8 +515,9 @@
 	/* INVARIANT:  fifo is currently empty. (testable) */
 
 	if (req) {
-		total = req->length - req->actual;
 		buf = req->buf + req->actual;
+		prefetch (buf);
+		total = req->length - req->actual;
 	} else {
 		total = 0;
 		buf = 0;
@@ -615,6 +615,7 @@
 	/* never overflow the rx buffer. the fifo reads packets until
 	 * it sees a short one; we might not be ready for them all.
 	 */
+	prefetchw (buf);
 	count = readl (&regs->ep_avail);
 	tmp = req->req.length - req->req.actual;
 	if (count > tmp) {
diff -Nru a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
--- a/drivers/usb/host/ohci-hcd.c	Wed Oct 15 00:46:35 2003
+++ b/drivers/usb/host/ohci-hcd.c	Wed Oct 15 00:46:35 2003
@@ -125,7 +125,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-static const char	hcd_name [] = "ohci-hcd";
+static const char	hcd_name [] = "ohci_hcd";
 
 #include "ohci.h"
 
diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
--- a/drivers/usb/host/uhci-hcd.c	Wed Oct 15 00:46:37 2003
+++ b/drivers/usb/host/uhci-hcd.c	Wed Oct 15 00:46:37 2003
@@ -2518,7 +2518,7 @@
 	return uhci_get_current_frame_number(hcd_to_uhci(hcd));
 }
 
-static const char hcd_name[] = "uhci-hcd";
+static const char hcd_name[] = "uhci_hcd";
 
 static const struct hc_driver uhci_driver = {
 	.description =		hcd_name,
diff -Nru a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
--- a/drivers/usb/misc/Kconfig	Wed Oct 15 00:46:38 2003
+++ b/drivers/usb/misc/Kconfig	Wed Oct 15 00:46:38 2003
@@ -15,7 +15,7 @@
 	  USB Audio driver.
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called audio.
+	  module will be called emi26.
 
 config USB_TIGL
 	tristate "Texas Instruments Graph Link USB (aka SilverLink) cable support"
diff -Nru a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
--- a/drivers/usb/serial/visor.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/usb/serial/visor.c	Wed Oct 15 00:46:36 2003
@@ -201,6 +201,8 @@
 		.driver_info = (kernel_ulong_t)&palm_os_3_probe },
 	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO_ID),
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
+	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO600_ID),
+		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID),
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID),
@@ -247,6 +249,7 @@
 static struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
 	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO_ID) },
+	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO600_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) },
diff -Nru a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
--- a/drivers/usb/serial/visor.h	Wed Oct 15 00:46:37 2003
+++ b/drivers/usb/serial/visor.h	Wed Oct 15 00:46:37 2003
@@ -20,6 +20,7 @@
 #define HANDSPRING_VENDOR_ID		0x082d
 #define HANDSPRING_VISOR_ID		0x0100
 #define HANDSPRING_TREO_ID		0x0200
+#define HANDSPRING_TREO600_ID		0x0300
 
 #define PALM_VENDOR_ID			0x0830
 #define PALM_M500_ID			0x0001
diff -Nru a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
--- a/drivers/usb/storage/Kconfig	Wed Oct 15 00:46:38 2003
+++ b/drivers/usb/storage/Kconfig	Wed Oct 15 00:46:38 2003
@@ -41,7 +41,7 @@
 
 config USB_STORAGE_ISD200
 	bool "ISD-200 USB/ATA Bridge support"
-	depends on USB_STORAGE
+	depends on USB_STORAGE && BLK_DEV_IDE
 	---help---
 	  Say Y here if you want to use USB Mass Store devices based
 	  on the In-Systems Design ISD-200 USB/ATA bridge.
diff -Nru a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
--- a/drivers/video/aty/aty128fb.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/video/aty/aty128fb.c	Wed Oct 15 00:46:36 2003
@@ -2041,9 +2041,9 @@
 #define ATY_MIRROR_CRT_ON	0x00000002
 
 /* out param: u32*	backlight value: 0 to 15 */
-#define FBIO_ATY128_GET_MIRROR	_IOR('@', 1, sizeof(__u32*))
+#define FBIO_ATY128_GET_MIRROR	_IOR('@', 1, __u32*)
 /* in param: u32*	backlight value: 0 to 15 */
-#define FBIO_ATY128_SET_MIRROR	_IOW('@', 2, sizeof(__u32*))
+#define FBIO_ATY128_SET_MIRROR	_IOW('@', 2, __u32*)
 
 static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
 			  u_long arg, struct fb_info *info)
diff -Nru a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c
--- a/drivers/video/imsttfb.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/video/imsttfb.c	Wed Oct 15 00:46:36 2003
@@ -1461,6 +1461,15 @@
 	unsigned long addr, size;
 	struct imstt_par *par;
 	struct fb_info *info;
+#ifdef CONFIG_PPC_OF
+	struct device_node *dp;
+	
+	dp = pci_device_to_OF_node(pdev);
+	if(dp)
+		printk(KERN_INFO "%s: OF name %s\n",__FUNCTION__, dp->name);
+	else
+		printk(KERN_ERR "imsttfb: no OF node for pci device\n");
+#endif /* CONFIG_PPC_OF */
 
 	size = sizeof(struct fb_info) + sizeof(struct imstt_par) +
 		sizeof(u32) * 16;
@@ -1488,6 +1497,11 @@
 	switch (pdev->device) {
 		case PCI_DEVICE_ID_IMS_TT128: /* IMS,tt128mbA */
 			par->ramdac = IBM;
+#ifdef CONFIG_PPC_OF
+			if (dp && ((strcmp(dp->name, "IMS,tt128mb8") == 0) ||
+				   (strcmp(dp->name, "IMS,tt128mb8A") == 0)))
+				par->ramdac = TVP;
+#endif /* CONFIG_PPC_OF */
 			break;
 		case PCI_DEVICE_ID_IMS_TT3D:  /* IMS,tt3d */
 			par->ramdac = TVP;
diff -Nru a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h
--- a/drivers/video/matrox/matroxfb_base.h	Wed Oct 15 00:46:36 2003
+++ b/drivers/video/matrox/matroxfb_base.h	Wed Oct 15 00:46:36 2003
@@ -55,7 +55,7 @@
 #if defined(CONFIG_PPC_PMAC)
 #include <asm/prom.h>
 #include <asm/pci-bridge.h>
-#include <video/macmodes.h>
+#include "../macmodes.h"
 #endif
 
 /* always compile support for 32MB... It cost almost nothing */
diff -Nru a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c
--- a/drivers/video/tridentfb.c	Wed Oct 15 00:46:36 2003
+++ b/drivers/video/tridentfb.c	Wed Oct 15 00:46:36 2003
@@ -28,7 +28,7 @@
 
 struct tridentfb_par {
 	int vclk;		//in MHz
-	unsigned int io_virt;	//iospace virtual memory address
+	unsigned long io_virt;	//iospace virtual memory address
 };
 
 unsigned char eng_oper;		//engine operation...
@@ -1102,7 +1102,7 @@
 		return -1;
 	}
 
-	default_par.io_virt = (unsigned int)ioremap_nocache(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
+	default_par.io_virt = (unsigned long)ioremap_nocache(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
 
 	if (!default_par.io_virt) {
 		release_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
diff -Nru a/fs/Kconfig b/fs/Kconfig
--- a/fs/Kconfig	Wed Oct 15 00:46:37 2003
+++ b/fs/Kconfig	Wed Oct 15 00:46:37 2003
@@ -1309,6 +1309,30 @@
 
 	  If unsure, say N.
 
+config NFS_DIRECTIO
+	bool "Allow direct I/O on NFS files (EXPERIMENTAL)"
+	depends on NFS_FS && EXPERIMENTAL
+	help
+	  This option enables applications to perform uncached I/O on files
+	  in NFS file systems using the O_DIRECT open() flag.  When O_DIRECT
+	  is set for a file, its data is not cached in the system's page
+	  cache.  Data is moved to and from user-level application buffers
+	  directly.  Unlike local disk-based file systems, NFS O_DIRECT has
+	  no alignment restrictions.
+
+	  Unless your program is designed to use O_DIRECT properly, you are
+	  much better off allowing the NFS client to manage data caching for
+	  you.  Misusing O_DIRECT can cause poor server performance or network
+	  storms.  This kernel build option defaults OFF to avoid exposing
+	  system administrators unwittingly to a potentially hazardous
+	  feature.
+
+	  For more details on NFS O_DIRECT, see fs/nfs/direct.c.
+
+	  If unsure, say N.  This reduces the size of the NFS client, and
+	  causes open() to return EINVAL if a file residing in NFS is
+	  opened with the O_DIRECT flag.
+
 config NFSD
 	tristate "NFS server support"
 	depends on INET
diff -Nru a/fs/binfmt_elf.c b/fs/binfmt_elf.c
--- a/fs/binfmt_elf.c	Wed Oct 15 00:46:36 2003
+++ b/fs/binfmt_elf.c	Wed Oct 15 00:46:36 2003
@@ -1084,7 +1084,7 @@
 	prstatus->pr_pid = p->pid;
 	prstatus->pr_ppid = p->parent->pid;
 	prstatus->pr_pgrp = process_group(p);
-	prstatus->pr_sid = process_session(p);
+	prstatus->pr_sid = p->session;
 	jiffies_to_timeval(p->utime, &prstatus->pr_utime);
 	jiffies_to_timeval(p->stime, &prstatus->pr_stime);
 	jiffies_to_timeval(p->cutime, &prstatus->pr_cutime);
@@ -1112,7 +1112,7 @@
 	psinfo->pr_pid = p->pid;
 	psinfo->pr_ppid = p->parent->pid;
 	psinfo->pr_pgrp = process_group(p);
-	psinfo->pr_sid = process_session(p);
+	psinfo->pr_sid = p->session;
 
 	i = p->state ? ffz(~p->state) + 1 : 0;
 	psinfo->pr_state = i;
diff -Nru a/fs/compat_ioctl.c b/fs/compat_ioctl.c
--- a/fs/compat_ioctl.c	Wed Oct 15 00:46:37 2003
+++ b/fs/compat_ioctl.c	Wed Oct 15 00:46:37 2003
@@ -1574,7 +1574,7 @@
 	 * To have permissions to do most of the vt ioctls, we either have
 	 * to be the owner of the tty, or super-user.
 	 */
-	if (process_tty(current) == tty || capable(CAP_SYS_ADMIN))
+	if (current->tty == tty || capable(CAP_SYS_ADMIN))
 		return 1;
 	return 0;                                                    
 }
diff -Nru a/fs/dnotify.c b/fs/dnotify.c
--- a/fs/dnotify.c	Wed Oct 15 00:46:36 2003
+++ b/fs/dnotify.c	Wed Oct 15 00:46:36 2003
@@ -93,7 +93,7 @@
 		prev = &odn->dn_next;
 	}
 
-	error = f_setown(filp, current->tgid, 1);
+	error = f_setown(filp, current->pid, 0);
 	if (error)
 		goto out_free;
 
diff -Nru a/fs/dquot.c b/fs/dquot.c
--- a/fs/dquot.c	Wed Oct 15 00:46:37 2003
+++ b/fs/dquot.c	Wed Oct 15 00:46:37 2003
@@ -668,12 +668,12 @@
 
 	if (!need_print_warning(dquot) || (flag && test_and_set_bit(flag, &dquot->dq_flags)))
 		return;
-	tty_write_message(process_tty(current), dquot->dq_sb->s_id);
+	tty_write_message(current->tty, dquot->dq_sb->s_id);
 	if (warntype == ISOFTWARN || warntype == BSOFTWARN)
-		tty_write_message(process_tty(current), ": warning, ");
+		tty_write_message(current->tty, ": warning, ");
 	else
-		tty_write_message(process_tty(current), ": write failed, ");
-	tty_write_message(process_tty(current), quotatypes[dquot->dq_type]);
+		tty_write_message(current->tty, ": write failed, ");
+	tty_write_message(current->tty, quotatypes[dquot->dq_type]);
 	switch (warntype) {
 		case IHARDWARN:
 			msg = " file limit reached.\n";
@@ -694,7 +694,7 @@
 			msg = " block quota exceeded.\n";
 			break;
 	}
-	tty_write_message(process_tty(current), msg);
+	tty_write_message(current->tty, msg);
 }
 
 static inline void flush_warnings(struct dquot **dquots, char *warntype)
diff -Nru a/fs/exec.c b/fs/exec.c
--- a/fs/exec.c	Wed Oct 15 00:46:36 2003
+++ b/fs/exec.c	Wed Oct 15 00:46:36 2003
@@ -596,11 +596,6 @@
 		newsig->group_stop_count = 0;
 		newsig->curr_target = NULL;
 		init_sigpending(&newsig->shared_pending);
-
-		newsig->pgrp = oldsig->pgrp;
-		newsig->session = oldsig->session;
-		newsig->leader = oldsig->leader;
-		newsig->tty_old_pgrp = oldsig->tty_old_pgrp;
 	}
 
 	if (thread_group_empty(current))
diff -Nru a/fs/jffs2/background.c b/fs/jffs2/background.c
--- a/fs/jffs2/background.c	Wed Oct 15 00:46:35 2003
+++ b/fs/jffs2/background.c	Wed Oct 15 00:46:35 2003
@@ -1,13 +1,13 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: background.c,v 1.38 2003/05/26 09:50:38 dwmw2 Exp $
+ * $Id: background.c,v 1.44 2003/10/08 13:29:55 dwmw2 Exp $
  *
  */
 
@@ -19,6 +19,7 @@
 #include <linux/completion.h>
 #include <linux/sched.h>
 #include <linux/unistd.h>
+#include <linux/suspend.h>
 #include "nodelist.h"
 
 
@@ -61,13 +62,6 @@
 
 void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c)
 {
-	if (c->mtd->type == MTD_NANDFLASH) {
-		/* stop a eventually scheduled wbuf flush timer */
-		del_timer_sync(&c->wbuf_timer);
-		/* make sure, that a scheduled wbuf flush task is completed */
-		flush_scheduled_work();
-	}
-
 	spin_lock(&c->erase_completion_lock);
 	if (c->gc_task) {
 		D1(printk(KERN_DEBUG "jffs2: Killing GC task %d\n", c->gc_task->pid));
@@ -82,6 +76,9 @@
 	struct jffs2_sb_info *c = _c;
 
 	daemonize("jffs2_gcd_mtd%d", c->mtd->index);
+	allow_signal(SIGKILL);
+	allow_signal(SIGSTOP);
+	allow_signal(SIGCONT);
 
 	c->gc_task = current;
 	up(&c->gc_thread_start);
@@ -89,10 +86,7 @@
 	set_user_nice(current, 10);
 
 	for (;;) {
-		spin_lock_irq(&current_sig_lock);
-		siginitsetinv (&current->blocked, sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT));
-		recalc_sigpending();
-		spin_unlock_irq(&current_sig_lock);
+		allow_signal(SIGHUP);
 
 		if (!thread_should_wake(c)) {
 			set_current_state (TASK_INTERRUPTIBLE);
@@ -104,6 +98,13 @@
 			schedule();
 		}
 
+		if (current->flags & PF_FREEZE) {
+			refrigerator(0);
+			/* refrigerator() should recalc sigpending for us
+			   but doesn't. No matter - allow_signal() will. */
+			continue;
+		}
+
 		cond_resched();
 
 		/* Put_super will send a SIGKILL and then wait on the sem. 
@@ -112,9 +113,7 @@
 			siginfo_t info;
 			unsigned long signr;
 
-			spin_lock_irq(&current_sig_lock);
-			signr = dequeue_signal(current, &current->blocked, &info);
-			spin_unlock_irq(&current_sig_lock);
+			signr = dequeue_signal_lock(current, &current->blocked, &info);
 
 			switch(signr) {
 			case SIGSTOP:
@@ -125,6 +124,7 @@
 
 			case SIGKILL:
 				D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGKILL received.\n"));
+			die:
 				spin_lock(&c->erase_completion_lock);
 				c->gc_task = NULL;
 				spin_unlock(&c->erase_completion_lock);
@@ -138,13 +138,13 @@
 			}
 		}
 		/* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */
-		spin_lock_irq(&current_sig_lock);
-		siginitsetinv (&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT));
-		recalc_sigpending();
-		spin_unlock_irq(&current_sig_lock);
+		disallow_signal(SIGHUP);
 
 		D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): pass\n"));
-		jffs2_garbage_collect_pass(c);
+		if (jffs2_garbage_collect_pass(c) == -ENOSPC) {
+			printk(KERN_NOTICE "No space for garbage collection. Aborting GC thread\n");
+			goto die;
+		}
 	}
 }
 
@@ -169,8 +169,8 @@
 	 */
 	dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size;
 
-	if (c->nr_free_blocks + c->nr_erasing_blocks < JFFS2_RESERVED_BLOCKS_GCTRIGGER && 
-			(dirty > c->sector_size)) 
+	if (c->nr_free_blocks + c->nr_erasing_blocks < c->resv_blocks_gctrigger && 
+			(dirty > c->nospc_dirty_size)) 
 		ret = 1;
 
 	D1(printk(KERN_DEBUG "thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n", 
diff -Nru a/fs/jffs2/build.c b/fs/jffs2/build.c
--- a/fs/jffs2/build.c	Wed Oct 15 00:46:36 2003
+++ b/fs/jffs2/build.c	Wed Oct 15 00:46:36 2003
@@ -1,13 +1,13 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: build.c,v 1.46 2003/04/29 17:12:26 gleixner Exp $
+ * $Id: build.c,v 1.52 2003/10/09 00:38:38 dwmw2 Exp $
  *
  */
 
@@ -228,6 +228,58 @@
 	return ret;
 }
 
+static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c)
+{
+	uint32_t size;
+
+	/* Deletion should almost _always_ be allowed. We're fairly
+	   buggered once we stop allowing people to delete stuff
+	   because there's not enough free space... */
+	c->resv_blocks_deletion = 2;
+
+	/* Be conservative about how much space we need before we allow writes. 
+	   On top of that which is required for deletia, require an extra 2%
+	   of the medium to be available, for overhead caused by nodes being
+	   split across blocks, etc. */
+
+	size = c->flash_size / 50; /* 2% of flash size */
+	size += c->nr_blocks * 100; /* And 100 bytes per eraseblock */
+	size += c->sector_size - 1; /* ... and round up */
+
+	c->resv_blocks_write = c->resv_blocks_deletion + (size / c->sector_size);
+
+	/* When do we let the GC thread run in the background */
+
+	c->resv_blocks_gctrigger = c->resv_blocks_write + 1;
+
+	/* When do we allow garbage collection to merge nodes to make 
+	   long-term progress at the expense of short-term space exhaustion? */
+	c->resv_blocks_gcmerge = c->resv_blocks_deletion + 1;
+
+	/* When do we allow garbage collection to eat from bad blocks rather
+	   than actually making progress? */
+	c->resv_blocks_gcbad = 0;//c->resv_blocks_deletion + 2;
+
+	/* If there's less than this amount of dirty space, don't bother
+	   trying to GC to make more space. It'll be a fruitless task */
+	c->nospc_dirty_size = c->sector_size + (c->flash_size / 100);
+
+	D1(printk(KERN_DEBUG "JFFS2 trigger levels (size %d KiB, block size %d KiB, %d blocks)\n",
+		  c->flash_size / 1024, c->sector_size / 1024, c->nr_blocks));
+	D1(printk(KERN_DEBUG "Blocks required to allow deletion:    %d (%d KiB)\n",
+		  c->resv_blocks_deletion, c->resv_blocks_deletion*c->sector_size/1024));
+	D1(printk(KERN_DEBUG "Blocks required to allow writes:      %d (%d KiB)\n",
+		  c->resv_blocks_write, c->resv_blocks_write*c->sector_size/1024));
+	D1(printk(KERN_DEBUG "Blocks required to quiesce GC thread: %d (%d KiB)\n",
+		  c->resv_blocks_gctrigger, c->resv_blocks_gctrigger*c->sector_size/1024));
+	D1(printk(KERN_DEBUG "Blocks required to allow GC merges:   %d (%d KiB)\n",
+		  c->resv_blocks_gcmerge, c->resv_blocks_gcmerge*c->sector_size/1024));
+	D1(printk(KERN_DEBUG "Blocks required to GC bad blocks:     %d (%d KiB)\n",
+		  c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024));
+	D1(printk(KERN_DEBUG "Amount of dirty space required to GC: %d bytes\n",
+		  c->nospc_dirty_size));
+} 
+
 int jffs2_do_mount_fs(struct jffs2_sb_info *c)
 {
 	int i;
@@ -276,5 +328,8 @@
 		kfree(c->blocks);
 		return -EIO;
 	}
+
+	jffs2_calc_trigger_levels(c);
+
 	return 0;
 }
diff -Nru a/fs/jffs2/compr.c b/fs/jffs2/compr.c
--- a/fs/jffs2/compr.c	Wed Oct 15 00:46:36 2003
+++ b/fs/jffs2/compr.c	Wed Oct 15 00:46:36 2003
@@ -1,13 +1,13 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
  *
  * Created by Arjan van de Ven <arjanv@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr.c,v 1.26 2003/01/12 13:21:28 dwmw2 Exp $
+ * $Id: compr.c,v 1.27 2003/10/04 08:33:06 dwmw2 Exp $
  *
  */
 
diff -Nru a/fs/jffs2/compr_rtime.c b/fs/jffs2/compr_rtime.c
--- a/fs/jffs2/compr_rtime.c	Wed Oct 15 00:46:37 2003
+++ b/fs/jffs2/compr_rtime.c	Wed Oct 15 00:46:37 2003
@@ -1,13 +1,13 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
  *
  * Created by Arjan van de Ven <arjanv@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr_rtime.c,v 1.10 2003/05/11 10:47:13 dwmw2 Exp $
+ * $Id: compr_rtime.c,v 1.11 2003/10/04 08:33:06 dwmw2 Exp $
  *
  *
  * Very simple lz77-ish encoder.
diff -Nru a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c
--- a/fs/jffs2/compr_zlib.c	Wed Oct 15 00:46:35 2003
+++ b/fs/jffs2/compr_zlib.c	Wed Oct 15 00:46:35 2003
@@ -1,13 +1,13 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr_zlib.c,v 1.23 2003/05/26 09:15:19 dwmw2 Exp $
+ * $Id: compr_zlib.c,v 1.24 2003/10/04 08:33:06 dwmw2 Exp $
  *
  */
 
diff -Nru a/fs/jffs2/dir.c b/fs/jffs2/dir.c
--- a/fs/jffs2/dir.c	Wed Oct 15 00:46:37 2003
+++ b/fs/jffs2/dir.c	Wed Oct 15 00:46:37 2003
@@ -1,13 +1,13 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: dir.c,v 1.77 2003/06/05 14:42:24 dwmw2 Exp $
+ * $Id: dir.c,v 1.82 2003/10/11 11:47:23 dwmw2 Exp $
  *
  */
 
@@ -22,18 +22,22 @@
 #include <linux/time.h>
 #include "nodelist.h"
 
-/* Urgh. Please tell me there's a nicer way of doing this. */
+/* Urgh. Please tell me there's a nicer way of doing these. */
 #include <linux/version.h>
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48)
 typedef int mknod_arg_t;
+#define NAMEI_COMPAT(x) ((void *)x)
 #else
 typedef dev_t mknod_arg_t;
+#define NAMEI_COMPAT(x) (x)
 #endif
 
 static int jffs2_readdir (struct file *, void *, filldir_t);
 
-static int jffs2_create (struct inode *,struct dentry *,int, struct nameidata *);
-static struct dentry *jffs2_lookup (struct inode *,struct dentry *, struct nameidata *);
+static int jffs2_create (struct inode *,struct dentry *,int,
+			 struct nameidata *);
+static struct dentry *jffs2_lookup (struct inode *,struct dentry *,
+				    struct nameidata *);
 static int jffs2_link (struct dentry *,struct inode *,struct dentry *);
 static int jffs2_unlink (struct inode *,struct dentry *);
 static int jffs2_symlink (struct inode *,struct dentry *,const char *);
@@ -54,8 +58,8 @@
 
 struct inode_operations jffs2_dir_inode_operations =
 {
-	.create =	jffs2_create,
-	.lookup =	jffs2_lookup,
+	.create =	NAMEI_COMPAT(jffs2_create),
+	.lookup =	NAMEI_COMPAT(jffs2_lookup),
 	.link =		jffs2_link,
 	.unlink =	jffs2_unlink,
 	.symlink =	jffs2_symlink,
@@ -73,7 +77,8 @@
    and we use the same hash function as the dentries. Makes this 
    nice and simple
 */
-static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target, struct nameidata *nd)
+static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
+				   struct nameidata *nd)
 {
 	struct jffs2_inode_info *dir_f;
 	struct jffs2_sb_info *c;
@@ -176,7 +181,7 @@
 
 
 static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
-		struct nameidata *nd)
+			struct nameidata *nd)
 {
 	struct jffs2_raw_inode *ri;
 	struct jffs2_inode_info *f, *dir_f;
@@ -292,7 +297,6 @@
 	struct jffs2_full_dirent *fd;
 	int namelen;
 	uint32_t alloclen, phys_ofs;
-	uint32_t writtenlen;
 	int ret;
 
 	/* FIXME: If you care. We'd need to use frags for the target
@@ -339,7 +343,7 @@
 	ri->data_crc = cpu_to_je32(crc32(0, target, strlen(target)));
 	ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
 	
-	fn = jffs2_write_dnode(c, f, ri, target, strlen(target), phys_ofs, &writtenlen);
+	fn = jffs2_write_dnode(c, f, ri, target, strlen(target), phys_ofs, ALLOC_NORMAL);
 
 	jffs2_free_raw_inode(ri);
 
@@ -356,20 +360,12 @@
 	f->metadata = fn;
 	up(&f->sem);
 
-	/* Work out where to put the dirent node now. */
-	writtenlen = PAD(writtenlen);
-	phys_ofs += writtenlen;
-	alloclen -= writtenlen;
-
-	if (alloclen < sizeof(*rd)+namelen) {
-		/* Not enough space left in this chunk. Get some more */
-		jffs2_complete_reservation(c);
-		ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
-		if (ret) {
-			/* Eep. */
-			jffs2_clear_inode(inode);
-			return ret;
-		}
+	jffs2_complete_reservation(c);
+	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+	if (ret) {
+		/* Eep. */
+		jffs2_clear_inode(inode);
+		return ret;
 	}
 
 	rd = jffs2_alloc_raw_dirent();
@@ -397,7 +393,7 @@
 	rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
 	rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
 
-	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
+	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL);
 
 	if (IS_ERR(fd)) {
 		/* dirent failed to write. Delete the inode normally 
@@ -436,7 +432,6 @@
 	struct jffs2_full_dirent *fd;
 	int namelen;
 	uint32_t alloclen, phys_ofs;
-	uint32_t writtenlen;
 	int ret;
 
 	mode |= S_IFDIR;
@@ -476,7 +471,7 @@
 	ri->data_crc = cpu_to_je32(0);
 	ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
 	
-	fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, &writtenlen);
+	fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL);
 
 	jffs2_free_raw_inode(ri);
 
@@ -493,20 +488,12 @@
 	f->metadata = fn;
 	up(&f->sem);
 
-	/* Work out where to put the dirent node now. */
-	writtenlen = PAD(writtenlen);
-	phys_ofs += writtenlen;
-	alloclen -= writtenlen;
-
-	if (alloclen < sizeof(*rd)+namelen) {
-		/* Not enough space left in this chunk. Get some more */
-		jffs2_complete_reservation(c);
-		ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
-		if (ret) {
-			/* Eep. */
-			jffs2_clear_inode(inode);
-			return ret;
-		}
+	jffs2_complete_reservation(c);
+	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+	if (ret) {
+		/* Eep. */
+		jffs2_clear_inode(inode);
+		return ret;
 	}
 	
 	rd = jffs2_alloc_raw_dirent();
@@ -534,7 +521,7 @@
 	rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
 	rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
 
-	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
+	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL);
 	
 	if (IS_ERR(fd)) {
 		/* dirent failed to write. Delete the inode normally 
@@ -591,7 +578,6 @@
 	jint16_t dev;
 	int devlen = 0;
 	uint32_t alloclen, phys_ofs;
-	uint32_t writtenlen;
 	int ret;
 
 	if (!old_valid_dev(rdev))
@@ -639,7 +625,7 @@
 	ri->data_crc = cpu_to_je32(crc32(0, &dev, devlen));
 	ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
 	
-	fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, phys_ofs, &writtenlen);
+	fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, phys_ofs, ALLOC_NORMAL);
 
 	jffs2_free_raw_inode(ri);
 
@@ -656,20 +642,12 @@
 	f->metadata = fn;
 	up(&f->sem);
 
-	/* Work out where to put the dirent node now. */
-	writtenlen = PAD(writtenlen);
-	phys_ofs += writtenlen;
-	alloclen -= writtenlen;
-
-	if (alloclen < sizeof(*rd)+namelen) {
-		/* Not enough space left in this chunk. Get some more */
-		jffs2_complete_reservation(c);
-		ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
-		if (ret) {
-			/* Eep. */
-			jffs2_clear_inode(inode);
-			return ret;
-		}
+	jffs2_complete_reservation(c);
+	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+	if (ret) {
+		/* Eep. */
+		jffs2_clear_inode(inode);
+		return ret;
 	}
 
 	rd = jffs2_alloc_raw_dirent();
@@ -700,7 +678,7 @@
 	rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
 	rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
 
-	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
+	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL);
 	
 	if (IS_ERR(fd)) {
 		/* dirent failed to write. Delete the inode normally 
diff -Nru a/fs/jffs2/erase.c b/fs/jffs2/erase.c
--- a/fs/jffs2/erase.c	Wed Oct 15 00:46:35 2003
+++ b/fs/jffs2/erase.c	Wed Oct 15 00:46:35 2003
@@ -1,13 +1,13 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: erase.c,v 1.51 2003/05/11 22:47:36 dwmw2 Exp $
+ * $Id: erase.c,v 1.53 2003/10/08 17:22:54 dwmw2 Exp $
  *
  */
 
@@ -123,10 +123,11 @@
 			D1(printk(KERN_DEBUG "Starting erase of pending block 0x%08x\n", jeb->offset));
 			list_del(&jeb->list);
 			c->erasing_size += c->sector_size;
+			c->wasted_size -= jeb->wasted_size;
 			c->free_size -= jeb->free_size;
 			c->used_size -= jeb->used_size;
 			c->dirty_size -= jeb->dirty_size;
-			jeb->used_size = jeb->dirty_size = jeb->free_size = 0;
+			jeb->wasted_size = jeb->used_size = jeb->dirty_size = jeb->free_size = 0;
 			jffs2_free_all_node_refs(c, jeb);
 			list_add(&jeb->list, &c->erasing_list);
 			spin_unlock(&c->erase_completion_lock);
diff -Nru a/fs/jffs2/file.c b/fs/jffs2/file.c
--- a/fs/jffs2/file.c	Wed Oct 15 00:46:38 2003
+++ b/fs/jffs2/file.c	Wed Oct 15 00:46:38 2003
@@ -1,13 +1,13 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: file.c,v 1.85 2003/05/26 09:50:38 dwmw2 Exp $
+ * $Id: file.c,v 1.96 2003/10/11 11:47:23 dwmw2 Exp $
  *
  */
 
@@ -29,24 +29,10 @@
 int jffs2_fsync(struct file *filp, struct dentry *dentry, int datasync)
 {
 	struct inode *inode = dentry->d_inode;
-	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
 	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
-	if (!c->wbuf || !c->wbuf_len)
-		return 0;
 
-	/* flush write buffer and update c->nextblock */
-	
-	/* FIXME NAND */
-	/* At the moment we flush the buffer, to make sure
-	 * that every thing is on the flash.
-	 * maybe we have to think about it to find a smarter
-	 * solution.
-	 */
-	down(&c->alloc_sem);
-	down(&f->sem);
-	jffs2_flush_wbuf(c,2);
-	up(&f->sem);
-	up(&c->alloc_sem);
+	/* Trigger GC to flush any pending writes for this inode */
+	jffs2_flush_wbuf_gc(c, inode->i_ino);
 			
 	return 0;	
 }
@@ -79,151 +65,6 @@
 	.commit_write =	jffs2_commit_write
 };
 
-int jffs2_setattr (struct dentry *dentry, struct iattr *iattr)
-{
-	struct jffs2_full_dnode *old_metadata, *new_metadata;
-	struct inode *inode = dentry->d_inode;
-	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
-	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
-	struct jffs2_raw_inode *ri;
-	unsigned short dev;
-	unsigned char *mdata = NULL;
-	int mdatalen = 0;
-	unsigned int ivalid;
-	uint32_t phys_ofs, alloclen;
-	int ret;
-	D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino));
-	ret = inode_change_ok(inode, iattr);
-	if (ret) 
-		return ret;
-
-	/* Special cases - we don't want more than one data node
-	   for these types on the medium at any time. So setattr
-	   must read the original data associated with the node
-	   (i.e. the device numbers or the target name) and write
-	   it out again with the appropriate data attached */
-	if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
-		/* For these, we don't actually need to read the old node */
-		dev =  old_encode_dev(dentry->d_inode->i_rdev);
-		mdata = (char *)&dev;
-		mdatalen = sizeof(dev);
-		D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen));
-	} else if (S_ISLNK(inode->i_mode)) {
-		mdatalen = f->metadata->size;
-		mdata = kmalloc(f->metadata->size, GFP_USER);
-		if (!mdata)
-			return -ENOMEM;
-		ret = jffs2_read_dnode(c, f->metadata, mdata, 0, mdatalen);
-		if (ret) {
-			kfree(mdata);
-			return ret;
-		}
-		D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of symlink target\n", mdatalen));
-	}
-
-	ri = jffs2_alloc_raw_inode();
-	if (!ri) {
-		if (S_ISLNK(inode->i_mode))
-			kfree(mdata);
-		return -ENOMEM;
-	}
-		
-	ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, ALLOC_NORMAL);
-	if (ret) {
-		jffs2_free_raw_inode(ri);
-		if (S_ISLNK(inode->i_mode & S_IFMT))
-			 kfree(mdata);
-		return ret;
-	}
-	down(&f->sem);
-	ivalid = iattr->ia_valid;
-	
-	ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-	ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
-	ri->totlen = cpu_to_je32(sizeof(*ri) + mdatalen);
-	ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
-
-	ri->ino = cpu_to_je32(inode->i_ino);
-	ri->version = cpu_to_je32(++f->highest_version);
-
-	ri->uid = cpu_to_je16((ivalid & ATTR_UID)?iattr->ia_uid:inode->i_uid);
-	ri->gid = cpu_to_je16((ivalid & ATTR_GID)?iattr->ia_gid:inode->i_gid);
-
-	if (ivalid & ATTR_MODE)
-		if (iattr->ia_mode & S_ISGID &&
-		    !in_group_p(je16_to_cpu(ri->gid)) && !capable(CAP_FSETID))
-			ri->mode = cpu_to_jemode(iattr->ia_mode & ~S_ISGID);
-		else 
-			ri->mode = cpu_to_jemode(iattr->ia_mode);
-	else
-		ri->mode = cpu_to_jemode(inode->i_mode);
-
-
-	ri->isize = cpu_to_je32((ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size);
-	ri->atime = cpu_to_je32(I_SEC((ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime));
-	ri->mtime = cpu_to_je32(I_SEC((ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime));
-	ri->ctime = cpu_to_je32(I_SEC((ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime));
-
-	ri->offset = cpu_to_je32(0);
-	ri->csize = ri->dsize = cpu_to_je32(mdatalen);
-	ri->compr = JFFS2_COMPR_NONE;
-	if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
-		/* It's an extension. Make it a hole node */
-		ri->compr = JFFS2_COMPR_ZERO;
-		ri->dsize = cpu_to_je32(iattr->ia_size - inode->i_size);
-		ri->offset = cpu_to_je32(inode->i_size);
-	}
-	ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
-	if (mdatalen)
-		ri->data_crc = cpu_to_je32(crc32(0, mdata, mdatalen));
-	else
-		ri->data_crc = cpu_to_je32(0);
-
-	new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, phys_ofs, NULL);
-	if (S_ISLNK(inode->i_mode))
-		kfree(mdata);
-	
-	if (IS_ERR(new_metadata)) {
-		jffs2_complete_reservation(c);
-		jffs2_free_raw_inode(ri);
-		up(&f->sem);
-		return PTR_ERR(new_metadata);
-	}
-	/* It worked. Update the inode */
-	inode->i_atime = ITIME(je32_to_cpu(ri->atime));
-	inode->i_ctime = ITIME(je32_to_cpu(ri->ctime));
-	inode->i_mtime = ITIME(je32_to_cpu(ri->mtime));
-	inode->i_mode = jemode_to_cpu(ri->mode);
-	inode->i_uid = je16_to_cpu(ri->uid);
-	inode->i_gid = je16_to_cpu(ri->gid);
-
-
-	old_metadata = f->metadata;
-
-	if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) {
-		vmtruncate(inode, iattr->ia_size);
-		jffs2_truncate_fraglist (c, &f->fragtree, iattr->ia_size);
-	}
-
-	if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
-		jffs2_add_full_dnode_to_inode(c, f, new_metadata);
-		inode->i_size = iattr->ia_size;
-		f->metadata = NULL;
-	} else {
-		f->metadata = new_metadata;
-	}
-	if (old_metadata) {
-		jffs2_mark_node_obsolete(c, old_metadata->raw);
-		jffs2_free_full_dnode(old_metadata);
-	}
-	jffs2_free_raw_inode(ri);
-
-	up(&f->sem);
-	jffs2_complete_reservation(c);
-
-	return 0;
-}
-
 int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg)
 {
 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
@@ -320,7 +161,7 @@
 		ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
 		ri.data_crc = cpu_to_je32(0);
 		
-		fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, NULL);
+		fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, ALLOC_NORMAL);
 
 		if (IS_ERR(fn)) {
 			ret = PTR_ERR(fn);
diff -Nru a/fs/jffs2/fs.c b/fs/jffs2/fs.c
--- a/fs/jffs2/fs.c	Wed Oct 15 00:46:36 2003
+++ b/fs/jffs2/fs.c	Wed Oct 15 00:46:36 2003
@@ -1,13 +1,13 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: fs.c,v 1.24 2003/04/29 09:52:58 dwmw2 Exp $
+ * $Id: fs.c,v 1.32 2003/10/11 11:47:23 dwmw2 Exp $
  *
  */
 
@@ -21,8 +21,159 @@
 #include <linux/pagemap.h>
 #include <linux/slab.h>
 #include <linux/vfs.h>
+#include <linux/crc32.h>
 #include "nodelist.h"
 
+
+static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
+{
+	struct jffs2_full_dnode *old_metadata, *new_metadata;
+	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
+	struct jffs2_raw_inode *ri;
+	unsigned short dev;
+	unsigned char *mdata = NULL;
+	int mdatalen = 0;
+	unsigned int ivalid;
+	uint32_t phys_ofs, alloclen;
+	int ret;
+	D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino));
+	ret = inode_change_ok(inode, iattr);
+	if (ret) 
+		return ret;
+
+	/* Special cases - we don't want more than one data node
+	   for these types on the medium at any time. So setattr
+	   must read the original data associated with the node
+	   (i.e. the device numbers or the target name) and write
+	   it out again with the appropriate data attached */
+	if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
+		/* For these, we don't actually need to read the old node */
+		dev = old_encode_dev(inode->i_rdev);
+		mdata = (char *)&dev;
+		mdatalen = sizeof(dev);
+		D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen));
+	} else if (S_ISLNK(inode->i_mode)) {
+		mdatalen = f->metadata->size;
+		mdata = kmalloc(f->metadata->size, GFP_USER);
+		if (!mdata)
+			return -ENOMEM;
+		ret = jffs2_read_dnode(c, f->metadata, mdata, 0, mdatalen);
+		if (ret) {
+			kfree(mdata);
+			return ret;
+		}
+		D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of symlink target\n", mdatalen));
+	}
+
+	ri = jffs2_alloc_raw_inode();
+	if (!ri) {
+		if (S_ISLNK(inode->i_mode))
+			kfree(mdata);
+		return -ENOMEM;
+	}
+		
+	ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+	if (ret) {
+		jffs2_free_raw_inode(ri);
+		if (S_ISLNK(inode->i_mode & S_IFMT))
+			 kfree(mdata);
+		return ret;
+	}
+	down(&f->sem);
+	ivalid = iattr->ia_valid;
+	
+	ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+	ri->totlen = cpu_to_je32(sizeof(*ri) + mdatalen);
+	ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
+
+	ri->ino = cpu_to_je32(inode->i_ino);
+	ri->version = cpu_to_je32(++f->highest_version);
+
+	ri->uid = cpu_to_je16((ivalid & ATTR_UID)?iattr->ia_uid:inode->i_uid);
+	ri->gid = cpu_to_je16((ivalid & ATTR_GID)?iattr->ia_gid:inode->i_gid);
+
+	if (ivalid & ATTR_MODE)
+		if (iattr->ia_mode & S_ISGID &&
+		    !in_group_p(je16_to_cpu(ri->gid)) && !capable(CAP_FSETID))
+			ri->mode = cpu_to_jemode(iattr->ia_mode & ~S_ISGID);
+		else 
+			ri->mode = cpu_to_jemode(iattr->ia_mode);
+	else
+		ri->mode = cpu_to_jemode(inode->i_mode);
+
+
+	ri->isize = cpu_to_je32((ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size);
+	ri->atime = cpu_to_je32(I_SEC((ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime));
+	ri->mtime = cpu_to_je32(I_SEC((ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime));
+	ri->ctime = cpu_to_je32(I_SEC((ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime));
+
+	ri->offset = cpu_to_je32(0);
+	ri->csize = ri->dsize = cpu_to_je32(mdatalen);
+	ri->compr = JFFS2_COMPR_NONE;
+	if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
+		/* It's an extension. Make it a hole node */
+		ri->compr = JFFS2_COMPR_ZERO;
+		ri->dsize = cpu_to_je32(iattr->ia_size - inode->i_size);
+		ri->offset = cpu_to_je32(inode->i_size);
+	}
+	ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
+	if (mdatalen)
+		ri->data_crc = cpu_to_je32(crc32(0, mdata, mdatalen));
+	else
+		ri->data_crc = cpu_to_je32(0);
+
+	new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, phys_ofs, ALLOC_NORMAL);
+	if (S_ISLNK(inode->i_mode))
+		kfree(mdata);
+	
+	if (IS_ERR(new_metadata)) {
+		jffs2_complete_reservation(c);
+		jffs2_free_raw_inode(ri);
+		up(&f->sem);
+		return PTR_ERR(new_metadata);
+	}
+	/* It worked. Update the inode */
+	inode->i_atime = ITIME(je32_to_cpu(ri->atime));
+	inode->i_ctime = ITIME(je32_to_cpu(ri->ctime));
+	inode->i_mtime = ITIME(je32_to_cpu(ri->mtime));
+	inode->i_mode = jemode_to_cpu(ri->mode);
+	inode->i_uid = je16_to_cpu(ri->uid);
+	inode->i_gid = je16_to_cpu(ri->gid);
+
+
+	old_metadata = f->metadata;
+
+	if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) {
+		vmtruncate(inode, iattr->ia_size);
+		jffs2_truncate_fraglist (c, &f->fragtree, iattr->ia_size);
+	}
+
+	if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
+		jffs2_add_full_dnode_to_inode(c, f, new_metadata);
+		inode->i_size = iattr->ia_size;
+		f->metadata = NULL;
+	} else {
+		f->metadata = new_metadata;
+	}
+	if (old_metadata) {
+		jffs2_mark_node_obsolete(c, old_metadata->raw);
+		jffs2_free_full_dnode(old_metadata);
+	}
+	jffs2_free_raw_inode(ri);
+
+	up(&f->sem);
+	jffs2_complete_reservation(c);
+
+	return 0;
+}
+
+int jffs2_setattr(struct dentry *dentry, struct iattr *iattr)
+{
+	return jffs2_do_setattr(dentry->d_inode, iattr);
+}
+
 int jffs2_statfs(struct super_block *sb, struct kstatfs *buf)
 {
 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
@@ -38,8 +189,8 @@
 	spin_lock(&c->erase_completion_lock);
 
 	avail = c->dirty_size + c->free_size;
-	if (avail > c->sector_size * JFFS2_RESERVED_BLOCKS_WRITE)
-		avail -= c->sector_size * JFFS2_RESERVED_BLOCKS_WRITE;
+	if (avail > c->sector_size * c->resv_blocks_write)
+		avail -= c->sector_size * c->resv_blocks_write;
 	else
 		avail = 0;
 
@@ -149,7 +300,7 @@
 	case S_IFIFO:
 		inode->i_op = &jffs2_file_inode_operations;
 		init_special_inode(inode, inode->i_mode,
-			old_decode_dev(je16_to_cpu(rdev)));
+				   old_decode_dev((je16_to_cpu(rdev))));
 		break;
 
 	default:
@@ -161,6 +312,27 @@
 	D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n"));
 }
 
+void jffs2_dirty_inode(struct inode *inode)
+{
+	struct iattr iattr;
+
+	if (!(inode->i_state & I_DIRTY_DATASYNC)) {
+		D1(printk(KERN_DEBUG "jffs2_dirty_inode() not calling setattr() for ino #%lu\n", inode->i_ino));
+		return;
+	}
+
+	D1(printk(KERN_DEBUG "jffs2_dirty_inode() calling setattr() for ino #%lu\n", inode->i_ino));
+
+	iattr.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_MTIME|ATTR_CTIME;
+	iattr.ia_mode = inode->i_mode;
+	iattr.ia_uid = inode->i_uid;
+	iattr.ia_gid = inode->i_gid;
+	iattr.ia_atime = inode->i_atime;
+	iattr.ia_mtime = inode->i_mtime;
+	iattr.ia_ctime = inode->i_ctime;
+
+	jffs2_do_setattr(inode, &iattr);
+}
 
 int jffs2_remount_fs (struct super_block *sb, int *flags, char *data)
 {
@@ -194,6 +366,7 @@
 	D1(printk(KERN_DEBUG "jffs2_write_super()\n"));
 	jffs2_garbage_collect_trigger(c);
 	jffs2_erase_pending_blocks(c);
+	jffs2_flush_wbuf_gc(c, 0);
 }
 
 
@@ -288,25 +461,10 @@
 	/* Joern -- stick alignment for weird 8-byte-page flash here */
 
 	if (jffs2_cleanmarker_oob(c)) {
-		/* Cleanmarker is out-of-band, so inline size zero */
-		c->cleanmarker_size = 0;
-	}
-
-	if (c->mtd->type == MTD_NANDFLASH) {
-		/* Initialise write buffer */
-		c->wbuf_pagesize = c->mtd->oobblock;
-		c->wbuf_ofs = 0xFFFFFFFF;
-		c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
-		if (!c->wbuf)
-			return -ENOMEM;
-
-		/* Initialise process for timed wbuf flush */
-		INIT_WORK(&c->wbuf_task,(void*) jffs2_wbuf_process, (void *)c);
-
-		/* Initialise timer for timed wbuf flush */
-		init_timer(&c->wbuf_timer);
-		c->wbuf_timer.function = jffs2_wbuf_timeout;
-		c->wbuf_timer.data = (unsigned long) c;
+		/* NAND (or other bizarre) flash... do setup accordingly */
+		ret = jffs2_nand_flash_setup(c);
+		if (ret)
+			return ret;
 	}
 
 	c->inocache_list = kmalloc(INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *), GFP_KERNEL);
@@ -352,7 +510,7 @@
  out_inohash:
 	kfree(c->inocache_list);
  out_wbuf:
-	if (c->wbuf)
-		kfree(c->wbuf);
+	jffs2_nand_flash_cleanup(c);
+
 	return ret;
 }
diff -Nru a/fs/jffs2/gc.c b/fs/jffs2/gc.c
--- a/fs/jffs2/gc.c	Wed Oct 15 00:46:36 2003
+++ b/fs/jffs2/gc.c	Wed Oct 15 00:46:36 2003
@@ -1,13 +1,13 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: gc.c,v 1.103 2003/05/22 18:01:02 dwmw2 Exp $
+ * $Id: gc.c,v 1.114 2003/10/09 13:53:35 dwmw2 Exp $
  *
  */
 
@@ -49,7 +49,7 @@
 	   put the clever wear-levelling algorithms. Eventually.  */
 	/* We possibly want to favour the dirtier blocks more when the
 	   number of free blocks is low. */
-	if (!list_empty(&c->bad_used_list) && c->nr_free_blocks > JFFS2_RESERVED_BLOCKS_GCBAD) {
+	if (!list_empty(&c->bad_used_list) && c->nr_free_blocks > c->resv_blocks_gcbad) {
 		D1(printk(KERN_DEBUG "Picking block from bad_used_list to GC next\n"));
 		nextlist = &c->bad_used_list;
 	} else if (n < 50 && !list_empty(&c->erasable_list)) {
@@ -274,7 +274,7 @@
 		if (ref_flags(raw) == REF_PRISTINE)
 			ic->state = INO_STATE_GC;
 		else {
-			D1(printk("Ino #%u is absent but node not REF_PRISTINE. Reading.\n", 
+			D1(printk(KERN_DEBUG "Ino #%u is absent but node not REF_PRISTINE. Reading.\n", 
 				  inum));
 		}
 		break;
@@ -493,6 +493,7 @@
 	int ret;
 	uint32_t phys_ofs, alloclen;
 	uint32_t crc;
+	int retried = 0;
 
 	D1(printk(KERN_DEBUG "Going to GC REF_PRISTINE node at 0x%08x\n", ref_offset(raw)));
 
@@ -573,13 +574,15 @@
 		ret = -ENOMEM;
 		goto out_node;
 	}
+
+	/* OK, all the CRCs are good; this node can just be copied as-is. */
+ retry:
 	nraw->flash_offset = phys_ofs;
 	nraw->totlen = raw->totlen;
 	nraw->next_phys = NULL;
 
-	/* OK, all the CRCs are good; this node can just be copied as-is. */
-
 	ret = jffs2_flash_write(c, phys_ofs, raw->totlen, &retlen, (char *)node);
+
 	if (ret || (retlen != raw->totlen)) {
 		printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n",
                        raw->totlen, phys_ofs, ret, retlen);
@@ -592,8 +595,34 @@
 			jffs2_mark_node_obsolete(c, nraw);
 		} else {
 			printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", nraw->flash_offset);
-                        jffs2_free_raw_node_ref(raw);
+                        jffs2_free_raw_node_ref(nraw);
 		}
+		if (!retried && (nraw == jffs2_alloc_raw_node_ref())) {
+			/* Try to reallocate space and retry */
+			uint32_t dummy;
+			struct jffs2_eraseblock *jeb = &c->blocks[phys_ofs / c->sector_size];
+
+			retried = 1;
+
+			D1(printk(KERN_DEBUG "Retrying failed write of REF_PRISTINE node.\n"));
+			
+			ACCT_SANITY_CHECK(c,jeb);
+			D1(ACCT_PARANOIA_CHECK(jeb));
+
+			ret = jffs2_reserve_space_gc(c, raw->totlen, &phys_ofs, &dummy);
+
+			if (!ret) {
+				D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", phys_ofs));
+
+				ACCT_SANITY_CHECK(c,jeb);
+				D1(ACCT_PARANOIA_CHECK(jeb));
+
+				goto retry;
+			}
+			D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret));
+			jffs2_free_raw_node_ref(nraw);
+		}
+
 		if (!ret)
 			ret = -EIO;
 		goto out_node;
@@ -684,7 +713,7 @@
 	ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
 	ri.data_crc = cpu_to_je32(crc32(0, mdata, mdatalen));
 
-	new_fn = jffs2_write_dnode(c, f, &ri, mdata, mdatalen, phys_ofs, NULL);
+	new_fn = jffs2_write_dnode(c, f, &ri, mdata, mdatalen, phys_ofs, ALLOC_GC);
 
 	if (IS_ERR(new_fn)) {
 		printk(KERN_WARNING "Error writing new dnode: %ld\n", PTR_ERR(new_fn));
@@ -728,7 +757,7 @@
 		       sizeof(rd)+rd.nsize, ret);
 		return ret;
 	}
-	new_fd = jffs2_write_dirent(c, f, &rd, fd->name, rd.nsize, phys_ofs, NULL);
+	new_fd = jffs2_write_dirent(c, f, &rd, fd->name, rd.nsize, phys_ofs, ALLOC_GC);
 
 	if (IS_ERR(new_fd)) {
 		printk(KERN_WARNING "jffs2_write_dirent in garbage_collect_dirent failed: %ld\n", PTR_ERR(new_fd));
@@ -951,7 +980,7 @@
 		       sizeof(ri), ret);
 		return ret;
 	}
-	new_fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, NULL);
+	new_fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, ALLOC_GC);
 
 	if (IS_ERR(new_fn)) {
 		printk(KERN_WARNING "Error writing new hole node: %ld\n", PTR_ERR(new_fn));
@@ -1010,7 +1039,7 @@
 {
 	struct jffs2_full_dnode *new_fn;
 	struct jffs2_raw_inode ri;
-	uint32_t alloclen, phys_ofs, offset, orig_end;	
+	uint32_t alloclen, phys_ofs, offset, orig_end, orig_start;	
 	int ret = 0;
 	unsigned char *comprbuf = NULL, *writebuf;
 	struct page *pg;
@@ -1023,29 +1052,129 @@
 		  f->inocache->ino, start, end));
 
 	orig_end = end;
+	orig_start = start;
 
-	/* If we're looking at the last node in the block we're
-	   garbage-collecting, we allow ourselves to merge as if the
-	   block was already erasing. We're likely to be GC'ing a
-	   partial page, and the next block we GC is likely to have
-	   the other half of this page right at the beginning, which
-	   means we'd expand it _then_, as nr_erasing_blocks would have
-	   increased since we checked, and in doing so would obsolete 
-	   the partial node which we'd have written here. Meaning that 
-	   the GC would churn and churn, and just leave dirty blocks in
-	   it's wake.
-	*/
-	if(c->nr_free_blocks + c->nr_erasing_blocks > JFFS2_RESERVED_BLOCKS_GCMERGE - (fn->raw->next_phys?0:1)) {
-		/* Shitloads of space */
-		/* FIXME: Integrate this properly with GC calculations */
-		start &= ~(PAGE_CACHE_SIZE-1);
-		end = min_t(uint32_t, start + PAGE_CACHE_SIZE, JFFS2_F_I_SIZE(f));
-		D1(printk(KERN_DEBUG "Plenty of free space, so expanding to write from offset 0x%x to 0x%x\n",
-			  start, end));
-		if (end < orig_end) {
-			printk(KERN_WARNING "Eep. jffs2_garbage_collect_dnode extended node to write, but it got smaller: start 0x%x, orig_end 0x%x, end 0x%x\n", start, orig_end, end);
-			end = orig_end;
+	if (c->nr_free_blocks + c->nr_erasing_blocks > c->resv_blocks_gcmerge) {
+		/* Attempt to do some merging. But only expand to cover logically
+		   adjacent frags if the block containing them is already considered
+		   to be dirty. Otherwise we end up with GC just going round in 
+		   circles dirtying the nodes it already wrote out, especially 
+		   on NAND where we have small eraseblocks and hence a much higher
+		   chance of nodes having to be split to cross boundaries. */
+
+		struct jffs2_node_frag *frag;
+		uint32_t min, max;
+
+		min = start & ~(PAGE_CACHE_SIZE-1);
+		max = min + PAGE_CACHE_SIZE;
+
+		frag = jffs2_lookup_node_frag(&f->fragtree, start);
+
+		/* BUG_ON(!frag) but that'll happen anyway... */
+
+		BUG_ON(frag->ofs != start);
+
+		/* First grow down... */
+		while((frag = frag_prev(frag)) && frag->ofs >= min) {
+
+			/* If the previous frag doesn't even reach the beginning, there's
+			   excessive fragmentation. Just merge. */
+			if (frag->ofs > min) {
+				D1(printk(KERN_DEBUG "Expanding down to cover partial frag (0x%x-0x%x)\n",
+					  frag->ofs, frag->ofs+frag->size));
+				start = frag->ofs;
+				continue;
+			}
+			/* OK. This frag holds the first byte of the page. */
+			if (!frag->node || !frag->node->raw) {
+				D1(printk(KERN_DEBUG "First frag in page is hole (0x%x-0x%x). Not expanding down.\n",
+					  frag->ofs, frag->ofs+frag->size));
+				break;
+			} else {
+
+				/* OK, it's a frag which extends to the beginning of the page. Does it live 
+				   in a block which is still considered clean? If so, don't obsolete it.
+				   If not, cover it anyway. */
+
+				struct jffs2_raw_node_ref *raw = frag->node->raw;
+				struct jffs2_eraseblock *jeb;
+
+				jeb = &c->blocks[raw->flash_offset / c->sector_size];
+
+				if (jeb == c->gcblock) {
+					D1(printk(KERN_DEBUG "Expanding down to cover frag (0x%x-0x%x) in gcblock at %08x\n",
+						  frag->ofs, frag->ofs+frag->size, ref_offset(raw)));
+					start = frag->ofs;
+					break;
+				}
+				if (!ISDIRTY(jeb->dirty_size + jeb->wasted_size)) {
+					D1(printk(KERN_DEBUG "Not expanding down to cover frag (0x%x-0x%x) in clean block %08x\n",
+						  frag->ofs, frag->ofs+frag->size, jeb->offset));
+					break;
+				}
+
+				D1(printk(KERN_DEBUG "Expanding down to cover frag (0x%x-0x%x) in dirty block %08x\n",
+						  frag->ofs, frag->ofs+frag->size, jeb->offset));
+				start = frag->ofs;
+				break;
+			}
+		}
+
+		/* ... then up */
+
+		/* Find last frag which is actually part of the node we're to GC. */
+		frag = jffs2_lookup_node_frag(&f->fragtree, end-1);
+
+		while((frag = frag_next(frag)) && frag->ofs+frag->size <= max) {
+
+			/* If the previous frag doesn't even reach the beginning, there's lots
+			   of fragmentation. Just merge. */
+			if (frag->ofs+frag->size < max) {
+				D1(printk(KERN_DEBUG "Expanding up to cover partial frag (0x%x-0x%x)\n",
+					  frag->ofs, frag->ofs+frag->size));
+				end = frag->ofs + frag->size;
+				continue;
+			}
+
+			if (!frag->node || !frag->node->raw) {
+				D1(printk(KERN_DEBUG "Last frag in page is hole (0x%x-0x%x). Not expanding up.\n",
+					  frag->ofs, frag->ofs+frag->size));
+				break;
+			} else {
+
+				/* OK, it's a frag which extends to the beginning of the page. Does it live 
+				   in a block which is still considered clean? If so, don't obsolete it.
+				   If not, cover it anyway. */
+
+				struct jffs2_raw_node_ref *raw = frag->node->raw;
+				struct jffs2_eraseblock *jeb;
+
+				jeb = &c->blocks[raw->flash_offset / c->sector_size];
+
+				if (jeb == c->gcblock) {
+					D1(printk(KERN_DEBUG "Expanding up to cover frag (0x%x-0x%x) in gcblock at %08x\n",
+						  frag->ofs, frag->ofs+frag->size, ref_offset(raw)));
+					end = frag->ofs + frag->size;
+					break;
+				}
+				if (!ISDIRTY(jeb->dirty_size + jeb->wasted_size)) {
+					D1(printk(KERN_DEBUG "Not expanding up to cover frag (0x%x-0x%x) in clean block %08x\n",
+						  frag->ofs, frag->ofs+frag->size, jeb->offset));
+					break;
+				}
+
+				D1(printk(KERN_DEBUG "Expanding up to cover frag (0x%x-0x%x) in dirty block %08x\n",
+						  frag->ofs, frag->ofs+frag->size, jeb->offset));
+				end = frag->ofs + frag->size;
+				break;
+			}
 		}
+		D1(printk(KERN_DEBUG "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x)\n", 
+			  orig_start, orig_end, start, end));
+
+		BUG_ON(end > JFFS2_F_I_SIZE(f));
+		BUG_ON(end < orig_end);
+		BUG_ON(start > orig_start);
 	}
 	
 	/* First, use readpage() to read the appropriate page into the page cache */
@@ -1114,7 +1243,7 @@
 		ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
 		ri.data_crc = cpu_to_je32(crc32(0, writebuf, cdatalen));
 	
-		new_fn = jffs2_write_dnode(c, f, &ri, writebuf, cdatalen, phys_ofs, NULL);
+		new_fn = jffs2_write_dnode(c, f, &ri, writebuf, cdatalen, phys_ofs, ALLOC_GC);
 
 		if (IS_ERR(new_fn)) {
 			printk(KERN_WARNING "Error writing new dnode: %ld\n", PTR_ERR(new_fn));
diff -Nru a/fs/jffs2/ioctl.c b/fs/jffs2/ioctl.c
--- a/fs/jffs2/ioctl.c	Wed Oct 15 00:46:37 2003
+++ b/fs/jffs2/ioctl.c	Wed Oct 15 00:46:37 2003
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: ioctl.c,v 1.6 2002/05/20 14:56:38 dwmw2 Exp $
+ * $Id: ioctl.c,v 1.7 2003/10/04 08:33:06 dwmw2 Exp $
  *
  */
 
diff -Nru a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c
--- a/fs/jffs2/malloc.c	Wed Oct 15 00:46:35 2003
+++ b/fs/jffs2/malloc.c	Wed Oct 15 00:46:35 2003
@@ -1,13 +1,13 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: malloc.c,v 1.24 2003/03/11 17:30:29 gleixner Exp $
+ * $Id: malloc.c,v 1.25 2003/10/04 08:33:06 dwmw2 Exp $
  *
  */
 
diff -Nru a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c
--- a/fs/jffs2/nodelist.c	Wed Oct 15 00:46:37 2003
+++ b/fs/jffs2/nodelist.c	Wed Oct 15 00:46:37 2003
@@ -1,13 +1,13 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodelist.c,v 1.79 2003/04/08 08:20:01 dwmw2 Exp $
+ * $Id: nodelist.c,v 1.80 2003/10/04 08:33:06 dwmw2 Exp $
  *
  */
 
diff -Nru a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
--- a/fs/jffs2/nodelist.h	Wed Oct 15 00:46:38 2003
+++ b/fs/jffs2/nodelist.h	Wed Oct 15 00:46:38 2003
@@ -1,13 +1,13 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodelist.h,v 1.93 2003/02/24 21:47:28 dwmw2 Exp $
+ * $Id: nodelist.h,v 1.104 2003/10/08 11:45:11 dwmw2 Exp $
  *
  */
 
@@ -29,7 +29,7 @@
 #endif
 
 #ifndef CONFIG_JFFS2_FS_DEBUG
-#define CONFIG_JFFS2_FS_DEBUG 2
+#define CONFIG_JFFS2_FS_DEBUG 1
 #endif
 
 #if CONFIG_JFFS2_FS_DEBUG > 0
@@ -201,10 +201,11 @@
 };
 
 #define ACCT_SANITY_CHECK(c, jeb) do { \
-	if (jeb->used_size + jeb->dirty_size + jeb->free_size + jeb->wasted_size + jeb->unchecked_size != c->sector_size) { \
-		printk(KERN_NOTICE "Eeep. Space accounting for block at 0x%08x is screwed\n", jeb->offset); \
+		struct jffs2_eraseblock *___j = jeb; \
+		if ((___j) && ___j->used_size + ___j->dirty_size + ___j->free_size + ___j->wasted_size + ___j->unchecked_size != c->sector_size) { \
+		printk(KERN_NOTICE "Eeep. Space accounting for block at 0x%08x is screwed\n", ___j->offset); \
 		printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + wasted %08x + unchecked %08x != total %08x\n", \
-		jeb->free_size, jeb->dirty_size, jeb->used_size, jeb->wasted_size, jeb->unchecked_size, c->sector_size); \
+		___j->free_size, ___j->dirty_size, ___j->used_size, ___j->wasted_size, ___j->unchecked_size, c->sector_size); \
 		BUG(); \
 	} \
 	if (c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size + c->wasted_size + c->unchecked_size != c->flash_size) { \
@@ -215,15 +216,46 @@
 	} \
 } while(0)
 
+static inline void paranoia_failed_dump(struct jffs2_eraseblock *jeb)
+{
+	struct jffs2_raw_node_ref *ref;
+	int i=0;
+
+	printk(KERN_NOTICE);
+	for (ref = jeb->first_node; ref; ref = ref->next_phys) {
+		printk("%08x->", ref_offset(ref));
+		if (++i == 8) {
+			i = 0;
+			printk("\n" KERN_NOTICE);
+		}
+	}
+	printk("\n");
+}
+
+
 #define ACCT_PARANOIA_CHECK(jeb) do { \
 		uint32_t my_used_size = 0; \
 		uint32_t my_unchecked_size = 0; \
 		struct jffs2_raw_node_ref *ref2 = jeb->first_node; \
 		while (ref2) { \
+			if (unlikely(ref2->flash_offset < jeb->offset || \
+				     ref2->flash_offset > jeb->offset + c->sector_size)) { \
+				printk(KERN_NOTICE "Node %08x shouldn't be in block at %08x!\n", \
+				       ref_offset(ref2), jeb->offset); \
+				paranoia_failed_dump(jeb); \
+				BUG(); \
+			} \
 			if (ref_flags(ref2) == REF_UNCHECKED) \
 				my_unchecked_size += ref2->totlen; \
 			else if (!ref_obsolete(ref2)) \
 				my_used_size += ref2->totlen; \
+			if (unlikely((!ref2->next_phys) != (ref2 == jeb->last_node))) { \
+				printk("ref for node at %p (phys %08x) has next_phys->%p (%08x), last_node->%p (phys %08x)\n", \
+				       ref2, ref_offset(ref2), ref2->next_phys, ref_offset(ref2->next_phys), \
+				       jeb->last_node, ref_offset(jeb->last_node)); \
+				paranoia_failed_dump(jeb); \
+				BUG(); \
+			} \
 			ref2 = ref2->next_phys; \
 		} \
 		if (my_used_size != jeb->used_size) { \
@@ -239,14 +271,7 @@
 #define ALLOC_NORMAL	0	/* Normal allocation */
 #define ALLOC_DELETION	1	/* Deletion node. Best to allow it */
 #define ALLOC_GC	2	/* Space requested for GC. Give it or die */
-
-#define JFFS2_RESERVED_BLOCKS_BASE 3						/* Number of free blocks there must be before we... */
-#define JFFS2_RESERVED_BLOCKS_WRITE (JFFS2_RESERVED_BLOCKS_BASE + 2)		/* ... allow a normal filesystem write */
-#define JFFS2_RESERVED_BLOCKS_DELETION (JFFS2_RESERVED_BLOCKS_BASE)		/* ... allow a normal filesystem deletion */
-#define JFFS2_RESERVED_BLOCKS_GCTRIGGER (JFFS2_RESERVED_BLOCKS_BASE + 3)	/* ... wake up the GC thread */
-#define JFFS2_RESERVED_BLOCKS_GCBAD (JFFS2_RESERVED_BLOCKS_BASE + 1)		/* ... pick a block from the bad_list to GC */
-#define JFFS2_RESERVED_BLOCKS_GCMERGE (JFFS2_RESERVED_BLOCKS_BASE)		/* ... merge pages when garbage collecting */
-
+#define ALLOC_NORETRY	3	/* For jffs2_write_dnode: On failure, return -EAGAIN instead of retrying */
 
 /* How much dirty space before it goes on the very_dirty_list */
 #define VERYDIRTY(c, size) ((size) >= ((c)->sector_size / 2))
@@ -314,8 +339,9 @@
 
 /* write.c */
 int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri);
-struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const unsigned char *data, uint32_t datalen, uint32_t flash_ofs,  uint32_t *writelen);
-struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_dirent *rd, const unsigned char *name, uint32_t namelen, uint32_t flash_ofs,  uint32_t *writelen);
+
+struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const unsigned char *data, uint32_t datalen, uint32_t flash_ofs, int alloc_mode);
+struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_dirent *rd, const unsigned char *name, uint32_t namelen, uint32_t flash_ofs, int alloc_mode);
 int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
 			    struct jffs2_raw_inode *ri, unsigned char *buf, 
 			    uint32_t offset, uint32_t writelen, uint32_t *retlen);
@@ -383,7 +409,8 @@
 
 #ifdef CONFIG_JFFS2_FS_NAND
 /* wbuf.c */
-int jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad);
+int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino);
+int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c);
 int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 int jffs2_nand_read_failcnt(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
diff -Nru a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c
--- a/fs/jffs2/nodemgmt.c	Wed Oct 15 00:46:36 2003
+++ b/fs/jffs2/nodemgmt.c	Wed Oct 15 00:46:36 2003
@@ -1,13 +1,13 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodemgmt.c,v 1.94 2003/02/19 17:50:26 gleixner Exp $
+ * $Id: nodemgmt.c,v 1.102 2003/10/08 17:21:19 dwmw2 Exp $
  *
  */
 
@@ -43,13 +43,10 @@
 int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio)
 {
 	int ret = -EAGAIN;
-	int blocksneeded = JFFS2_RESERVED_BLOCKS_WRITE;
+	int blocksneeded = c->resv_blocks_write;
 	/* align it */
 	minsize = PAD(minsize);
 
-	if (prio == ALLOC_DELETION)
-		blocksneeded = JFFS2_RESERVED_BLOCKS_DELETION;
-
 	D1(printk(KERN_DEBUG "jffs2_reserve_space(): Requested 0x%x bytes\n", minsize));
 	down(&c->alloc_sem);
 
@@ -63,8 +60,6 @@
 			int ret;
 			uint32_t dirty, avail;
 
-			up(&c->alloc_sem);
-			
 			/* calculate real dirty size
 			 * dirty_size contains blocks on erase_pending_list
 			 * those blocks are counted in c->nr_erasing_blocks.
@@ -78,10 +73,16 @@
 			 * of nodes.
 			 */
 			dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size + c->unchecked_size;
-			if (dirty < c->sector_size) {
-				D1(printk(KERN_DEBUG "dirty size 0x%08x + unchecked_size 0x%08x < sector size 0x%08x, returning -ENOSPC\n",
+			if (dirty < c->nospc_dirty_size) {
+				if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) {
+					printk(KERN_NOTICE "jffs2_reserve_space(): Low on dirty space to GC, but it's a deletion. Allowing...\n");
+					break;
+				}
+				D1(printk(KERN_DEBUG "dirty size 0x%08x + unchecked_size 0x%08x < nospc_dirty_size 0x%08x, returning -ENOSPC\n",
 					  dirty, c->unchecked_size, c->sector_size));
+
 				spin_unlock(&c->erase_completion_lock);
+				up(&c->alloc_sem);
 				return -ENOSPC;
 			}
 			
@@ -96,12 +97,20 @@
 			 */
 			avail = c->free_size + c->dirty_size + c->erasing_size + c->unchecked_size;
 			if ( (avail / c->sector_size) <= blocksneeded) {
+				if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) {
+					printk(KERN_NOTICE "jffs2_reserve_space(): Low on possibly available space, but it's a deletion. Allowing...\n");
+					break;
+				}
+
 				D1(printk(KERN_DEBUG "max. available size 0x%08x  < blocksneeded * sector_size 0x%08x, returning -ENOSPC\n",
 					  avail, blocksneeded * c->sector_size));
 				spin_unlock(&c->erase_completion_lock);
+				up(&c->alloc_sem);
 				return -ENOSPC;
 			}
-			
+
+			up(&c->alloc_sem);
+
 			D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, wasted_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n",
 				  c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->wasted_size, c->used_size, c->erasing_size, c->bad_size,
 				  c->free_size + c->dirty_size + c->wasted_size + c->used_size + c->erasing_size + c->bad_size, c->flash_size));
@@ -158,12 +167,13 @@
 	if (jeb && minsize > jeb->free_size) {
 		/* Skip the end of this block and file it as having some dirty space */
 		/* If there's a pending write to it, flush now */
-		if (c->wbuf_len) {
+		if (jffs2_wbuf_dirty(c)) {
 			spin_unlock(&c->erase_completion_lock);
 			D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));			    
-			jffs2_flush_wbuf(c, 1);
+			jffs2_flush_wbuf_pad(c);
 			spin_lock(&c->erase_completion_lock);
-			/* We know nobody's going to have changed nextblock. Just continue */
+			jeb = c->nextblock;
+			goto restart;
 		}
 		c->wasted_size += jeb->free_size;
 		c->free_size -= jeb->free_size;
@@ -219,7 +229,7 @@
 				D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));
 				/* c->nextblock is NULL, no update to c->nextblock allowed */			    
 				spin_unlock(&c->erase_completion_lock);
-				jffs2_flush_wbuf(c, 1);
+				jffs2_flush_wbuf_pad(c);
 				spin_lock(&c->erase_completion_lock);
 				/* Have another go. It'll be on the erasable_list now */
 				return -EAGAIN;
@@ -344,10 +354,10 @@
 		/* If it lives on the dirty_list, jffs2_reserve_space will put it there */
 		D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
 			  jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
-		if (c->wbuf_len) {
+		if (jffs2_wbuf_dirty(c)) {
 			/* Flush the last write in the block if it's outstanding */
 			spin_unlock(&c->erase_completion_lock);
-			jffs2_flush_wbuf(c, 1);
+			jffs2_flush_wbuf_pad(c);
 			spin_lock(&c->erase_completion_lock);
 		}
 
@@ -370,6 +380,20 @@
 	up(&c->alloc_sem);
 }
 
+static inline int on_list(struct list_head *obj, struct list_head *head)
+{
+	struct list_head *this;
+
+	list_for_each(this, head) {
+		if (this == obj) {
+			D1(printk("%p is on list at %p\n", obj, head));
+			return 1;
+
+		}
+	}
+	return 0;
+}
+
 void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref)
 {
 	struct jffs2_eraseblock *jeb;
@@ -418,11 +442,26 @@
 	// Take care, that wasted size is taken into concern
 	if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + ref->totlen)) && jeb != c->nextblock) {
 		D1(printk("Dirtying\n"));
-		addedsize = ref->totlen + jeb->wasted_size;
-		jeb->dirty_size += addedsize;
-		c->dirty_size += addedsize;
-		c->wasted_size -= jeb->wasted_size;
-		jeb->wasted_size = 0;
+		addedsize = ref->totlen;
+		jeb->dirty_size += ref->totlen;
+		c->dirty_size += ref->totlen;
+
+		/* Convert wasted space to dirty, if not a bad block */
+		if (jeb->wasted_size) {
+			if (on_list(&jeb->list, &c->bad_used_list)) {
+				D1(printk(KERN_DEBUG "Leaving block at %08x on the bad_used_list\n",
+					  jeb->offset));
+				addedsize = 0; /* To fool the refiling code later */
+			} else {
+				D1(printk(KERN_DEBUG "Converting %d bytes of wasted space to dirty in block at %08x\n",
+					  jeb->wasted_size, jeb->offset));
+				addedsize += jeb->wasted_size;
+				jeb->dirty_size += jeb->wasted_size;
+				c->dirty_size += jeb->wasted_size;
+				c->wasted_size -= jeb->wasted_size;
+				jeb->wasted_size = 0;
+			}
+		}
 	} else {
 		D1(printk("Wasting\n"));
 		addedsize = 0;
@@ -455,7 +494,7 @@
 			D1(printk(KERN_DEBUG "Eraseblock at 0x%08x completely dirtied. Removing from (dirty?) list...\n", jeb->offset));
 			list_del(&jeb->list);
 		}
-		if (c->wbuf_len) {
+		if (jffs2_wbuf_dirty(c)) {
 			D1(printk(KERN_DEBUG "...and adding to erasable_pending_wbuf_list\n"));
 			list_add_tail(&jeb->list, &c->erasable_pending_wbuf_list);
 #if 0 /* This check was added to allow us to find places where we added nodes to the lists
@@ -506,7 +545,7 @@
 		D1(printk(KERN_DEBUG "...and adding to dirty_list\n"));
 		list_add_tail(&jeb->list, &c->dirty_list);
 	} else if (VERYDIRTY(c, jeb->dirty_size) &&
-		   !VERYDIRTY(c, jeb->dirty_size - ref->totlen)) {
+		   !VERYDIRTY(c, jeb->dirty_size - addedsize)) {
 		D1(printk(KERN_DEBUG "Eraseblock at 0x%08x is now very dirty. Removing from dirty list...\n", jeb->offset));
 		list_del(&jeb->list);
 		D1(printk(KERN_DEBUG "...and adding to very_dirty_list\n"));
@@ -569,7 +608,7 @@
 	printk(KERN_DEBUG "erasing_size: %08x\n", c->erasing_size);
 	printk(KERN_DEBUG "bad_size: %08x\n", c->bad_size);
 	printk(KERN_DEBUG "sector_size: %08x\n", c->sector_size);
-	printk(KERN_DEBUG "jffs2_reserved_blocks size: %08x\n",c->sector_size * JFFS2_RESERVED_BLOCKS_WRITE);
+	printk(KERN_DEBUG "jffs2_reserved_blocks size: %08x\n",c->sector_size * c->resv_blocks_write);
 
 	if (c->nextblock) {
 		printk(KERN_DEBUG "nextblock: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
@@ -672,7 +711,7 @@
 
 		list_for_each(this, &c->erasable_pending_wbuf_list) {
 			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-			printk(KERN_DEBUG "erase_pending_wbuf_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
+			printk(KERN_DEBUG "erasable_pending_wbuf_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
 			       jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
 		}
 	}
diff -Nru a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
--- a/fs/jffs2/os-linux.h	Wed Oct 15 00:46:36 2003
+++ b/fs/jffs2/os-linux.h	Wed Oct 15 00:46:36 2003
@@ -1,13 +1,13 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2002 Red Hat, Inc.
+ * Copyright (C) 2002-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: os-linux.h,v 1.26 2003/05/16 18:45:25 dwmw2 Exp $
+ * $Id: os-linux.h,v 1.37 2003/10/11 11:47:23 dwmw2 Exp $
  *
  */
 
@@ -19,6 +19,9 @@
 #define os_to_jffs2_mode(x) (x)
 #define jffs2_to_os_mode(x) (x)
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,73)
+#define kstatfs statfs
+#endif
 
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
 #define JFFS2_INODE_INFO(i) (list_entry(i, struct jffs2_inode_info, vfs_inode))
@@ -68,7 +71,7 @@
 
 /* Hmmm. P'raps generic code should only ever see versions of signal
    functions which do the locking automatically? */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,40)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,40) && !defined(__rh_config_h__)
 #define current_sig_lock current->sigmask_lock
 #else
 #define current_sig_lock current->sighand->siglock
@@ -108,10 +111,14 @@
 
 #define jffs2_flash_write(c, ofs, len, retlen, buf) ((c)->mtd->write((c)->mtd, ofs, len, retlen, buf))
 #define jffs2_flash_read(c, ofs, len, retlen, buf) ((c)->mtd->read((c)->mtd, ofs, len, retlen, buf))
-#define jffs2_flush_wbuf(c, flag) do { ; } while(0)
+#define jffs2_flush_wbuf_pad(c) ({ (void)(c), 0; })
+#define jffs2_flush_wbuf_gc(c, i) ({ (void)(c), (void) i, 0; })
 #define jffs2_nand_read_failcnt(c,jeb) do { ; } while(0)
 #define jffs2_write_nand_badblock(c,jeb) do { ; } while(0)
-#define jffs2_flash_writev jffs2_flash_direct_writev
+#define jffs2_nand_flash_setup(c) (0)
+#define jffs2_nand_flash_cleanup(c) do {} while(0)
+#define jffs2_wbuf_dirty(c) (0)
+#define jffs2_flash_writev(a,b,c,d,e,f) jffs2_flash_direct_writev(a,b,c,d,e)
 #define jffs2_wbuf_timeout NULL
 #define jffs2_wbuf_process NULL
 
@@ -122,11 +129,11 @@
 
 #define jffs2_flash_write_oob(c, ofs, len, retlen, buf) ((c)->mtd->write_oob((c)->mtd, ofs, len, retlen, buf))
 #define jffs2_flash_read_oob(c, ofs, len, retlen, buf) ((c)->mtd->read_oob((c)->mtd, ofs, len, retlen, buf))
-
+#define jffs2_wbuf_dirty(c) (!!(c)->wbuf_len)
 struct kstatfs;
 
 /* wbuf.c */
-int jffs2_flash_writev(struct jffs2_sb_info *c, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen);
+int jffs2_flash_writev(struct jffs2_sb_info *c, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino);
 int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf);
 int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, u_char *buf);
 int jffs2_check_oob_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,int mode);
@@ -135,6 +142,8 @@
 int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 void jffs2_wbuf_timeout(unsigned long data);
 void jffs2_wbuf_process(void *data);
+int jffs2_nand_flash_setup(struct jffs2_sb_info *c);
+void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c);
 #endif /* NAND */
 
 /* background.c */
@@ -151,7 +160,6 @@
 extern struct inode_operations jffs2_file_inode_operations;
 extern struct address_space_operations jffs2_file_address_operations;
 int jffs2_fsync(struct file *, struct dentry *, int);
-int jffs2_setattr (struct dentry *dentry, struct iattr *iattr);
 int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg);
 int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg);
 int jffs2_readpage (struct file *, struct page *);
@@ -165,8 +173,10 @@
 extern struct inode_operations jffs2_symlink_inode_operations;
 
 /* fs.c */
+int jffs2_setattr (struct dentry *, struct iattr *);
 void jffs2_read_inode (struct inode *);
 void jffs2_clear_inode (struct inode *);
+void jffs2_dirty_inode(struct inode *inode);
 struct inode *jffs2_new_inode (struct inode *dir_i, int mode,
 			       struct jffs2_raw_inode *ri);
 int jffs2_statfs (struct super_block *, struct kstatfs *);
diff -Nru a/fs/jffs2/pushpull.h b/fs/jffs2/pushpull.h
--- a/fs/jffs2/pushpull.h	Wed Oct 15 00:46:35 2003
+++ b/fs/jffs2/pushpull.h	Wed Oct 15 00:46:35 2003
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001, 2002 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: pushpull.h,v 1.8 2002/05/20 14:56:38 dwmw2 Exp $
+ * $Id: pushpull.h,v 1.9 2003/10/04 08:33:06 dwmw2 Exp $
  *
  */
 
diff -Nru a/fs/jffs2/read.c b/fs/jffs2/read.c
--- a/fs/jffs2/read.c	Wed Oct 15 00:46:36 2003
+++ b/fs/jffs2/read.c	Wed Oct 15 00:46:36 2003
@@ -1,13 +1,13 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: read.c,v 1.31 2003/01/14 14:06:22 dwmw2 Exp $
+ * $Id: read.c,v 1.34 2003/10/04 08:33:06 dwmw2 Exp $
  *
  */
 
@@ -16,6 +16,7 @@
 #include <linux/crc32.h>
 #include <linux/pagemap.h>
 #include <linux/mtd/mtd.h>
+#include <linux/compiler.h>
 #include "nodelist.h"
 
 int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsigned char *buf, int ofs, int len)
@@ -165,7 +166,7 @@
 	/* Now we're pointing at the first frag which overlaps our page */
 	while(offset < end) {
 		D2(printk(KERN_DEBUG "jffs2_read_inode_range: offset %d, end %d\n", offset, end));
-		if (!frag || frag->ofs > offset) {
+		if (unlikely(!frag || frag->ofs > offset)) {
 			uint32_t holesize = end - offset;
 			if (frag) {
 				D1(printk(KERN_NOTICE "Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", f->inocache->ino, frag->ofs, offset));
@@ -177,13 +178,7 @@
 			buf += holesize;
 			offset += holesize;
 			continue;
-		} else if (frag->ofs < offset && (offset & (PAGE_CACHE_SIZE-1)) != 0) {
-			D1(printk(KERN_NOTICE "Eep. Overlap in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n",
-				  f->inocache->ino, frag->ofs, offset));
-			D1(jffs2_print_frag_list(f));
-			memset(buf, 0, end - offset);
-			return -EIO;
-		} else if (!frag->node) {
+		} else if (unlikely(!frag->node)) {
 			uint32_t holeend = min(end, frag->ofs + frag->size);
 			D1(printk(KERN_DEBUG "Filling frag hole from %d-%d (frag 0x%x 0x%x)\n", offset, holeend, frag->ofs, frag->ofs + frag->size));
 			memset(buf, 0, holeend - offset);
diff -Nru a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
--- a/fs/jffs2/readinode.c	Wed Oct 15 00:46:35 2003
+++ b/fs/jffs2/readinode.c	Wed Oct 15 00:46:35 2003
@@ -1,13 +1,13 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: readinode.c,v 1.106 2003/05/14 06:53:26 dwmw2 Exp $
+ * $Id: readinode.c,v 1.107 2003/10/04 08:33:06 dwmw2 Exp $
  *
  */
 
diff -Nru a/fs/jffs2/scan.c b/fs/jffs2/scan.c
--- a/fs/jffs2/scan.c	Wed Oct 15 00:46:37 2003
+++ b/fs/jffs2/scan.c	Wed Oct 15 00:46:37 2003
@@ -1,13 +1,13 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: scan.c,v 1.100 2003/06/05 14:42:24 dwmw2 Exp $
+ * $Id: scan.c,v 1.104 2003/10/11 14:52:48 dwmw2 Exp $
  *
  */
 #include <linux/kernel.h>
@@ -65,6 +65,16 @@
 #define BLK_STATE_ALLDIRTY	4
 #define BLK_STATE_BADBLOCK	5
 
+static inline int min_free(struct jffs2_sb_info *c)
+{
+	uint32_t min = 2 * sizeof(struct jffs2_raw_inode);
+#ifdef CONFIG_JFFS2_FS_NAND
+	if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize)
+		return c->wbuf_pagesize;
+#endif
+	return min;
+
+}
 int jffs2_scan_medium(struct jffs2_sb_info *c)
 {
 	int i, ret;
@@ -106,7 +116,7 @@
 		ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), buf_size);
 
 		if (ret < 0)
-			return ret;
+			goto out;
 
 		ACCT_PARANOIA_CHECK(jeb);
 
@@ -151,8 +161,7 @@
                            Later when we do snapshots, this must be the most recent block,
                            not the one with most free space.
                         */
-                        if (jeb->free_size > 2*sizeof(struct jffs2_raw_inode) && 
-			    (jffs2_can_mark_obsolete(c) || jeb->free_size > c->wbuf_pagesize) &&
+                        if (jeb->free_size > min_free(c) && 
 			    (!c->nextblock || c->nextblock->free_size < jeb->free_size)) {
                                 /* Better candidate for the next writes to go to */
                                 if (c->nextblock) {
@@ -210,7 +219,7 @@
 		c->dirty_size -= c->nextblock->dirty_size;
 		c->nextblock->dirty_size = 0;
 	}
-
+#ifdef CONFIG_JFFS2_FS_NAND
 	if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size & (c->wbuf_pagesize-1))) {
 		/* If we're going to start writing into a block which already 
 		   contains data, and the end of the data isn't page-aligned,
@@ -226,21 +235,25 @@
 		c->nextblock->free_size -= skip;
 		c->free_size -= skip;
 	}
+#endif
 	if (c->nr_erasing_blocks) {
 		if ( !c->used_size && ((empty_blocks+bad_blocks)!= c->nr_blocks || bad_blocks == c->nr_blocks) ) {
 			printk(KERN_NOTICE "Cowardly refusing to erase blocks on filesystem with no valid JFFS2 nodes\n");
 			printk(KERN_NOTICE "empty_blocks %d, bad_blocks %d, c->nr_blocks %d\n",empty_blocks,bad_blocks,c->nr_blocks);
-			return -EIO;
+			ret = -EIO;
+			goto out;
 		}
 		jffs2_erase_pending_trigger(c);
 	}
+	ret = 0;
+ out:
 	if (buf_size)
 		kfree(flashbuf);
 #ifndef __ECOS
 	else 
 		c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size);
 #endif
-	return 0;
+	return ret;
 }
 
 static int jffs2_fill_scan_buf (struct jffs2_sb_info *c, unsigned char *buf,
@@ -672,6 +685,7 @@
 			       ofs, je32_to_cpu(ri->node_crc), crc);
 			/* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */
 			DIRTY_SPACE(PAD(je32_to_cpu(ri->totlen)));
+			jffs2_free_raw_node_ref(raw);
 			return 0;
 		}
 		ic = jffs2_scan_make_ino_cache(c, ino);
diff -Nru a/fs/jffs2/super.c b/fs/jffs2/super.c
--- a/fs/jffs2/super.c	Wed Oct 15 00:46:36 2003
+++ b/fs/jffs2/super.c	Wed Oct 15 00:46:36 2003
@@ -1,13 +1,13 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: super.c,v 1.79 2003/05/27 22:35:42 dwmw2 Exp $
+ * $Id: super.c,v 1.90 2003/10/11 11:47:23 dwmw2 Exp $
  *
  */
 
@@ -26,8 +26,7 @@
 #include <linux/namei.h>
 #include "nodelist.h"
 
-void jffs2_put_super (struct super_block *);
-
+static void jffs2_put_super(struct super_block *);
 
 static kmem_cache_t *jffs2_inode_cachep;
 
@@ -65,7 +64,8 @@
 	.write_super =	jffs2_write_super,
 	.statfs =	jffs2_statfs,
 	.remount_fs =	jffs2_remount_fs,
-	.clear_inode =	jffs2_clear_inode
+	.clear_inode =	jffs2_clear_inode,
+	.dirty_inode =	jffs2_dirty_inode,
 };
 
 static int jffs2_sb_compare(struct super_block *sb, void *data)
@@ -136,8 +136,7 @@
 		/* Failure case... */
 		up_write(&sb->s_umount);
 		deactivate_super(sb);
-		sb = ERR_PTR(ret);
-		goto out_put1;
+		return ERR_PTR(ret);
 	}
 
 	sb->s_flags |= MS_ACTIVE;
@@ -145,7 +144,6 @@
 
  out_put:
 	kfree(c);
- out_put1:
 	put_mtd_device(mtd);
 
 	return sb;
@@ -253,8 +251,7 @@
 	return ERR_PTR(err);
 }
 
-
-void jffs2_put_super (struct super_block *sb)
+static void jffs2_put_super (struct super_block *sb)
 {
 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
 
@@ -263,13 +260,12 @@
 	if (!(sb->s_flags & MS_RDONLY))
 		jffs2_stop_garbage_collect_thread(c);
 	down(&c->alloc_sem);
-	jffs2_flush_wbuf(c, 1);
+	jffs2_flush_wbuf_pad(c);
 	up(&c->alloc_sem);
 	jffs2_free_ino_caches(c);
 	jffs2_free_raw_node_refs(c);
 	kfree(c->blocks);
-	if (c->wbuf)
-		kfree(c->wbuf);
+	jffs2_nand_flash_cleanup(c);
 	kfree(c->inocache_list);
 	if (c->mtd->sync)
 		c->mtd->sync(c->mtd);
@@ -284,7 +280,7 @@
 	put_mtd_device(c->mtd);
 	kfree(c);
 }
- 
+
 static struct file_system_type jffs2_fs_type = {
 	.owner =	THIS_MODULE,
 	.name =		"jffs2",
@@ -292,13 +288,15 @@
 	.kill_sb =	jffs2_kill_sb,
 };
 
-
-
 static int __init init_jffs2_fs(void)
 {
 	int ret;
 
-	printk(KERN_INFO "JFFS2 version 2.1. (C) 2001, 2002 Red Hat, Inc.\n");
+	printk(KERN_INFO "JFFS2 version 2.2."
+#ifdef CONFIG_FS_JFFS2_NAND
+	       " (NAND)"
+#endif
+	       " (C) 2001-2003 Red Hat, Inc.\n");
 
 	jffs2_inode_cachep = kmem_cache_create("jffs2_i",
 					     sizeof(struct jffs2_inode_info),
diff -Nru a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c
--- a/fs/jffs2/symlink.c	Wed Oct 15 00:46:35 2003
+++ b/fs/jffs2/symlink.c	Wed Oct 15 00:46:35 2003
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001, 2002 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: symlink.c,v 1.11 2002/07/23 17:00:45 dwmw2 Exp $
+ * $Id: symlink.c,v 1.12 2003/10/04 08:33:07 dwmw2 Exp $
  *
  */
 
diff -Nru a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
--- a/fs/jffs2/wbuf.c	Wed Oct 15 00:46:36 2003
+++ b/fs/jffs2/wbuf.c	Wed Oct 15 00:46:36 2003
@@ -1,13 +1,13 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: wbuf.c,v 1.30 2003/02/19 17:48:49 gleixner Exp $
+ * $Id: wbuf.c,v 1.53 2003/10/11 11:46:09 dwmw2 Exp $
  *
  */
 
@@ -18,28 +18,86 @@
 #include <linux/mtd/nand.h>
 #include "nodelist.h"
 
+/* For testing write failures */
+#undef BREAKME
+#undef BREAKMEHEADER
+
+#ifdef BREAKME
+static unsigned char *brokenbuf;
+#endif
+
 /* max. erase failures before we mark a block bad */
 #define MAX_ERASE_FAILURES 	5
 
 /* two seconds timeout for timed wbuf-flushing */
 #define WBUF_FLUSH_TIMEOUT	2 * HZ
 
-#define JFFS2_OOB_ECCPOS0		0
-#define JFFS2_OOB_ECCPOS1		1
-#define JFFS2_OOB_ECCPOS2		2
-#define JFFS2_OOB_ECCPOS3		3
-#define JFFS2_OOB_ECCPOS4		6
-#define JFFS2_OOB_ECCPOS5		7
+struct jffs2_inodirty {
+	uint32_t ino;
+	struct jffs2_inodirty *next;
+};
 
-#define NAND_JFFS2_OOB8_FSDAPOS		6
-#define NAND_JFFS2_OOB16_FSDAPOS	8
-#define NAND_JFFS2_OOB8_FSDALEN		2
-#define NAND_JFFS2_OOB16_FSDALEN	8
+static struct jffs2_inodirty inodirty_nomem;
 
-struct nand_oobinfo jffs2_oobinfo = {
-	.useecc = 1,
-	.eccpos = {JFFS2_OOB_ECCPOS0, JFFS2_OOB_ECCPOS1, JFFS2_OOB_ECCPOS2, JFFS2_OOB_ECCPOS3, JFFS2_OOB_ECCPOS4, JFFS2_OOB_ECCPOS5}
-};
+static int jffs2_wbuf_pending_for_ino(struct jffs2_sb_info *c, uint32_t ino)
+{
+	struct jffs2_inodirty *this = c->wbuf_inodes;
+
+	/* If a malloc failed, consider _everything_ dirty */
+	if (this == &inodirty_nomem)
+		return 1;
+
+	/* If ino == 0, _any_ non-GC writes mean 'yes' */
+	if (this && !ino)
+		return 1;
+
+	/* Look to see if the inode in question is pending in the wbuf */
+	while (this) {
+		if (this->ino == ino)
+			return 1;
+		this = this->next;
+	}
+	return 0;
+}
+
+static void jffs2_clear_wbuf_ino_list(struct jffs2_sb_info *c)
+{
+	struct jffs2_inodirty *this;
+
+	this = c->wbuf_inodes;
+
+	if (this != &inodirty_nomem) {
+		while (this) {
+			struct jffs2_inodirty *next = this->next;
+			kfree(this);
+			this = next;
+		}
+	}
+	c->wbuf_inodes = NULL;
+}
+
+static void jffs2_wbuf_dirties_inode(struct jffs2_sb_info *c, uint32_t ino)
+{
+	struct jffs2_inodirty *new;
+
+	/* Mark the superblock dirty so that kupdated will flush... */
+	OFNI_BS_2SFFJ(c)->s_dirt = 1;
+
+	if (jffs2_wbuf_pending_for_ino(c, ino))
+		return;
+
+	new = kmalloc(sizeof(*new), GFP_KERNEL);
+	if (!new) {
+		D1(printk(KERN_DEBUG "No memory to allocate inodirty. Fallback to all considered dirty\n"));
+		jffs2_clear_wbuf_ino_list(c);
+		c->wbuf_inodes = &inodirty_nomem;
+		return;
+	}
+	new->ino = ino;
+	new->next = c->wbuf_inodes;
+	c->wbuf_inodes = new;
+	return;
+}
 
 static inline void jffs2_refile_wbuf_blocks(struct jffs2_sb_info *c)
 {
@@ -70,74 +128,267 @@
 	}
 }
 
-/* 
-*	Timed flushing of wbuf. If we have no consecutive write to wbuf, within	
-*	the specified time, we flush the contents with padding !
-*/
-void jffs2_wbuf_timeout (unsigned long data)
-{
-	struct jffs2_sb_info *c = (struct jffs2_sb_info *) data;
-	/* 
-	* Wake up the flush process, we need process context to have the right 
-	* to sleep on flash write
-	*/
-	D1(printk(KERN_DEBUG "jffs2_wbuf_timeout(): timer expired\n"));
-	schedule_work(&c->wbuf_task);
-}
+/* Recover from failure to write wbuf. Recover the nodes up to the
+ * wbuf, not the one which we were starting to try to write. */
 
-/*
-*	Process for timed wbuf flush
-*
-*	FIXME What happens, if we have a write failure there ????
-*/
-void jffs2_wbuf_process (void *data)
+static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
 {
-	struct jffs2_sb_info *c = (struct jffs2_sb_info *) data;	
-	
-	D1(printk(KERN_DEBUG "jffs2_wbuf_process() entered\n"));
-	
-	/* Check, if the timer is active again */
-	if (timer_pending (&c->wbuf_timer)) {
-		D1(printk (KERN_DEBUG "Nothing to do, timer is active again\n"));
+	struct jffs2_eraseblock *jeb, *new_jeb;
+	struct jffs2_raw_node_ref **first_raw, **raw;
+	size_t retlen;
+	int ret;
+	unsigned char *buf;
+	uint32_t start, end, ofs, len;
+
+	spin_lock(&c->erase_completion_lock);
+
+	jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
+
+	D1(printk("About to refile bad block at %08x\n", jeb->offset));
+
+	D2(jffs2_dump_block_lists(c));
+	/* File the existing block on the bad_used_list.... */
+	if (c->nextblock == jeb)
+		c->nextblock = NULL;
+	else /* Not sure this should ever happen... need more coffee */
+		list_del(&jeb->list);
+	if (jeb->first_node) {
+		D1(printk("Refiling block at %08x to bad_used_list\n", jeb->offset));
+		list_add(&jeb->list, &c->bad_used_list);
+	} else {
+		BUG();
+		/* It has to have had some nodes or we couldn't be here */
+		D1(printk("Refiling block at %08x to erase_pending_list\n", jeb->offset));
+		list_add(&jeb->list, &c->erase_pending_list);
+		c->nr_erasing_blocks++;
+		jffs2_erase_pending_trigger(c);
+	}
+	D2(jffs2_dump_block_lists(c));
+
+	/* Adjust its size counts accordingly */
+	c->wasted_size += jeb->free_size;
+	c->free_size -= jeb->free_size;
+	jeb->wasted_size += jeb->free_size;
+	jeb->free_size = 0;
+
+	ACCT_SANITY_CHECK(c,jeb);
+	D1(ACCT_PARANOIA_CHECK(jeb));
+
+	/* Find the first node to be recovered, by skipping over every
+	   node which ends before the wbuf starts, or which is obsolete. */
+	first_raw = &jeb->first_node;
+	while (*first_raw && 
+	       (ref_obsolete(*first_raw) ||
+		(ref_offset(*first_raw) + (*first_raw)->totlen) < c->wbuf_ofs)) {
+		D1(printk(KERN_DEBUG "Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n",
+			  ref_offset(*first_raw), ref_flags(*first_raw),
+			  (ref_offset(*first_raw) + (*first_raw)->totlen),
+			  c->wbuf_ofs));
+		first_raw = &(*first_raw)->next_phys;
+	}
+
+	if (!*first_raw) {
+		/* All nodes were obsolete. Nothing to recover. */
+		D1(printk(KERN_DEBUG "No non-obsolete nodes to be recovered. Just filing block bad\n"));
+		spin_unlock(&c->erase_completion_lock);
 		return;
 	}
 
-	if (down_trylock(&c->alloc_sem)) {
-		/* If someone else has the alloc_sem, they're about to
-		   write anyway. So no need to waste space by
-		   padding */
-		D1(printk (KERN_DEBUG "jffs2_wbuf_process() alloc_sem already occupied\n"));
-		return;
-	}	
+	start = ref_offset(*first_raw);
+	end = ref_offset(*first_raw) + (*first_raw)->totlen;
 
-	D1(printk (KERN_DEBUG "jffs2_wbuf_process() alloc_sem got\n"));
+	/* Find the last node to be recovered */
+	raw = first_raw;
+	while ((*raw)) {
+		if (!ref_obsolete(*raw))
+			end = ref_offset(*raw) + (*raw)->totlen;
 
-	if (!c->nextblock) {
-		D1(printk(KERN_DEBUG "jffs2_wbuf_process(): nextblock NULL, nothing to do\n"));
-		if (c->wbuf_len) {
-			printk(KERN_WARNING "jffs2_wbuf_process(): c->wbuf_len is 0x%03x but nextblock is NULL!\n", c->wbuf_len);
-			up(&c->alloc_sem);
-			BUG();
+		raw = &(*raw)->next_phys;
+	}
+	spin_unlock(&c->erase_completion_lock);
+
+	D1(printk(KERN_DEBUG "wbuf recover %08x-%08x\n", start, end));
+
+	buf = NULL;
+	if (start < c->wbuf_ofs) {
+		/* First affected node was already partially written.
+		 * Attempt to reread the old data into our buffer. */
+
+		buf = kmalloc(end - start, GFP_KERNEL);
+		if (!buf) {
+			printk(KERN_CRIT "Malloc failure in wbuf recovery. Data loss ensues.\n");
+
+			goto read_failed;
 		}
+
+		/* Do the read... */
+		ret = c->mtd->read_ecc(c->mtd, start, c->wbuf_ofs - start, &retlen, buf, NULL, c->oobinfo);
+		if (ret == -EIO && retlen == c->wbuf_ofs - start) {
+			/* ECC recovered */
+			ret = 0;
+		}
+		if (ret || retlen != c->wbuf_ofs - start) {
+			printk(KERN_CRIT "Old data are already lost in wbuf recovery. Data loss ensues.\n");
+
+			kfree(buf);
+			buf = NULL;
+		read_failed:
+			first_raw = &(*first_raw)->next_phys;
+			/* If this was the only node to be recovered, give up */
+			if (!(*first_raw))
+				return;
+
+			/* It wasn't. Go on and try to recover nodes complete in the wbuf */
+			start = ref_offset(*first_raw);
+		} else {
+			/* Read succeeded. Copy the remaining data from the wbuf */
+			memcpy(buf + (c->wbuf_ofs - start), c->wbuf, end - c->wbuf_ofs);
+		}
+	}
+	/* OK... we're to rewrite (end-start) bytes of data from first_raw onwards.
+	   Either 'buf' contains the data, or we find it in the wbuf */
+
+
+	/* ... and get an allocation of space from a shiny new block instead */
+	ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len);
+	if (ret) {
+		printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n");
+		if (buf)
+			kfree(buf);
 		return;
 	}
-	
-	
-	/* if !c->nextblock then the tail will have got flushed from
-	   jffs2_do_reserve_space() anyway. */
-	if(c->nextblock)
-		jffs2_flush_wbuf(c, 2); /* pad and adjust nextblock */
+	if (end-start >= c->wbuf_pagesize) {
+		/* Need to do another write immediately. This, btw,
+		 means that we'll be writing from 'buf' and not from
+		 the wbuf. Since if we're writing from the wbuf there
+		 won't be more than a wbuf full of data, now will
+		 there? :) */
+
+		uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize);
+
+		D1(printk(KERN_DEBUG "Write 0x%x bytes at 0x%08x in wbuf recover\n",
+			  towrite, ofs));
+	  
+#ifdef BREAKMEHEADER
+		static int breakme;
+		if (breakme++ == 20) {
+			printk(KERN_NOTICE "Faking write error at 0x%08x\n", ofs);
+			breakme = 0;
+			c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen,
+					  brokenbuf, NULL, c->oobinfo);
+			ret = -EIO;
+		} else
+#endif
+			ret = c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen,
+						buf, NULL, c->oobinfo);
+
+		if (ret || retlen != towrite) {
+			/* Argh. We tried. Really we did. */
+			printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n");
+			kfree(buf);
+
+			if (retlen) {
+				struct jffs2_raw_node_ref *raw2;
+
+				raw2 = jffs2_alloc_raw_node_ref();
+				if (!raw2)
+					return;
+
+				raw2->flash_offset = ofs | REF_OBSOLETE;
+				raw2->totlen = (*first_raw)->totlen;
+				raw2->next_phys = NULL;
+				raw2->next_in_ino = NULL;
 
-	up(&c->alloc_sem);
-}
+				jffs2_add_physical_node_ref(c, raw2);
+			}
+			return;
+		}
+		printk(KERN_NOTICE "Recovery of wbuf succeeded to %08x\n", ofs);
+
+		c->wbuf_len = (end - start) - towrite;
+		c->wbuf_ofs = ofs + towrite;
+		memcpy(c->wbuf, buf + towrite, c->wbuf_len);
+		/* Don't muck about with c->wbuf_inodes. False positives are harmless. */
 
+		kfree(buf);
+	} else {
+		/* OK, now we're left with the dregs in whichever buffer we're using */
+		if (buf) {
+			memcpy(c->wbuf, buf, end-start);
+			kfree(buf);
+		} else {
+			memmove(c->wbuf, c->wbuf + (start - c->wbuf_ofs), end - start);
+		}
+		c->wbuf_ofs = ofs;
+		c->wbuf_len = end - start;
+	}
+
+	/* Now sort out the jffs2_raw_node_refs, moving them from the old to the next block */
+	new_jeb = &c->blocks[ofs / c->sector_size];
+
+	spin_lock(&c->erase_completion_lock);
+	if (new_jeb->first_node) {
+		/* Odd, but possible with ST flash later maybe */
+		new_jeb->last_node->next_phys = *first_raw;
+	} else {
+		new_jeb->first_node = *first_raw;
+	}
+
+	raw = first_raw;
+	while (*raw) {
+		D1(printk(KERN_DEBUG "Refiling block of %08x at %08x(%d) to %08x\n",
+			  (*raw)->totlen, ref_offset(*raw), ref_flags(*raw), ofs));
+
+		if (ref_obsolete(*raw)) {
+			/* Shouldn't really happen much */
+			new_jeb->dirty_size += (*raw)->totlen;
+			new_jeb->free_size -= (*raw)->totlen;
+			c->dirty_size += (*raw)->totlen;
+		} else {
+			new_jeb->used_size += (*raw)->totlen;
+			new_jeb->free_size -= (*raw)->totlen;
+			jeb->dirty_size += (*raw)->totlen;
+			jeb->used_size  -= (*raw)->totlen;
+			c->dirty_size += (*raw)->totlen;
+		}
+		c->free_size -= (*raw)->totlen;
+		(*raw)->flash_offset = ofs | ref_flags(*raw);
+		ofs += (*raw)->totlen;
+		new_jeb->last_node = *raw;
+
+		raw = &(*raw)->next_phys;
+	}
+
+	/* Fix up the original jeb now it's on the bad_list */
+	*first_raw = NULL;
+	if (first_raw == &jeb->first_node) {
+		jeb->last_node = NULL;
+		D1(printk(KERN_DEBUG "Failing block at %08x is now empty. Moving to erase_pending_list\n", jeb->offset));
+		list_del(&jeb->list);
+		list_add(&jeb->list, &c->erase_pending_list);
+		c->nr_erasing_blocks++;
+		jffs2_erase_pending_trigger(c);
+	}
+	else
+		jeb->last_node = container_of(first_raw, struct jffs2_raw_node_ref, next_phys);
+
+	ACCT_SANITY_CHECK(c,jeb);
+        D1(ACCT_PARANOIA_CHECK(jeb));
+
+	ACCT_SANITY_CHECK(c,new_jeb);
+        D1(ACCT_PARANOIA_CHECK(new_jeb));
+
+	spin_unlock(&c->erase_completion_lock);
+
+	D1(printk(KERN_DEBUG "wbuf recovery completed OK\n"));
+}
 
 /* Meaning of pad argument:
    0: Do not pad. Probably pointless - we only ever use this when we can't pad anyway.
    1: Pad, do not adjust nextblock free_size
    2: Pad, adjust nextblock free_size
 */
-int jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
+static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
 {
 	int ret;
 	size_t retlen;
@@ -153,9 +404,6 @@
 		BUG();
 	}
 
-	/* delete a eventually started timed wbuf flush */
-	del_timer_sync(&c->wbuf_timer);
-
 	if(!c->wbuf || !c->wbuf_len)
 		return 0;
 
@@ -179,28 +427,30 @@
 	/* else jffs2_flash_writev has actually filled in the rest of the
 	   buffer for us, and will deal with the node refs etc. later. */
 	
-	ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, &jffs2_oobinfo);
-	
+#ifdef BREAKME
+	static int breakme;
+	if (breakme++ == 20) {
+		printk(KERN_NOTICE "Faking write error at 0x%08x\n", c->wbuf_ofs);
+		breakme = 0;
+		c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize,
+					&retlen, brokenbuf, NULL, c->oobinfo);
+		ret = -EIO;
+	} else 
+#endif
+	ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, c->oobinfo);
+
+
 	if (ret || retlen != c->wbuf_pagesize) {
 		if (ret)
-			printk(KERN_CRIT "jffs2_flush_wbuf(): Write failed with %d\n",ret);
-		else
-			printk(KERN_CRIT "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n",
+			printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n",ret);
+		else {
+			printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n",
 				retlen, c->wbuf_pagesize);
-			
-		ret = -EIO;		
-		/* CHECKME NAND 
-		   So that the caller knows what happened. If
-		   we were called from jffs2_flash_writev(), it'll
-		   know to return failure and _its_ caller will
-		   try again. writev gives back to jffs2_write_xxx 
-		   in write.c. There are the real fixme's
-		 */
+			ret = -EIO;
+		}
+
+		jffs2_wbuf_recover(c);
 
-		/*  FIXME NAND
-		   If we were called from GC or fsync, there's no repair kit yet
-		*/
-		    
 		return ret; 
 	}
 
@@ -230,18 +480,71 @@
 	/* Stick any now-obsoleted blocks on the erase_pending_list */
 	spin_lock(&c->erase_completion_lock);
 	jffs2_refile_wbuf_blocks(c);
+	jffs2_clear_wbuf_ino_list(c);
 	spin_unlock(&c->erase_completion_lock);
 
 	memset(c->wbuf,0xff,c->wbuf_pagesize);
-	/* adjust write buffer offset, else we get a non contigous write bug */
-	c->wbuf_ofs+= c->wbuf_pagesize;
+	/* adjust write buffer offset, else we get a non contiguous write bug */
+	c->wbuf_ofs += c->wbuf_pagesize;
 	c->wbuf_len = 0;
 	return 0;
 }
 
+/* Trigger garbage collection to flush the write-buffer. 
+   If ino arg is zero, do it if _any_ real (i.e. not GC) writes are
+   outstanding. If ino arg non-zero, do it only if a write for the 
+   given inode is outstanding. */
+int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
+{
+	uint32_t old_wbuf_ofs;
+	uint32_t old_wbuf_len;
+	int ret = 0;
+
+	D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() called for ino #%u...\n", ino));
+
+	down(&c->alloc_sem);
+	if (!jffs2_wbuf_pending_for_ino(c, ino)) {
+		D1(printk(KERN_DEBUG "Ino #%d not pending in wbuf. Returning\n", ino));
+		up(&c->alloc_sem);
+		return 0;
+	}
+
+	old_wbuf_ofs = c->wbuf_ofs;
+	old_wbuf_len = c->wbuf_len;
+
+	while (old_wbuf_len &&
+	       old_wbuf_ofs == c->wbuf_ofs) {
+
+		up(&c->alloc_sem);
+
+		D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() calls gc pass\n"));
+
+		ret = jffs2_garbage_collect_pass(c);
+		if (ret) {
+			/* GC failed. Flush it with padding instead */
+			down(&c->alloc_sem);
+			ret = __jffs2_flush_wbuf(c, 2);
+			break;
+		}
+		down(&c->alloc_sem);
+	}
+
+	D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() ends...\n"));
+
+	up(&c->alloc_sem);
+	return ret;
+}
+
+/* Pad write-buffer to end and write it, wasting space. */
+int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c)
+{
+	return __jffs2_flush_wbuf(c, 1);
+}
+
+
 #define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) )
 #define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) )
-int jffs2_flash_writev(struct jffs2_sb_info *c, const struct iovec *invecs, unsigned long count, loff_t to, size_t *retlen)
+int jffs2_flash_writev(struct jffs2_sb_info *c, const struct iovec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino)
 {
 	struct iovec outvecs[3];
 	uint32_t totlen = 0;
@@ -275,7 +578,7 @@
 		/* It's a write to a new block */
 		if (c->wbuf_len) {
 			D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx causes flush of wbuf at 0x%08x\n", (unsigned long)to, c->wbuf_ofs));
-			ret = jffs2_flush_wbuf(c, 1);
+			ret = jffs2_flush_wbuf_pad(c);
 			if (ret) {
 				/* the underlying layer has to check wbuf_len to do the cleanup */
 				D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret));
@@ -341,16 +644,18 @@
 		}			
 		
 		/* write buffer is full, flush buffer */
-		ret = jffs2_flush_wbuf(c, 0);
+		ret = __jffs2_flush_wbuf(c, 0);
 		if (ret) {
 			/* the underlying layer has to check wbuf_len to do the cleanup */
 			D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret));
+			/* Retlen zero to make sure our caller doesn't mark the space dirty.
+			   We've already done everything that's necessary */
 			*retlen = 0;
 			return ret;
 		}
 		outvec_to += donelen;
 		c->wbuf_ofs = outvec_to;
-		
+
 		/* All invecs done ? */
 		if (invec == count)
 			goto alldone;
@@ -396,7 +701,7 @@
 		outvecs[splitvec].iov_len = split_ofs;
 
 		/* We did cross a page boundary, so we write some now */
-		ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, &jffs2_oobinfo); 
+		ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo); 
 		if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) {
 			/* At this point we have no problem,
 			   c->wbuf is empty. 
@@ -433,13 +738,14 @@
 	}
 	c->wbuf_len = wbuf_ptr - c->wbuf;
 
-alldone:	
+	/* If there's a remainder in the wbuf and it's a non-GC write,
+	   remember that the wbuf affects this ino */
+alldone:
 	*retlen = donelen;
-	/* Setup timed wbuf flush, if buffer len != 0 */
-	if (c->wbuf_len) {
-		D1(printk (KERN_DEBUG "jffs2_flash_writev: mod wbuf_timer\n"));	
-		mod_timer(&c->wbuf_timer, jiffies + WBUF_FLUSH_TIMEOUT);
-	}
+
+	if (c->wbuf_len && ino)
+		jffs2_wbuf_dirties_inode(c, ino);
+
 	return 0;
 }
 
@@ -456,7 +762,7 @@
 
 	vecs[0].iov_base = (unsigned char *) buf;
 	vecs[0].iov_len = len;
-	return jffs2_flash_writev(c, vecs, 1, ofs, retlen);
+	return jffs2_flash_writev(c, vecs, 1, ofs, retlen, 0);
 }
 
 /*
@@ -469,7 +775,7 @@
 
 	/* Read flash */
 	if (!jffs2_can_mark_obsolete(c)) {
-		ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, &jffs2_oobinfo);
+		ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo);
 
 		if ( (ret == -EIO) && (*retlen == len) ) {
 			printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n",
@@ -525,22 +831,12 @@
 {
 	unsigned char *buf;
 	int 	ret = 0;
-	int	i,len,cnt,page;
+	int	i,len,page;
 	size_t  retlen;
-	int	fsdata_pos,badblock_pos,oob_size;
+	int	oob_size;
 
 	oob_size = c->mtd->oobsize;
 
-	switch(c->mtd->ecctype) {
-	case MTD_ECC_SW:		
-		fsdata_pos = (c->wbuf_pagesize == 256) ? NAND_JFFS2_OOB8_FSDAPOS : NAND_JFFS2_OOB16_FSDAPOS;
-		badblock_pos = NAND_BADBLOCK_POS;
-		break;
-	default:
-		D1(printk(KERN_WARNING "jffs2_write_oob_empty(): Invalid ECC type\n"));
-		return -EINVAL;
-	}	
-
 	/* allocate a buffer for all oob data in this sector */
 	len = 4 * oob_size;
 	buf = kmalloc(len, GFP_KERNEL);
@@ -568,19 +864,22 @@
 	/* Special check for first two pages */
 	for (page = 0; page < 2 * oob_size; page += oob_size) {
 		/* Check for bad block marker */
-		if (buf[page+badblock_pos] != 0xff) {
+		if (buf[page+c->badblock_pos] != 0xff) {
 			D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Bad or failed block at %08x\n",jeb->offset));
 			/* Return 2 for bad and 3 for failed block 
 			   bad goes to list_bad and failed to list_erase */
 			ret = (!page) ? 2 : 3;
 			goto out;
 		}
-		cnt = oob_size;
-		if (mode)
-			cnt -= fsdata_pos;
-		for(i = 0; i < cnt ; i+=sizeof(unsigned short)) {
-			unsigned short dat = *(unsigned short *)(&buf[page+i]);
-			if(dat != 0xffff) {
+		for(i = 0; i < oob_size ; i++) {
+			/* Yeah, we know about the cleanmarker. */
+			if (mode && i >= c->fsdata_pos && 
+			    i < c->fsdata_pos+c->fsdata_len)
+				continue;
+
+			if (buf[page+i] != 0xFF) {
+				D2(printk(KERN_DEBUG "Found %02x at %x in OOB for %08x\n",
+					  buf[page+i], page+i, jeb->offset));
 				ret = 1; 
 				goto out;
 			}
@@ -617,23 +916,11 @@
 	unsigned char *p;
 	int ret, i, cnt, retval = 0;
 	size_t retlen, offset;
-	int fsdata_pos, fsdata_len, oob_size, badblock_pos;
+	int oob_size;
 
 	offset = jeb->offset;
 	oob_size = c->mtd->oobsize;
 
-	switch (c->mtd->ecctype) {
-	case MTD_ECC_SW:
-		fsdata_pos = (c->wbuf_pagesize == 256) ? NAND_JFFS2_OOB8_FSDAPOS : NAND_JFFS2_OOB16_FSDAPOS;
-		fsdata_len = (c->wbuf_pagesize == 256) ? NAND_JFFS2_OOB8_FSDALEN : NAND_JFFS2_OOB16_FSDALEN;
-		badblock_pos = NAND_BADBLOCK_POS;
-		break;
-	default:
-		D1 (printk (KERN_WARNING "jffs2_write_nand_cleanmarker(): Invalid ECC type\n"));
-		return -EINVAL;
-	}
-
-
 	/* Loop through the physical blocks */
 	for (cnt = 0; cnt < (c->sector_size / c->mtd->erasesize); cnt++) {
 		/*
@@ -653,14 +940,15 @@
 		}
 
 		/* Check for bad block marker */
-		if (buf[badblock_pos] != 0xff) {
-			D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Bad block at %08x\n", jeb->offset));
+		if (buf[c->badblock_pos] != 0xff) {
+			D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Bad block at %08x (has %02x %02x in badblock_pos %d\n",
+				    jeb->offset, buf[c->badblock_pos],  buf[c->badblock_pos + oob_size], c->badblock_pos));
 			return 2;
 		}
 
 		/* Check for failure counter in the second page */
-		if (buf[badblock_pos + oob_size] != 0xff) {
-			D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Block marked as failed at %08x, fail count:%d\n", jeb->offset, buf[badblock_pos + oob_size]));
+		if (buf[c->badblock_pos + oob_size] != 0xff) {
+			D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Block marked as failed at %08x, fail count:%d\n", jeb->offset, buf[c->badblock_pos + oob_size]));
 			return 3;
 		}
 
@@ -671,12 +959,19 @@
 			n.totlen = cpu_to_je32 (8);
 			p = (unsigned char *) &n;
 
-			for (i = 0; i < fsdata_len; i++) {
-				if (buf[fsdata_pos + i] != p[i]) {
-					D2 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Cleanmarker node not detected in block at %08x\n", jeb->offset));
+			for (i = 0; i < c->fsdata_len; i++) {
+				if (buf[c->fsdata_pos + i] != p[i]) {
 					retval = 1;
 				}
 			}
+			D1(if (retval == 1) {
+				printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Cleanmarker node not detected in block at %08x\n", jeb->offset);
+				printk(KERN_WARNING "OOB at %08x was ", offset);
+				for (i=0; i < oob_size; i++) {
+					printk("%02x ", buf[i]);
+				}
+				printk("\n");
+			})
 		}
 		offset += c->mtd->erasesize;
 	}
@@ -687,31 +982,20 @@
 {
 	struct 	jffs2_unknown_node n;
 	int 	ret;
-	int	fsdata_pos,fsdata_len;
 	size_t 	retlen;
 
-	switch(c->mtd->ecctype) {
-	case MTD_ECC_SW:	
-		fsdata_pos = (c->wbuf_pagesize == 256) ? NAND_JFFS2_OOB8_FSDAPOS : NAND_JFFS2_OOB16_FSDAPOS;
-		fsdata_len = (c->wbuf_pagesize == 256) ? NAND_JFFS2_OOB8_FSDALEN : NAND_JFFS2_OOB16_FSDALEN;
-		break;
-	default:
-		D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Invalid ECC type\n"));
-		return -EINVAL;
-	}	
-	
 	n.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
 	n.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
 	n.totlen = cpu_to_je32(8);
 
-	ret = jffs2_flash_write_oob(c, jeb->offset + fsdata_pos, fsdata_len, &retlen, (unsigned char *)&n);
+	ret = jffs2_flash_write_oob(c, jeb->offset + c->fsdata_pos, c->fsdata_len, &retlen, (unsigned char *)&n);
 	
 	if (ret) {
 		D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Write failed for block at %08x: error %d\n", jeb->offset, ret));
 		return ret;
 	}
-	if (retlen != fsdata_len) {
-		D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Short write for block at %08x: %zd not %d\n", jeb->offset, retlen, fsdata_len));
+	if (retlen != c->fsdata_len) {
+		D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Short write for block at %08x: %zd not %d\n", jeb->offset, retlen, c->fsdata_len));
 		return ret;
 	}
 	return 0;
@@ -725,18 +1009,9 @@
 	unsigned char buf[16];
 	int	ret;
 	size_t 	retlen;
-	int	oob_size, badblock_pos;
+	int	oob_size;
 
 	oob_size = c->mtd->oobsize;
-
-	switch(c->mtd->ecctype) {
-	case MTD_ECC_SW:	
-		badblock_pos = NAND_BADBLOCK_POS;
-		break;
-	default:
-		D1(printk(KERN_WARNING "jffs2_nand_read_failcnt(): Invalid ECC type\n"));
-		return -EINVAL;
-	}	
 	
 	ret = c->mtd->read_oob(c->mtd, jeb->offset + c->mtd->oobblock, oob_size , &retlen, buf);
 	
@@ -750,7 +1025,7 @@
 		return -EIO;
 	}
 
-	jeb->bad_count =  buf[badblock_pos];	
+	jeb->bad_count =  buf[c->badblock_pos];	
 	return 0;
 }
 
@@ -767,25 +1042,16 @@
 int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
 {
 	unsigned char buf = 0x0;
-	int 	ret,pos;
+	int 	ret;
 	size_t 	retlen;
 
-	switch(c->mtd->ecctype) {
-	case MTD_ECC_SW:	
-		pos = NAND_BADBLOCK_POS;
-		break;
-	default:
-		D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Invalid ECC type\n"));
-		return -EINVAL;
-	}	
-
 	/* if the count is < max, we try to write the counter to the 2nd page oob area */
 	if( ++jeb->bad_count < MAX_ERASE_FAILURES) {
 		buf = (unsigned char)jeb->bad_count;
-		pos += c->mtd->oobblock;
+		c->badblock_pos += c->mtd->oobblock;
 	}
 	
-	ret = jffs2_flash_write_oob(c, jeb->offset + pos, 1, &retlen, &buf);
+	ret = jffs2_flash_write_oob(c, jeb->offset + c->badblock_pos, 1, &retlen, &buf);
 	
 	if (ret) {
 		D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Write failed for block at %08x: error %d\n", jeb->offset, ret));
@@ -796,4 +1062,89 @@
 		return ret;
 	}
 	return 0;
+}
+
+#define JFFS2_OOB_ECCPOS0		0
+#define JFFS2_OOB_ECCPOS1		1
+#define JFFS2_OOB_ECCPOS2		2
+#define JFFS2_OOB_ECCPOS3		3
+#define JFFS2_OOB_ECCPOS4		6
+#define JFFS2_OOB_ECCPOS5		7
+
+#define NAND_JFFS2_OOB8_FSDAPOS		6
+#define NAND_JFFS2_OOB16_FSDAPOS	8
+#define NAND_JFFS2_OOB8_FSDALEN		2
+#define NAND_JFFS2_OOB16_FSDALEN	8
+
+static struct nand_oobinfo jffs2_oobinfo_swecc = {
+	.useecc = 1,
+	.eccpos = {JFFS2_OOB_ECCPOS0, JFFS2_OOB_ECCPOS1, JFFS2_OOB_ECCPOS2,
+		   JFFS2_OOB_ECCPOS3, JFFS2_OOB_ECCPOS4, JFFS2_OOB_ECCPOS5}
+};
+
+static struct nand_oobinfo jffs2_oobinfo_docecc = {
+	.useecc = 1,
+	.eccpos = {0,1,2,3,4,5}
+};
+
+
+
+int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
+{
+	/* Cleanmarker is out-of-band, so inline size zero */
+	c->cleanmarker_size = 0;
+
+	/* Initialise write buffer */
+	c->wbuf_pagesize = c->mtd->oobblock;
+	c->wbuf_ofs = 0xFFFFFFFF;
+
+	/* FIXME: If we had a generic way of describing the hardware's
+	   use of OOB area, we could perhaps make this generic too. */
+	switch(c->mtd->ecctype) {
+	case MTD_ECC_SW:
+		D1(printk(KERN_DEBUG "JFFS2 using software ECC\n"));
+		c->oobinfo = &jffs2_oobinfo_swecc;
+		if (c->mtd->oobsize == 8) {
+			c->fsdata_pos = NAND_JFFS2_OOB8_FSDAPOS;
+			c->fsdata_len = NAND_JFFS2_OOB8_FSDALEN;
+		} else {
+			c->fsdata_pos = NAND_JFFS2_OOB16_FSDAPOS;
+			c->fsdata_len = NAND_JFFS2_OOB16_FSDALEN;
+		}
+		c->badblock_pos = NAND_BADBLOCK_POS;
+		break;
+
+	case MTD_ECC_RS_DiskOnChip:
+		D1(printk(KERN_DEBUG "JFFS2 using DiskOnChip hardware ECC\n"));
+		c->oobinfo = &jffs2_oobinfo_docecc;
+		c->fsdata_pos = 6;
+		c->fsdata_len = NAND_JFFS2_OOB16_FSDALEN;
+		c->badblock_pos = 15;
+		break;
+
+	default:
+		printk("JFFS2 doesn't yet know how to handle ECC type %d\n",
+		       c->mtd->ecctype);
+		return -EINVAL;
+	}
+
+	c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
+	if (!c->wbuf)
+		return -ENOMEM;
+
+#ifdef BREAKME
+	if (!brokenbuf)
+		brokenbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
+	if (!brokenbuf) {
+		kfree(c->wbuf);
+		return -ENOMEM;
+	}
+	memset(brokenbuf, 0xdb, c->wbuf_pagesize);
+#endif
+	return 0;
+}
+
+void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c)
+{
+	kfree(c->wbuf);
 }
diff -Nru a/fs/jffs2/write.c b/fs/jffs2/write.c
--- a/fs/jffs2/write.c	Wed Oct 15 00:46:36 2003
+++ b/fs/jffs2/write.c	Wed Oct 15 00:46:36 2003
@@ -1,13 +1,13 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: write.c,v 1.65 2003/01/21 18:11:29 dwmw2 Exp $
+ * $Id: write.c,v 1.75 2003/10/08 11:45:11 dwmw2 Exp $
  *
  */
 
@@ -86,7 +86,7 @@
 /* jffs2_write_dnode - given a raw_inode, allocate a full_dnode for it, 
    write it to the flash, link it into the existing inode/fragment list */
 
-struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const unsigned char *data, uint32_t datalen, uint32_t flash_ofs,  uint32_t *writelen)
+struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const unsigned char *data, uint32_t datalen, uint32_t flash_ofs, int alloc_mode)
 
 {
 	struct jffs2_raw_node_ref *raw;
@@ -94,6 +94,7 @@
 	size_t retlen;
 	struct iovec vecs[2];
 	int ret;
+	int retried = 0;
 	unsigned long cnt = 2;
 
 	D1(if(je32_to_cpu(ri->hdr_crc) != crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)) {
@@ -120,24 +121,28 @@
 		jffs2_free_raw_node_ref(raw);
 		return ERR_PTR(-ENOMEM);
 	}
-	raw->flash_offset = flash_ofs;
-	raw->totlen = PAD(sizeof(*ri)+datalen);
-	raw->next_phys = NULL;
 
 	fn->ofs = je32_to_cpu(ri->offset);
 	fn->size = je32_to_cpu(ri->dsize);
 	fn->frags = 0;
-	fn->raw = raw;
 
 	/* check number of valid vecs */
 	if (!datalen || !data)
 		cnt = 1;
+ retry:
+	fn->raw = raw;
+
+	raw->flash_offset = flash_ofs;
+	raw->totlen = PAD(sizeof(*ri)+datalen);
+	raw->next_phys = NULL;
+
+	ret = jffs2_flash_writev(c, vecs, cnt, flash_ofs, &retlen,
+				 (alloc_mode==ALLOC_GC)?0:f->inocache->ino);
 
-	ret = jffs2_flash_writev(c, vecs, cnt, flash_ofs, &retlen);
-		
 	if (ret || (retlen != sizeof(*ri) + datalen)) {
 		printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", 
 		       sizeof(*ri)+datalen, flash_ofs, ret, retlen);
+
 		/* Mark the space as dirtied */
 		if (retlen) {
 			/* Doesn't belong to any inode */
@@ -155,11 +160,42 @@
 			printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset);
 			jffs2_free_raw_node_ref(raw);
 		}
+		if (!retried && alloc_mode != ALLOC_NORETRY && (raw = jffs2_alloc_raw_node_ref())) {
+			/* Try to reallocate space and retry */
+			uint32_t dummy;
+			struct jffs2_eraseblock *jeb = &c->blocks[flash_ofs / c->sector_size];
 
+			retried = 1;
+
+			D1(printk(KERN_DEBUG "Retrying failed write.\n"));
+			
+			ACCT_SANITY_CHECK(c,jeb);
+			D1(ACCT_PARANOIA_CHECK(jeb));
+
+			if (alloc_mode == ALLOC_GC) {
+				ret = jffs2_reserve_space_gc(c, sizeof(*ri) + datalen, &flash_ofs, &dummy);
+			} else {
+				/* Locking pain */
+				up(&f->sem);
+				jffs2_complete_reservation(c);
+			
+				ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &flash_ofs, &dummy, alloc_mode);
+				down(&f->sem);
+			}
+
+			if (!ret) {
+				D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs));
+
+				ACCT_SANITY_CHECK(c,jeb);
+				D1(ACCT_PARANOIA_CHECK(jeb));
+
+				goto retry;
+			}
+			D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret));
+			jffs2_free_raw_node_ref(raw);
+		}
 		/* Release the full_dnode which is now useless, and return */
 		jffs2_free_full_dnode(fn);
-		if (writelen)
-			*writelen = retlen;
 		return ERR_PTR(ret?ret:-EIO);
 	}
 	/* Mark the space used */
@@ -184,19 +220,21 @@
 		  flash_ofs, ref_flags(raw), je32_to_cpu(ri->dsize), 
 		  je32_to_cpu(ri->csize), je32_to_cpu(ri->node_crc),
 		  je32_to_cpu(ri->data_crc), je32_to_cpu(ri->totlen)));
-	if (writelen)
-		*writelen = retlen;
 
-	f->inocache->nodes = raw;
+	if (retried) {
+		ACCT_SANITY_CHECK(c,NULL);
+	}
+
 	return fn;
 }
 
-struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_dirent *rd, const unsigned char *name, uint32_t namelen, uint32_t flash_ofs,  uint32_t *writelen)
+struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_dirent *rd, const unsigned char *name, uint32_t namelen, uint32_t flash_ofs, int alloc_mode)
 {
 	struct jffs2_raw_node_ref *raw;
 	struct jffs2_full_dirent *fd;
 	size_t retlen;
 	struct iovec vecs[2];
+	int retried = 0;
 	int ret;
 
 	D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n", 
@@ -225,11 +263,6 @@
 		jffs2_free_raw_node_ref(raw);
 		return ERR_PTR(-ENOMEM);
 	}
-	raw->flash_offset = flash_ofs;
-	raw->totlen = PAD(sizeof(*rd)+namelen);
-	raw->next_in_ino = f->inocache->nodes;
-	f->inocache->nodes = raw;
-	raw->next_phys = NULL;
 
 	fd->version = je32_to_cpu(rd->version);
 	fd->ino = je32_to_cpu(rd->ino);
@@ -237,14 +270,22 @@
 	fd->type = rd->type;
 	memcpy(fd->name, name, namelen);
 	fd->name[namelen]=0;
+
+ retry:
 	fd->raw = raw;
 
-	ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen);
+	raw->flash_offset = flash_ofs;
+	raw->totlen = PAD(sizeof(*rd)+namelen);
+	raw->next_phys = NULL;
+
+	ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen,
+				 (alloc_mode==ALLOC_GC)?0:fd->ino);
 	if (ret || (retlen != sizeof(*rd) + namelen)) {
 		printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", 
 			       sizeof(*rd)+namelen, flash_ofs, ret, retlen);
 		/* Mark the space as dirtied */
 		if (retlen) {
+			raw->next_in_ino = NULL;
 			raw->flash_offset |= REF_OBSOLETE;
 			jffs2_add_physical_node_ref(c, raw);
 			jffs2_mark_node_obsolete(c, raw);
@@ -252,20 +293,53 @@
 			printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset);
 			jffs2_free_raw_node_ref(raw);
 		}
+		if (!retried && (raw = jffs2_alloc_raw_node_ref())) {
+			/* Try to reallocate space and retry */
+			uint32_t dummy;
+			struct jffs2_eraseblock *jeb = &c->blocks[flash_ofs / c->sector_size];
+
+			retried = 1;
 
+			D1(printk(KERN_DEBUG "Retrying failed write.\n"));
+
+			ACCT_SANITY_CHECK(c,jeb);
+			D1(ACCT_PARANOIA_CHECK(jeb));
+
+			if (alloc_mode == ALLOC_GC) {
+				ret = jffs2_reserve_space_gc(c, sizeof(*rd) + namelen, &flash_ofs, &dummy);
+			} else {
+				/* Locking pain */
+				up(&f->sem);
+				jffs2_complete_reservation(c);
+			
+				ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &flash_ofs, &dummy, alloc_mode);
+				down(&f->sem);
+			}
+
+			if (!ret) {
+				D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs));
+				ACCT_SANITY_CHECK(c,jeb);
+				D1(ACCT_PARANOIA_CHECK(jeb));
+				goto retry;
+			}
+			D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret));
+			jffs2_free_raw_node_ref(raw);
+		}
 		/* Release the full_dnode which is now useless, and return */
 		jffs2_free_full_dirent(fd);
-		if (writelen)
-			*writelen = retlen;
 		return ERR_PTR(ret?ret:-EIO);
 	}
 	/* Mark the space used */
 	raw->flash_offset |= REF_PRISTINE;
 	jffs2_add_physical_node_ref(c, raw);
-	if (writelen)
-		*writelen = retlen;
 
+	raw->next_in_ino = f->inocache->nodes;
 	f->inocache->nodes = raw;
+
+	if (retried) {
+		ACCT_SANITY_CHECK(c,NULL);
+	}
+
 	return fd;
 }
 
@@ -288,7 +362,9 @@
 		unsigned char comprtype = JFFS2_COMPR_NONE;
 		uint32_t phys_ofs, alloclen;
 		uint32_t datalen, cdatalen;
+		int retried = 0;
 
+	retry:
 		D2(printk(KERN_DEBUG "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", writelen, offset));
 
 		ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen, ALLOC_NORMAL);
@@ -331,7 +407,7 @@
 		ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
 		ri->data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen));
 
-		fn = jffs2_write_dnode(c, f, ri, comprbuf, cdatalen, phys_ofs, NULL);
+		fn = jffs2_write_dnode(c, f, ri, comprbuf, cdatalen, phys_ofs, ALLOC_NORETRY);
 
 		if (comprtype != JFFS2_COMPR_NONE)
 			kfree(comprbuf);
@@ -340,6 +416,12 @@
 			ret = PTR_ERR(fn);
 			up(&f->sem);
 			jffs2_complete_reservation(c);
+			if (!retried) {
+				/* Write error to be retried */
+				retried = 1;
+				D1(printk(KERN_DEBUG "Retrying node write in jffs2_write_inode_range()\n"));
+				goto retry;
+			}
 			break;
 		}
 		ret = jffs2_add_full_dnode_to_inode(c, f, fn);
@@ -381,7 +463,6 @@
 	struct jffs2_full_dnode *fn;
 	struct jffs2_full_dirent *fd;
 	uint32_t alloclen, phys_ofs;
-	uint32_t writtenlen;
 	int ret;
 
 	/* Try to reserve enough space for both node and dirent. 
@@ -397,7 +478,7 @@
 	ri->data_crc = cpu_to_je32(0);
 	ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
 
-	fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, &writtenlen);
+	fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL);
 
 	D1(printk(KERN_DEBUG "jffs2_do_create created file with mode 0x%x\n",
 		  jemode_to_cpu(ri->mode)));
@@ -414,22 +495,14 @@
 	*/
 	f->metadata = fn;
 
-	/* Work out where to put the dirent node now. */
-	writtenlen = PAD(writtenlen);
-	phys_ofs += writtenlen;
-	alloclen -= writtenlen;
 	up(&f->sem);
-
-	if (alloclen < sizeof(*rd)+namelen) {
-		/* Not enough space left in this chunk. Get some more */
-		jffs2_complete_reservation(c);
-		ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+	jffs2_complete_reservation(c);
+	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
 		
-		if (ret) {
-			/* Eep. */
-			D1(printk(KERN_DEBUG "jffs2_reserve_space() for dirent failed\n"));
-			return ret;
-		}
+	if (ret) {
+		/* Eep. */
+		D1(printk(KERN_DEBUG "jffs2_reserve_space() for dirent failed\n"));
+		return ret;
 	}
 
 	rd = jffs2_alloc_raw_dirent();
@@ -455,7 +528,7 @@
 	rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
 	rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
 
-	fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, &writtenlen);
+	fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_NORMAL);
 
 	jffs2_free_raw_dirent(rd);
 	
@@ -513,7 +586,7 @@
 	rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
 	rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
 
-	fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, NULL);
+	fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_DELETION);
 	
 	jffs2_free_raw_dirent(rd);
 
@@ -598,7 +671,7 @@
 	rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
 	rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
 
-	fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, NULL);
+	fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_NORMAL);
 	
 	jffs2_free_raw_dirent(rd);
 
diff -Nru a/fs/jffs2/writev.c b/fs/jffs2/writev.c
--- a/fs/jffs2/writev.c	Wed Oct 15 00:46:36 2003
+++ b/fs/jffs2/writev.c	Wed Oct 15 00:46:36 2003
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001, 2002 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: writev.c,v 1.3 2002/08/08 08:35:21 dwmw2 Exp $
+ * $Id: writev.c,v 1.4 2003/10/04 08:33:07 dwmw2 Exp $
  *
  */
 
diff -Nru a/fs/jfs/file.c b/fs/jfs/file.c
--- a/fs/jfs/file.c	Wed Oct 15 00:46:37 2003
+++ b/fs/jfs/file.c	Wed Oct 15 00:46:37 2003
@@ -34,10 +34,12 @@
 	struct inode *inode = dentry->d_inode;
 	int rc = 0;
 
-	if (!(inode->i_state & I_DIRTY))
-		return rc;
-	if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
+	if (!(inode->i_state & I_DIRTY) ||
+	    (datasync && !(inode->i_state & I_DIRTY_DATASYNC))) {
+		/* Make sure committed changes hit the disk */
+		jfs_flush_journal(JFS_SBI(inode->i_sb)->log, 1);
 		return rc;
+	}
 
 	rc |= jfs_commit_inode(inode, 1);
 
diff -Nru a/fs/jfs/inode.c b/fs/jfs/inode.c
--- a/fs/jfs/inode.c	Wed Oct 15 00:46:35 2003
+++ b/fs/jfs/inode.c	Wed Oct 15 00:46:35 2003
@@ -107,14 +107,18 @@
 
 void jfs_write_inode(struct inode *inode, int wait)
 {
+	if (test_cflag(COMMIT_Nolink, inode))
+		return;
 	/*
 	 * If COMMIT_DIRTY is not set, the inode isn't really dirty.
 	 * It has been committed since the last change, but was still
-	 * on the dirty inode list
+	 * on the dirty inode list.
 	 */
-	if (test_cflag(COMMIT_Nolink, inode) ||
-	    !test_cflag(COMMIT_Dirty, inode))
+	 if (!test_cflag(COMMIT_Dirty, inode)) {
+		/* Make sure committed changes hit the disk */
+		jfs_flush_journal(JFS_SBI(inode->i_sb)->log, wait);
 		return;
+	 }
 
 	if (jfs_commit_inode(inode, wait)) {
 		jfs_err("jfs_write_inode: jfs_commit_inode failed!");
diff -Nru a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
--- a/fs/jfs/jfs_dmap.c	Wed Oct 15 00:46:37 2003
+++ b/fs/jfs/jfs_dmap.c	Wed Oct 15 00:46:37 2003
@@ -1,5 +1,5 @@
 /*
- *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Copyright (C) International Business Machines Corp., 2000-2003
  *
  *   This program is free software;  you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -18,6 +18,7 @@
 
 #include <linux/fs.h>
 #include "jfs_incore.h"
+#include "jfs_superblock.h"
 #include "jfs_dmap.h"
 #include "jfs_imap.h"
 #include "jfs_lock.h"
@@ -134,7 +135,6 @@
 static int dbMaxBud(u8 * cp);
 s64 dbMapFileSizeToMapSize(struct inode *ipbmap);
 int blkstol2(s64 nb);
-void fsDirty(void);
 
 int cntlz(u32 value);
 int cnttz(u32 word);
@@ -382,7 +382,15 @@
 	IREAD_LOCK(ipbmap);
 
 	/* block to be freed better be within the mapsize. */
-	assert(blkno + nblocks <= bmp->db_mapsize);
+	if (blkno + nblocks > bmp->db_mapsize) {
+		IREAD_UNLOCK(ipbmap);
+		printk(KERN_ERR "blkno = %Lx, nblocks = %Lx\n",
+		       (unsigned long long) blkno,
+		       (unsigned long long) nblocks);
+		jfs_error(ip->i_sb,
+			  "dbFree: block to be freed is outside the map");
+		return -EIO;
+	}
 
 	/*
 	 * free the blocks a dmap at a time.
@@ -465,7 +473,14 @@
 	int lsn, difft, diffp;
 
 	/* the blocks better be within the mapsize. */
-	assert(blkno + nblocks <= bmp->db_mapsize);
+	if (blkno + nblocks > bmp->db_mapsize) {
+		printk(KERN_ERR "blkno = %Lx, nblocks = %Lx\n",
+		       (unsigned long long) blkno,
+		       (unsigned long long) nblocks);
+		jfs_error(ipbmap->i_sb,
+			  "dbUpdatePMap: blocks are outside the map");
+		return -EIO;
+	}
 
 	/* compute delta of transaction lsn from log syncpt */
 	lsn = tblk->lsn;
@@ -757,7 +772,10 @@
 	mapSize = bmp->db_mapsize;
 
 	/* the hint should be within the map */
-	assert(hint < mapSize);
+	if (hint >= mapSize) {
+		jfs_error(ip->i_sb, "dbAlloc: the hint is outside the map");
+		return -EIO;
+	}
 
 	/* if the number of blocks to be allocated is greater than the
 	 * allocation group size, try to allocate anywhere.
@@ -1104,7 +1122,12 @@
 
 	/* better be within the file system */
 	bmp = sbi->bmap;
-	assert(lastblkno >= 0 && lastblkno < bmp->db_mapsize);
+	if (lastblkno < 0 || lastblkno >= bmp->db_mapsize) {
+		IREAD_UNLOCK(ipbmap);
+		jfs_error(ip->i_sb,
+			  "dbExtend: the block is outside the filesystem");
+		return -EIO;
+	}
 
 	/* we'll attempt to extend the current allocation in place by
 	 * allocating the additional blocks as the blocks immediately
@@ -1145,11 +1168,10 @@
 		DBALLOC(bmp->db_DBmap, bmp->db_mapsize, extblkno,
 			addnblocks);
 		write_metapage(mp);
-	} else {
+	} else
 		/* we were not successful */
 		release_metapage(mp);
-		assert(rc == -ENOSPC || rc == -EIO);
-	}
+
 
 	return (rc);
 }
@@ -1414,7 +1436,12 @@
 	/* allocation request should not be for more than the
 	 * allocation group size.
 	 */
-	assert(l2nb <= bmp->db_agl2size);
+	if (l2nb > bmp->db_agl2size) {
+		jfs_error(bmp->db_ipbmap->i_sb,
+			  "dbAllocAG: allocation request is larger than the "
+			  "allocation group size");
+		return -EIO;
+	}
 
 	/* determine the starting block number of the allocation
 	 * group.
@@ -1441,13 +1468,13 @@
 	if (bmp->db_agsize == BPERDMAP
 	    || bmp->db_agfree[agno] == bmp->db_agsize) {
 		rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results);
-		/* assert(!(rc == -ENOSPC && bmp->db_agfree[agno] == bmp->db_agsize)); */
 		if ((rc == -ENOSPC) &&
 		    (bmp->db_agfree[agno] == bmp->db_agsize)) {
-			jfs_err("dbAllocAG: removed assert, but still need to "
-				"debug here\nblkno = 0x%Lx, nblocks = 0x%Lx",
-				(unsigned long long) blkno,
-				(unsigned long long) nblocks);
+			printk(KERN_ERR "blkno = %Lx, blocks = %Lx\n",
+			       (unsigned long long) blkno,
+			       (unsigned long long) nblocks);
+			jfs_error(bmp->db_ipbmap->i_sb,
+				  "dbAllocAG: dbAllocCtl failed in free AG");
 		}
 		return (rc);
 	}
@@ -1496,7 +1523,11 @@
 					break;
 				}
 			}
-			assert(n < 4);
+			if (n == 4) {
+				jfs_error(bmp->db_ipbmap->i_sb,
+					  "dbAllocAG: failed descending stree");
+				return -EIO;
+			}
 		}
 
 		/* determine the block number within the file system
@@ -1531,7 +1562,12 @@
 			if ((rc =
 			     dbFindCtl(bmp, l2nb, bmp->db_aglevel - 1,
 				       &blkno))) {
-				assert(rc != -ENOSPC);
+				if (rc == -ENOSPC) {
+					jfs_error(bmp->db_ipbmap->i_sb,
+						  "dbAllocAG: control page "
+						  "inconsistent");
+					return -EIO;
+				}
 				return (rc);
 			}
 		}
@@ -1539,7 +1575,11 @@
 		/* allocate the blocks.
 		 */
 		rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results);
-		assert(rc != -ENOSPC);
+		if (rc == -ENOSPC) {
+			jfs_error(bmp->db_ipbmap->i_sb,
+				  "dbAllocAG: unable to allocate blocks");
+			rc = -EIO;
+		}
 		return (rc);
 	}
 
@@ -1595,7 +1635,11 @@
 	/* allocate the blocks.
 	 */
 	rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results);
-	assert(rc != -ENOSPC);
+	if (rc == -ENOSPC) {
+		jfs_error(bmp->db_ipbmap->i_sb,
+			  "dbAllocAny: unable to allocate blocks");
+		return -EIO;
+	}
 	return (rc);
 }
 
@@ -1666,7 +1710,11 @@
 		/* space found ?
 		 */
 		if (rc) {
-			assert(lev == level);
+			if (lev != level) {
+				jfs_error(bmp->db_ipbmap->i_sb,
+					  "dbFindCtl: dmap inconsistent");
+				return -EIO;
+			}
 			return -ENOSPC;
 		}
 
@@ -1785,7 +1833,13 @@
 
 		/* the dmap better be all free.
 		 */
-		assert(dp->tree.stree[ROOT] == L2BPERDMAP);
+		if (dp->tree.stree[ROOT] != L2BPERDMAP) {
+			release_metapage(mp);
+			jfs_error(bmp->db_ipbmap->i_sb,
+				  "dbAllocCtl: the dmap is not all free");
+			rc = -EIO;
+			goto backout;
+		}
 
 		/* determine how many blocks to allocate from this dmap.
 		 */
@@ -1828,8 +1882,8 @@
 			/* could not back out.  mark the file system
 			 * to indicate that we have leaked blocks.
 			 */
-			fsDirty();	/* !!! */
-			jfs_err("dbAllocCtl: I/O Error: Block Leakage.");
+			jfs_error(bmp->db_ipbmap->i_sb,
+				  "dbAllocCtl: I/O Error: Block Leakage.");
 			continue;
 		}
 		dp = (struct dmap *) mp->data;
@@ -1841,8 +1895,8 @@
 			 * to indicate that we have leaked blocks.
 			 */
 			release_metapage(mp);
-			fsDirty();	/* !!! */
-			jfs_err("dbAllocCtl: Block Leakage.");
+			jfs_error(bmp->db_ipbmap->i_sb,
+				  "dbAllocCtl: Block Leakage.");
 			continue;
 		}
 
@@ -2137,7 +2191,12 @@
 			 * the allocated words.
 			 */
 			for (; nwords > 0; nwords -= nw) {
-				assert(leaf[word] >= BUDMIN);
+			        if (leaf[word] < BUDMIN) {
+					jfs_error(bmp->db_ipbmap->i_sb,
+						  "dbAllocBits: leaf page "
+						  "corrupt");
+					break;
+				}
 
 				/* determine what the leaf value should be
 				 * updated to as the minimum of the l2 number
@@ -2489,7 +2548,11 @@
 			 * of the maximum free buddy system.
 			 */
 			assert(level == bmp->db_maxlevel);
-			assert(bmp->db_maxfreebud == oldroot);
+			if (bmp->db_maxfreebud != oldroot) {
+				jfs_error(bmp->db_ipbmap->i_sb,
+					  "dbAdjCtl: the maximum free buddy is "
+					  "not the old root");
+			}
 			bmp->db_maxfreebud = dcp->stree[ROOT];
 		}
 	}
@@ -3040,24 +3103,6 @@
 
 
 /*
- * NAME:	fsDirty()
- *
- * FUNCTION:    xxx
- *
- * PARAMETERS:
- *      ipmnt	- mount inode
- *
- * RETURN VALUES:
- *      none
- */
-void fsDirty(void)
-{
-	printk("fsDirty(): bye-bye\n");
-	assert(0);
-}
-
-
-/*
  * NAME:    	dbAllocBottomUp()
  *
  * FUNCTION:	alloc the specified block range from the working block
@@ -3343,7 +3388,10 @@
 	/* get L2 page */
 	p = BMAPBLKNO + nbperpage;	/* L2 page */
 	l2mp = read_metapage(ipbmap, p, PSIZE, 0);
-	assert(l2mp);
+	if (!l2mp) {
+		jfs_error(ipbmap->i_sb, "dbExtendFS: L2 page could not be read");
+		return -EIO;
+	}
 	l2dcp = (struct dmapctl *) l2mp->data;
 
 	/* compute start L1 */
@@ -3504,7 +3552,9 @@
 		}
 	}			/* for each L1 in a L2 */
 
-	assert(0);
+	jfs_error(ipbmap->i_sb,
+		  "dbExtendFS: function has not returned as expected");
+	return -EIO;
 
 	/*
 	 *      finalize bmap control page
@@ -3568,7 +3618,10 @@
 			if (bmp->db_agfree[bmp->db_agpref] >= avgfree)
 				break;
 		}
-		assert(bmp->db_agpref < bmp->db_numag);
+		if (bmp->db_agpref >= bmp->db_numag) {
+			jfs_error(ipbmap->i_sb,
+				  "cannot find ag with average freespace");
+		}
 	}
 
 	/*
@@ -3589,10 +3642,6 @@
 		n <<= 2;
 	}
 
-/*
-printk("bmap: agpref:%d aglevel:%d agheigth:%d agwidth:%d\n",
-	bmp->db_agpref, bmp->db_aglevel, bmp->db_agheigth, bmp->db_agwidth);
-*/
 }
 
 
@@ -3616,9 +3665,6 @@
 static int dbInitDmap(struct dmap * dp, s64 Blkno, int nblocks)
 {
 	int blkno, w, b, r, nw, nb, i;
-/*
-printk("sbh_dmap:  in dbInitDmap blkno:%Ld nblocks:%ld\n", Blkno, nblocks); 
-*/
 
 	/* starting block number within the dmap */
 	blkno = Blkno & (BPERDMAP - 1);
@@ -3678,10 +3724,6 @@
 	 * mark bits following the range to be freed (non-existing 
 	 * blocks) as allocated (ONES)
 	 */
-/*
-printk("sbh_dmap:  in dbInitDmap, preparing to mark unbacked, blkno:%ld nblocks:%ld\n",
-		blkno, nblocks); 
-*/
 
 	if (blkno == BPERDMAP)
 		goto initTree;
@@ -3691,9 +3733,6 @@
 
 	/* does nblocks fall on a 32-bit boundary ? */
 	b = blkno & (DBWORD - 1);
-/*
-printk("sbh_dmap:  in dbInitDmap, b:%ld w:%ld mask: %lx\n", b, w, (ONES>>b)); 
-*/
 	if (b) {
 		/* mark a partial word allocated */
 		dp->wmap[w] = dp->pmap[w] = cpu_to_le32(ONES >> b);
@@ -3990,7 +4029,7 @@
 
 	dbmap = (u32 *) xmalloc(npages * 4096, L2PSIZE, kernel_heap);
 	if (dbmap == NULL)
-		assert(0);
+		BUG();	/* Not robust since this is only unused debug code */
 
 	for (n = 0, d = dbmap; n < npages; n++, d += 1024)
 		bzero(d, 4096);
@@ -4004,7 +4043,9 @@
 				   db_l2nbperpage);
 		mp = read_metapage(ipbmap, lblkno, PSIZE, 0);
 		if (mp == NULL) {
-			assert(0);
+			jfs_error(ipbmap->i_sb,
+				  "DBinitmap: could not read disk map page");
+			continue;
 		}
 		dp = (struct dmap *) mp->data;
 
diff -Nru a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
--- a/fs/jfs/jfs_dtree.c	Wed Oct 15 00:46:37 2003
+++ b/fs/jfs/jfs_dtree.c	Wed Oct 15 00:46:37 2003
@@ -1,5 +1,5 @@
 /*
- *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Copyright (C) International Business Machines Corp., 2000-2003
  *
  *   This program is free software;  you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -130,9 +130,8 @@
 		if (((P)->header.nextindex > (((BN)==0)?DTROOTMAXSLOT:(P)->header.maxslot)) ||\
 		    ((BN) && ((P)->header.maxslot > DTPAGEMAXSLOT)))\
 		{\
-			jfs_err("DT_GETPAGE: dtree page corrupt");\
 			BT_PUTPAGE(MP);\
-			updateSuper((IP)->i_sb, FM_DIRTY);\
+			jfs_error((IP)->i_sb, "DT_GETPAGE: dtree page corrupt");\
 			MP = NULL;\
 			RC = -EIO;\
 		}\
@@ -768,8 +767,7 @@
 			/* Something's corrupted, mark filesytem dirty so
 			 * chkdsk will fix it.
 			 */
-			jfs_err("stack overrun in dtSearch!");
-			updateSuper(sb, FM_DIRTY);
+			jfs_error(sb, "stack overrun in dtSearch!");
 			rc = -EIO;
 			goto out;
 		}
@@ -3204,11 +3202,12 @@
 				d_namleft -= len;
 				/* Sanity Check */
 				if (d_namleft == 0) {
-					jfs_err("JFS:Dtree error: ino = "
-						"%ld, bn=%Ld, index = %d",
-						(long)ip->i_ino,(long long)bn,
-						i);
-					updateSuper(ip->i_sb, FM_DIRTY);
+					jfs_error(ip->i_sb,
+						  "JFS:Dtree error: ino = "
+						  "%ld, bn=%Ld, index = %d",
+						  (long)ip->i_ino,
+						  (long long)bn,
+						  i);
 					goto skip_one;
 				}
 				len = min(d_namleft, DTSLOTDATALEN);
diff -Nru a/fs/jfs/jfs_extent.c b/fs/jfs/jfs_extent.c
--- a/fs/jfs/jfs_extent.c	Wed Oct 15 00:46:36 2003
+++ b/fs/jfs/jfs_extent.c	Wed Oct 15 00:46:36 2003
@@ -1,5 +1,5 @@
 /*
- *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Copyright (C) International Business Machines Corp., 2000-2003
  *
  *   This program is free software;  you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -18,6 +18,7 @@
 
 #include <linux/fs.h>
 #include "jfs_incore.h"
+#include "jfs_superblock.h"
 #include "jfs_dmap.h"
 #include "jfs_extent.h"
 #include "jfs_debug.h"
@@ -403,8 +404,10 @@
 	 */
 	xp->flag &= XAD_NOTRECORDED;
 
-	assert(xadl.nxad == 1);
-	assert(lengthXAD(xp) == nbperpage);
+        if(xadl.nxad != 1 || lengthXAD(xp) != nbperpage) {          
+		jfs_error(ip->i_sb, "extHint: corrupt xtree");
+		return -EIO;
+        }
 
 	return (0);
 }
diff -Nru a/fs/jfs/jfs_filsys.h b/fs/jfs/jfs_filsys.h
--- a/fs/jfs/jfs_filsys.h	Wed Oct 15 00:46:36 2003
+++ b/fs/jfs/jfs_filsys.h	Wed Oct 15 00:46:36 2003
@@ -1,5 +1,5 @@
 /*
- *   Copyright (c) International Business Machines Corp., 2000-2003
+ *   Copyright (C) International Business Machines Corp., 2000-2003
  *
  *   This program is free software;  you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -31,6 +31,11 @@
  */
 /* mount time flag to disable journaling to disk */
 #define JFS_NOINTEGRITY 0x00000010
+
+/* mount time flags for error handling */
+#define JFS_ERR_REMOUNT_RO 0x00000002   /* remount read-only */
+#define JFS_ERR_CONTINUE   0x00000004   /* continue */
+#define JFS_ERR_PANIC      0x00000008   /* panic */
 
 /* platform option (conditional compilation) */
 #define JFS_AIX		0x80000000	/* AIX support */
diff -Nru a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
--- a/fs/jfs/jfs_imap.c	Wed Oct 15 00:46:36 2003
+++ b/fs/jfs/jfs_imap.c	Wed Oct 15 00:46:36 2003
@@ -1,5 +1,5 @@
 /*
- *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Copyright (C) International Business Machines Corp., 2000-2003
  *
  *   This program is free software;  you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -410,8 +410,7 @@
 	dp += rel_inode;
 
 	if (ip->i_ino != le32_to_cpu(dp->di_number)) {
-		jfs_err("diRead: i_ino != di_number");
-		updateSuper(ip->i_sb, FM_DIRTY);
+		jfs_error(ip->i_sb, "diRead: i_ino != di_number");
 		rc = -EIO;
 	} else if (le32_to_cpu(dp->di_nlink) == 0)
 		rc = -ESTALE;
@@ -641,9 +640,12 @@
 
 	ino = ip->i_ino & (INOSPERIAG - 1);
 
-	assert(lengthPXD(&(jfs_ip->ixpxd)) ==
-	       JFS_IP(ipimap)->i_imap->im_nbperiext);
-	assert(addressPXD(&(jfs_ip->ixpxd)));
+	if (!addressPXD(&(jfs_ip->ixpxd)) ||
+	    (lengthPXD(&(jfs_ip->ixpxd)) !=
+	     JFS_IP(ipimap)->i_imap->im_nbperiext)) {
+		jfs_error(ip->i_sb, "diWrite: ixpxd invalid");
+		return -EIO;
+	}
 
 	/*
 	 * read the page of disk inode containing the specified inode:
@@ -918,12 +920,11 @@
 	/* make sure that the iag is contained within 
 	 * the map.
 	 */
-	//assert(iagno < imap->im_nextiag);
 	if (iagno >= imap->im_nextiag) {
-		jfs_err("diFree: inum = %d, iagno = %d, nextiag = %d",
-			(uint) inum, iagno, imap->im_nextiag);
 		dump_mem("imap", imap, 32);
-		updateSuper(ip->i_sb, FM_DIRTY);
+		jfs_error(ip->i_sb,
+			  "diFree: inum = %d, iagno = %d, nextiag = %d",
+			  (uint) inum, iagno, imap->im_nextiag);
 		return -EIO;
 	}
 
@@ -957,22 +958,28 @@
 	bitno = ino & (INOSPEREXT - 1);
 	mask = HIGHORDER >> bitno;
 
-	assert(le32_to_cpu(iagp->wmap[extno]) & mask);
-#ifdef _STILL_TO_PORT
-	assert((le32_to_cpu(iagp->pmap[extno]) & mask) == 0);
-#endif				/*  _STILL_TO_PORT */
-	assert(addressPXD(&iagp->inoext[extno]));
+	if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) {
+		jfs_error(ip->i_sb,
+			  "diFree: wmap shows inode already free");
+	}
+
+	if (!addressPXD(&iagp->inoext[extno])) {
+		release_metapage(mp);
+		IREAD_UNLOCK(ipimap);
+		AG_UNLOCK(imap, agno);
+		jfs_error(ip->i_sb, "diFree: invalid inoext");
+		return -EIO;
+	}
 
 	/* compute the bitmap for the extent reflecting the freed inode.
 	 */
 	bitmap = le32_to_cpu(iagp->wmap[extno]) & ~mask;
 
 	if (imap->im_agctl[agno].numfree > imap->im_agctl[agno].numinos) {
-		jfs_err("diFree: numfree > numinos");
 		release_metapage(mp);
 		IREAD_UNLOCK(ipimap);
 		AG_UNLOCK(imap, agno);
-		updateSuper(ip->i_sb, FM_DIRTY);
+		jfs_error(ip->i_sb, "diFree: numfree > numinos");
 		return -EIO;
 	}
 	/*
@@ -1136,7 +1143,6 @@
 				if ((rc =
 				     diIAGRead(imap, inofreefwd, &cmp)))
 					goto error_out;
-				assert(cmp != NULL);
 				ciagp = (struct iag *) cmp->data;
 			}
 			assert(ciagp != NULL);
@@ -1151,7 +1157,6 @@
 				if ((rc =
 				     diIAGRead(imap, inofreeback, &dmp)))
 					goto error_out;
-				assert(dmp != NULL);
 				diagp = (struct iag *) dmp->data;
 			}
 			assert(diagp != NULL);
@@ -1224,7 +1229,9 @@
 	 * the permanent map should have been updated already 
 	 * for the inode being freed.
 	 */
-	assert(iagp->pmap[extno] == 0);
+	if (iagp->pmap[extno] != 0) {
+		jfs_error(ip->i_sb, "diFree: the pmap does not show inode free");
+	}
 	iagp->wmap[extno] = 0;
 	DBG_DIFREE(imap, inum);
 	PXDlength(&iagp->inoext[extno], 0);
@@ -1304,7 +1311,7 @@
 	iplist[1] = (struct inode *) (size_t)iagno;
 	iplist[2] = (struct inode *) (size_t)extno;
 
-	rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE);	// D233382
+	rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE);
 
 	txEnd(tid);
 
@@ -1434,6 +1441,7 @@
 	iagno = INOTOIAG(inum);
 	if ((rc = diIAGRead(imap, iagno, &mp))) {
 		IREAD_UNLOCK(ipimap);
+		AG_UNLOCK(imap, agno);
 		return (rc);
 	}
 	iagp = (struct iag *) mp->data;
@@ -1536,10 +1544,16 @@
 				 */
 				rem = diFindFree(inosmap, 0);
 				extno = (sword << L2EXTSPERSUM) + rem;
-				rem =
-				    diFindFree(le32_to_cpu
-					       (iagp->wmap[extno]), 0);
-				assert(rem < INOSPEREXT);
+				rem = diFindFree(le32_to_cpu(iagp->wmap[extno]),
+						 0);
+				if (rem >= INOSPEREXT) {
+					IREAD_UNLOCK(ipimap);
+					AG_UNLOCK(imap, agno);
+					jfs_error(ip->i_sb,
+						  "diAlloc: can't find free bit "
+						  "in wmap");
+					return EIO;
+				}
 
 				/* determine the inode number within the
 				 * iag and allocate the inode from the
@@ -1548,9 +1562,9 @@
 				ino = (extno << L2INOSPEREXT) + rem;
 				rc = diAllocBit(imap, iagp, ino);
 				IREAD_UNLOCK(ipimap);
-				if (rc) {
+				if (rc)
 					assert(rc == -EIO);
-				} else {
+				else {
 					/* set the results of the allocation
 					 * and write the iag.
 					 */
@@ -1678,8 +1692,7 @@
 	numinos = imap->im_agctl[agno].numinos;
 
 	if (numfree > numinos) {
-		jfs_err("diAllocAG: numfree > numinos");
-		updateSuper(ip->i_sb, FM_DIRTY);
+		jfs_error(ip->i_sb, "diAllocAG: numfree > numinos");
 		return -EIO;
 	}
 
@@ -1827,12 +1840,10 @@
 	/* better be free inodes in this iag if it is on the
 	 * list.
 	 */
-	//assert(iagp->nfreeinos);
 	if (!iagp->nfreeinos) {
-		jfs_err("diAllocIno: nfreeinos = 0, but iag on freelist");
-		jfs_err("  agno = %d, iagno = %d", agno, iagno);
-		dump_mem("iag", iagp, 64);
-		updateSuper(ip->i_sb, FM_DIRTY);
+		IREAD_UNLOCK(imap->im_ipimap);
+		jfs_error(ip->i_sb,
+			  "diAllocIno: nfreeinos = 0, but iag on freelist");
 		return -EIO;
 	}
 
@@ -1840,7 +1851,12 @@
 	 * with free inodes.
 	 */
 	for (sword = 0;; sword++) {
-		assert(sword < SMAPSZ);
+		if (sword >= SMAPSZ) {
+			IREAD_UNLOCK(imap->im_ipimap);
+			jfs_error(ip->i_sb,
+				  "diAllocIno: free inode not found in summary map");
+			return -EIO;
+		}
 
 		if (~iagp->inosmap[sword])
 			break;
@@ -1850,13 +1866,21 @@
 	 * the extent number.
 	 */
 	rem = diFindFree(le32_to_cpu(iagp->inosmap[sword]), 0);
-	assert(rem < EXTSPERSUM);
+	if (rem >= EXTSPERSUM) {
+		IREAD_UNLOCK(imap->im_ipimap);
+		jfs_error(ip->i_sb, "diAllocIno: no free extent found");
+		return -EIO;
+	}
 	extno = (sword << L2EXTSPERSUM) + rem;
 
 	/* find the first free inode in the extent.
 	 */
 	rem = diFindFree(le32_to_cpu(iagp->wmap[extno]), 0);
-	assert(rem < INOSPEREXT);
+	if (rem >= INOSPEREXT) {
+		IREAD_UNLOCK(imap->im_ipimap);
+		jfs_error(ip->i_sb, "diAllocIno: free inode not found");
+		return -EIO;
+	}
 
 	/* compute the inode number within the iag. 
 	 */
@@ -1939,7 +1963,9 @@
 		 */
 		IREAD_LOCK(imap->im_ipimap);
 		if ((rc = diIAGRead(imap, iagno, &mp))) {
-			assert(0);
+			IREAD_UNLOCK(imap->im_ipimap);
+			jfs_error(ip->i_sb, "diAllocExt: error reading iag");
+			return rc;
 		}
 		iagp = (struct iag *) mp->data;
 	}
@@ -1947,7 +1973,13 @@
 	/* using the free extent summary map, find a free extent.
 	 */
 	for (sword = 0;; sword++) {
-		assert(sword < SMAPSZ);
+		if (sword >= SMAPSZ) {
+			release_metapage(mp);
+			IREAD_UNLOCK(imap->im_ipimap);
+			jfs_error(ip->i_sb,
+				  "diAllocExt: free ext summary map not found");
+			return -EIO;
+		}
 		if (~iagp->extsmap[sword])
 			break;
 	}
@@ -1955,7 +1987,12 @@
 	/* determine the extent number of the free extent.
 	 */
 	rem = diFindFree(le32_to_cpu(iagp->extsmap[sword]), 0);
-	assert(rem < EXTSPERSUM);
+	if (rem >= EXTSPERSUM) {
+		release_metapage(mp);
+		IREAD_UNLOCK(imap->im_ipimap);
+		jfs_error(ip->i_sb, "diAllocExt: free extent not found");
+		return -EIO;
+	}
 	extno = (sword << L2EXTSPERSUM) + rem;
 
 	/* initialize the new extent.
@@ -2066,9 +2103,18 @@
 
 	/* the inode should be free and backed.
 	 */
-	assert((le32_to_cpu(iagp->pmap[extno]) & mask) == 0);
-	assert((le32_to_cpu(iagp->wmap[extno]) & mask) == 0);
-	assert(addressPXD(&iagp->inoext[extno]) != 0);
+	if (((le32_to_cpu(iagp->pmap[extno]) & mask) != 0) ||
+	    ((le32_to_cpu(iagp->wmap[extno]) & mask) != 0) ||
+	    (addressPXD(&iagp->inoext[extno]) == 0)) {
+		if (amp)
+			release_metapage(amp);
+		if (bmp)
+			release_metapage(bmp);
+
+		jfs_error(imap->im_ipimap->i_sb,
+			  "diAllocBit: iag inconsistent");
+		return -EIO;
+	}
 
 	/* mark the inode as allocated in the working map.
 	 */
@@ -2172,7 +2218,10 @@
 
 	/* better have free extents.
 	 */
-	assert(iagp->nfreeexts);
+	if (!iagp->nfreeexts) {
+		jfs_error(imap->im_ipimap->i_sb, "diNewExt: no free extents");
+		return -EIO;
+	}
 
 	/* get the inode map inode.
 	 */
@@ -2240,7 +2289,12 @@
 					goto error_out;
 				ciagp = (struct iag *) cmp->data;
 			}
-			assert(ciagp != NULL);
+			if (ciagp == NULL) {
+				jfs_error(imap->im_ipimap->i_sb,
+					  "diNewExt: ciagp == NULL");
+				rc = -EIO;
+				goto error_out;
+			}
 		}
 	}
 
@@ -2474,7 +2528,14 @@
 		/* acquire inode map lock */
 		IWRITE_LOCK(ipimap);
 
-		assert(ipimap->i_size >> L2PSIZE == imap->im_nextiag + 1);
+		if (ipimap->i_size >> L2PSIZE != imap->im_nextiag + 1) {
+			IWRITE_UNLOCK(ipimap);
+			IAGFREE_UNLOCK(imap);
+			jfs_error(imap->im_ipimap->i_sb,
+				  "diNewIAG: ipimap->i_size is wrong");
+			return -EIO;
+		}
+
 
 		/* get the next avaliable iag number */
 		iagno = imap->im_nextiag;
@@ -2507,7 +2568,6 @@
 
 		/* assign a buffer for the page */
 		mp = get_metapage(ipimap, xaddr, PSIZE, 1);
-		//bp = bmAssign(ipimap, blkno, xaddr, PSIZE, bmREAD_PAGE);
 		if (!mp) {
 			/* Free the blocks allocated for the iag since it was
 			 * not successfully added to the inode map
@@ -2734,7 +2794,11 @@
 	/* get the iag number containing the inode */
 	iagno = INOTOIAG(inum);
 	/* make sure that the iag is contained within the map */
-	assert(iagno < imap->im_nextiag);
+	if (iagno >= imap->im_nextiag) {
+		jfs_error(ipimap->i_sb,
+			  "diUpdatePMap: the iag is outside the map");
+		return -EIO;
+	}
 	/* read the iag */
 	IREAD_LOCK(ipimap);
 	rc = diIAGRead(imap, iagno, &mp);
@@ -2759,14 +2823,14 @@
 		 * of last reference release;
 		 */
 		if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) {
-			jfs_err("diUpdatePMap: inode %ld not marked as "
-				"allocated in wmap!", inum);
-			updateSuper(ipimap->i_sb, FM_DIRTY);
+			jfs_error(ipimap->i_sb, 
+				  "diUpdatePMap: inode %ld not marked as "
+				  "allocated in wmap!", inum);
 		}
 		if (!(le32_to_cpu(iagp->pmap[extno]) & mask)) {
-			jfs_err("diUpdatePMap: inode %ld not marked as "
-				"allocated in pmap!", inum);
-			updateSuper(ipimap->i_sb, FM_DIRTY);
+			jfs_error(ipimap->i_sb,
+				  "diUpdatePMap: inode %ld not marked as "
+				  "allocated in pmap!", inum);
 		}
 		/* update the bitmap for the extent of the freed inode */
 		iagp->pmap[extno] &= cpu_to_le32(~mask);
@@ -2778,8 +2842,18 @@
 		/* The inode should be already allocated in the working map
 		 * and should be free in persistent map;
 		 */
-		assert(le32_to_cpu(iagp->wmap[extno]) & mask);
-		assert((le32_to_cpu(iagp->pmap[extno]) & mask) == 0);
+		if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) {
+			jfs_error(ipimap->i_sb,
+				  "diUpdatePMap: the inode is not allocated in "
+				  "the working map");
+			return -EIO;
+		}
+		if ((le32_to_cpu(iagp->pmap[extno]) & mask) != 0) {
+			jfs_error(ipimap->i_sb,
+				  "diUpdatePMap: the inode is not free in the "
+				  "persistent map");
+			return -EIO;
+		}
 		/* update the bitmap for the extent of the allocated inode */
 		iagp->pmap[extno] |= cpu_to_le32(mask);
 	}
@@ -2817,7 +2891,6 @@
 		mp->clsn = tblk->clsn;
 		LOGSYNC_UNLOCK(log);
 	}
-//      bmLazyWrite(mp, log->flag & JFS_COMMIT);
 	write_metapage(mp);
 	return (0);
 }
@@ -2872,7 +2945,12 @@
 			continue;
 		}
 		iagp = (struct iag *) bp->data;
-		assert(le32_to_cpu(iagp->iagnum) == i);
+		if (le32_to_cpu(iagp->iagnum) != i) {
+			release_metapage(bp);
+			jfs_error(ipimap->i_sb,
+				  "diExtendFs: unexpected value of iagnum");
+			return -EIO;
+		}
 
 		/* leave free iag in the free iag list */
 		if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) {  
@@ -2884,9 +2962,6 @@
 		agstart = le64_to_cpu(iagp->agstart);
 		/* iagp->agstart = agstart & ~(mp->db_agsize - 1); */
 		n = agstart >> mp->db_agl2size;
-/*
-printf("diExtendFS: iag:%d agstart:%Ld agno:%d\n", i, agstart, n);
-*/
 
 		/* compute backed inodes */
 		numinos = (EXTSPERIAG - le32_to_cpu(iagp->nfreeexts))
@@ -2947,8 +3022,12 @@
 		write_metapage(bp);
 	}
 
-	ASSERT(xnuminos == atomic_read(&imap->im_numinos) &&
-	       xnumfree == atomic_read(&imap->im_numfree));
+	if (xnuminos != atomic_read(&imap->im_numinos) ||
+	    xnumfree != atomic_read(&imap->im_numfree)) {
+		jfs_error(ipimap->i_sb,
+			  "diExtendFs: numinos or numfree incorrect");
+		return -EIO;
+	}
 
 	return rcx;
 }
diff -Nru a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c
--- a/fs/jfs/jfs_metapage.c	Wed Oct 15 00:46:36 2003
+++ b/fs/jfs/jfs_metapage.c	Wed Oct 15 00:46:36 2003
@@ -1,6 +1,6 @@
 /*
- *   Copyright (c) International Business Machines Corp., 2000-2002
- *   Portions Copyright (c) Christoph Hellwig, 2001-2002
+ *   Copyright (C) International Business Machines Corp., 2000-2003
+ *   Portions Copyright (C) Christoph Hellwig, 2001-2002
  *
  *   This program is free software;  you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -22,6 +22,7 @@
 #include <linux/buffer_head.h>
 #include <linux/mempool.h>
 #include "jfs_incore.h"
+#include "jfs_superblock.h"
 #include "jfs_filsys.h"
 #include "jfs_metapage.h"
 #include "jfs_txnmgr.h"
@@ -233,14 +234,23 @@
 	if (mp) {
 	      page_found:
 		if (test_bit(META_discard, &mp->flag)) {
-			assert(new);	/* It's okay to reuse a discarded
-					 * if we expect it to be empty
-					 */
+			if (!new) {
+				spin_unlock(&meta_lock);
+				jfs_error(inode->i_sb,
+					  "__get_metapage: using a "
+					  "discarded metapage");
+				return NULL;
+			}
 			clear_bit(META_discard, &mp->flag);
 		}
 		mp->count++;
 		jfs_info("__get_metapage: found 0x%p, in hash", mp);
-		assert(mp->logical_size == size);
+		if (mp->logical_size != size) {
+			spin_unlock(&meta_lock);
+			jfs_error(inode->i_sb,
+				  "__get_metapage: mp->logical_size != size");
+			return NULL;
+		}
 		lock_metapage(mp);
 		spin_unlock(&meta_lock);
 	} else {
diff -Nru a/fs/jfs/jfs_superblock.h b/fs/jfs/jfs_superblock.h
--- a/fs/jfs/jfs_superblock.h	Wed Oct 15 00:46:36 2003
+++ b/fs/jfs/jfs_superblock.h	Wed Oct 15 00:46:36 2003
@@ -1,5 +1,5 @@
 /*
- *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Copyright (C) International Business Machines Corp., 2000-2003
  *
  *   This program is free software;  you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -108,5 +108,6 @@
 
 extern int readSuper(struct super_block *, struct buffer_head **);
 extern int updateSuper(struct super_block *, uint);
+extern void jfs_error(struct super_block *, const char *, ...);
 
 #endif /*_H_JFS_SUPERBLOCK */
diff -Nru a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
--- a/fs/jfs/jfs_txnmgr.c	Wed Oct 15 00:46:37 2003
+++ b/fs/jfs/jfs_txnmgr.c	Wed Oct 15 00:46:37 2003
@@ -1,6 +1,6 @@
 /*
- *   Copyright (c) International Business Machines Corp., 2000-2003
- *   Portions Copyright (c) Christoph Hellwig, 2001-2002
+ *   Copyright (C) International Business Machines Corp., 2000-2003
+ *   Portions Copyright (C) Christoph Hellwig, 2001-2002
  *
  *   This program is free software;  you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -1442,7 +1442,6 @@
 		 * page is not itself logged, to prevent pageout of the map
 		 * page before the log;
 		 */
-		assert(tlck->type & tlckFREE);
 
 		/* log LOG_NOREDOINOEXT of the freed inode extent for
 		 * logredo() to start NoRedoPage filters, and to update
@@ -2655,7 +2654,7 @@
 	 * mark filesystem dirty
 	 */
 	if (dirty)
-		updateSuper(tblk->sb, FM_DIRTY);
+		jfs_error(tblk->sb, "txAbort");
 
 	return;
 }
@@ -2714,7 +2713,7 @@
 	/*
 	 * mark filesystem dirty
 	 */
-	updateSuper(cd->sb, FM_DIRTY);
+	jfs_error(cd->sb, "txAbortCommit");
 }
 
 
diff -Nru a/fs/jfs/jfs_xtree.c b/fs/jfs/jfs_xtree.c
--- a/fs/jfs/jfs_xtree.c	Wed Oct 15 00:46:36 2003
+++ b/fs/jfs/jfs_xtree.c	Wed Oct 15 00:46:36 2003
@@ -1,5 +1,5 @@
 /*
- *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Copyright (C) International Business Machines Corp., 2000-2003
  *
  *   This program is free software;  you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -60,21 +60,21 @@
 #define XT_PAGE(IP, MP) BT_PAGE(IP, MP, xtpage_t, i_xtroot)
 
 /* get page buffer for specified block address */
+/* ToDo: Replace this ugly macro with a function */
 #define XT_GETPAGE(IP, BN, MP, SIZE, P, RC)\
 {\
-        BT_GETPAGE(IP, BN, MP, xtpage_t, SIZE, P, RC, i_xtroot)\
-        if (!(RC))\
-        {\
-                if ((le16_to_cpu((P)->header.nextindex) < XTENTRYSTART) ||\
-                    (le16_to_cpu((P)->header.nextindex) > le16_to_cpu((P)->header.maxentry)) ||\
-                    (le16_to_cpu((P)->header.maxentry) > (((BN)==0)?XTROOTMAXSLOT:PSIZE>>L2XTSLOTSIZE)))\
-                {\
-                        jfs_err("XT_GETPAGE: xtree page corrupt");\
+	BT_GETPAGE(IP, BN, MP, xtpage_t, SIZE, P, RC, i_xtroot)\
+	if (!(RC))\
+	{\
+		if ((le16_to_cpu((P)->header.nextindex) < XTENTRYSTART) ||\
+		    (le16_to_cpu((P)->header.nextindex) > le16_to_cpu((P)->header.maxentry)) ||\
+		    (le16_to_cpu((P)->header.maxentry) > (((BN)==0)?XTROOTMAXSLOT:PSIZE>>L2XTSLOTSIZE)))\
+		{\
+			jfs_error((IP)->i_sb, "XT_GETPAGE: xtree page corrupt");\
 			BT_PUTPAGE(MP);\
-			updateSuper((IP)->i_sb, FM_DIRTY);\
 			MP = NULL;\
-                        RC = -EIO;\
-                }\
+			RC = -EIO;\
+		}\
         }\
 }
 
@@ -1611,14 +1611,21 @@
 	/* there must exist extent to be extended */
 	if ((rc = xtSearch(ip, xoff - 1, &cmp, &btstack, XT_INSERT)))
 		return rc;
-	assert(cmp == 0);
+	if (cmp != 0) {
+		jfs_error(ip->i_sb, "xtExtend: xtSearch did not find extent");
+		return -EIO;
+	}
 
 	/* retrieve search result */
 	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
 
 	/* extension must be contiguous */
 	xad = &p->xad[index];
-	assert((offsetXAD(xad) + lengthXAD(xad)) == xoff);
+	if ((offsetXAD(xad) + lengthXAD(xad)) != xoff) {
+		XT_PUTPAGE(mp);
+		jfs_error(ip->i_sb, "xtExtend: extension is not contiguous");
+		return -EIO;
+	}
 
 	/*
 	 * acquire a transaction lock on the leaf page;
@@ -1771,14 +1778,22 @@
 	/* there must exist extent to be tailgated */
 	if ((rc = xtSearch(ip, xoff, &cmp, &btstack, XT_INSERT)))
 		return rc;
-	assert(cmp == 0);
+	if (cmp != 0) {
+		jfs_error(ip->i_sb, "xtTailgate: couldn't find extent");
+		return -EIO;
+	}
 
 	/* retrieve search result */
 	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
 
 	/* entry found must be last entry */
 	nextindex = le16_to_cpu(p->header.nextindex);
-	assert(index == nextindex - 1);
+	if (index != nextindex - 1) {
+		XT_PUTPAGE(mp);
+		jfs_error(ip->i_sb,
+			  "xtTailgate: the entry found is not the last entry");
+		return -EIO;
+	}
 
 	BT_MARK_DIRTY(mp, ip);
 	/*
@@ -1941,13 +1956,14 @@
 	nxoff = offsetXAD(nxad);
 	nxlen = lengthXAD(nxad);
 	nxaddr = addressXAD(nxad);
-/*
-printf("xtUpdate: nxflag:0x%x nxoff:0x%lx nxlen:0x%x nxaddr:0x%lx\n",
-        nxad->flag, (ulong)nxoff, nxlen, (ulong)nxaddr);
-*/
+
 	if ((rc = xtSearch(ip, nxoff, &cmp, &btstack, XT_INSERT)))
 		return rc;
-	assert(cmp == 0);
+
+	if (cmp != 0) {
+		jfs_error(ip->i_sb, "xtUpdate: Could not find extent");
+		return -EIO;
+	}
 
 	/* retrieve search result */
 	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index0);
@@ -1966,14 +1982,15 @@
 	xoff = offsetXAD(xad);
 	xlen = lengthXAD(xad);
 	xaddr = addressXAD(xad);
-/*
-printf("xtUpdate: xflag:0x%x xoff:0x%lx xlen:0x%x xaddr:0x%lx\n",
-        xflag, (ulong)xoff, xlen, (ulong)xaddr);
-*/
 
 	/* nXAD must be completely contained within XAD */
-	assert(xoff <= nxoff);
-	assert(nxoff + nxlen <= xoff + xlen);
+	if ((xoff > nxoff) ||
+	    (nxoff + nxlen > xoff + xlen)) {
+		XT_PUTPAGE(mp);
+		jfs_error(ip->i_sb,
+			  "xtUpdate: nXAD in not completely contained within XAD");
+		return -EIO;
+	}
 
 	index = index0;
 	newindex = index + 1;
@@ -2118,7 +2135,11 @@
 	} else if (xoff == nxoff)
 		goto out;
 
-	assert(xoff < nxoff);
+	if (xoff >= nxoff) {
+		XT_PUTPAGE(mp);
+		jfs_error(ip->i_sb, "xtUpdate: xoff >= nxoff");
+		return -EIO;
+	}
 /* #endif _JFS_WIP_COALESCE */
 
 	/*
@@ -2135,9 +2156,6 @@
 
 	/* insert nXAD:recorded */
 	if (nextindex == le16_to_cpu(p->header.maxentry)) {
-/*
-printf("xtUpdate.updateRight.split p:0x%p\n", p);
-*/
 		rootsplit = p->header.flag & BT_ROOT;
 
 		/* xtSpliUp() unpins leaf pages */
@@ -2248,18 +2266,23 @@
 
 	/* recompute split pages */
 	if (nextindex == le16_to_cpu(p->header.maxentry)) {
-/*
-printf("xtUpdate: updateRight+Left recompute split pages: p:0x%p\n", p);
-*/
 		XT_PUTPAGE(mp);
 
 		if ((rc = xtSearch(ip, nxoff, &cmp, &btstack, XT_INSERT)))
 			return rc;
-		assert(cmp == 0);
+		if (cmp != 0) {
+			jfs_error(ip->i_sb, "xtUpdate: xtSearch failed");
+			return -EIO;
+		}
 
 		/* retrieve search result */
 		XT_GETSEARCH(ip, btstack.top, bn, mp, p, index0);
-		assert(index0 == index);
+		if (index0 != index) {
+			XT_PUTPAGE(mp);
+			jfs_error(ip->i_sb,
+				  "xtUpdate: unexpected value of index");
+			return -EIO;
+		}
 	}
 
 	/*
@@ -2755,6 +2778,7 @@
  *              txCommit() to commit all the allocation before call
  *              this routine.
  */
+int
 xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad,	/* old XAD */
 	   s64 nxaddr,		/* new xaddr */
 	   int xtype)
@@ -3925,7 +3949,11 @@
 		rc = xtSearch(ip, xoff, &cmp, &btstack, 0);
 		if (rc)
 			return rc;
-		assert(cmp == 0);
+		if (cmp != 0) {
+			jfs_error(ip->i_sb,
+				  "xtTruncate_pmap: did not find extent");
+			return -EIO;
+		}
 		XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
 	} else {
 		/*
diff -Nru a/fs/jfs/namei.c b/fs/jfs/namei.c
--- a/fs/jfs/namei.c	Wed Oct 15 00:46:37 2003
+++ b/fs/jfs/namei.c	Wed Oct 15 00:46:37 2003
@@ -1,6 +1,6 @@
 /*
- *   Copyright (c) International Business Machines Corp., 2000-2002
- *   Portions Copyright (c) Christoph Hellwig, 2001-2002
+ *   Copyright (C) International Business Machines Corp., 2000-2003
+ *   Portions Copyright (C) Christoph Hellwig, 2001-2002
  *
  *   This program is free software;  you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -19,6 +19,7 @@
 
 #include <linux/fs.h>
 #include "jfs_incore.h"
+#include "jfs_superblock.h"
 #include "jfs_inode.h"
 #include "jfs_dinode.h"
 #include "jfs_dmap.h"
@@ -1138,7 +1139,17 @@
 		new_ip->i_nlink--;
 		if (S_ISDIR(new_ip->i_mode)) {
 			new_ip->i_nlink--;
-			assert(new_ip->i_nlink == 0);
+			if (new_ip->i_nlink) {
+				up(&JFS_IP(new_dir)->commit_sem);
+				up(&JFS_IP(old_ip)->commit_sem);
+				if (old_dir != new_dir)
+					up(&JFS_IP(old_dir)->commit_sem);
+				if (!S_ISDIR(old_ip->i_mode) && new_ip)
+					IWRITE_UNLOCK(new_ip);
+				jfs_error(new_ip->i_sb,
+					  "jfs_rename: new_ip->i_nlink != 0");
+				return -EIO;
+			}
 			tblk = tid_to_tblock(tid);
 			tblk->xflag |= COMMIT_DELETE;
 			tblk->ip = new_ip;
diff -Nru a/fs/jfs/resize.c b/fs/jfs/resize.c
--- a/fs/jfs/resize.c	Wed Oct 15 00:46:37 2003
+++ b/fs/jfs/resize.c	Wed Oct 15 00:46:37 2003
@@ -1,5 +1,5 @@
 /*
- *   Copyright (c) International Business Machines  Corp., 2000-2003
+ *   Copyright (C) International Business Machines  Corp., 2000-2003
  *
  *   This program is free software;  you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -523,7 +523,7 @@
 	goto resume;
 
       error_out:
-	updateSuper(sb, FM_DIRTY);
+	jfs_error(sb, "jfs_extendfs");
 
       resume:
 	/*
diff -Nru a/fs/jfs/super.c b/fs/jfs/super.c
--- a/fs/jfs/super.c	Wed Oct 15 00:46:36 2003
+++ b/fs/jfs/super.c	Wed Oct 15 00:46:36 2003
@@ -1,6 +1,6 @@
 /*
- *   Copyright (c) International Business Machines Corp., 2000-2003
- *   Portions Copyright (c) Christoph Hellwig, 2001-2002
+ *   Copyright (C) International Business Machines Corp., 2000-2003
+ *   Portions Copyright (C) Christoph Hellwig, 2001-2002
  *
  *   This program is free software;  you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -85,6 +85,42 @@
 extern wait_queue_head_t jfs_commit_thread_wait;
 extern wait_queue_head_t jfs_sync_thread_wait;
 
+static void jfs_handle_error(struct super_block *sb)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+
+	if (sb->s_flags & MS_RDONLY)
+		return;
+
+	updateSuper(sb, FM_DIRTY);
+
+	if (sbi->flag & JFS_ERR_PANIC)
+		panic("JFS (device %s): panic forced after error\n",
+			sb->s_id);
+	else if (sbi->flag & JFS_ERR_REMOUNT_RO) {
+		jfs_err("ERROR: (device %s): remounting filesystem "
+			"as read-only\n",
+			sb->s_id);
+		sb->s_flags |= MS_RDONLY;
+	} 
+
+	/* nothing is done for continue beyond marking the superblock dirty */
+}
+
+void jfs_error(struct super_block *sb, const char * function, ...)
+{
+	static char error_buf[256];
+	va_list args;
+
+	va_start(args, function);
+	vsprintf(error_buf, function, args);
+	va_end(args);
+
+	printk(KERN_ERR "ERROR: (device %s): %s\n", sb->s_id, error_buf);
+
+	jfs_handle_error(sb);
+}
+
 static struct inode *jfs_alloc_inode(struct super_block *sb)
 {
 	struct jfs_inode_info *jfs_inode;
@@ -167,7 +203,7 @@
 
 enum {
 	Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize,
-	Opt_ignore, Opt_err,
+	Opt_errors, Opt_ignore, Opt_err,
 };
 
 static match_table_t tokens = {
@@ -175,6 +211,7 @@
 	{Opt_nointegrity, "nointegrity"},
 	{Opt_iocharset, "iocharset=%s"},
 	{Opt_resize, "resize=%u"},
+	{Opt_errors, "errors=%s"},
 	{Opt_ignore, "noquota"},
 	{Opt_ignore, "quota"},
 	{Opt_ignore, "usrquota"},
@@ -234,6 +271,31 @@
 				*newLVSize = simple_strtoull(resize, &resize, 0);
 			break;
 		}
+		case Opt_errors:
+		{
+			char *errors = args[0].from;
+			if (!errors || !*errors)
+				goto cleanup;
+			if (!strcmp(errors, "continue")) {
+				*flag &= ~JFS_ERR_REMOUNT_RO;
+				*flag &= ~JFS_ERR_PANIC;
+				*flag |= JFS_ERR_CONTINUE;
+			} else if (!strcmp(errors, "remount-ro")) {
+				*flag &= ~JFS_ERR_CONTINUE;
+				*flag &= ~JFS_ERR_PANIC;
+				*flag |= JFS_ERR_REMOUNT_RO;
+			} else if (!strcmp(errors, "panic")) {
+				*flag &= ~JFS_ERR_CONTINUE;
+				*flag &= ~JFS_ERR_REMOUNT_RO;
+				*flag |= JFS_ERR_PANIC;
+			} else {
+				printk(KERN_ERR
+				       "JFS: %s is an invalid error handler\n",
+				       errors);
+				goto cleanup;
+			}
+			break;
+		}
 		default:
 			printk("jfs: Unrecognized mount option \"%s\" "
 					" or missing value\n", p);
@@ -316,7 +378,9 @@
 	memset(sbi, 0, sizeof (struct jfs_sb_info));
 	sb->s_fs_info = sbi;
 
-	flag = 0;
+	/* initialize the mount flag and determine the default error handler */
+	flag = JFS_ERR_REMOUNT_RO;
+
 	if (!parse_options((char *) data, sb, &newLVSize, &flag)) {
 		kfree(sbi);
 		return -EINVAL;
diff -Nru a/fs/jfs/xattr.c b/fs/jfs/xattr.c
--- a/fs/jfs/xattr.c	Wed Oct 15 00:46:36 2003
+++ b/fs/jfs/xattr.c	Wed Oct 15 00:46:36 2003
@@ -1,6 +1,6 @@
 /*
- *   Copyright (c) International Business Machines  Corp., 2000-2002
- *   Copyright (c) Christoph Hellwig, 2002
+ *   Copyright (C) International Business Machines  Corp., 2000-2003
+ *   Copyright (C) Christoph Hellwig, 2002
  *
  *   This program is free software;  you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -20,6 +20,7 @@
 #include <linux/fs.h>
 #include <linux/xattr.h>
 #include "jfs_incore.h"
+#include "jfs_superblock.h"
 #include "jfs_dmap.h"
 #include "jfs_debug.h"
 #include "jfs_dinode.h"
@@ -381,7 +382,10 @@
 		return ea_read_inline(ip, ealist);
 
 	nbytes = sizeDXD(&ji->ea);
-	assert(nbytes);
+	if (!nbytes) {
+		jfs_error(sb, "ea_read: nbytes is 0");
+		return -EIO;
+	}
 
 	/* 
 	 * Figure out how many blocks were allocated when this EA list was
@@ -477,7 +481,10 @@
 		}
 		current_blocks = 0;
 	} else {
-		assert(ji->ea.flag & DXD_EXTENT);
+		if (!(ji->ea.flag & DXD_EXTENT)) {
+			jfs_error(sb, "ea_get: invalid ea.flag)");
+			return -EIO;
+		}
 		current_blocks = (ea_size + sb->s_blocksize - 1) >>
 		    sb->s_blocksize_bits;
 	}
diff -Nru a/fs/locks.c b/fs/locks.c
--- a/fs/locks.c	Wed Oct 15 00:46:37 2003
+++ b/fs/locks.c	Wed Oct 15 00:46:37 2003
@@ -1288,7 +1288,7 @@
 
 	locks_insert_lock(before, fl);
 
-	error = f_setown(filp, current->tgid, 1);
+	error = f_setown(filp, current->pid, 0);
 out_unlock:
 	unlock_kernel();
 	return error;
diff -Nru a/fs/nfs/direct.c b/fs/nfs/direct.c
--- a/fs/nfs/direct.c	Wed Oct 15 00:46:37 2003
+++ b/fs/nfs/direct.c	Wed Oct 15 00:46:37 2003
@@ -1,7 +1,7 @@
 /*
  * linux/fs/nfs/direct.c
  *
- * Copyright (C) 2001 by Chuck Lever <cel@netapp.com>
+ * Copyright (C) 2003 by Chuck Lever <cel@netapp.com>
  *
  * High-performance uncached I/O for the Linux NFS client
  *
@@ -26,19 +26,23 @@
  * also supports uncaching whole NFS partitions with "-o forcedirectio,"
  * an undocumented mount option.
  *
- * Designed by Jeff Kimmel, Chuck Lever, and Trond Myklebust.
+ * Designed by Jeff Kimmel, Chuck Lever, and Trond Myklebust, with
+ * help from Andrew Morton.
  *
  * 18 Dec 2001	Initial implementation for 2.4  --cel
  * 08 Jul 2002	Version for 2.4.19, with bug fixes --trondmy
- * 24 Sep 2002	Rewrite to use asynchronous RPCs, port to 2.5  --cel
+ * 08 Jun 2003	Port to 2.5 APIs  --cel
  *
  */
 
 #include <linux/config.h>
+#include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
+#include <linux/smp_lock.h>
 #include <linux/file.h>
-#include <linux/errno.h>
+#include <linux/pagemap.h>
+
 #include <linux/nfs_fs.h>
 #include <linux/nfs_page.h>
 #include <linux/sunrpc/clnt.h>
@@ -46,35 +50,41 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-#define NFSDBG_FACILITY		(NFSDBG_PAGECACHE | NFSDBG_VFS)
+#define NFSDBG_FACILITY		NFSDBG_VFS
 #define VERF_SIZE		(2 * sizeof(__u32))
+#define MAX_DIRECTIO_SIZE	(4096UL << PAGE_SHIFT)
 
 
 /**
- * nfs_get_user_pages - find and set up page representing user buffer
- * addr: user-space address of target buffer
- * size: total size in bytes of target buffer
- * @pages: returned array of page struct pointers underlying target buffer
- * write: whether or not buffer is target of a write operation
+ * nfs_get_user_pages - find and set up pages underlying user's buffer
+ * rw: direction (read or write)
+ * user_addr: starting address of this segment of user's buffer
+ * count: size of this segment
+ * @pages: returned array of page struct pointers underlying user's buffer
  */
 static inline int
-nfs_get_user_pages(unsigned long addr, size_t size,
-		struct page ***pages, int rw)
+nfs_get_user_pages(int rw, unsigned long user_addr, size_t size,
+		struct page ***pages)
 {
 	int result = -ENOMEM;
-	unsigned page_count = (unsigned) size >> PAGE_SHIFT;
-	unsigned array_size = (page_count * sizeof(struct page *)) + 2U;
+	unsigned long page_count;
+	size_t array_size;
 
-	*pages = (struct page **) kmalloc(array_size, GFP_KERNEL);
+	/* set an arbitrary limit to prevent arithmetic overflow */
+	if (size > MAX_DIRECTIO_SIZE)
+		return -EFBIG;
+
+	page_count = (user_addr + size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	page_count -= user_addr >> PAGE_SHIFT;
+
+	array_size = (page_count * sizeof(struct page *));
+	*pages = kmalloc(array_size, GFP_KERNEL);
 	if (*pages) {
 		down_read(&current->mm->mmap_sem);
-		result = get_user_pages(current, current->mm, addr,
-					page_count, (rw == WRITE), 0,
+		result = get_user_pages(current, current->mm, user_addr,
+					page_count, (rw == READ), 0,
 					*pages, NULL);
 		up_read(&current->mm->mmap_sem);
-		if (result < 0)
-			printk(KERN_ERR "%s: get_user_pages result %d\n",
-					__FUNCTION__, result);
 	}
 	return result;
 }
@@ -83,177 +93,366 @@
  * nfs_free_user_pages - tear down page struct array
  * @pages: array of page struct pointers underlying target buffer
  */
-static inline void
-nfs_free_user_pages(struct page **pages, unsigned count)
+static void
+nfs_free_user_pages(struct page **pages, int npages, int do_dirty)
 {
-	unsigned page = 0;
+	int i;
+	for (i = 0; i < npages; i++) {
+		if (do_dirty)
+			set_page_dirty_lock(pages[i]);
+		page_cache_release(pages[i]);
+	}
+	kfree(pages);
+}
 
-	while (count--)
-		page_cache_release(pages[page++]);
+/**
+ * nfs_direct_read_seg - Read in one iov segment.  Generate separate
+ *                        read RPCs for each "rsize" bytes.
+ * @inode: target inode
+ * @file: target file (may be NULL)
+ * user_addr: starting address of this segment of user's buffer
+ * count: size of this segment
+ * file_offset: offset in file to begin the operation
+ * @pages: array of addresses of page structs defining user's buffer
+ * nr_pages: size of pages array
+ */
+static int
+nfs_direct_read_seg(struct inode *inode, struct file *file,
+		unsigned long user_addr, size_t count, loff_t file_offset,
+		struct page **pages, int nr_pages)
+{
+	const unsigned int rsize = NFS_SERVER(inode)->rsize;
+	int tot_bytes = 0;
+	int curpage = 0;
+	struct nfs_read_data	rdata = {
+		.inode		= inode,
+		.args		= {
+			.fh		= NFS_FH(inode),
+		},
+		.res		= {
+			.fattr		= &rdata.fattr,
+		},
+	};
+
+	rdata.args.pgbase = user_addr & ~PAGE_MASK;
+	rdata.args.offset = file_offset;
+        do {
+		int result;
+
+		rdata.args.count = count;
+                if (rdata.args.count > rsize)
+                        rdata.args.count = rsize;
+		rdata.args.pages = &pages[curpage];
+
+		dprintk("NFS: direct read: c=%u o=%Ld ua=%lu, pb=%u, cp=%u\n",
+			rdata.args.count, (long long) rdata.args.offset,
+			user_addr + tot_bytes, rdata.args.pgbase, curpage);
+
+		lock_kernel();
+		result = NFS_PROTO(inode)->read(&rdata, file);
+		unlock_kernel();
+
+		if (result <= 0) {
+			if (tot_bytes > 0)
+				break;
+			if (result == -EISDIR)
+				result = -EINVAL;
+			return result;
+		}
 
-	kfree(pages);
+                tot_bytes += result;
+		if (rdata.res.eof)
+			break;
+
+                rdata.args.offset += result;
+		rdata.args.pgbase += result;
+		curpage += rdata.args.pgbase >> PAGE_SHIFT;
+		rdata.args.pgbase &= ~PAGE_MASK;
+		count -= result;
+	} while (count != 0);
+
+	/* XXX: should we zero the rest of the user's buffer if we
+	 *      hit eof? */
+
+	return tot_bytes;
 }
 
 /**
- * nfs_iov2pagelist - convert an array of iovecs to a list of page requests
- * @inode: inode of target file
- * @cred: credentials of user who requested I/O
+ * nfs_direct_read - For each iov segment, map the user's buffer
+ *                   then generate read RPCs.
+ * @inode: target inode
+ * @file: target file (may be NULL)
  * @iov: array of vectors that define I/O buffer
- * offset: where in file to begin the read
+ * file_offset: offset in file to begin the operation
  * nr_segs: size of iovec array
- * @requests: append new page requests to this list head
+ *
+ * generic_file_direct_IO has already pushed out any non-direct
+ * writes so that this read will see them when we read from the
+ * server.
  */
 static int
-nfs_iov2pagelist(int rw, const struct inode *inode,
-		const struct rpc_cred *cred,
-		const struct iovec *iov, loff_t offset,
-		unsigned long nr_segs, struct list_head *requests)
+nfs_direct_read(struct inode *inode, struct file *file,
+		const struct iovec *iov, loff_t file_offset,
+		unsigned long nr_segs)
 {
-	unsigned seg;
 	int tot_bytes = 0;
-	struct page **pages;
+	unsigned long seg = 0;
+
+	while ((seg < nr_segs) && (tot_bytes >= 0)) {
+		int result, page_count;
+		struct page **pages;
+		const struct iovec *vec = &iov[seg++];
+		unsigned long user_addr = (unsigned long) vec->iov_base;
+		size_t size = vec->iov_len;
+
+                page_count = nfs_get_user_pages(READ, user_addr, size, &pages);
+                if (page_count < 0) {
+                        nfs_free_user_pages(pages, 0, 0);
+			if (tot_bytes > 0)
+				break;
+                        return page_count;
+                }
+
+		result = nfs_direct_read_seg(inode, file, user_addr, size,
+				file_offset, pages, page_count);
+
+		nfs_free_user_pages(pages, page_count, 1);
+
+		if (result <= 0) {
+			if (tot_bytes > 0)
+				break;
+			return result;
+		}
+		tot_bytes += result;
+		file_offset += result;
+		if (result < size)
+			break;
+	}
+
+	return tot_bytes;
+}
 
-	/* for each iovec in the array... */
-	for (seg = 0; seg < nr_segs; seg++) {
-		const unsigned long user_addr =
-					(unsigned long) iov[seg].iov_base;
-		size_t bytes = iov[seg].iov_len;
-		unsigned int pg_offset = (user_addr & ~PAGE_MASK);
-		int page_count, page = 0;
-
-		page_count = nfs_get_user_pages(user_addr, bytes, &pages, rw);
-		if (page_count < 0) {
-			nfs_release_list(requests);
-			return page_count;
+/**
+ * nfs_direct_write_seg - Write out one iov segment.  Generate separate
+ *                        write RPCs for each "wsize" bytes, then commit.
+ * @inode: target inode
+ * @file: target file (may be NULL)
+ * user_addr: starting address of this segment of user's buffer
+ * count: size of this segment
+ * file_offset: offset in file to begin the operation
+ * @pages: array of addresses of page structs defining user's buffer
+ * nr_pages: size of pages array
+ */
+static int
+nfs_direct_write_seg(struct inode *inode, struct file *file,
+		unsigned long user_addr, size_t count, loff_t file_offset,
+		struct page **pages, int nr_pages)
+{
+	const unsigned int wsize = NFS_SERVER(inode)->wsize;
+	size_t request;
+	int need_commit;
+	int tot_bytes;
+	int curpage;
+	struct nfs_writeverf first_verf;
+	struct nfs_write_data	wdata = {
+		.inode		= inode,
+		.args		= {
+			.fh		= NFS_FH(inode),
+		},
+		.res		= {
+			.fattr		= &wdata.fattr,
+			.verf		= &wdata.verf,
+		},
+	};
+
+	wdata.args.stable = NFS_UNSTABLE;
+	if (IS_SYNC(inode) || NFS_PROTO(inode)->version == 2 || count <= wsize)
+		wdata.args.stable = NFS_FILE_SYNC;
+
+retry:
+	need_commit = 0;
+	tot_bytes = 0;
+	curpage = 0;
+	request = count;
+	wdata.args.pgbase = user_addr & ~PAGE_MASK;
+	wdata.args.offset = file_offset;
+        do {
+		int result;
+
+		wdata.args.count = request;
+                if (wdata.args.count > wsize)
+                        wdata.args.count = wsize;
+		wdata.args.pages = &pages[curpage];
+
+		dprintk("NFS: direct write: c=%u o=%Ld ua=%lu, pb=%u, cp=%u\n",
+			wdata.args.count, (long long) wdata.args.offset,
+			user_addr + tot_bytes, wdata.args.pgbase, curpage);
+
+		lock_kernel();
+		result = NFS_PROTO(inode)->write(&wdata, file);
+		unlock_kernel();
+
+		if (result <= 0) {
+			if (tot_bytes > 0)
+				break;
+			return result;
 		}
 
-		/* ...build as many page requests as required */
-		while (bytes > 0) {
-			struct nfs_page *new;
-			const unsigned int pg_bytes = (bytes > PAGE_SIZE) ?
-							PAGE_SIZE : bytes;
-
-			new = nfs_create_request((struct rpc_cred *) cred,
-						 (struct inode *) inode,
-						 pages[page],
-						 pg_offset, pg_bytes);
-			if (IS_ERR(new)) {
-				nfs_free_user_pages(pages, page_count);
-				nfs_release_list(requests);
-				return PTR_ERR(new);
-			}
-			new->wb_index = offset;
-			nfs_list_add_request(new, requests);
-
-			/* after the first page */
-			pg_offset = 0;
-			offset += PAGE_SIZE;
-			tot_bytes += pg_bytes;
-			bytes -= pg_bytes;
-			page++;
+		if (tot_bytes == 0)
+			memcpy(&first_verf.verifier, &wdata.verf.verifier,
+								VERF_SIZE);
+		if (wdata.verf.committed != NFS_FILE_SYNC) {
+			need_commit = 1;
+			if (memcmp(&first_verf.verifier,
+					&wdata.verf.verifier, VERF_SIZE))
+				goto sync_retry;
 		}
 
-		/* don't release pages here -- I/O completion will do that */
-		nfs_free_user_pages(pages, 0);
+                tot_bytes += result;
+                wdata.args.offset += result;
+		wdata.args.pgbase += result;
+		curpage += wdata.args.pgbase >> PAGE_SHIFT;
+		wdata.args.pgbase &= ~PAGE_MASK;
+		request -= result;
+	} while (request != 0);
+
+	/*
+	 * Commit data written so far, even in the event of an error
+	 */
+	if (need_commit) {
+		int result;
+
+		wdata.args.count = tot_bytes;
+		wdata.args.offset = file_offset;
+
+		lock_kernel();
+		result = NFS_PROTO(inode)->commit(&wdata, file);
+		unlock_kernel();
+
+		if (result < 0 || memcmp(&first_verf.verifier,
+						&wdata.verf.verifier,
+						VERF_SIZE) != 0)
+			goto sync_retry;
 	}
 
 	return tot_bytes;
+
+sync_retry:
+	wdata.args.stable = NFS_FILE_SYNC;
+	goto retry;
 }
 
 /**
- * do_nfs_direct_IO - Read or write data without caching
- * @inode: inode of target file
- * @cred: credentials of user who requested I/O
+ * nfs_direct_write - For each iov segment, map the user's buffer
+ *                    then generate write and commit RPCs.
+ * @inode: target inode
+ * @file: target file (may be NULL)
  * @iov: array of vectors that define I/O buffer
- * offset: where in file to begin the read
+ * file_offset: offset in file to begin the operation
  * nr_segs: size of iovec array
  *
- * Break the passed-in iovec into a series of page-sized or smaller
- * requests, where each page is mapped for direct user-land I/O.
- *
- * For each of these pages, create an NFS page request and
- * append it to an automatic list of page requests.
- *
- * When all page requests have been queued, start the I/O on the
- * whole list.  The underlying routines coalesce the pages on the
- * list into a bunch of asynchronous "r/wsize" network requests.
- *
- * I/O completion automatically unmaps and releases the pages.
+ * Upon return, generic_file_direct_IO invalidates any cached pages
+ * that non-direct readers might access, so they will pick up these
+ * writes immediately.
  */
 static int
-do_nfs_direct_IO(int rw, const struct inode *inode,
-		const struct rpc_cred *cred, const struct iovec *iov,
-		loff_t offset, unsigned long nr_segs)
+nfs_direct_write(struct inode *inode, struct file *file,
+		const struct iovec *iov, loff_t file_offset,
+		unsigned long nr_segs)
 {
-	LIST_HEAD(requests);
-	int result, tot_bytes;
-
-	result = nfs_iov2pagelist(rw, inode, cred, iov, offset, nr_segs,
-								&requests);
-	if (result < 0)
-		return result;
-	tot_bytes = result;
+	int tot_bytes = 0;
+	unsigned long seg = 0;
 
-	switch (rw) {
-	case READ:
-		if (IS_SYNC(inode) || (NFS_SERVER(inode)->rsize < PAGE_SIZE)) {
-			result = nfs_direct_read_sync(inode, cred, iov, offset, nr_segs);
-			break;
+	while ((seg < nr_segs) && (tot_bytes >= 0)) {
+		int result, page_count;
+		struct page **pages;
+		const struct iovec *vec = &iov[seg++];
+		unsigned long user_addr = (unsigned long) vec->iov_base;
+		size_t size = vec->iov_len;
+
+                page_count = nfs_get_user_pages(WRITE, user_addr, size, &pages);
+                if (page_count < 0) {
+                        nfs_free_user_pages(pages, 0, 0);
+			if (tot_bytes > 0)
+				break;
+                        return page_count;
+                }
+
+		result = nfs_direct_write_seg(inode, file, user_addr, size,
+				file_offset, pages, page_count);
+		nfs_free_user_pages(pages, page_count, 0);
+
+		if (result <= 0) {
+			if (tot_bytes > 0)
+				break;
+			return result;
 		}
-		result = nfs_pagein_list(&requests, NFS_SERVER(inode)->rpages);
-		nfs_wait_for_reads(&requests);
-		break;
-	case WRITE:
-		if (IS_SYNC(inode) || (NFS_SERVER(inode)->wsize < PAGE_SIZE))
-			result = nfs_direct_write_sync(inode, cred, iov, offset, nr_segs);
-		else
-			result = nfs_flush_list(&requests,
-					NFS_SERVER(inode)->wpages, FLUSH_WAIT);
-
-		/* invalidate cache so non-direct readers pick up changes */
-		invalidate_inode_pages((struct inode *) inode);
-		break;
-	default:
-		result = -EINVAL;
-		break;
+		tot_bytes += result;
+		file_offset += result;
+		if (result < size)
+			break;
 	}
+	/* Zap the page cache if we managed to write */
+	if (tot_bytes > 0)
+		invalidate_remote_inode(inode);
 
-	if (result < 0)
-		return result;
 	return tot_bytes;
 }
 
 /**
  * nfs_direct_IO - NFS address space operation for direct I/O
  * rw: direction (read or write)
- * @file: file struct of target file
+ * @iocb: target I/O control block
  * @iov: array of vectors that define I/O buffer
- * offset: offset in file to begin the operation
+ * file_offset: offset in file to begin the operation
  * nr_segs: size of iovec array
  *
+ * Usually a file system implements direct I/O by calling out to
+ * blockdev_direct_IO.  The NFS client doesn't have a backing block
+ * device, so we do everything by hand instead.
+ *
  * The inode's i_sem is no longer held by the VFS layer before it calls
  * this function to do a write.
  */
 int
 nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
-		loff_t offset, unsigned long nr_segs)
+		loff_t file_offset, unsigned long nr_segs)
 {
-	/* None of this works yet, so prevent it from compiling. */
-#if 0
-	int result;
+	int result = -EINVAL;
+	struct file *file = iocb->ki_filp;
 	struct dentry *dentry = file->f_dentry;
-	const struct inode *inode = dentry->d_inode->i_mapping->host;
-	const struct rpc_cred *cred = nfs_file_cred(file);
-#endif
-
-	dfprintk(VFS, "NFS: direct_IO(%s) (%s/%s) off/no(%Lu/%lu)\n",
-				((rw == READ) ? "READ" : "WRITE"),
-				dentry->d_parent->d_name.name,
-				dentry->d_name.name, offset, nr_segs);
+	struct inode *inode = dentry->d_inode;
+
+	/*
+	 * No support for async yet
+	 */
+	if (!is_sync_kiocb(iocb))
+		goto out;
+
+	result = nfs_revalidate_inode(NFS_SERVER(inode), inode);
+	if (result < 0)
+		goto out;
+
+	switch (rw) {
+	case READ:
+		dprintk("NFS: direct_IO(read) (%s) off/no(%Lu/%lu)\n",
+				dentry->d_name.name, file_offset, nr_segs);
 
-	result = do_nfs_direct_IO(rw, inode, cred, iov, offset, nr_segs);
+		result = nfs_direct_read(inode, file, iov,
+						file_offset, nr_segs);
+		break;
+	case WRITE:
+		dprintk("NFS: direct_IO(write) (%s) off/no(%Lu/%lu)\n",
+				dentry->d_name.name, file_offset, nr_segs);
 
-	dfprintk(VFS, "NFS: direct_IO result = %d\n", result);
+		result = nfs_direct_write(inode, file, iov,
+						file_offset, nr_segs);
+		break;
+	default:
+		break;
+	}
 
+out:
+	dprintk("NFS: direct_IO result=%d\n", result);
 	return result;
 }
diff -Nru a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
--- a/fs/nfs/nfs3proc.c	Wed Oct 15 00:46:36 2003
+++ b/fs/nfs/nfs3proc.c	Wed Oct 15 00:46:36 2003
@@ -284,6 +284,29 @@
 	return status < 0? status : wdata->res.count;
 }
 
+static int
+nfs3_proc_commit(struct nfs_write_data *cdata, struct file *filp)
+{
+	struct inode *		inode = cdata->inode;
+	struct nfs_fattr *	fattr = cdata->res.fattr;
+	struct rpc_message	msg = {
+		.rpc_proc	= &nfs3_procedures[NFS3PROC_COMMIT],
+		.rpc_argp	= &cdata->args,
+		.rpc_resp	= &cdata->res,
+	};
+	int			status;
+
+	dprintk("NFS call  commit %d @ %Ld\n", cdata->args.count,
+			(long long) cdata->args.offset);
+	fattr->valid = 0;
+	msg.rpc_cred = nfs_cred(inode, filp);
+	status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
+	if (status >= 0)
+		nfs3_write_refresh_inode(inode, fattr);
+	dprintk("NFS reply commit: %d\n", status);
+	return status;
+}
+
 /*
  * Create a regular file.
  * For now, we don't implement O_EXCL.
@@ -883,6 +906,7 @@
 	.readlink	= nfs3_proc_readlink,
 	.read		= nfs3_proc_read,
 	.write		= nfs3_proc_write,
+	.commit		= nfs3_proc_commit,
 	.create		= nfs3_proc_create,
 	.remove		= nfs3_proc_remove,
 	.unlink_setup	= nfs3_proc_unlink_setup,
diff -Nru a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
--- a/fs/nfs/nfs4proc.c	Wed Oct 15 00:46:37 2003
+++ b/fs/nfs/nfs4proc.c	Wed Oct 15 00:46:37 2003
@@ -1038,7 +1038,6 @@
 		.rpc_proc	= &nfs4_procedures[NFSPROC4_CLNT_READ],
 		.rpc_argp	= &rdata->args,
 		.rpc_resp	= &rdata->res,
-		.rpc_cred	= rdata->cred,
 	};
 	unsigned long timestamp = jiffies;
 	int status;
@@ -1053,8 +1052,11 @@
 		struct nfs4_state *state;
 		state = (struct nfs4_state *)filp->private_data;
 		memcpy(&rdata->args.stateid, &state->stateid, sizeof(rdata->args.stateid));
-	} else
+		msg.rpc_cred = state->owner->so_cred;
+	} else {
 		memcpy(&rdata->args.stateid, &zero_stateid, sizeof(rdata->args.stateid));
+		msg.rpc_cred = NFS_I(inode)->mm_cred;
+	}
 
 	fattr->valid = 0;
 	status = rpc_call_sync(server->client, &msg, flags);
@@ -1079,7 +1081,6 @@
 		.rpc_proc	= &nfs4_procedures[NFSPROC4_CLNT_WRITE],
 		.rpc_argp	= &wdata->args,
 		.rpc_resp	= &wdata->res,
-		.rpc_cred	= wdata->cred,
 	};
 	int status;
 
@@ -1093,15 +1094,54 @@
 		struct nfs4_state *state;
 		state = (struct nfs4_state *)filp->private_data;
 		memcpy(&wdata->args.stateid, &state->stateid, sizeof(wdata->args.stateid));
-	} else
+		msg.rpc_cred = state->owner->so_cred;
+	} else {
 		memcpy(&wdata->args.stateid, &zero_stateid, sizeof(wdata->args.stateid));
+		msg.rpc_cred = NFS_I(inode)->mm_cred;
+	}
 
 	fattr->valid = 0;
 	status = rpc_call_sync(server->client, &msg, rpcflags);
+	NFS_CACHEINV(inode);
 	dprintk("NFS reply write: %d\n", status);
 	return status;
 }
 
+static int
+nfs4_proc_commit(struct nfs_write_data *cdata, struct file *filp)
+{
+	struct inode *inode = cdata->inode;
+	struct nfs_fattr *fattr = cdata->res.fattr;
+	struct nfs_server *server = NFS_SERVER(inode);
+	struct rpc_message msg = {
+		.rpc_proc	= &nfs4_procedures[NFSPROC4_CLNT_COMMIT],
+		.rpc_argp	= &cdata->args,
+		.rpc_resp	= &cdata->res,
+	};
+	int status;
+
+	dprintk("NFS call  commit %d @ %Ld\n", cdata->args.count,
+			(long long) cdata->args.offset);
+
+	/*
+	 * Try first to use O_WRONLY, then O_RDWR stateid.
+	 */
+	if (filp) {
+		struct nfs4_state *state;
+		state = (struct nfs4_state *)filp->private_data;
+		memcpy(&cdata->args.stateid, &state->stateid, sizeof(cdata->args.stateid));
+		msg.rpc_cred = state->owner->so_cred;
+	} else {
+		memcpy(&cdata->args.stateid, &zero_stateid, sizeof(cdata->args.stateid));
+		msg.rpc_cred = NFS_I(inode)->mm_cred;
+	}
+
+	fattr->valid = 0;
+	status = rpc_call_sync(server->client, &msg, 0);
+	dprintk("NFS reply commit: %d\n", status);
+	return status;
+}
+
 /*
  * Got race?
  * We will need to arrange for the VFS layer to provide an atomic open.
@@ -1772,7 +1812,7 @@
 	.readlink	= nfs4_proc_readlink,
 	.read		= nfs4_proc_read,
 	.write		= nfs4_proc_write,
-	.commit		= NULL,
+	.commit		= nfs4_proc_commit,
 	.create		= nfs4_proc_create,
 	.remove		= nfs4_proc_remove,
 	.unlink_setup	= nfs4_proc_unlink_setup,
diff -Nru a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
--- a/fs/nfs/nfs4xdr.c	Wed Oct 15 00:46:38 2003
+++ b/fs/nfs/nfs4xdr.c	Wed Oct 15 00:46:38 2003
@@ -2323,6 +2323,8 @@
 	status = decode_read_getattr(&xdr, res->fattr);
 	if (!status)
 		status = -nfs_stat_to_errno(hdr.status);
+	if (!status)
+		status = res->count;
 out:
 	return status;
 }
diff -Nru a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
--- a/fs/nfs/pagelist.c	Wed Oct 15 00:46:37 2003
+++ b/fs/nfs/pagelist.c	Wed Oct 15 00:46:37 2003
@@ -154,26 +154,6 @@
 }
 
 /**
- * nfs_release_list - cleanly dispose of an unattached list of page requests
- * @list: list of doomed page requests
- */
-void
-nfs_release_list(struct list_head *list)
-{
-	while (!list_empty(list)) {
-		struct nfs_page *req = nfs_list_entry(list);
-
-		nfs_list_remove_request(req);
-
-		page_cache_release(req->wb_page);
-
-		/* Release struct file or cached credential */
-		nfs_clear_request(req);
-		nfs_page_free(req);
-	}
-}
-
-/**
  * nfs_list_add_request - Insert a request into a sorted list
  * @req: request
  * @head: head of list into which to insert the request.
@@ -219,37 +199,6 @@
 	if (!NFS_WBACK_BUSY(req))
 		return 0;
 	return nfs_wait_event(clnt, req->wb_wait, !NFS_WBACK_BUSY(req));
-}
-
-/**
- * nfs_wait_for_reads - wait for outstanding requests to complete
- * @head: list of page requests to wait for
- */
-int
-nfs_wait_for_reads(struct list_head *head)
-{
-	struct list_head *p = head->next;
-	unsigned int res = 0;
-
-	while (p != head) {
-		struct nfs_page *req = nfs_list_entry(p);
-		int error;
-
-		if (!NFS_WBACK_BUSY(req))
-			continue;
-
-		req->wb_count++;
-		error = nfs_wait_on_request(req);
-		if (error < 0)
-			return error;
-		nfs_list_remove_request(req);
-		nfs_clear_request(req);
-		nfs_page_free(req);
-
-		p = head->next;
-		res++;
-	}
-	return res;
 }
 
 /**
diff -Nru a/fs/open.c b/fs/open.c
--- a/fs/open.c	Wed Oct 15 00:46:35 2003
+++ b/fs/open.c	Wed Oct 15 00:46:35 2003
@@ -1035,7 +1035,7 @@
 asmlinkage long sys_vhangup(void)
 {
 	if (capable(CAP_SYS_TTY_CONFIG)) {
-		tty_vhangup(process_tty(current));
+		tty_vhangup(current->tty);
 		return 0;
 	}
 	return -EPERM;
diff -Nru a/fs/proc/array.c b/fs/proc/array.c
--- a/fs/proc/array.c	Wed Oct 15 00:46:37 2003
+++ b/fs/proc/array.c	Wed Oct 15 00:46:37 2003
@@ -304,9 +304,9 @@
 	mm = task->mm;
 	if(mm)
 		mm = mmgrab(mm);
-	if (process_tty(task)) {
-		tty_pgrp = process_tty(task)->pgrp;
-		tty_nr = new_encode_dev(tty_devnum(process_tty(task)));
+	if (task->tty) {
+		tty_pgrp = task->tty->pgrp;
+		tty_nr = new_encode_dev(tty_devnum(task->tty));
 	}
 	task_unlock(task);
 	if (mm) {
@@ -345,7 +345,7 @@
 		state,
 		ppid,
 		process_group(task),
-		process_session(task),
+		task->session,
 		tty_nr,
 		tty_pgrp,
 		task->flags,
diff -Nru a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c
--- a/fs/proc/proc_devtree.c	Wed Oct 15 00:46:37 2003
+++ b/fs/proc/proc_devtree.c	Wed Oct 15 00:46:37 2003
@@ -59,11 +59,14 @@
 		 * Unfortunately proc_register puts each new entry
 		 * at the beginning of the list.  So we rearrange them.
 		 */
-		ent = create_proc_read_entry(pp->name, S_IRUGO, de,
-					     property_read_proc, pp);
+		ent = create_proc_read_entry(pp->name, strncmp(pp->name, "security-", 9) ?
+					     S_IRUGO : S_IRUSR, de, property_read_proc, pp);
 		if (ent == 0)
 			break;
-		ent->size = pp->length;
+		if (!strncmp(pp->name, "security-", 9))
+		     ent->size = 0; /* don't leak number of password chars */
+		else
+		     ent->size = pp->length;
 		*lastp = ent;
 		lastp = &ent->next;
 	}
diff -Nru a/fs/xfs/linux/xfs_aops.c b/fs/xfs/linux/xfs_aops.c
--- a/fs/xfs/linux/xfs_aops.c	Wed Oct 15 00:46:37 2003
+++ b/fs/xfs/linux/xfs_aops.c	Wed Oct 15 00:46:37 2003
@@ -984,8 +984,7 @@
 	if (error)
 		return -error;
 
-        return blockdev_direct_IO(rw, iocb, inode,
-		pbmap.pbm_target->pbr_bdev,
+        return blockdev_direct_IO(rw, iocb, inode, pbmap.pbm_target->pbr_bdev,
 		iov, offset, nr_segs,
 		linvfs_get_blocks_direct,
 		linvfs_unwritten_convert_direct);
diff -Nru a/fs/xfs/linux/xfs_file.c b/fs/xfs/linux/xfs_file.c
--- a/fs/xfs/linux/xfs_file.c	Wed Oct 15 00:46:36 2003
+++ b/fs/xfs/linux/xfs_file.c	Wed Oct 15 00:46:36 2003
@@ -58,29 +58,55 @@
 static struct vm_operations_struct linvfs_file_vm_ops;
 
 
-STATIC ssize_t
-linvfs_read(
+STATIC inline ssize_t
+__linvfs_read(
 	struct kiocb		*iocb,
 	char __user		*buf,
+	int			ioflags,
 	size_t			count,
 	loff_t			pos)
 {
 	struct iovec		iov = {buf, count};
+	struct file		*file = iocb->ki_filp;
 	vnode_t			*vp;
 	int			error;
 
 	BUG_ON(iocb->ki_pos != pos);
-	vp = LINVFS_GET_VP(iocb->ki_filp->f_dentry->d_inode);
-	VOP_READ(vp, iocb, &iov, 1, &iocb->ki_pos, NULL, error);
 
+	if (unlikely(file->f_flags & O_DIRECT))
+		ioflags |= IO_ISDIRECT;
+	vp = LINVFS_GET_VP(file->f_dentry->d_inode);
+	VOP_READ(vp, iocb, &iov, 1, &iocb->ki_pos, ioflags, NULL, error);
 	return error;
 }
 
 
 STATIC ssize_t
-linvfs_write(
+linvfs_read(
+	struct kiocb		*iocb,
+	char __user		*buf,
+	size_t			count,
+	loff_t			pos)
+{
+	return __linvfs_read(iocb, buf, 0, count, pos);
+}
+
+STATIC ssize_t
+linvfs_read_invis(
+	struct kiocb		*iocb,
+	char __user		*buf,
+	size_t			count,
+	loff_t			pos)
+{
+	return __linvfs_read(iocb, buf, IO_INVIS, count, pos);
+}
+
+
+STATIC inline ssize_t
+__linvfs_write(
 	struct kiocb	*iocb,
 	const char 	*buf,
+	int		ioflags,
 	size_t		count,
 	loff_t		pos)
 {
@@ -89,25 +115,48 @@
 	struct inode	*inode = file->f_dentry->d_inode->i_mapping->host;
 	vnode_t		*vp = LINVFS_GET_VP(inode);
 	int		error;
-	int		direct = file->f_flags & O_DIRECT;
 
 	BUG_ON(iocb->ki_pos != pos);
-
-	if (direct) {
-		VOP_WRITE(vp, iocb, &iov, 1, &iocb->ki_pos, NULL, error);
+	if (unlikely(file->f_flags & O_DIRECT)) {
+		ioflags |= IO_ISDIRECT;
+		VOP_WRITE(vp, iocb, &iov, 1, &iocb->ki_pos,
+				ioflags, NULL, error);
 	} else {
 		down(&inode->i_sem);
-		VOP_WRITE(vp, iocb, &iov, 1, &iocb->ki_pos, NULL, error);
+		VOP_WRITE(vp, iocb, &iov, 1, &iocb->ki_pos,
+				ioflags, NULL, error);
 		up(&inode->i_sem);
 	}
-
 	return error;
 }
 
+
 STATIC ssize_t
-linvfs_readv(
+linvfs_write(
+	struct kiocb		*iocb,
+	const char __user	*buf,
+	size_t			count,
+	loff_t			pos)
+{
+	return __linvfs_write(iocb, buf, 0, count, pos);
+}
+
+STATIC ssize_t
+linvfs_write_invis(
+	struct kiocb		*iocb,
+	const char __user	*buf,
+	size_t			count,
+	loff_t			pos)
+{
+	return __linvfs_write(iocb, buf, IO_INVIS, count, pos);
+}
+
+
+STATIC inline ssize_t
+__linvfs_readv(
 	struct file		*file,
 	const struct iovec 	*iov,
+	int			ioflags,
 	unsigned long		nr_segs,
 	loff_t			*ppos)
 {
@@ -118,7 +167,10 @@
 
 	init_sync_kiocb(&kiocb, file);
 	kiocb.ki_pos = *ppos;
-	VOP_READ(vp, &kiocb, iov, nr_segs, &kiocb.ki_pos, NULL, error);
+
+	if (unlikely(file->f_flags & O_DIRECT))
+		ioflags |= IO_ISDIRECT;
+	VOP_READ(vp, &kiocb, iov, nr_segs, &kiocb.ki_pos, ioflags, NULL, error);
 	if (-EIOCBQUEUED == error)
 		error = wait_on_sync_kiocb(&kiocb);
 	*ppos = kiocb.ki_pos;
@@ -127,25 +179,49 @@
 }
 
 STATIC ssize_t
-linvfs_writev(
+linvfs_readv(
 	struct file		*file,
 	const struct iovec 	*iov,
 	unsigned long		nr_segs,
 	loff_t			*ppos)
 {
+	return __linvfs_readv(file, iov, 0, nr_segs, ppos);
+}
+
+STATIC ssize_t
+linvfs_readv_invis(
+	struct file		*file,
+	const struct iovec 	*iov,
+	unsigned long		nr_segs,
+	loff_t			*ppos)
+{
+	return __linvfs_readv(file, iov, IO_INVIS, nr_segs, ppos);
+}
+
+
+STATIC inline ssize_t
+__linvfs_writev(
+	struct file		*file,
+	const struct iovec 	*iov,
+	int			ioflags,
+	unsigned long		nr_segs,
+	loff_t			*ppos)
+{
 	struct inode	*inode = file->f_dentry->d_inode->i_mapping->host;
 	vnode_t		*vp = LINVFS_GET_VP(inode);
 	struct		kiocb kiocb;
 	int		error;
-	int		direct = file->f_flags & O_DIRECT;
 
 	init_sync_kiocb(&kiocb, file);
 	kiocb.ki_pos = *ppos;
-	if (direct) {
-		VOP_WRITE(vp, &kiocb, iov, nr_segs, &kiocb.ki_pos, NULL, error);
+	if (unlikely(file->f_flags & O_DIRECT)) {
+		ioflags |= IO_ISDIRECT;
+		VOP_WRITE(vp, &kiocb, iov, nr_segs, &kiocb.ki_pos,
+				ioflags, NULL, error);
 	} else {
 		down(&inode->i_sem);
-		VOP_WRITE(vp, &kiocb, iov, nr_segs, &kiocb.ki_pos, NULL, error);
+		VOP_WRITE(vp, &kiocb, iov, nr_segs, &kiocb.ki_pos,
+				ioflags, NULL, error);
 		up(&inode->i_sem);
 	}
 	if (-EIOCBQUEUED == error)
@@ -155,6 +231,27 @@
 	return error;
 }
 
+
+STATIC ssize_t
+linvfs_writev(
+	struct file		*file,
+	const struct iovec 	*iov,
+	unsigned long		nr_segs,
+	loff_t			*ppos)
+{
+	return __linvfs_writev(file, iov, 0, nr_segs, ppos);
+}
+
+STATIC ssize_t
+linvfs_writev_invis(
+	struct file		*file,
+	const struct iovec 	*iov,
+	unsigned long		nr_segs,
+	loff_t			*ppos)
+{
+	return __linvfs_writev(file, iov, IO_INVIS, nr_segs, ppos);
+}
+
 STATIC ssize_t
 linvfs_sendfile(
 	struct file		*filp,
@@ -166,8 +263,7 @@
 	vnode_t			*vp = LINVFS_GET_VP(filp->f_dentry->d_inode);
 	int			error;
 
-	VOP_SENDFILE(vp, filp, ppos, count, actor, target, NULL, error);
-
+	VOP_SENDFILE(vp, filp, ppos, 0, count, actor, target, NULL, error);
 	return error;
 }
 
@@ -260,7 +356,6 @@
 		return -ENOMEM;
 
 	uio.uio_iov = &iov;
-	uio.uio_fmode = filp->f_mode;
 	uio.uio_segflg = UIO_SYSSPACE;
 	curr_offset = filp->f_pos;
 	if (filp->f_pos != 0x7fffffff)
@@ -346,7 +441,30 @@
 	vnode_t		*vp = LINVFS_GET_VP(inode);
 
 	ASSERT(vp);
-	VOP_IOCTL(vp, inode, filp, cmd, arg, error);
+	VOP_IOCTL(vp, inode, filp, 0, cmd, arg, error);
+	VMODIFY(vp);
+
+	/* NOTE:  some of the ioctl's return positive #'s as a
+	 *	  byte count indicating success, such as
+	 *	  readlink_by_handle.  So we don't "sign flip"
+	 *	  like most other routines.  This means true
+	 *	  errors need to be returned as a negative value.
+	 */
+	return error;
+}
+
+STATIC int
+linvfs_ioctl_invis(
+	struct inode	*inode,
+	struct file	*filp,
+	unsigned int	cmd,
+	unsigned long	arg)
+{
+	int		error;
+	vnode_t		*vp = LINVFS_GET_VP(inode);
+
+	ASSERT(vp);
+	VOP_IOCTL(vp, inode, filp, IO_INVIS, cmd, arg, error);
 	VMODIFY(vp);
 
 	/* NOTE:  some of the ioctl's return positive #'s as a
@@ -395,6 +513,23 @@
 	.release	= linvfs_release,
 	.fsync		= linvfs_fsync,
 };
+
+struct file_operations linvfs_invis_file_operations = {
+	.llseek		= generic_file_llseek,
+	.read		= do_sync_read,
+	.write		= do_sync_write,
+	.readv		= linvfs_readv_invis,
+	.writev		= linvfs_writev_invis,
+	.aio_read	= linvfs_read_invis,
+	.aio_write	= linvfs_write_invis,
+	.sendfile	= linvfs_sendfile,
+	.ioctl		= linvfs_ioctl_invis,
+	.mmap		= linvfs_file_mmap,
+	.open		= linvfs_open,
+	.release	= linvfs_release,
+	.fsync		= linvfs_fsync,
+};
+
 
 struct file_operations linvfs_dir_operations = {
 	.read		= generic_read_dir,
diff -Nru a/fs/xfs/linux/xfs_ioctl.c b/fs/xfs/linux/xfs_ioctl.c
--- a/fs/xfs/linux/xfs_ioctl.c	Wed Oct 15 00:46:37 2003
+++ b/fs/xfs/linux/xfs_ioctl.c	Wed Oct 15 00:46:37 2003
@@ -373,7 +373,8 @@
 		put_unused_fd(new_fd);
 		return -XFS_ERROR(-PTR_ERR(filp));
 	}
-	filp->f_mode |= FINVIS;
+	if (inode->i_mode & S_IFREG)
+		filp->f_op = &linvfs_invis_file_operations;
 
 	fd_install(new_fd, filp);
 	return new_fd;
@@ -415,12 +416,11 @@
 
 	auio.uio_iov	= &aiov;
 	auio.uio_iovcnt	= 1;
-	auio.uio_fmode	= FINVIS;
 	auio.uio_offset	= 0;
 	auio.uio_segflg	= UIO_USERSPACE;
 	auio.uio_resid	= olen;
 
-	VOP_READLINK(vp, &auio, NULL, error);
+	VOP_READLINK(vp, &auio, IO_INVIS, NULL, error);
 
 	VN_RELE(vp);
 	return (olen - auio.uio_resid);
@@ -575,6 +575,7 @@
 	bhv_desc_t		*bdp,
 	vnode_t			*vp,
 	struct file		*filp,
+	int			flags,
 	unsigned int		cmd,
 	unsigned long		arg);
 
@@ -606,6 +607,7 @@
 xfs_ioc_getbmap(
 	bhv_desc_t		*bdp,
 	struct file		*filp,
+	int			flags,
 	unsigned int		cmd,
 	unsigned long		arg);
 
@@ -619,6 +621,7 @@
 	bhv_desc_t		*bdp,
 	struct inode		*inode,
 	struct file		*filp,
+	int			ioflags,
 	unsigned int		cmd,
 	unsigned long		arg)
 {
@@ -652,7 +655,7 @@
 		    !capable(CAP_SYS_ADMIN))
 			return -EPERM;
 
-		return xfs_ioc_space(bdp, vp, filp, cmd, arg);
+		return xfs_ioc_space(bdp, vp, filp, ioflags, cmd, arg);
 
 	case XFS_IOC_DIOINFO: {
 		struct dioattr	da;
@@ -703,7 +706,7 @@
 
 	case XFS_IOC_GETBMAP:
 	case XFS_IOC_GETBMAPA:
-		return xfs_ioc_getbmap(bdp, filp, cmd, arg);
+		return xfs_ioc_getbmap(bdp, filp, ioflags, cmd, arg);
 
 	case XFS_IOC_GETBMAPX:
 		return xfs_ioc_getbmapx(bdp, arg);
@@ -865,6 +868,7 @@
 	bhv_desc_t		*bdp,
 	vnode_t			*vp,
 	struct file		*filp,
+	int			ioflags,
 	unsigned int		cmd,
 	unsigned long		arg)
 {
@@ -886,7 +890,7 @@
 
 	if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
 		attr_flags |= ATTR_NONBLOCK;
-	if (filp->f_mode & FINVIS)
+	if (ioflags & IO_INVIS)
 		attr_flags |= ATTR_DMI;
 
 	error = xfs_change_file_space(bdp, cmd, &bf, filp->f_pos,
@@ -1153,6 +1157,7 @@
 xfs_ioc_getbmap(
 	bhv_desc_t		*bdp,
 	struct file		*filp,
+	int			ioflags,
 	unsigned int		cmd,
 	unsigned long		arg)
 {
@@ -1167,7 +1172,7 @@
 		return -XFS_ERROR(EINVAL);
 
 	iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0);
-	if (filp->f_mode & FINVIS)
+	if (ioflags & IO_INVIS)
 		iflags |= BMV_IF_NO_DMAPI_READ;
 
 	error = xfs_getbmap(bdp, &bm, (struct getbmap *)arg+1, iflags);
diff -Nru a/fs/xfs/linux/xfs_iops.c b/fs/xfs/linux/xfs_iops.c
--- a/fs/xfs/linux/xfs_iops.c	Wed Oct 15 00:46:36 2003
+++ b/fs/xfs/linux/xfs_iops.c	Wed Oct 15 00:46:36 2003
@@ -386,9 +386,8 @@
 	uio.uio_segflg = UIO_USERSPACE;
 	uio.uio_resid = size;
 	uio.uio_iovcnt = 1;
-	uio.uio_fmode = 0;
 
-	VOP_READLINK(vp, &uio, NULL, error);
+	VOP_READLINK(vp, &uio, 0, NULL, error);
 	if (error)
 		return -error;
 
@@ -433,10 +432,9 @@
 	uio->uio_offset = 0;
 	uio->uio_segflg = UIO_SYSSPACE;
 	uio->uio_resid = MAXNAMELEN;
-	uio->uio_fmode = 0;
 	uio->uio_iovcnt = 1;
 
-	VOP_READLINK(vp, uio, NULL, error);
+	VOP_READLINK(vp, uio, 0, NULL, error);
 	if (error) {
 		kfree(uio);
 		kfree(link);
diff -Nru a/fs/xfs/linux/xfs_iops.h b/fs/xfs/linux/xfs_iops.h
--- a/fs/xfs/linux/xfs_iops.h	Wed Oct 15 00:46:37 2003
+++ b/fs/xfs/linux/xfs_iops.h	Wed Oct 15 00:46:37 2003
@@ -61,6 +61,7 @@
 extern struct inode_operations linvfs_symlink_inode_operations;
 
 extern struct file_operations linvfs_file_operations;
+extern struct file_operations linvfs_invis_file_operations;
 extern struct file_operations linvfs_dir_operations;
 
 extern struct address_space_operations linvfs_aops;
diff -Nru a/fs/xfs/linux/xfs_linux.h b/fs/xfs/linux/xfs_linux.h
--- a/fs/xfs/linux/xfs_linux.h	Wed Oct 15 00:46:35 2003
+++ b/fs/xfs/linux/xfs_linux.h	Wed Oct 15 00:46:35 2003
@@ -195,8 +195,6 @@
 
 #define MAXPATHLEN	1024
 
-#define FINVIS		0x0100	/* don't update timestamps - XFS */
-
 #define MIN(a,b)	(min(a,b))
 #define MAX(a,b)	(max(a,b))
 #define howmany(x, y)	(((x)+((y)-1))/(y))
diff -Nru a/fs/xfs/linux/xfs_lrw.c b/fs/xfs/linux/xfs_lrw.c
--- a/fs/xfs/linux/xfs_lrw.c	Wed Oct 15 00:46:35 2003
+++ b/fs/xfs/linux/xfs_lrw.c	Wed Oct 15 00:46:35 2003
@@ -149,6 +149,7 @@
 	const struct iovec	*iovp,
 	unsigned int		segs,
 	loff_t			*offset,
+	int			ioflags,
 	cred_t			*credp)
 {
 	struct file		*file = iocb->ki_filp;
@@ -159,8 +160,6 @@
 	xfs_mount_t		*mp;
 	vnode_t			*vp;
 	unsigned long		seg;
-	int			direct = (file->f_flags & O_DIRECT);
-	int			invisible = (file->f_mode & FINVIS);
 
 	ip = XFS_BHVTOI(bdp);
 	vp = BHV_TO_VNODE(bdp);
@@ -183,7 +182,7 @@
 	}
 	/* END copy & waste from filemap.c */
 
-	if (direct) {
+	if (ioflags & IO_ISDIRECT) {
 		pb_target_t	*target =
 			(ip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
 				mp->m_rtdev_targp : mp->m_ddev_targp;
@@ -214,7 +213,8 @@
 	 */
 	xfs_ilock(ip, XFS_IOLOCK_SHARED);
 
-	if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) && !invisible) {
+	if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) &&
+	    !(ioflags & IO_INVIS)) {
 		int error;
 		vrwlock_t locktype = VRWLOCK_READ;
 
@@ -226,14 +226,13 @@
 		}
 	}
 
-	/* We need to deal with the iovec case seperately here */
 	ret = __generic_file_aio_read(iocb, iovp, segs, offset);
 	xfs_iunlock(ip, XFS_IOLOCK_SHARED);
 
 	if (ret > 0)
 		XFS_STATS_ADD(xs_read_bytes, ret);
 
-	if (!invisible)
+	if (likely(!(ioflags & IO_INVIS)))
 		xfs_ichgtime(ip, XFS_ICHGTIME_ACC);
 
 	return ret;
@@ -244,6 +243,7 @@
 	bhv_desc_t		*bdp,
 	struct file		*filp,
 	loff_t			*offset,
+	int			ioflags,
 	size_t			count,
 	read_actor_t		actor,
 	void			*target,
@@ -254,7 +254,6 @@
 	xfs_inode_t		*ip;
 	xfs_mount_t		*mp;
 	vnode_t			*vp;
-	int			invisible = (filp->f_mode & FINVIS);
 
 	ip = XFS_BHVTOI(bdp);
 	vp = BHV_TO_VNODE(bdp);
@@ -274,7 +273,9 @@
 		return -EIO;
 
 	xfs_ilock(ip, XFS_IOLOCK_SHARED);
-	if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) && !invisible) {
+
+	if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) &&
+	    (!(ioflags & IO_INVIS))) {
 		vrwlock_t locktype = VRWLOCK_READ;
 		int error;
 
@@ -289,8 +290,7 @@
 	xfs_iunlock(ip, XFS_IOLOCK_SHARED);
 
 	XFS_STATS_ADD(xs_read_bytes, ret);
-	if (!invisible)
-		xfs_ichgtime(ip, XFS_ICHGTIME_ACC);
+	xfs_ichgtime(ip, XFS_ICHGTIME_ACC);
 	return ret;
 }
 
@@ -518,6 +518,7 @@
 	const struct iovec	*iovp,
 	unsigned int		segs,
 	loff_t			*offset,
+	int			ioflags,
 	cred_t			*credp)
 {
 	struct file		*file = iocb->ki_filp;
@@ -532,8 +533,6 @@
 	vnode_t			*vp;
 	unsigned long		seg;
 	int			iolock;
-	int			direct = (file->f_flags & O_DIRECT);
-	int			invisible = (file->f_mode & FINVIS);
 	int			eventsent = 0;
 	vrwlock_t		locktype;
 
@@ -569,7 +568,7 @@
 		return -EIO;
 	}
 
-	if (direct) {
+	if (ioflags & IO_ISDIRECT) {
 		pb_target_t	*target =
 			(xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
 				mp->m_rtdev_targp : mp->m_ddev_targp;
@@ -586,6 +585,7 @@
 	}
 
 	xfs_ilock(xip, XFS_ILOCK_EXCL|iolock);
+
 	isize = xip->i_d.di_size;
 	limit = XFS_MAXIOFFSET(mp);
 
@@ -608,7 +608,7 @@
 	}
 
 	if ((DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_WRITE) &&
-	    !invisible && !eventsent)) {
+	    !(ioflags & IO_INVIS) && !eventsent)) {
 		loff_t		savedsize = *offset;
 
 		xfs_iunlock(xip, XFS_ILOCK_EXCL);
@@ -642,7 +642,7 @@
 	 *
 	 * We must update xfs' times since revalidate will overcopy xfs.
 	 */
-	if (size && !invisible)
+	if (size && !(ioflags & IO_INVIS))
 		xfs_ichgtime(xip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
 
 	/*
@@ -654,7 +654,7 @@
 	 * to zero it out up to the new size.
 	 */
 
-	if (!direct && (*offset > isize && isize)) {
+	if (!(ioflags & IO_ISDIRECT) && (*offset > isize && isize)) {
 		error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, *offset,
 			isize, *offset + size);
 		if (error) {
@@ -671,9 +671,9 @@
 	 * setgid binaries.
 	 */
 
-	if (((xip->i_d.di_mode & ISUID) ||
-	    ((xip->i_d.di_mode & (ISGID | (IEXEC >> 3))) ==
-		(ISGID | (IEXEC >> 3)))) &&
+	if (((xip->i_d.di_mode & S_ISUID) ||
+	    ((xip->i_d.di_mode & (S_ISGID | S_IXGRP)) ==
+		(S_ISGID | S_IXGRP))) &&
 	     !capable(CAP_FSETID)) {
 		error = xfs_write_clear_setuid(xip);
 		if (error) {
@@ -683,14 +683,15 @@
 	}
 
 retry:
-	if (direct) {
+	if (ioflags & IO_ISDIRECT) {
 		xfs_inval_cached_pages(vp, &xip->i_iocore, *offset, 1, 1);
 	}
 
 	ret = generic_file_aio_write_nolock(iocb, iovp, segs, offset);
 
 	if ((ret == -ENOSPC) &&
-	    DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_NOSPACE) && !invisible) {
+	    DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_NOSPACE) &&
+	    !(ioflags & IO_INVIS)) {
 
 		xfs_rwunlock(bdp, locktype);
 		error = XFS_SEND_NAMESP(xip->i_mount, DM_EVENT_NOSPACE, vp,
@@ -851,7 +852,7 @@
 	xfs_inode_t	*ip = XFS_BHVTOI(bdp);
 	xfs_iocore_t	*io = &ip->i_iocore;
 
-	ASSERT((ip->i_d.di_mode & IFMT) == IFREG);
+	ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFREG);
 	ASSERT(((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != 0) ==
 	       ((ip->i_iocore.io_flags & XFS_IOCORE_RT) != 0));
 
diff -Nru a/fs/xfs/linux/xfs_lrw.h b/fs/xfs/linux/xfs_lrw.h
--- a/fs/xfs/linux/xfs_lrw.h	Wed Oct 15 00:46:35 2003
+++ b/fs/xfs/linux/xfs_lrw.h	Wed Oct 15 00:46:35 2003
@@ -56,12 +56,12 @@
 				xfs_fsize_t, xfs_fsize_t);
 extern ssize_t xfs_read(struct bhv_desc *, struct kiocb *,
 				const struct iovec *, unsigned int,
-				loff_t *, struct cred *);
+				loff_t *, int, struct cred *);
 extern ssize_t xfs_write(struct bhv_desc *, struct kiocb *,
 				const struct iovec *, unsigned int,
-				loff_t *, struct cred *);
+				loff_t *, int, struct cred *);
 extern ssize_t xfs_sendfile(struct bhv_desc *, struct file *,
-				loff_t *, size_t, read_actor_t,
+				loff_t *, int, size_t, read_actor_t,
 				void *, struct cred *);
 
 extern int xfs_iomap(struct xfs_iocore *, xfs_off_t, ssize_t, int,
diff -Nru a/fs/xfs/linux/xfs_super.c b/fs/xfs/linux/xfs_super.c
--- a/fs/xfs/linux/xfs_super.c	Wed Oct 15 00:46:37 2003
+++ b/fs/xfs/linux/xfs_super.c	Wed Oct 15 00:46:37 2003
@@ -373,7 +373,7 @@
 init_inodecache( void )
 {
 	linvfs_inode_cachep = kmem_cache_create("linvfs_icache",
-				sizeof(vnode_t), 0, 
+				sizeof(vnode_t), 0,
 				SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
 				init_once, NULL);
 
@@ -579,7 +579,7 @@
 	if (sb->s_flags & MS_RDONLY)
 		return;
 	VFS_ROOT(vfsp, &vp, error);
-	VOP_IOCTL(vp, LINVFS_GET_IP(vp), NULL, XFS_IOC_FREEZE, 0, error);
+	VOP_IOCTL(vp, LINVFS_GET_IP(vp), NULL, 0, XFS_IOC_FREEZE, 0, error);
 	VN_RELE(vp);
 }
 
@@ -592,7 +592,7 @@
 	int			error;
 
 	VFS_ROOT(vfsp, &vp, error);
-	VOP_IOCTL(vp, LINVFS_GET_IP(vp), NULL, XFS_IOC_THAW, 0, error);
+	VOP_IOCTL(vp, LINVFS_GET_IP(vp), NULL, 0, XFS_IOC_THAW, 0, error);
 	VN_RELE(vp);
 }
 
diff -Nru a/fs/xfs/linux/xfs_sysctl.h b/fs/xfs/linux/xfs_sysctl.h
--- a/fs/xfs/linux/xfs_sysctl.h	Wed Oct 15 00:46:35 2003
+++ b/fs/xfs/linux/xfs_sysctl.h	Wed Oct 15 00:46:35 2003
@@ -47,7 +47,7 @@
 
 typedef struct xfs_param {
 	xfs_sysctl_val_t restrict_chown;/* Root/non-root can give away files.*/
-	xfs_sysctl_val_t sgid_inherit;	/* Inherit ISGID bit if process' GID 
+	xfs_sysctl_val_t sgid_inherit;	/* Inherit S_ISGID bit if process' GID 
 					 * is not a member of the parent dir
 					 * GID */
 	xfs_sysctl_val_t symlink_mode;	/* Link creat mode affected by umask */
diff -Nru a/fs/xfs/linux/xfs_vfs.h b/fs/xfs/linux/xfs_vfs.h
--- a/fs/xfs/linux/xfs_vfs.h	Wed Oct 15 00:46:35 2003
+++ b/fs/xfs/linux/xfs_vfs.h	Wed Oct 15 00:46:35 2003
@@ -44,8 +44,8 @@
 
 typedef struct vfs {
 	u_int			vfs_flag;	/* flags */
-	__kernel_fsid_t			vfs_fsid;	/* file system ID */
-	__kernel_fsid_t			*vfs_altfsid;	/* An ID fixed for life of FS */
+	fsid_t			vfs_fsid;	/* file system ID */
+	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;
diff -Nru a/fs/xfs/linux/xfs_vnode.h b/fs/xfs/linux/xfs_vnode.h
--- a/fs/xfs/linux/xfs_vnode.h	Wed Oct 15 00:46:38 2003
+++ b/fs/xfs/linux/xfs_vnode.h	Wed Oct 15 00:46:38 2003
@@ -155,9 +155,17 @@
 #define VMODIFIED	       0x8	/* XFS inode state possibly differs */
 					/* to the Linux inode state.	*/
 
-typedef enum vrwlock	{ VRWLOCK_NONE, VRWLOCK_READ,
-			  VRWLOCK_WRITE, VRWLOCK_WRITE_DIRECT,
-			  VRWLOCK_TRY_READ, VRWLOCK_TRY_WRITE } vrwlock_t;
+/*
+ * Values for the VOP_RWLOCK and VOP_RWUNLOCK flags parameter.
+ */
+typedef enum vrwlock {
+	VRWLOCK_NONE,
+	VRWLOCK_READ,
+	VRWLOCK_WRITE,
+	VRWLOCK_WRITE_DIRECT,
+	VRWLOCK_TRY_READ,
+	VRWLOCK_TRY_WRITE
+} vrwlock_t;
 
 /*
  * Return values for VOP_INACTIVE.  A return value of
@@ -182,15 +190,15 @@
 typedef int	(*vop_open_t)(bhv_desc_t *, struct cred *);
 typedef ssize_t (*vop_read_t)(bhv_desc_t *, struct kiocb *,
 				const struct iovec *, unsigned int,
-				loff_t *, struct cred *);
+				loff_t *, int, struct cred *);
 typedef ssize_t (*vop_write_t)(bhv_desc_t *, struct kiocb *,
 				const struct iovec *, unsigned int,
-				loff_t *, struct cred *);
+				loff_t *, int, struct cred *);
 typedef ssize_t (*vop_sendfile_t)(bhv_desc_t *, struct file *,
-				loff_t *, size_t, read_actor_t,
+				loff_t *, int, size_t, read_actor_t,
 				void *, struct cred *);
 typedef int	(*vop_ioctl_t)(bhv_desc_t *, struct inode *, struct file *,
-				unsigned int, unsigned long);
+				int, unsigned int, unsigned long);
 typedef int	(*vop_getattr_t)(bhv_desc_t *, struct vattr *, int,
 				struct cred *);
 typedef int	(*vop_setattr_t)(bhv_desc_t *, struct vattr *, int,
@@ -212,7 +220,8 @@
 				int *);
 typedef int	(*vop_symlink_t)(bhv_desc_t *, vname_t *, struct vattr *,
 				char *, vnode_t **, struct cred *);
-typedef int	(*vop_readlink_t)(bhv_desc_t *, struct uio *, struct cred *);
+typedef int	(*vop_readlink_t)(bhv_desc_t *, struct uio *, int,
+				struct cred *);
 typedef int	(*vop_fsync_t)(bhv_desc_t *, int, struct cred *,
 				xfs_off_t, xfs_off_t);
 typedef int	(*vop_inactive_t)(bhv_desc_t *, struct cred *);
@@ -284,12 +293,12 @@
  */
 #define _VOP_(op, vp)	(*((vnodeops_t *)(vp)->v_fops)->op)
 
-#define VOP_READ(vp,file,iov,segs,offset,cr,rv)			\
-	rv = _VOP_(vop_read, vp)((vp)->v_fbhv,file,iov,segs,offset,cr)
-#define VOP_WRITE(vp,file,iov,segs,offset,cr,rv)		\
-	rv = _VOP_(vop_write, vp)((vp)->v_fbhv,file,iov,segs,offset,cr)
-#define VOP_SENDFILE(vp,f,off,cnt,act,targ,cr,rv)		\
-	rv = _VOP_(vop_sendfile, vp)((vp)->v_fbhv,f,off,cnt,act,targ,cr)
+#define VOP_READ(vp,file,iov,segs,offset,ioflags,cr,rv)			\
+	rv = _VOP_(vop_read, vp)((vp)->v_fbhv,file,iov,segs,offset,ioflags,cr)
+#define VOP_WRITE(vp,file,iov,segs,offset,ioflags,cr,rv)		\
+	rv = _VOP_(vop_write, vp)((vp)->v_fbhv,file,iov,segs,offset,ioflags,cr)
+#define VOP_SENDFILE(vp,f,off,ioflags,cnt,act,targ,cr,rv)		\
+	rv = _VOP_(vop_sendfile, vp)((vp)->v_fbhv,f,off,ioflags,cnt,act,targ,cr)
 #define VOP_BMAP(vp,of,sz,rw,b,n,rv)					\
 	rv = _VOP_(vop_bmap, vp)((vp)->v_fbhv,of,sz,rw,b,n)
 #define VOP_OPEN(vp, cr, rv)						\
@@ -318,8 +327,8 @@
 	rv = _VOP_(vop_readdir, vp)((vp)->v_fbhv,uiop,cr,eofp)
 #define	VOP_SYMLINK(dvp,d,vap,tnm,vpp,cr,rv)				\
 	rv = _VOP_(vop_symlink, dvp) ((dvp)->v_fbhv,d,vap,tnm,vpp,cr)
-#define	VOP_READLINK(vp,uiop,cr,rv)					\
-	rv = _VOP_(vop_readlink, vp)((vp)->v_fbhv,uiop,cr)
+#define	VOP_READLINK(vp,uiop,fl,cr,rv)					\
+	rv = _VOP_(vop_readlink, vp)((vp)->v_fbhv,uiop,fl,cr)
 #define	VOP_FSYNC(vp,f,cr,b,e,rv)					\
 	rv = _VOP_(vop_fsync, vp)((vp)->v_fbhv,f,cr,b,e)
 #define VOP_INACTIVE(vp, cr, rv)					\
@@ -366,15 +375,20 @@
  */
 #define VOP_FLUSH_PAGES(vp, first, last, flags, fiopt, rv)		\
 	rv = _VOP_(vop_flush_pages, vp)((vp)->v_fbhv,first,last,flags,fiopt)
-#define VOP_IOCTL(vp, inode, filp, cmd, arg, rv)			\
-	rv = _VOP_(vop_ioctl, vp)((vp)->v_fbhv,inode,filp,cmd,arg)
+#define VOP_IOCTL(vp, inode, filp, fl, cmd, arg, rv)			\
+	rv = _VOP_(vop_ioctl, vp)((vp)->v_fbhv,inode,filp,fl,cmd,arg)
 #define VOP_IFLUSH(vp, flags, rv)					\
 	rv = _VOP_(vop_iflush, vp)((vp)->v_fbhv, flags)
 
 /*
- * Flags for VOP_IFLUSH call
+ * Flags for read/write calls - same values as IRIX
  */
+#define IO_ISDIRECT	0x00004		/* bypass page cache */
+#define IO_INVIS	0x00020		/* don't update inode timestamps */
 
+/*
+ * Flags for VOP_IFLUSH call
+ */
 #define FLUSH_SYNC		1	/* wait for flush to complete	*/
 #define FLUSH_INODE		2	/* flush the inode itself	*/
 #define FLUSH_LOG		4	/* force the last log entry for
diff -Nru a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
--- a/fs/xfs/quota/xfs_qm.c	Wed Oct 15 00:46:35 2003
+++ b/fs/xfs/quota/xfs_qm.c	Wed Oct 15 00:46:35 2003
@@ -1433,7 +1433,7 @@
 	}
 	memset(&zerocr, 0, sizeof(zerocr));
 
-	if ((error = xfs_dir_ialloc(&tp, mp->m_rootip, IFREG, 1, 0,
+	if ((error = xfs_dir_ialloc(&tp, mp->m_rootip, S_IFREG, 1, 0,
 				   &zerocr, 0, 1, ip, &committed))) {
 		xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
 				 XFS_TRANS_ABORT);
diff -Nru a/fs/xfs/support/move.c b/fs/xfs/support/move.c
--- a/fs/xfs/support/move.c	Wed Oct 15 00:46:36 2003
+++ b/fs/xfs/support/move.c	Wed Oct 15 00:46:36 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 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
@@ -45,30 +45,28 @@
 int
 uio_read(caddr_t src, size_t len, struct uio *uio)
 {
-	struct iovec *iov;
-	u_int cnt;
-	int error;
-
-	if (len > 0 && uio->uio_resid) {
-		iov = uio->uio_iov;
-		cnt = (u_int)iov->iov_len;
-		if (cnt == 0)
-			return 0;
-		if (cnt > len)
-			cnt = (u_int)len;
-		if (uio->uio_segflg == UIO_USERSPACE) {
-			error = copy_to_user(iov->iov_base, src, cnt);
-			if (error)
-				return EFAULT;
-		} else if (uio->uio_segflg == UIO_SYSSPACE) {
-			memcpy(iov->iov_base, src, cnt);
-		} else {
-			ASSERT(0);
-		}
-		iov->iov_base = (void *)((char *)iov->iov_base + cnt);
-		iov->iov_len -= cnt;
-		uio->uio_resid -= cnt;
-		uio->uio_offset += cnt;
+	size_t	count;
+
+	if (!len || !uio->uio_resid)
+		return 0;
+
+	count = uio->uio_iov->iov_len;
+	if (!count)
+		return 0;
+	if (count > len)
+		count = len;
+
+	if (uio->uio_segflg == UIO_USERSPACE) {
+		if (copy_to_user(uio->uio_iov->iov_base, src, count))
+			return EFAULT;
+	} else {
+		ASSERT(uio->uio_segflg == UIO_SYSSPACE);
+		memcpy(uio->uio_iov->iov_base, src, count);
 	}
+
+	uio->uio_iov->iov_base = (void*)((char*)uio->uio_iov->iov_base + count);
+	uio->uio_iov->iov_len -= count;
+	uio->uio_offset += count;
+	uio->uio_resid -= count;
 	return 0;
 }
diff -Nru a/fs/xfs/support/move.h b/fs/xfs/support/move.h
--- a/fs/xfs/support/move.h	Wed Oct 15 00:46:36 2003
+++ b/fs/xfs/support/move.h	Wed Oct 15 00:46:36 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 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
@@ -28,32 +28,60 @@
  * For further information regarding this notice, see:
  *
  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ * 
+ * Portions Copyright (c) 1982, 1986, 1993, 1994
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
-
 #ifndef __XFS_SUPPORT_MOVE_H__
 #define __XFS_SUPPORT_MOVE_H__
 
 #include <linux/uio.h>
 #include <asm/uaccess.h>
 
-typedef struct iovec iovec_t;
+/* Segment flag values. */
+enum uio_seg {
+	UIO_USERSPACE,          /* from user data space */
+	UIO_SYSSPACE,           /* from system space */
+};
 
-typedef struct uio {
-	iovec_t         *uio_iov;       /* pointer to array of iovecs */
-	int             uio_iovcnt;     /* number of iovecs */
-	int             uio_fmode;      /* file mode flags */
-	xfs_off_t       uio_offset;     /* file offset */
-	short           uio_segflg;     /* address space (kernel or user) */
-	ssize_t         uio_resid;      /* residual count */
-} uio_t;
+struct uio {
+	struct iovec	*uio_iov;
+	int             uio_iovcnt;
+	xfs_off_t       uio_offset;
+	int		uio_resid;
+	enum uio_seg	uio_segflg;
+};
 
-/*
- * Segment flag values.
- */
-typedef enum uio_seg {
-	UIO_USERSPACE,          /* uio_iov describes user space */
-	UIO_SYSSPACE,           /* uio_iov describes system space */
-} uio_seg_t;
+typedef struct uio uio_t;
+typedef struct iovec iovec_t;
 
 extern int	uio_read (caddr_t, size_t, uio_t *);
 
diff -Nru a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c
--- a/fs/xfs/xfs_attr.c	Wed Oct 15 00:46:37 2003
+++ b/fs/xfs/xfs_attr.c	Wed Oct 15 00:46:37 2003
@@ -143,7 +143,7 @@
 		/*
 		 * Do we answer them, or ignore them?
 		 */
-		if ((error = xfs_iaccess(ip, IREAD, cred))) {
+		if ((error = xfs_iaccess(ip, S_IRUSR, cred))) {
 			xfs_iunlock(ip, XFS_ILOCK_SHARED);
 			return(XFS_ERROR(error));
 		}
@@ -239,7 +239,7 @@
 		return (EIO);
 
 	xfs_ilock(dp, XFS_ILOCK_SHARED);
-	if ((error = xfs_iaccess(dp, IWRITE, cred))) {
+	if ((error = xfs_iaccess(dp, S_IWUSR, cred))) {
 		xfs_iunlock(dp, XFS_ILOCK_SHARED);
 		return(XFS_ERROR(error));
 	}
@@ -498,7 +498,7 @@
 		return (EIO);
 
 	xfs_ilock(dp, XFS_ILOCK_SHARED);
-	if ((error = xfs_iaccess(dp, IWRITE, cred))) {
+	if ((error = xfs_iaccess(dp, S_IWUSR, cred))) {
 		xfs_iunlock(dp, XFS_ILOCK_SHARED);
 		return(XFS_ERROR(error));
 	} else if (XFS_IFORK_Q(dp) == 0 ||
@@ -687,7 +687,7 @@
 	 * Do they have permission?
 	 */
 	xfs_ilock(dp, XFS_ILOCK_SHARED);
-	if ((error = xfs_iaccess(dp, IREAD, cred))) {
+	if ((error = xfs_iaccess(dp, S_IRUSR, cred))) {
 		xfs_iunlock(dp, XFS_ILOCK_SHARED);
 		return(XFS_ERROR(error));
 	}
diff -Nru a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
--- a/fs/xfs/xfs_bmap.c	Wed Oct 15 00:46:37 2003
+++ b/fs/xfs/xfs_bmap.c	Wed Oct 15 00:46:37 2003
@@ -521,7 +521,7 @@
 
 	if (ip->i_df.if_bytes <= XFS_IFORK_DSIZE(ip))
 		return 0;
-	if ((ip->i_d.di_mode & IFMT) == IFDIR) {
+	if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
 		mp = ip->i_mount;
 		memset(&dargs, 0, sizeof(dargs));
 		dargs.dp = ip;
@@ -3354,7 +3354,7 @@
 	 * We don't want to deal with the case of keeping inode data inline yet.
 	 * So sending the data fork of a regular inode is invalid.
 	 */
-	ASSERT(!((ip->i_d.di_mode & IFMT) == IFREG &&
+	ASSERT(!((ip->i_d.di_mode & S_IFMT) == S_IFREG &&
 		 whichfork == XFS_DATA_FORK));
 	ifp = XFS_IFORK_PTR(ip, whichfork);
 	ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL);
diff -Nru a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
--- a/fs/xfs/xfs_buf_item.c	Wed Oct 15 00:46:35 2003
+++ b/fs/xfs/xfs_buf_item.c	Wed Oct 15 00:46:35 2003
@@ -162,6 +162,7 @@
 #endif
 
 STATIC void	xfs_buf_error_relse(xfs_buf_t *bp);
+STATIC void	xfs_buf_do_callbacks(xfs_buf_t *bp, xfs_log_item_t *lip);
 
 /*
  * This returns the number of log iovecs needed to log the
@@ -417,22 +418,25 @@
 		ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
 		ASSERT(!(XFS_BUF_ISDELAYWRITE(bp)));
 		ASSERT(XFS_BUF_ISSTALE(bp));
-/**
-		ASSERT(bp->b_pincount == 0);
-**/
 		ASSERT(bip->bli_format.blf_flags & XFS_BLI_CANCEL);
 		xfs_buf_item_trace("UNPIN STALE", bip);
 		xfs_buftrace("XFS_UNPIN STALE", bp);
-		AIL_LOCK(mp,s);
 		/*
 		 * If we get called here because of an IO error, we may
 		 * or may not have the item on the AIL. xfs_trans_delete_ail()
 		 * will take care of that situation.
 		 * xfs_trans_delete_ail() drops the AIL lock.
 		 */
-		xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip, s);
-		xfs_buf_item_relse(bp);
-		ASSERT(XFS_BUF_FSPRIVATE(bp, void *) == NULL);
+		if (bip->bli_flags & XFS_BLI_STALE_INODE) {
+			xfs_buf_do_callbacks(bp, (xfs_log_item_t *)bip);
+			XFS_BUF_FSPRIVATE(bp, void *) = NULL;
+			XFS_BUF_CLR_IODONE_FUNC(bp);
+		} else {
+			AIL_LOCK(mp,s);
+			xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip, s);
+			xfs_buf_item_relse(bp);
+			ASSERT(XFS_BUF_FSPRIVATE(bp, void *) == NULL);
+		}
 		xfs_buf_relse(bp);
 	}
 }
diff -Nru a/fs/xfs/xfs_buf_item.h b/fs/xfs/xfs_buf_item.h
--- a/fs/xfs/xfs_buf_item.h	Wed Oct 15 00:46:37 2003
+++ b/fs/xfs/xfs_buf_item.h	Wed Oct 15 00:46:37 2003
@@ -96,6 +96,7 @@
 #define	XFS_BLI_STALE		0x04
 #define	XFS_BLI_LOGGED		0x08
 #define	XFS_BLI_INODE_ALLOC_BUF	0x10
+#define XFS_BLI_STALE_INODE	0x20
 
 
 #ifdef __KERNEL__
@@ -130,7 +131,7 @@
  * items which have been canceled and should not be replayed.
  */
 typedef struct xfs_buf_cancel {
-	xfs_daddr_t			bc_blkno;
+	xfs_daddr_t		bc_blkno;
 	uint			bc_len;
 	int			bc_refcount;
 	struct xfs_buf_cancel	*bc_next;
diff -Nru a/fs/xfs/xfs_clnt.h b/fs/xfs/xfs_clnt.h
--- a/fs/xfs/xfs_clnt.h	Wed Oct 15 00:46:37 2003
+++ b/fs/xfs/xfs_clnt.h	Wed Oct 15 00:46:37 2003
@@ -99,5 +99,6 @@
 #define XFSMNT_NOUUID		0x01000000	/* Ignore fs uuid */
 #define XFSMNT_DMAPI		0x02000000	/* enable dmapi/xdsm */
 #define XFSMNT_NOLOGFLUSH	0x04000000	/* Don't flush for log blocks */
+#define XFSMNT_IDELETE		0x08000000	/* inode cluster delete */
 
 #endif	/* __XFS_CLNT_H__ */
diff -Nru a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c
--- a/fs/xfs/xfs_dfrag.c	Wed Oct 15 00:46:35 2003
+++ b/fs/xfs/xfs_dfrag.c	Wed Oct 15 00:46:35 2003
@@ -154,12 +154,12 @@
 		goto error0;
 	}
 	if ((current->fsuid != ip->i_d.di_uid) &&
-	    (error = xfs_iaccess(ip, IWRITE, NULL)) &&
+	    (error = xfs_iaccess(ip, S_IWUSR, NULL)) &&
 	    !capable_cred(NULL, CAP_FOWNER)) {
 		goto error0;
 	}
 	if ((current->fsuid != tip->i_d.di_uid) &&
-	    (error = xfs_iaccess(tip, IWRITE, NULL)) &&
+	    (error = xfs_iaccess(tip, S_IWUSR, NULL)) &&
 	    !capable_cred(NULL, CAP_FOWNER)) {
 		goto error0;
 	}
diff -Nru a/fs/xfs/xfs_dinode.h b/fs/xfs/xfs_dinode.h
--- a/fs/xfs/xfs_dinode.h	Wed Oct 15 00:46:37 2003
+++ b/fs/xfs/xfs_dinode.h	Wed Oct 15 00:46:37 2003
@@ -107,7 +107,7 @@
 		xfs_dir_shortform_t di_dirsf;	/* shortform directory */
 		xfs_dir2_sf_t	di_dir2sf;	/* shortform directory v2 */
 		char		di_c[1];	/* local contents */
-		xfs_dev_t	di_dev;		/* device for IFCHR/IFBLK */
+		xfs_dev_t	di_dev;		/* device for S_IFCHR/S_IFBLK */
 		uuid_t		di_muuid;	/* mount point value */
 		char		di_symlink[1];	/* local symbolic link */
 	}		di_u;
@@ -435,25 +435,6 @@
 #define XFS_DFORK_NEXT_SET(dip,w,n)             XFS_DFORK_NEXT_SET_ARCH(dip,w,n,ARCH_NOCONVERT)
 
 #endif
-
-/*
- * File types (mode field)
- */
-#define	IFMT		S_IFMT
-#define	IFSOCK		S_IFSOCK
-#define	IFLNK		S_IFLNK
-#define	IFREG		S_IFREG
-#define	IFBLK		S_IFBLK
-#define	IFDIR		S_IFDIR
-#define	IFCHR		S_IFCHR
-#define	IFIFO		S_IFIFO
-
-#define	ISUID		S_ISUID
-#define	ISGID		S_ISGID
-#define	ISVTX		S_ISVTX
-#define	IREAD		S_IRUSR
-#define	IWRITE		S_IWUSR
-#define	IEXEC		S_IXUSR
 
 #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_DINODE)
 xfs_dinode_t *xfs_buf_to_dinode(struct xfs_buf *bp);
diff -Nru a/fs/xfs/xfs_dir.c b/fs/xfs/xfs_dir.c
--- a/fs/xfs/xfs_dir.c	Wed Oct 15 00:46:36 2003
+++ b/fs/xfs/xfs_dir.c	Wed Oct 15 00:46:36 2003
@@ -216,7 +216,7 @@
 {
 	xfs_dir_sf_hdr_t *hdr;
 
-	ASSERT((dp->i_d.di_mode & IFMT) == IFDIR);
+	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 	if (dp->i_d.di_size == 0)
 		return(1);
 	if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp))
@@ -238,7 +238,7 @@
 	args.dp = dir;
 	args.trans = trans;
 
-	ASSERT((dir->i_d.di_mode & IFMT) == IFDIR);
+	ASSERT((dir->i_d.di_mode & S_IFMT) == S_IFDIR);
 	if ((error = xfs_dir_ino_validate(trans->t_mountp, parent_dir->i_ino)))
 		return error;
 
@@ -257,7 +257,7 @@
 	xfs_da_args_t args;
 	int retval, newsize, done;
 
-	ASSERT((dp->i_d.di_mode & IFMT) == IFDIR);
+	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 
 	if ((retval = xfs_dir_ino_validate(trans->t_mountp, inum)))
 		return (retval);
@@ -321,7 +321,7 @@
 	xfs_da_args_t args;
 	int retval, newsize;
 
-	ASSERT((dp->i_d.di_mode & IFMT) == IFDIR);
+	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 	/*
 	 * Fill in the arg structure for this request.
 	 */
@@ -366,7 +366,7 @@
 	xfs_da_args_t args;
 	int count, totallen, newsize, retval;
 
-	ASSERT((dp->i_d.di_mode & IFMT) == IFDIR);
+	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 	XFS_STATS_INC(xs_dir_remove);
 	/*
 	 * Fill in the arg structure for this request.
@@ -409,7 +409,7 @@
 	xfs_da_args_t args;
 	int retval;
 
-	ASSERT((dp->i_d.di_mode & IFMT) == IFDIR);
+	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 
 	XFS_STATS_INC(xs_dir_lookup);
 	/*
@@ -455,7 +455,7 @@
 	xfs_dir_put_t put;
 
 	XFS_STATS_INC(xs_dir_getdents);
-	ASSERT((dp->i_d.di_mode & IFMT) == IFDIR);
+	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 
 	/*
 	 * If our caller has given us a single contiguous memory buffer,
@@ -499,7 +499,7 @@
 	xfs_da_args_t args;
 	int retval;
 
-	ASSERT((dp->i_d.di_mode & IFMT) == IFDIR);
+	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 
 	if ((retval = xfs_dir_ino_validate(trans->t_mountp, inum)))
 		return retval;
@@ -545,7 +545,7 @@
 
 
 
-	if ((INT_GET(dp->di_core.di_mode, ARCH_CONVERT) & IFMT) != IFDIR) {
+	if ((INT_GET(dp->di_core.di_mode, ARCH_CONVERT) & S_IFMT) != S_IFDIR) {
 		return 0;
 	}
 	if (INT_GET(dp->di_core.di_format, ARCH_CONVERT) != XFS_DINODE_FMT_LOCAL) {
diff -Nru a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c
--- a/fs/xfs/xfs_dir2.c	Wed Oct 15 00:46:38 2003
+++ b/fs/xfs/xfs_dir2.c	Wed Oct 15 00:46:38 2003
@@ -155,7 +155,7 @@
 {
 	xfs_dir2_sf_t	*sfp;		/* shortform directory structure */
 
-	ASSERT((dp->i_d.di_mode & IFMT) == IFDIR);
+	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 	/*
 	 * Might happen during shutdown.
 	 */
@@ -183,7 +183,7 @@
 	memset((char *)&args, 0, sizeof(args));
 	args.dp = dp;
 	args.trans = tp;
-	ASSERT((dp->i_d.di_mode & IFMT) == IFDIR);
+	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 	if ((error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino))) {
 		return error;
 	}
@@ -208,7 +208,7 @@
 	int			rval;		/* return value */
 	int			v;		/* type-checking value */
 
-	ASSERT((dp->i_d.di_mode & IFMT) == IFDIR);
+	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 	if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) {
 		return rval;
 	}
@@ -261,7 +261,7 @@
 	int		rval;		/* return value */
 	int		v;		/* type-checking value */
 
-	ASSERT((dp->i_d.di_mode & IFMT) == IFDIR);
+	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 	XFS_STATS_INC(xs_dir_lookup);
 
 	/*
@@ -319,7 +319,7 @@
 	int		rval;		/* return value */
 	int		v;		/* type-checking value */
 
-	ASSERT((dp->i_d.di_mode & IFMT) == IFDIR);
+	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 	XFS_STATS_INC(xs_dir_remove);
 	/*
 	 * Fill in the arg structure for this request.
@@ -369,7 +369,7 @@
 	int		rval;		/* return value */
 	int		v;		/* type-checking value */
 
-	ASSERT((dp->i_d.di_mode & IFMT) == IFDIR);
+	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 	XFS_STATS_INC(xs_dir_getdents);
 	/*
 	 * If our caller has given us a single contiguous aligned memory buffer,
@@ -422,7 +422,7 @@
 	int		rval;		/* return value */
 	int		v;		/* type-checking value */
 
-	ASSERT((dp->i_d.di_mode & IFMT) == IFDIR);
+	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 
 	if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) {
 		return rval;
@@ -473,7 +473,7 @@
 	int		rval;		/* return value */
 	int		v;		/* type-checking value */
 
-	ASSERT((dp->i_d.di_mode & IFMT) == IFDIR);
+	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 	/*
 	 * Fill in the arg structure for this request.
 	 */
diff -Nru a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c
--- a/fs/xfs/xfs_ialloc.c	Wed Oct 15 00:46:37 2003
+++ b/fs/xfs/xfs_ialloc.c	Wed Oct 15 00:46:37 2003
@@ -57,6 +57,7 @@
 #include "xfs_bit.h"
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
+#include "xfs_bmap.h"
 
 /*
  * Log specified fields for the inode given by bp and off.
@@ -921,7 +922,10 @@
 int
 xfs_difree(
 	xfs_trans_t	*tp,		/* transaction pointer */
-	xfs_ino_t	inode)		/* inode to be freed */
+	xfs_ino_t	inode,		/* inode to be freed */
+	xfs_bmap_free_t	*flist,		/* extents to free */
+	int		*delete,	/* set if inode cluster was deleted */
+	xfs_ino_t	*first_ino)	/* first inode in deleted cluster */
 {
 	/* REFERENCED */
 	xfs_agblock_t	agbno;	/* block number containing inode */
@@ -932,6 +936,7 @@
 	xfs_btree_cur_t	*cur;	/* inode btree cursor */
 	int		error;	/* error return value */
 	int		i;	/* result code */
+	int		ilen;	/* inodes in an inode cluster */
 	xfs_mount_t	*mp;	/* mount structure for filesystem */
 	int		off;	/* offset of inode in inode chunk */
 	xfs_inobt_rec_t	rec;	/* btree record */
@@ -995,10 +1000,11 @@
 			if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino,
 					&rec.ir_freecount, &rec.ir_free, &i, ARCH_NOCONVERT)))
 				goto error0;
-			XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
-			freecount += rec.ir_freecount;
-			if ((error = xfs_inobt_increment(cur, 0, &i)))
-				goto error0;
+			if (i) {
+				freecount += rec.ir_freecount;
+				if ((error = xfs_inobt_increment(cur, 0, &i)))
+					goto error0;
+			}
 		} while (i == 1);
 		ASSERT(freecount == INT_GET(agi->agi_freecount, ARCH_CONVERT) ||
 		       XFS_FORCED_SHUTDOWN(mp));
@@ -1033,20 +1039,60 @@
 	 */
 	XFS_INOBT_SET_FREE(&rec, off, ARCH_NOCONVERT);
 	rec.ir_freecount++;
-	if ((error = xfs_inobt_update(cur, rec.ir_startino, rec.ir_freecount, rec.ir_free))) {
-		cmn_err(CE_WARN,
-			"xfs_difree: xfs_inobt_update()  returned an error %d on %s.  Returning error.",
-			error, mp->m_fsname);
-		goto error0;
-	}
+
 	/*
-	 * Change the inode free counts and log the ag/sb changes.
+	 * When an inode cluster is free, it becomes elgible for removal
 	 */
-	INT_MOD(agi->agi_freecount, ARCH_CONVERT, 1);
-	xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT);
-	down_read(&mp->m_peraglock);
-	mp->m_perag[agno].pagi_freecount++;
-	up_read(&mp->m_peraglock);
+	if ((mp->m_flags & XFS_MOUNT_IDELETE) &&
+	    (rec.ir_freecount == XFS_IALLOC_INODES(mp))) {
+
+		*delete = 1;
+		*first_ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino);
+
+		/*
+		 * Remove the inode cluster from the AGI B+Tree, adjust the
+		 * AGI and Superblock inode counts, and mark the disk space
+		 * to be freed when the transaction is committed.
+		 */
+		ilen = XFS_IALLOC_INODES(mp);
+		INT_MOD(agi->agi_count, ARCH_CONVERT, -ilen);
+		INT_MOD(agi->agi_freecount, ARCH_CONVERT, -(ilen - 1));
+		xfs_ialloc_log_agi(tp, agbp, XFS_AGI_COUNT | XFS_AGI_FREECOUNT);
+		down_read(&mp->m_peraglock);
+		mp->m_perag[agno].pagi_freecount -= ilen - 1;
+		up_read(&mp->m_peraglock);
+		xfs_trans_mod_sb(tp, XFS_TRANS_SB_ICOUNT, -ilen);
+		xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -(ilen - 1));
+
+		if ((error = xfs_inobt_delete(cur, &i))) {
+			cmn_err(CE_WARN, "xfs_difree: xfs_inobt_delete returned an error %d on %s.\n",
+				error, mp->m_fsname);
+			goto error0;
+		}
+
+		xfs_bmap_add_free(XFS_AGB_TO_FSB(mp,
+				agno, XFS_INO_TO_AGBNO(mp,rec.ir_startino)),
+				XFS_IALLOC_BLOCKS(mp), flist, mp);
+	} else {
+		*delete = 0;
+
+		if ((error = xfs_inobt_update(cur, rec.ir_startino, rec.ir_freecount, rec.ir_free))) {
+			cmn_err(CE_WARN,
+				"xfs_difree: xfs_inobt_update()  returned an error %d on %s.  Returning error.",
+				error, mp->m_fsname);
+			goto error0;
+		}
+		/* 
+		 * Change the inode free counts and log the ag/sb changes.
+		 */
+		INT_MOD(agi->agi_freecount, ARCH_CONVERT, 1);
+		xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT);
+		down_read(&mp->m_peraglock);
+		mp->m_perag[agno].pagi_freecount++;
+		up_read(&mp->m_peraglock);
+		xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, 1);
+	}
+
 #ifdef DEBUG
 	if (cur->bc_nlevels == 1) {
 		int freecount = 0;
@@ -1054,20 +1100,23 @@
 		if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i)))
 			goto error0;
 		do {
-			if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino,
-					&rec.ir_freecount, &rec.ir_free, &i, ARCH_NOCONVERT)))
-				goto error0;
-			XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
-			freecount += rec.ir_freecount;
-			if ((error = xfs_inobt_increment(cur, 0, &i)))
+			if ((error = xfs_inobt_get_rec(cur,
+					&rec.ir_startino,
+					&rec.ir_freecount,
+					&rec.ir_free, &i,
+					ARCH_NOCONVERT)))
 				goto error0;
+			if (i) {
+				freecount += rec.ir_freecount;
+				if ((error = xfs_inobt_increment(cur, 0, &i)))
+					goto error0;
+			}
 		} while (i == 1);
 		ASSERT(freecount == INT_GET(agi->agi_freecount, ARCH_CONVERT) ||
 		       XFS_FORCED_SHUTDOWN(mp));
 	}
 #endif
 	xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
-	xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, 1);
 	return 0;
 
 error0:
@@ -1114,7 +1163,7 @@
 	agbno = XFS_AGINO_TO_AGBNO(mp, agino);
 	if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks ||
 	    ino != XFS_AGINO_TO_INO(mp, agno, agino)) {
-#if 0
+#ifdef DEBUG
 		if (agno >= mp->m_sb.sb_agcount) {
 			xfs_fs_cmn_err(CE_ALERT, mp,
 					"xfs_dilocate: agno (%d) >= "
diff -Nru a/fs/xfs/xfs_ialloc.h b/fs/xfs/xfs_ialloc.h
--- a/fs/xfs/xfs_ialloc.h	Wed Oct 15 00:46:36 2003
+++ b/fs/xfs/xfs_ialloc.h	Wed Oct 15 00:46:36 2003
@@ -134,7 +134,10 @@
 int					/* error */
 xfs_difree(
 	struct xfs_trans *tp,		/* transaction pointer */
-	xfs_ino_t	inode);		/* inode to be freed */
+	xfs_ino_t	inode,		/* inode to be freed */
+	struct xfs_bmap_free *flist,	/* extents to free */
+	int		*delete,	/* set if inode cluster was deleted */
+	xfs_ino_t	*first_ino);	/* first inode in deleted cluster */
 
 /*
  * Return the location of the inode in bno/len/off,
diff -Nru a/fs/xfs/xfs_ialloc_btree.c b/fs/xfs/xfs_ialloc_btree.c
--- a/fs/xfs/xfs_ialloc_btree.c	Wed Oct 15 00:46:36 2003
+++ b/fs/xfs/xfs_ialloc_btree.c	Wed Oct 15 00:46:36 2003
@@ -49,6 +49,7 @@
 #include "xfs_btree.h"
 #include "xfs_ialloc.h"
 #include "xfs_alloc.h"
+#include "xfs_error.h"
 
 /*
  * Inode allocation management for XFS.
@@ -73,7 +74,6 @@
  * Internal functions.
  */
 
-#ifdef _NOTYET_
 /*
  * Single level of the xfs_inobt_delete record deletion routine.
  * Delete record pointed to by cur/level.
@@ -87,8 +87,7 @@
 	int			*stat)	/* fail/done/go-on */
 {
 	xfs_buf_t		*agbp;	/* buffer for a.g. inode header */
-	xfs_agnumber_t		agfbno;	/* agf block of freed btree block */
-	xfs_buf_t		*agfbp;	/* bp of agf block of freed block */
+	xfs_mount_t		*mp;	/* mount structure */
 	xfs_agi_t		*agi;	/* allocation group inode header */
 	xfs_inobt_block_t	*block;	/* btree block record/key lives in */
 	xfs_agblock_t		bno;	/* btree block number */
@@ -96,15 +95,15 @@
 	int			error;	/* error return value */
 	int			i;	/* loop index */
 	xfs_inobt_key_t		key;	/* kp points here if block is level 0 */
-	xfs_inobt_key_t		*kp;	/* pointer to btree keys */
+	xfs_inobt_key_t		*kp = NULL;	/* pointer to btree keys */
 	xfs_agblock_t		lbno;	/* left block's block number */
 	xfs_buf_t		*lbp;	/* left block's buffer pointer */
 	xfs_inobt_block_t	*left;	/* left btree block */
 	xfs_inobt_key_t		*lkp;	/* left block key pointer */
 	xfs_inobt_ptr_t		*lpp;	/* left block address pointer */
-	int			lrecs;	/* number of records in left block */
+	int			lrecs = 0;	/* number of records in left block */
 	xfs_inobt_rec_t		*lrp;	/* left block record pointer */
-	xfs_inobt_ptr_t		*pp;	/* pointer to btree addresses */
+	xfs_inobt_ptr_t		*pp = NULL;	/* pointer to btree addresses */
 	int			ptr;	/* index in btree block for this rec */
 	xfs_agblock_t		rbno;	/* right block's block number */
 	xfs_buf_t		*rbp;	/* right block's buffer pointer */
@@ -112,10 +111,12 @@
 	xfs_inobt_key_t		*rkp;	/* right block key pointer */
 	xfs_inobt_rec_t		*rp;	/* pointer to btree records */
 	xfs_inobt_ptr_t		*rpp;	/* right block address pointer */
-	int			rrecs;	/* number of records in right block */
+	int			rrecs = 0;	/* number of records in right block */
+	int			numrecs;
 	xfs_inobt_rec_t		*rrp;	/* right block record pointer */
 	xfs_btree_cur_t		*tcur;	/* temporary btree cursor */
 
+	mp = cur->bc_mp;
 
 	/*
 	 * Get the index of the entry being deleted, check for nothing there.
@@ -125,19 +126,22 @@
 		*stat = 0;
 		return 0;
 	}
+
 	/*
 	 * Get the buffer & block containing the record or key/ptr.
 	 */
 	bp = cur->bc_bufs[level];
 	block = XFS_BUF_TO_INOBT_BLOCK(bp);
 #ifdef DEBUG
-	if (error = xfs_btree_check_sblock(cur, block, level, bp))
+	if ((error = xfs_btree_check_sblock(cur, block, level, bp)))
 		return error;
 #endif
 	/*
 	 * Fail if we're off the end of the block.
 	 */
-	if (ptr > INT_GET(block->bb_numrecs, ARCH_CONVERT)) {
+
+	numrecs = INT_GET(block->bb_numrecs, ARCH_CONVERT);
+	if (ptr > numrecs) {
 		*stat = 0;
 		return 0;
 	}
@@ -150,18 +154,18 @@
 		kp = XFS_INOBT_KEY_ADDR(block, 1, cur);
 		pp = XFS_INOBT_PTR_ADDR(block, 1, cur);
 #ifdef DEBUG
-		for (i = ptr; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) {
-			if (error = xfs_btree_check_sptr(cur, INT_GET(pp[i], ARCH_CONVERT), level))
+		for (i = ptr; i < numrecs; i++) {
+			if ((error = xfs_btree_check_sptr(cur, INT_GET(pp[i], ARCH_CONVERT), level)))
 				return error;
 		}
 #endif
-		if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) {
+		if (ptr < numrecs) {
 			memmove(&kp[ptr - 1], &kp[ptr],
-				(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*kp));
+				(numrecs - ptr) * sizeof(*kp));
 			memmove(&pp[ptr - 1], &pp[ptr],
-				(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*pp));
-			xfs_inobt_log_keys(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1);
-			xfs_inobt_log_ptrs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1);
+				(numrecs - ptr) * sizeof(*kp));
+			xfs_inobt_log_keys(cur, bp, ptr, numrecs - 1);
+			xfs_inobt_log_ptrs(cur, bp, ptr, numrecs - 1);
 		}
 	}
 	/*
@@ -170,24 +174,25 @@
 	 */
 	else {
 		rp = XFS_INOBT_REC_ADDR(block, 1, cur);
-		if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) {
+		if (ptr < numrecs) {
 			memmove(&rp[ptr - 1], &rp[ptr],
-				(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*rp));
-			xfs_inobt_log_recs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1);
+				(numrecs - ptr) * sizeof(*rp));
+			xfs_inobt_log_recs(cur, bp, ptr, numrecs - 1);
 		}
 		/*
 		 * If it's the first record in the block, we'll need a key
 		 * structure to pass up to the next level (updkey).
 		 */
 		if (ptr == 1) {
-			INT_COPY(key.ir_startino, rp->ir_startino, ARCH_CONVERT);
+			key.ir_startino = rp->ir_startino;
 			kp = &key;
 		}
 	}
 	/*
 	 * Decrement and log the number of entries in the block.
 	 */
-	INT_MOD(block->bb_numrecs, ARCH_CONVERT, -1);
+	numrecs--;
+	INT_SET(block->bb_numrecs, ARCH_CONVERT, numrecs);
 	xfs_inobt_log_block(cur->bc_tp, bp, XFS_BB_NUMRECS);
 	/*
 	 * Is this the root level?  If so, we're almost done.
@@ -199,7 +204,7 @@
 		 * and it's NOT the leaf level,
 		 * then we can get rid of this level.
 		 */
-		if (INT_GET(block->bb_numrecs, ARCH_CONVERT) == 1 && level > 0) {
+		if (numrecs == 1 && level > 0) {
 			agbp = cur->bc_private.i.agbp;
 			agi = XFS_BUF_TO_AGI(agbp);
 			/*
@@ -207,12 +212,13 @@
 			 * Make it the new root of the btree.
 			 */
 			bno = INT_GET(agi->agi_root, ARCH_CONVERT);
-			INT_COPY(agi->agi_root, *pp, ARCH_CONVERT);
+			agi->agi_root = *pp;
 			INT_MOD(agi->agi_level, ARCH_CONVERT, -1);
 			/*
 			 * Free the block.
 			 */
-			if (error = xfs_free_extent(cur->bc_tp, bno, 1))
+			if ((error = xfs_free_extent(cur->bc_tp,
+				XFS_AGB_TO_FSB(mp, cur->bc_private.i.agno, bno), 1)))
 				return error;
 			xfs_trans_binval(cur->bc_tp, bp);
 			xfs_ialloc_log_agi(cur->bc_tp, agbp,
@@ -222,21 +228,6 @@
 			 */
 			cur->bc_bufs[level] = NULL;
 			cur->bc_nlevels--;
-			/*
-			 * To ensure that the freed block is not used for
-			 * user data until this transaction is permanent,
-			 * we lock the agf buffer for this ag until the
-			 * transaction record makes it to the on-disk log.
-			 */
-			agfbno = XFS_AG_DADDR(cur->bc_mp,
-					      cur->bc_private.i.agno,
-					      XFS_AGF_DADDR(mp));
-			if (error = xfs_trans_read_buf(cur->bc_mp, cur->bc_tp,
-					cur->bc_mp->m_ddev_targp, agfbno,
-					XFS_FSS_TO_BB(mp, 1), 0, &agfbp))
-				return error;
-			ASSERT(!XFS_BUF_GETERROR(agfbp));
-			xfs_trans_bhold_until_committed(cur->bc_tp, agfbp);
 		} else if (level > 0 &&
 			   (error = xfs_inobt_decrement(cur, level, &i)))
 			return error;
@@ -253,7 +244,7 @@
 	 * If the number of records remaining in the block is at least
 	 * the minimum, we're done.
 	 */
-	if (INT_GET(block->bb_numrecs, ARCH_CONVERT) >= XFS_INOBT_BLOCK_MINRECS(level, cur)) {
+	if (numrecs >= XFS_INOBT_BLOCK_MINRECS(level, cur)) {
 		if (level > 0 &&
 		    (error = xfs_inobt_decrement(cur, level, &i)))
 			return error;
@@ -273,7 +264,7 @@
 	 * Duplicate the cursor so our btree manipulations here won't
 	 * disrupt the next level up.
 	 */
-	if (error = xfs_btree_dup_cursor(cur, &tcur))
+	if ((error = xfs_btree_dup_cursor(cur, &tcur)))
 		return error;
 	/*
 	 * If there's a right sibling, see if it's ok to shift an entry
@@ -286,7 +277,7 @@
 		 */
 		i = xfs_btree_lastrec(tcur, level);
 		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
-		if (error = xfs_inobt_increment(tcur, level, &i))
+		if ((error = xfs_inobt_increment(tcur, level, &i)))
 			goto error0;
 		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
 		i = xfs_btree_lastrec(tcur, level);
@@ -297,7 +288,7 @@
 		rbp = tcur->bc_bufs[level];
 		right = XFS_BUF_TO_INOBT_BLOCK(rbp);
 #ifdef DEBUG
-		if (error = xfs_btree_check_sblock(cur, right, level, rbp))
+		if ((error = xfs_btree_check_sblock(cur, right, level, rbp)))
 			goto error0;
 #endif
 		/*
@@ -311,7 +302,7 @@
 		 */
 		if (INT_GET(right->bb_numrecs, ARCH_CONVERT) - 1 >=
 		     XFS_INOBT_BLOCK_MINRECS(level, cur)) {
-			if (error = xfs_inobt_lshift(tcur, level, &i))
+			if ((error = xfs_inobt_lshift(tcur, level, &i)))
 				goto error0;
 			if (i) {
 				ASSERT(INT_GET(block->bb_numrecs, ARCH_CONVERT) >=
@@ -334,7 +325,7 @@
 		rrecs = INT_GET(right->bb_numrecs, ARCH_CONVERT);
 		if (lbno != NULLAGBLOCK) {
 			xfs_btree_firstrec(tcur, level);
-			if (error = xfs_inobt_decrement(tcur, level, &i))
+			if ((error = xfs_inobt_decrement(tcur, level, &i)))
 				goto error0;
 		}
 	}
@@ -348,7 +339,7 @@
 		 * previous block.
 		 */
 		xfs_btree_firstrec(tcur, level);
-		if (error = xfs_inobt_decrement(tcur, level, &i))
+		if ((error = xfs_inobt_decrement(tcur, level, &i)))
 			goto error0;
 		xfs_btree_firstrec(tcur, level);
 		/*
@@ -357,7 +348,7 @@
 		lbp = tcur->bc_bufs[level];
 		left = XFS_BUF_TO_INOBT_BLOCK(lbp);
 #ifdef DEBUG
-		if (error = xfs_btree_check_sblock(cur, left, level, lbp))
+		if ((error = xfs_btree_check_sblock(cur, left, level, lbp)))
 			goto error0;
 #endif
 		/*
@@ -371,7 +362,7 @@
 		 */
 		if (INT_GET(left->bb_numrecs, ARCH_CONVERT) - 1 >=
 		     XFS_INOBT_BLOCK_MINRECS(level, cur)) {
-			if (error = xfs_inobt_rshift(tcur, level, &i))
+			if ((error = xfs_inobt_rshift(tcur, level, &i)))
 				goto error0;
 			if (i) {
 				ASSERT(INT_GET(block->bb_numrecs, ARCH_CONVERT) >=
@@ -402,41 +393,44 @@
 	 * See if we can join with the left neighbor block.
 	 */
 	if (lbno != NULLAGBLOCK &&
-	    lrecs + INT_GET(block->bb_numrecs, ARCH_CONVERT) <= XFS_INOBT_BLOCK_MAXRECS(level, cur)) {
+	    lrecs + numrecs <= XFS_INOBT_BLOCK_MAXRECS(level, cur)) {
 		/*
 		 * Set "right" to be the starting block,
 		 * "left" to be the left neighbor.
 		 */
 		rbno = bno;
 		right = block;
+		rrecs = INT_GET(right->bb_numrecs, ARCH_CONVERT);
 		rbp = bp;
-		if (error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp,
+		if ((error = xfs_btree_read_bufs(mp, cur->bc_tp,
 				cur->bc_private.i.agno, lbno, 0, &lbp,
-				XFS_INO_BTREE_REF))
+				XFS_INO_BTREE_REF)))
 			return error;
 		left = XFS_BUF_TO_INOBT_BLOCK(lbp);
-		if (error = xfs_btree_check_sblock(cur, left, level, lbp))
+		lrecs = INT_GET(left->bb_numrecs, ARCH_CONVERT);
+		if ((error = xfs_btree_check_sblock(cur, left, level, lbp)))
 			return error;
 	}
 	/*
 	 * If that won't work, see if we can join with the right neighbor block.
 	 */
 	else if (rbno != NULLAGBLOCK &&
-		 rrecs + INT_GET(block->bb_numrecs, ARCH_CONVERT) <=
-		  XFS_INOBT_BLOCK_MAXRECS(level, cur)) {
+		 rrecs + numrecs <= XFS_INOBT_BLOCK_MAXRECS(level, cur)) {
 		/*
 		 * Set "left" to be the starting block,
 		 * "right" to be the right neighbor.
 		 */
 		lbno = bno;
 		left = block;
+		lrecs = INT_GET(left->bb_numrecs, ARCH_CONVERT);
 		lbp = bp;
-		if (error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp,
+		if ((error = xfs_btree_read_bufs(mp, cur->bc_tp,
 				cur->bc_private.i.agno, rbno, 0, &rbp,
-				XFS_INO_BTREE_REF))
+				XFS_INO_BTREE_REF)))
 			return error;
 		right = XFS_BUF_TO_INOBT_BLOCK(rbp);
-		if (error = xfs_btree_check_sblock(cur, right, level, rbp))
+		rrecs = INT_GET(right->bb_numrecs, ARCH_CONVERT);
+		if ((error = xfs_btree_check_sblock(cur, right, level, rbp)))
 			return error;
 	}
 	/*
@@ -457,40 +451,53 @@
 		/*
 		 * It's a non-leaf.  Move keys and pointers.
 		 */
-		lkp = XFS_INOBT_KEY_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur);
-		lpp = XFS_INOBT_PTR_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur);
+		lkp = XFS_INOBT_KEY_ADDR(left, lrecs + 1, cur);
+		lpp = XFS_INOBT_PTR_ADDR(left, lrecs + 1, cur);
 		rkp = XFS_INOBT_KEY_ADDR(right, 1, cur);
 		rpp = XFS_INOBT_PTR_ADDR(right, 1, cur);
 #ifdef DEBUG
-		for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) {
-			if (error = xfs_btree_check_sptr(cur, INT_GET(rpp[i], ARCH_CONVERT), level))
+		for (i = 0; i < rrecs; i++) {
+			if ((error = xfs_btree_check_sptr(cur, INT_GET(rpp[i], ARCH_CONVERT), level)))
 				return error;
 		}
 #endif
-		memcpy(lkp, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lkp));
-		memcpy(lpp, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lpp));
-		xfs_inobt_log_keys(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1,
-				   INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT));
-		xfs_inobt_log_ptrs(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1,
-				   INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT));
+		memcpy(lkp, rkp, rrecs * sizeof(*lkp));
+		memcpy(lpp, rpp, rrecs * sizeof(*lpp));
+		xfs_inobt_log_keys(cur, lbp, lrecs + 1, lrecs + rrecs);
+		xfs_inobt_log_ptrs(cur, lbp, lrecs + 1, lrecs + rrecs);
 	} else {
 		/*
 		 * It's a leaf.  Move records.
 		 */
-		lrp = XFS_INOBT_REC_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur);
+		lrp = XFS_INOBT_REC_ADDR(left, lrecs + 1, cur);
 		rrp = XFS_INOBT_REC_ADDR(right, 1, cur);
-		memcpy(lrp, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lrp));
-		xfs_inobt_log_recs(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1,
-				   INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT));
+		memcpy(lrp, rrp, rrecs * sizeof(*lrp));
+		xfs_inobt_log_recs(cur, lbp, lrecs + 1, lrecs + rrecs);
+	}
+	/*
+	 * If we joined with the left neighbor, set the buffer in the
+	 * cursor to the left block, and fix up the index.
+	 */
+	if (bp != lbp) {
+		xfs_btree_setbuf(cur, level, lbp);
+		cur->bc_ptrs[level] += lrecs;
 	}
 	/*
+	 * If we joined with the right neighbor and there's a level above
+	 * us, increment the cursor at that level.
+	 */
+	else if (level + 1 < cur->bc_nlevels &&
+		 (error = xfs_alloc_increment(cur, level + 1, &i)))
+		return error;
+	/*
 	 * Fix up the number of records in the surviving block.
 	 */
-	INT_MOD(left->bb_numrecs, ARCH_CONVERT, INT_GET(right->bb_numrecs, ARCH_CONVERT));
+	lrecs += rrecs;
+	INT_SET(left->bb_numrecs, ARCH_CONVERT, lrecs);
 	/*
 	 * Fix up the right block pointer in the surviving block, and log it.
 	 */
-	INT_COPY(left->bb_rightsib, right->bb_rightsib, ARCH_CONVERT);
+	left->bb_rightsib = right->bb_rightsib;
 	xfs_inobt_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB);
 	/*
 	 * If there is a right sibling now, make it point to the
@@ -500,12 +507,12 @@
 		xfs_inobt_block_t	*rrblock;
 		xfs_buf_t		*rrbp;
 
-		if (error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp,
+		if ((error = xfs_btree_read_bufs(mp, cur->bc_tp,
 				cur->bc_private.i.agno, INT_GET(left->bb_rightsib, ARCH_CONVERT), 0,
-				&rrbp, XFS_INO_BTREE_REF))
+				&rrbp, XFS_INO_BTREE_REF)))
 			return error;
 		rrblock = XFS_BUF_TO_INOBT_BLOCK(rrbp);
-		if (error = xfs_btree_check_sblock(cur, rrblock, level, rrbp))
+		if ((error = xfs_btree_check_sblock(cur, rrblock, level, rrbp)))
 			return error;
 		INT_SET(rrblock->bb_leftsib, ARCH_CONVERT, lbno);
 		xfs_inobt_log_block(cur->bc_tp, rrbp, XFS_BB_LEFTSIB);
@@ -513,41 +520,11 @@
 	/*
 	 * Free the deleting block.
 	 */
-	if (error = xfs_free_extent(cur->bc_tp, rbno, 1))
+	if ((error = xfs_free_extent(cur->bc_tp, XFS_AGB_TO_FSB(mp,
+				     cur->bc_private.i.agno, rbno), 1)))
 		return error;
 	xfs_trans_binval(cur->bc_tp, rbp);
 	/*
-	 * To ensure that the freed block is not used for
-	 * user data until this transaction is permanent,
-	 * we lock the agf buffer for this ag until the
-	 * transaction record makes it to the on-disk log.
-	 */
-	agfbno = XFS_AG_DADDR(cur->bc_mp, cur->bc_private.i.agno,
-			      XFS_AGF_DADDR(mp));
-	if (error = xfs_trans_read_buf(cur->bc_mp, cur->bc_tp,
-			cur->bc_mp->m_ddev_targp, agfbno,
-			XFS_FSS_TO_BB(mp, 1), 0, &agfbp))
-		return error;
-	ASSERT(!XFS_BUF_GETERROR(agfbp));
-	xfs_trans_bhold_until_committed(cur->bc_tp, agfbp);
-	/*
-	 * If we joined with the left neighbor, set the buffer in the
-	 * cursor to the left block, and fix up the index.
-	 */
-	if (bp != lbp) {
-		cur->bc_bufs[level] = lbp;
-		cur->bc_ptrs[level] += INT_GET(left->bb_numrecs, ARCH_CONVERT);
-		cur->bc_ra[level] = 0;
-	}
-	/*
-	 * If we joined with the right neighbor and there's a level above
-	 * us, increment the cursor at that level.
-	 */
-	else if (level + 1 < cur->bc_nlevels &&
-		 (error = xfs_inobt_increment(cur, level + 1, &i))) {
-		return error;
-	}
-	/*
 	 * Readjust the ptr at this level if it's not a leaf, since it's
 	 * still pointing at the deletion point, which makes the cursor
 	 * inconsistent.  If this makes the ptr 0, the caller fixes it up.
@@ -565,7 +542,6 @@
 	xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR);
 	return error;
 }
-#endif	/* _NOTYET_ */
 
 /*
  * Insert one record/level.  Return information to the caller
@@ -590,6 +566,7 @@
 	xfs_btree_cur_t		*ncur;	/* new cursor to be used at next lvl */
 	xfs_inobt_key_t		nkey;	/* new key value, from split */
 	xfs_inobt_rec_t		nrec;	/* new record value, for caller */
+	int			numrecs;
 	int			optr;	/* old ptr value */
 	xfs_inobt_ptr_t		*pp;	/* pointer to btree addresses */
 	int			ptr;	/* index in btree block for this rec */
@@ -622,13 +599,14 @@
 	 */
 	bp = cur->bc_bufs[level];
 	block = XFS_BUF_TO_INOBT_BLOCK(bp);
+	numrecs = INT_GET(block->bb_numrecs, ARCH_CONVERT);
 #ifdef DEBUG
 	if ((error = xfs_btree_check_sblock(cur, block, level, bp)))
 		return error;
 	/*
 	 * Check that the new entry is being inserted in the right place.
 	 */
-	if (ptr <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) {
+	if (ptr <= numrecs) {
 		if (level == 0) {
 			rp = XFS_INOBT_REC_ADDR(block, ptr, cur);
 			xfs_btree_check_rec(cur->bc_btnum, recp, rp);
@@ -644,7 +622,7 @@
 	 * If the block is full, we can't insert the new entry until we
 	 * make the block un-full.
 	 */
-	if (INT_GET(block->bb_numrecs, ARCH_CONVERT) == XFS_INOBT_BLOCK_MAXRECS(level, cur)) {
+	if (numrecs == XFS_INOBT_BLOCK_MAXRECS(level, cur)) {
 		/*
 		 * First, try shifting an entry to the right neighbor.
 		 */
@@ -695,6 +673,7 @@
 	 * At this point we know there's room for our new entry in the block
 	 * we're pointing at.
 	 */
+	numrecs = INT_GET(block->bb_numrecs, ARCH_CONVERT);
 	if (level > 0) {
 		/*
 		 * It's a non-leaf entry.  Make a hole for the new data
@@ -703,15 +682,15 @@
 		kp = XFS_INOBT_KEY_ADDR(block, 1, cur);
 		pp = XFS_INOBT_PTR_ADDR(block, 1, cur);
 #ifdef DEBUG
-		for (i = INT_GET(block->bb_numrecs, ARCH_CONVERT); i >= ptr; i--) {
+		for (i = numrecs; i >= ptr; i--) {
 			if ((error = xfs_btree_check_sptr(cur, INT_GET(pp[i - 1], ARCH_CONVERT), level)))
 				return error;
 		}
 #endif
 		memmove(&kp[ptr], &kp[ptr - 1],
-			(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*kp));
+			(numrecs - ptr + 1) * sizeof(*kp));
 		memmove(&pp[ptr], &pp[ptr - 1],
-			(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*pp));
+			(numrecs - ptr + 1) * sizeof(*pp));
 		/*
 		 * Now stuff the new data in, bump numrecs and log the new data.
 		 */
@@ -721,23 +700,25 @@
 #endif
 		kp[ptr - 1] = key; /* INT_: struct copy */
 		INT_SET(pp[ptr - 1], ARCH_CONVERT, *bnop);
-		INT_MOD(block->bb_numrecs, ARCH_CONVERT, +1);
-		xfs_inobt_log_keys(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT));
-		xfs_inobt_log_ptrs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT));
+		numrecs++;
+		INT_SET(block->bb_numrecs, ARCH_CONVERT, numrecs);
+		xfs_inobt_log_keys(cur, bp, ptr, numrecs);
+		xfs_inobt_log_ptrs(cur, bp, ptr, numrecs);
 	} else {
 		/*
 		 * It's a leaf entry.  Make a hole for the new record.
 		 */
 		rp = XFS_INOBT_REC_ADDR(block, 1, cur);
 		memmove(&rp[ptr], &rp[ptr - 1],
-			(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*rp));
+			(numrecs - ptr + 1) * sizeof(*rp));
 		/*
 		 * Now stuff the new record in, bump numrecs
 		 * and log the new data.
 		 */
 		rp[ptr - 1] = *recp; /* INT_: struct copy */
-		INT_MOD(block->bb_numrecs, ARCH_CONVERT, +1);
-		xfs_inobt_log_recs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT));
+		numrecs++;
+		INT_SET(block->bb_numrecs, ARCH_CONVERT, numrecs);
+		xfs_inobt_log_recs(cur, bp, ptr, numrecs);
 	}
 	/*
 	 * Log the new number of records in the btree header.
@@ -747,7 +728,7 @@
 	/*
 	 * Check that the key/record is in the right place, now.
 	 */
-	if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) {
+	if (ptr < numrecs) {
 		if (level == 0)
 			xfs_btree_check_rec(cur->bc_btnum, rp + ptr - 1,
 				rp + ptr);
@@ -1774,7 +1755,6 @@
 	return 0;
 }
 
-#ifdef _NOTYET_
 /*
  * Delete the record pointed to by cur.
  * The cursor refers to the place where the record was (could be inserted)
@@ -1795,13 +1775,13 @@
 	 * Otherwise we are done.
 	 */
 	for (level = 0, i = 2; i == 2; level++) {
-		if (error = xfs_inobt_delrec(cur, level, &i))
+		if ((error = xfs_inobt_delrec(cur, level, &i)))
 			return error;
 	}
 	if (i == 0) {
 		for (level = 1; level < cur->bc_nlevels; level++) {
 			if (cur->bc_ptrs[level] == 0) {
-				if (error = xfs_inobt_decrement(cur, level, &i))
+				if ((error = xfs_inobt_decrement(cur, level, &i)))
 					return error;
 				break;
 			}
@@ -1810,7 +1790,7 @@
 	*stat = i;
 	return 0;
 }
-#endif	/* _NOTYET_ */
+
 
 /*
  * Get the data from the pointed-to record.
diff -Nru a/fs/xfs/xfs_ialloc_btree.h b/fs/xfs/xfs_ialloc_btree.h
--- a/fs/xfs/xfs_ialloc_btree.h	Wed Oct 15 00:46:36 2003
+++ b/fs/xfs/xfs_ialloc_btree.h	Wed Oct 15 00:46:36 2003
@@ -225,7 +225,6 @@
 	int			level,	/* level in btree, 0 is leaf */
 	int			*stat); /* success/failure */
 
-#ifdef _NOTYET_
 /*
  * Delete the record pointed to by cur.
  * The cursor refers to the place where the record was (could be inserted)
@@ -235,7 +234,6 @@
 xfs_inobt_delete(
 	struct xfs_btree_cur	*cur,	/* btree cursor */
 	int			*stat);	/* success/failure */
-#endif	/* _NOTYET_ */
 
 /*
  * Get the data from the pointed-to record.
diff -Nru a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
--- a/fs/xfs/xfs_iget.c	Wed Oct 15 00:46:38 2003
+++ b/fs/xfs/xfs_iget.c	Wed Oct 15 00:46:38 2003
@@ -258,6 +258,7 @@
 			if (newnode) {
 				xfs_iocore_inode_reinit(ip);
 			}
+			ip->i_flags &= ~XFS_ISTALE;
 
 			vn_trace_exit(vp, "xfs_iget.found",
 						(inst_t *)__return_address);
diff -Nru a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
--- a/fs/xfs/xfs_inode.c	Wed Oct 15 00:46:38 2003
+++ b/fs/xfs/xfs_inode.c	Wed Oct 15 00:46:38 2003
@@ -36,6 +36,7 @@
 #include "xfs_inum.h"
 #include "xfs_log.h"
 #include "xfs_trans.h"
+#include "xfs_trans_priv.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
 #include "xfs_dir.h"
@@ -486,11 +487,11 @@
 		return XFS_ERROR(EFSCORRUPTED);
 	}
 
-	switch (ip->i_d.di_mode & IFMT) {
-	case IFIFO:
-	case IFCHR:
-	case IFBLK:
-	case IFSOCK:
+	switch (ip->i_d.di_mode & S_IFMT) {
+	case S_IFIFO:
+	case S_IFCHR:
+	case S_IFBLK:
+	case S_IFSOCK:
 		if (unlikely(INT_GET(dip->di_core.di_format, ARCH_CONVERT) != XFS_DINODE_FMT_DEV)) {
 			XFS_CORRUPTION_ERROR("xfs_iformat(3)", XFS_ERRLEVEL_LOW,
 					      ip->i_mount, dip);
@@ -500,15 +501,15 @@
 		ip->i_df.if_u2.if_rdev = INT_GET(dip->di_u.di_dev, ARCH_CONVERT);
 		break;
 
-	case IFREG:
-	case IFLNK:
-	case IFDIR:
+	case S_IFREG:
+	case S_IFLNK:
+	case S_IFDIR:
 		switch (INT_GET(dip->di_core.di_format, ARCH_CONVERT)) {
 		case XFS_DINODE_FMT_LOCAL:
 			/*
 			 * no local regular files yet
 			 */
-			if (unlikely((INT_GET(dip->di_core.di_mode, ARCH_CONVERT) & IFMT) == IFREG)) {
+			if (unlikely((INT_GET(dip->di_core.di_mode, ARCH_CONVERT) & S_IFMT) == S_IFREG)) {
 				xfs_fs_cmn_err(CE_WARN, ip->i_mount,
 					"corrupt inode (local format for regular file) %Lu.  Unmount and run xfs_repair.",
 					(unsigned long long) ip->i_ino);
@@ -1171,20 +1172,20 @@
 
 	if (XFS_INHERIT_GID(pip, vp->v_vfsp)) {
 		ip->i_d.di_gid = pip->i_d.di_gid;
-		if ((pip->i_d.di_mode & ISGID) && (mode & IFMT) == IFDIR) {
-			ip->i_d.di_mode |= ISGID;
+		if ((pip->i_d.di_mode & S_ISGID) && (mode & S_IFMT) == S_IFDIR) {
+			ip->i_d.di_mode |= S_ISGID;
 		}
 	}
 
 	/*
 	 * If the group ID of the new file does not match the effective group
-	 * ID or one of the supplementary group IDs, the ISGID bit is cleared
+	 * ID or one of the supplementary group IDs, the S_ISGID bit is cleared
 	 * (and only if the irix_sgid_inherit compatibility variable is set).
 	 */
 	if ((irix_sgid_inherit) &&
-	    (ip->i_d.di_mode & ISGID) &&
+	    (ip->i_d.di_mode & S_ISGID) &&
 	    (!in_group_p((gid_t)ip->i_d.di_gid))) {
-		ip->i_d.di_mode &= ~ISGID;
+		ip->i_d.di_mode &= ~S_ISGID;
 	}
 
 	ip->i_d.di_size = 0;
@@ -1199,18 +1200,18 @@
 	ip->i_d.di_dmstate = 0;
 	ip->i_d.di_flags = 0;
 	flags = XFS_ILOG_CORE;
-	switch (mode & IFMT) {
-	case IFIFO:
-	case IFCHR:
-	case IFBLK:
-	case IFSOCK:
+	switch (mode & S_IFMT) {
+	case S_IFIFO:
+	case S_IFCHR:
+	case S_IFBLK:
+	case S_IFSOCK:
 		ip->i_d.di_format = XFS_DINODE_FMT_DEV;
 		ip->i_df.if_u2.if_rdev = rdev;
 		ip->i_df.if_flags = 0;
 		flags |= XFS_ILOG_DEV;
 		break;
-	case IFREG:
-	case IFDIR:
+	case S_IFREG:
+	case S_IFDIR:
 		if (pip->i_d.di_flags &
 		    (XFS_DIFLAG_NOATIME|XFS_DIFLAG_NODUMP|XFS_DIFLAG_SYNC)) {
 			if ((pip->i_d.di_flags & XFS_DIFLAG_NOATIME) &&
@@ -1223,7 +1224,7 @@
 			    xfs_inherit_sync)
 				ip->i_d.di_flags |= XFS_DIFLAG_SYNC;
 		}
-	case IFLNK:
+	case S_IFLNK:
 		ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS;
 		ip->i_df.if_flags = XFS_IFEXTENTS;
 		ip->i_df.if_bytes = ip->i_df.if_real_bytes = 0;
@@ -1267,7 +1268,7 @@
 	int		nimaps;
 	xfs_bmbt_irec_t	imaps[2];
 
-	if ((ip->i_d.di_mode & IFMT) != IFREG)
+	if ((ip->i_d.di_mode & S_IFMT) != S_IFREG)
 		return;
 
 	if ( ip->i_d.di_flags & XFS_DIFLAG_REALTIME )
@@ -2103,6 +2104,180 @@
 	return 0;
 }
 
+static __inline__ int xfs_inode_clean(xfs_inode_t *ip)
+{
+	return (((ip->i_itemp == NULL) ||
+		!(ip->i_itemp->ili_format.ilf_fields & XFS_ILOG_ALL)) &&
+		(ip->i_update_core == 0));
+}
+
+void
+xfs_ifree_cluster(
+	xfs_inode_t	*free_ip,
+	xfs_trans_t	*tp,
+	xfs_ino_t	inum)
+{
+	xfs_mount_t		*mp = free_ip->i_mount;
+	int			blks_per_cluster;
+	int			nbufs;
+	int			ninodes;
+	int			i, j, found, pre_flushed;
+	xfs_daddr_t		blkno;
+	xfs_buf_t		*bp;
+	xfs_ihash_t		*ih;
+	xfs_inode_t		*ip, **ip_found;
+	xfs_inode_log_item_t	*iip;
+	xfs_log_item_t		*lip;
+	SPLDECL(s);
+
+	if (mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(mp)) {
+		blks_per_cluster = 1;
+		ninodes = mp->m_sb.sb_inopblock;
+		nbufs = XFS_IALLOC_BLOCKS(mp);
+	} else {
+		blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) /
+					mp->m_sb.sb_blocksize;
+		ninodes = blks_per_cluster * mp->m_sb.sb_inopblock;
+		nbufs = XFS_IALLOC_BLOCKS(mp) / blks_per_cluster;
+	}
+
+	ip_found = kmem_alloc(ninodes * sizeof(xfs_inode_t *), KM_NOFS);
+
+	for (j = 0; j < nbufs; j++, inum += ninodes) {
+		blkno = XFS_AGB_TO_DADDR(mp, XFS_INO_TO_AGNO(mp, inum),
+					 XFS_INO_TO_AGBNO(mp, inum));
+
+
+		/*
+		 * Look for each inode in memory and attempt to lock it,
+		 * we can be racing with flush and tail pushing here.
+		 * any inode we get the locks on, add to an array of
+		 * inode items to process later.
+		 *
+		 * The get the buffer lock, we could beat a flush
+		 * or tail pushing thread to the lock here, in which
+		 * case they will go looking for the inode buffer
+		 * and fail, we need some other form of interlock
+		 * here.
+		 */
+		found = 0;
+		for (i = 0; i < ninodes; i++) {
+			ih = XFS_IHASH(mp, inum + i);
+			read_lock(&ih->ih_lock);
+			for (ip = ih->ih_next; ip != NULL; ip = ip->i_next) {
+				if (ip->i_ino == inum + i)
+					break;
+			}
+
+			/* Inode not in memory or we found it already,
+			 * nothing to do
+			 */
+			if (!ip || (ip->i_flags & XFS_ISTALE)) {
+				read_unlock(&ih->ih_lock);
+				continue;
+			}
+
+			if (xfs_inode_clean(ip)) {
+				read_unlock(&ih->ih_lock);
+				continue;
+			}
+
+			/* If we can get the locks then add it to the
+			 * list, otherwise by the time we get the bp lock
+			 * below it will already be attached to the
+			 * inode buffer.
+			 */
+
+			/* This inode will already be locked - by us, lets
+			 * keep it that way.
+			 */
+
+			if (ip == free_ip) {
+				if (xfs_iflock_nowait(ip)) {
+					ip->i_flags |= XFS_ISTALE;
+
+					if (xfs_inode_clean(ip)) {
+						xfs_ifunlock(ip);
+					} else {
+						ip_found[found++] = ip;
+					}
+				}
+				read_unlock(&ih->ih_lock);
+				continue;
+			}
+
+			if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) {
+				if (xfs_iflock_nowait(ip)) {
+					ip->i_flags |= XFS_ISTALE;
+
+					if (xfs_inode_clean(ip)) {
+						xfs_ifunlock(ip);
+						xfs_iunlock(ip, XFS_ILOCK_EXCL);
+					} else {
+						ip_found[found++] = ip;
+					}
+				} else {
+					xfs_iunlock(ip, XFS_ILOCK_EXCL);
+				}
+			}
+
+			read_unlock(&ih->ih_lock);
+		}
+
+		bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, blkno, 
+					mp->m_bsize * blks_per_cluster,
+					XFS_BUF_LOCK);
+
+		pre_flushed = 0;
+		lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *);
+		while (lip) {
+			if (lip->li_type == XFS_LI_INODE) {
+				iip = (xfs_inode_log_item_t *)lip;
+				ASSERT(iip->ili_logged == 1);
+				lip->li_cb = (void(*)(xfs_buf_t*,xfs_log_item_t*)) xfs_istale_done;
+				AIL_LOCK(mp,s);
+				iip->ili_flush_lsn = iip->ili_item.li_lsn;
+				AIL_UNLOCK(mp, s);
+				iip->ili_inode->i_flags |= XFS_ISTALE;
+				pre_flushed++;
+			}
+			lip = lip->li_bio_list;
+		}
+
+		for (i = 0; i < found; i++) {
+			ip = ip_found[i];
+			iip = ip->i_itemp;
+
+			if (!iip) {
+				ip->i_update_core = 0;
+				xfs_ifunlock(ip);
+				xfs_iunlock(ip, XFS_ILOCK_EXCL);
+				continue;
+			}
+
+			iip->ili_last_fields = iip->ili_format.ilf_fields;
+			iip->ili_format.ilf_fields = 0;
+			iip->ili_logged = 1;
+			AIL_LOCK(mp,s);
+			iip->ili_flush_lsn = iip->ili_item.li_lsn;
+			AIL_UNLOCK(mp, s);
+
+			xfs_buf_attach_iodone(bp,
+				(void(*)(xfs_buf_t*,xfs_log_item_t*))
+				xfs_istale_done, (xfs_log_item_t *)iip);
+			if (ip != free_ip) {
+				xfs_iunlock(ip, XFS_ILOCK_EXCL);
+			}
+		}
+
+		if (found || pre_flushed)
+			xfs_trans_stale_inode_buf(tp, bp);
+		xfs_trans_binval(tp, bp);
+	}
+
+	kmem_free(ip_found, ninodes * sizeof(xfs_inode_t *));
+}
+
 /*
  * This is called to return an inode to the inode free list.
  * The inode should already be truncated to 0 length and have
@@ -2116,9 +2291,12 @@
 int
 xfs_ifree(
 	xfs_trans_t	*tp,
-	xfs_inode_t	*ip)
+	xfs_inode_t	*ip,
+	xfs_bmap_free_t	*flist)
 {
-	int	error;
+	int			error;
+	int			delete;
+	xfs_ino_t		first_ino;
 
 	ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE));
 	ASSERT(ip->i_transp == tp);
@@ -2126,7 +2304,7 @@
 	ASSERT(ip->i_d.di_nextents == 0);
 	ASSERT(ip->i_d.di_anextents == 0);
 	ASSERT((ip->i_d.di_size == 0) ||
-	       ((ip->i_d.di_mode & IFMT) != IFREG));
+	       ((ip->i_d.di_mode & S_IFMT) != S_IFREG));
 	ASSERT(ip->i_d.di_nblocks == 0);
 
 	/*
@@ -2137,7 +2315,7 @@
 		return error;
 	}
 
-	error = xfs_difree(tp, ip->i_ino);
+	error = xfs_difree(tp, ip->i_ino, flist, &delete, &first_ino);
 	if (error != 0) {
 		return error;
 	}
@@ -2149,13 +2327,17 @@
 		XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);
 	ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS;
 	ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
-
 	/*
 	 * Bump the generation count so no one will be confused
 	 * by reincarnations of this inode.
 	 */
 	ip->i_d.di_gen++;
 	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+
+	if (delete) {
+		xfs_ifree_cluster(ip, tp, first_ino);
+	}
+
 	return 0;
 }
 
@@ -2564,10 +2746,10 @@
 	xfs_inode_t	*ip)
 {
 
-	switch (ip->i_d.di_mode & IFMT) {
-	case IFREG:
-	case IFDIR:
-	case IFLNK:
+	switch (ip->i_d.di_mode & S_IFMT) {
+	case S_IFREG:
+	case S_IFDIR:
+	case S_IFLNK:
 		xfs_idestroy_fork(ip, XFS_DATA_FORK);
 		break;
 	}
@@ -3208,7 +3390,7 @@
 			ip->i_ino, ip, ip->i_d.di_magic);
 		goto corrupt_out;
 	}
-	if ((ip->i_d.di_mode & IFMT) == IFREG) {
+	if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) {
 		if (XFS_TEST_ERROR(
 		    (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) &&
 		    (ip->i_d.di_format != XFS_DINODE_FMT_BTREE),
@@ -3218,7 +3400,7 @@
 				ip->i_ino, ip);
 			goto corrupt_out;
 		}
-	} else if ((ip->i_d.di_mode & IFMT) == IFDIR) {
+	} else if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
 		if (XFS_TEST_ERROR(
 		    (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) &&
 		    (ip->i_d.di_format != XFS_DINODE_FMT_BTREE) &&
@@ -3507,7 +3689,7 @@
 	if ((error = _MAC_XFS_IACCESS(ip, mode, cr)))
 		return XFS_ERROR(error);
 
-	if (mode & IWRITE) {
+	if (mode & S_IWUSR) {
 		umode_t		imode = inode->i_mode;
 
 		if (IS_RDONLY(inode) &&
@@ -3540,13 +3722,13 @@
 	 * Read/write DACs are always overridable.
 	 * Executable DACs are overridable if at least one exec bit is set.
 	 */
-	if ((orgmode & (IREAD|IWRITE)) || (inode->i_mode & S_IXUGO))
+	if ((orgmode & (S_IRUSR|S_IWUSR)) || (inode->i_mode & S_IXUGO))
 		if (capable_cred(cr, CAP_DAC_OVERRIDE))
 			return 0;
 
-	if ((orgmode == IREAD) ||
-	    (((ip->i_d.di_mode & IFMT) == IFDIR) &&
-	     (!(orgmode & ~(IWRITE|IEXEC))))) {
+	if ((orgmode == S_IRUSR) ||
+	    (((ip->i_d.di_mode & S_IFMT) == S_IFDIR) &&
+	     (!(orgmode & ~(S_IWUSR|S_IXUSR))))) {
 		if (capable_cred(cr, CAP_DAC_READ_SEARCH))
 			return 0;
 #ifdef	NOISE
diff -Nru a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
--- a/fs/xfs/xfs_inode.h	Wed Oct 15 00:46:37 2003
+++ b/fs/xfs/xfs_inode.h	Wed Oct 15 00:46:37 2003
@@ -179,7 +179,7 @@
  * Inode hashing and hash bucket locking.
  */
 #define XFS_BUCKETS(mp) (37*(mp)->m_sb.sb_agcount-1)
-#define XFS_IHASH(mp,ino) ((mp)->m_ihash + (((uint)ino) % (mp)->m_ihsize))
+#define XFS_IHASH(mp,ino) ((mp)->m_ihash + (((uint)(ino)) % (mp)->m_ihsize))
 
 /*
  * This is the xfs inode cluster hash.  This hash is used by xfs_iflush to
@@ -362,7 +362,8 @@
 #define XFS_IUIOSZ	0x0002  /* inode i/o sizes have been explicitly set */
 #define XFS_IQUIESCE    0x0004  /* we have started quiescing for this inode */
 #define XFS_IRECLAIM    0x0008  /* we have started reclaiming this inode    */
-#define XFS_IRECLAIMABLE 0x0010 /* inode can be reclaimed */
+#define XFS_ISTALE	0x0010	/* inode has been staled */
+#define XFS_IRECLAIMABLE 0x0020 /* inode can be reclaimed */
 
 /*
  * Flags for inode locking.
@@ -437,12 +438,12 @@
 #define XFS_CHASH(mp,blk) ((mp)->m_chash + (((uint)blk) % (mp)->m_chsize))
 
 /*
- * For multiple groups support: if ISGID bit is set in the parent
+ * For multiple groups support: if S_ISGID bit is set in the parent
  * directory, group of new file is set to that of the parent, and
- * new subdirectory gets ISGID bit from parent.
+ * new subdirectory gets S_ISGID bit from parent.
  */
 #define XFS_INHERIT_GID(pip, vfsp)	((pip) != NULL && \
-	(((vfsp)->vfs_flag & VFS_GRPID) || ((pip)->i_d.di_mode & ISGID)))
+	(((vfsp)->vfs_flag & VFS_GRPID) || ((pip)->i_d.di_mode & S_ISGID)))
 
 /*
  * xfs_iget.c prototypes.
@@ -487,7 +488,8 @@
 			   struct xfs_buf **, boolean_t *, xfs_inode_t **);
 void		xfs_xlate_dinode_core(xfs_caddr_t, struct xfs_dinode_core *, int,
 			   xfs_arch_t);
-int		xfs_ifree(struct xfs_trans *, xfs_inode_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 *,
diff -Nru a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
--- a/fs/xfs/xfs_inode_item.c	Wed Oct 15 00:46:37 2003
+++ b/fs/xfs/xfs_inode_item.c	Wed Oct 15 00:46:37 2003
@@ -631,6 +631,14 @@
 		}
 		/* NOTREACHED */
 	}
+
+	/* Stale items should force out the iclog */
+	if (ip->i_flags & XFS_ISTALE) {
+		xfs_ifunlock(ip);
+		xfs_iunlock(ip, XFS_ILOCK_SHARED|XFS_IUNLOCK_NONOTIFY);
+		return XFS_ITEM_PINNED;
+	}
+
 #ifdef DEBUG
 	if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
 		ASSERT(iip->ili_format.ilf_fields != 0);
@@ -1073,4 +1081,12 @@
 	 * Release the inode's flush lock since we're done with it.
 	 */
 	xfs_ifunlock(ip);
+}
+
+void
+xfs_istale_done(
+	xfs_buf_t		*bp,
+	xfs_inode_log_item_t	*iip)
+{
+	xfs_iflush_abort(iip->ili_inode);
 }
diff -Nru a/fs/xfs/xfs_inode_item.h b/fs/xfs/xfs_inode_item.h
--- a/fs/xfs/xfs_inode_item.h	Wed Oct 15 00:46:37 2003
+++ b/fs/xfs/xfs_inode_item.h	Wed Oct 15 00:46:37 2003
@@ -189,6 +189,7 @@
 void	xfs_inode_item_init(struct xfs_inode *, struct xfs_mount *);
 void	xfs_inode_item_destroy(struct xfs_inode *);
 void	xfs_iflush_done(struct xfs_buf *, xfs_inode_log_item_t *);
+void	xfs_istale_done(struct xfs_buf *, xfs_inode_log_item_t *);
 void	xfs_iflush_abort(struct xfs_inode *);
 
 #endif	/* __KERNEL__ */
diff -Nru a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
--- a/fs/xfs/xfs_log_recover.c	Wed Oct 15 00:46:36 2003
+++ b/fs/xfs/xfs_log_recover.c	Wed Oct 15 00:46:36 2003
@@ -1529,17 +1529,35 @@
 	xlog_recover_t		*trans)
 {
 	xlog_recover_item_t	*first_item, *itemq, *itemq_next;
+	xfs_buf_log_format_t	*buf_f;
+	xfs_buf_log_format_v1_t	*obuf_f;
+	ushort			flags;
 
 	first_item = itemq = trans->r_itemq;
 	trans->r_itemq = NULL;
 	do {
 		itemq_next = itemq->ri_next;
+		buf_f = (xfs_buf_log_format_t *)itemq->ri_buf[0].i_addr;
 		switch (ITEM_TYPE(itemq)) {
 		case XFS_LI_BUF:
+			flags = buf_f->blf_flags;
+			break;
 		case XFS_LI_6_1_BUF:
 		case XFS_LI_5_3_BUF:
-			xlog_recover_insert_item_frontq(&trans->r_itemq, itemq);
+			obuf_f = (xfs_buf_log_format_v1_t*)buf_f;
+			flags = obuf_f->blf_flags;
 			break;
+		}
+
+		switch (ITEM_TYPE(itemq)) {
+		case XFS_LI_BUF:
+		case XFS_LI_6_1_BUF:
+		case XFS_LI_5_3_BUF:
+			if ((!flags & XFS_BLI_CANCEL)) {
+				xlog_recover_insert_item_frontq(&trans->r_itemq,
+								itemq);
+				break;
+			}
 		case XFS_LI_INODE:
 		case XFS_LI_6_1_INODE:
 		case XFS_LI_5_3_INODE:
@@ -1668,32 +1686,16 @@
  * made at that point.
  */
 STATIC int
-xlog_recover_do_buffer_pass2(
+xlog_check_buffer_cancelled(
 	xlog_t			*log,
-	xfs_buf_log_format_t	*buf_f)
+	xfs_daddr_t		blkno,
+	uint			len,
+	ushort			flags)
 {
 	xfs_buf_cancel_t	*bcp;
 	xfs_buf_cancel_t	*prevp;
 	xfs_buf_cancel_t	**bucket;
-	xfs_buf_log_format_v1_t	*obuf_f;
-	xfs_daddr_t		blkno = 0;
-	ushort			flags = 0;
-	uint			len = 0;
 
-	switch (buf_f->blf_type) {
-	case XFS_LI_BUF:
-		blkno = buf_f->blf_blkno;
-		flags = buf_f->blf_flags;
-		len = buf_f->blf_len;
-		break;
-	case XFS_LI_6_1_BUF:
-	case XFS_LI_5_3_BUF:
-		obuf_f = (xfs_buf_log_format_v1_t*)buf_f;
-		blkno = (xfs_daddr_t) obuf_f->blf_blkno;
-		flags = obuf_f->blf_flags;
-		len = (xfs_daddr_t) obuf_f->blf_len;
-		break;
-	}
 	if (log->l_buf_cancel_table == NULL) {
 		/*
 		 * There is nothing in the table built in pass one,
@@ -1755,6 +1757,34 @@
 	return 0;
 }
 
+STATIC int
+xlog_recover_do_buffer_pass2(
+	xlog_t			*log,
+	xfs_buf_log_format_t	*buf_f)
+{
+	xfs_buf_log_format_v1_t	*obuf_f;
+	xfs_daddr_t		blkno = 0;
+	ushort			flags = 0;
+	uint			len = 0;
+
+	switch (buf_f->blf_type) {
+	case XFS_LI_BUF:
+		blkno = buf_f->blf_blkno;
+		flags = buf_f->blf_flags;
+		len = buf_f->blf_len;
+		break;
+	case XFS_LI_6_1_BUF:
+	case XFS_LI_5_3_BUF:
+		obuf_f = (xfs_buf_log_format_v1_t*)buf_f;
+		blkno = (xfs_daddr_t) obuf_f->blf_blkno;
+		flags = obuf_f->blf_flags;
+		len = (xfs_daddr_t) obuf_f->blf_len;
+		break;
+	}
+
+	return xlog_check_buffer_cancelled(log, blkno, len, flags);
+}
+
 /*
  * Perform recovery for a buffer full of inodes.  In these buffers,
  * the only data which should be recovered is that which corresponds
@@ -2009,7 +2039,7 @@
 	if (id != -1 && id != INT_GET(ddq->d_id, ARCH_CONVERT)) {
 		if (flags & XFS_QMOPT_DOWARN)
 			cmn_err(CE_ALERT,
-			"%s : ondisk-dquot 0x%x, ID mismatch: "
+			"%s : ondisk-dquot 0x%p, ID mismatch: "
 			"0x%x expected, found id 0x%x",
 			str, ddq, id, INT_GET(ddq->d_id, ARCH_CONVERT));
 		errs++;
@@ -2023,7 +2053,7 @@
 			    !INT_ISZERO(ddq->d_id, ARCH_CONVERT)) {
 				if (flags & XFS_QMOPT_DOWARN)
 					cmn_err(CE_ALERT,
-					"%s : Dquot ID 0x%x (0x%x) "
+					"%s : Dquot ID 0x%x (0x%p) "
 					"BLK TIMER NOT STARTED",
 					str, (int)
 					INT_GET(ddq->d_id, ARCH_CONVERT), ddq);
@@ -2037,7 +2067,7 @@
 			    !INT_ISZERO(ddq->d_id, ARCH_CONVERT)) {
 				if (flags & XFS_QMOPT_DOWARN)
 					cmn_err(CE_ALERT,
-					"%s : Dquot ID 0x%x (0x%x) "
+					"%s : Dquot ID 0x%x (0x%p) "
 					"INODE TIMER NOT STARTED",
 					str, (int)
 					INT_GET(ddq->d_id, ARCH_CONVERT), ddq);
@@ -2289,6 +2319,14 @@
 		imap.im_blkno = 0;
 		xfs_imap(log->l_mp, 0, ino, &imap, 0);
 	}
+
+	/*
+	 * Inode buffers can be freed, look out for it,
+	 * and do not replay the inode.
+	 */
+	if (xlog_check_buffer_cancelled(log, imap.im_blkno, imap.im_len, 0))
+		return 0;
+
 	bp = xfs_buf_read_flags(mp->m_ddev_targp, imap.im_blkno, imap.im_len,
 								XFS_BUF_LOCK);
 	if (XFS_BUF_ISERROR(bp)) {
@@ -2345,7 +2383,7 @@
 	/* Take the opportunity to reset the flush iteration count */
 	dicp->di_flushiter = 0;
 
-	if (unlikely((dicp->di_mode & IFMT) == IFREG)) {
+	if (unlikely((dicp->di_mode & S_IFMT) == S_IFREG)) {
 		if ((dicp->di_format != XFS_DINODE_FMT_EXTENTS) &&
 		    (dicp->di_format != XFS_DINODE_FMT_BTREE)) {
 			XFS_CORRUPTION_ERROR("xlog_recover_do_inode_trans(3)",
@@ -2356,7 +2394,7 @@
 				item, dip, bp, ino);
 			return XFS_ERROR(EFSCORRUPTED);
 		}
-	} else if (unlikely((dicp->di_mode & IFMT) == IFDIR)) {
+	} else if (unlikely((dicp->di_mode & S_IFMT) == S_IFDIR)) {
 		if ((dicp->di_format != XFS_DINODE_FMT_EXTENTS) &&
 		    (dicp->di_format != XFS_DINODE_FMT_BTREE) &&
 		    (dicp->di_format != XFS_DINODE_FMT_LOCAL)) {
diff -Nru a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
--- a/fs/xfs/xfs_mount.c	Wed Oct 15 00:46:36 2003
+++ b/fs/xfs/xfs_mount.c	Wed Oct 15 00:46:36 2003
@@ -903,7 +903,7 @@
 	 *  File systems that don't support user level file handles (i.e.
 	 *  all of them except for XFS) will leave vfs_altfsid as NULL.
 	 */
-	vfsp->vfs_altfsid = (__kernel_fsid_t *)mp->m_fixedfsid;
+	vfsp->vfs_altfsid = (fsid_t *)mp->m_fixedfsid;
 	mp->m_dmevmask = 0;	/* not persistent; set after each mount */
 
 	/*
@@ -977,7 +977,7 @@
 	rvp = XFS_ITOV(rip);
 	VMAP(rvp, vmap);
 
-	if (unlikely((rip->i_d.di_mode & IFMT) != IFDIR)) {
+	if (unlikely((rip->i_d.di_mode & S_IFMT) != S_IFDIR)) {
 		cmn_err(CE_WARN, "XFS: corrupted root inode");
 		prdev("Root inode %llu is not a directory",
 		      mp->m_ddev_targp, (unsigned long long)rip->i_ino);
diff -Nru a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
--- a/fs/xfs/xfs_mount.h	Wed Oct 15 00:46:35 2003
+++ b/fs/xfs/xfs_mount.h	Wed Oct 15 00:46:35 2003
@@ -416,6 +416,7 @@
 #define XFS_MOUNT_32BITINOOPT	0x00008000	/* saved mount option state */
 #define XFS_MOUNT_NOUUID	0x00010000	/* ignore uuid during mount */
 #define XFS_MOUNT_NOLOGFLUSH	0x00020000
+#define XFS_MOUNT_IDELETE	0x00040000	/* delete empty inode clusters*/
 
 /*
  * Default minimum read and write sizes.
diff -Nru a/fs/xfs/xfs_rename.c b/fs/xfs/xfs_rename.c
--- a/fs/xfs/xfs_rename.c	Wed Oct 15 00:46:36 2003
+++ b/fs/xfs/xfs_rename.c	Wed Oct 15 00:46:36 2003
@@ -326,7 +326,7 @@
 
 	ASSERT(src_ip != NULL);
 
-	if ((src_ip->i_d.di_mode & IFMT) == IFDIR) {
+	if ((src_ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
 		/*
 		 * Check for link count overflow on target_dp
 		 */
@@ -340,7 +340,7 @@
 	}
 
 	new_parent = (src_dp != target_dp);
-	src_is_directory = ((src_ip->i_d.di_mode & IFMT) == IFDIR);
+	src_is_directory = ((src_ip->i_d.di_mode & S_IFMT) == S_IFDIR);
 
 	/*
 	 * Drop the locks on our inodes so that we can do the ancestor
@@ -449,7 +449,7 @@
 		 * target and source are directories and that target can be
 		 * destroyed, or that neither is a directory.
 		 */
-		if ((target_ip->i_d.di_mode & IFMT) == IFDIR) {
+		if ((target_ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
 			/*
 			 * Make sure target dir is empty.
 			 */
diff -Nru a/fs/xfs/xfs_rw.c b/fs/xfs/xfs_rw.c
--- a/fs/xfs/xfs_rw.c	Wed Oct 15 00:46:38 2003
+++ b/fs/xfs/xfs_rw.c	Wed Oct 15 00:46:38 2003
@@ -86,17 +86,17 @@
 	xfs_ilock(ip, XFS_ILOCK_EXCL);
 	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
 	xfs_trans_ihold(tp, ip);
-	ip->i_d.di_mode &= ~ISUID;
+	ip->i_d.di_mode &= ~S_ISUID;
 
 	/*
 	 * Note that we don't have to worry about mandatory
 	 * file locking being disabled here because we only
-	 * clear the ISGID bit if the Group execute bit is
+	 * clear the S_ISGID bit if the Group execute bit is
 	 * on, but if it was on then mandatory locking wouldn't
 	 * have been enabled.
 	 */
-	if (ip->i_d.di_mode & (IEXEC >> 3)) {
-		ip->i_d.di_mode &= ~ISGID;
+	if (ip->i_d.di_mode & S_IXGRP) {
+		ip->i_d.di_mode &= ~S_ISGID;
 	}
 	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 	xfs_trans_set_sync(tp);
diff -Nru a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
--- a/fs/xfs/xfs_trans.c	Wed Oct 15 00:46:36 2003
+++ b/fs/xfs/xfs_trans.c	Wed Oct 15 00:46:36 2003
@@ -365,7 +365,6 @@
 
 	switch (field) {
 	case XFS_TRANS_SB_ICOUNT:
-		ASSERT(delta > 0);
 		tp->t_icount_delta += delta;
 		break;
 	case XFS_TRANS_SB_IFREE:
diff -Nru a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
--- a/fs/xfs/xfs_trans.h	Wed Oct 15 00:46:37 2003
+++ b/fs/xfs/xfs_trans.h	Wed Oct 15 00:46:37 2003
@@ -703,6 +703,8 @@
  *    the agi hash list and counters: sector size
  *    the inode btree entry: block size
  *    the on disk inode before ours in the agi hash list: inode cluster size
+ *    the inode btree: max depth * blocksize
+ *    the allocation btrees: 2 trees * (max depth - 1) * block size
  */
 #define	XFS_CALC_IFREE_LOG_RES(mp) \
 	((mp)->m_sb.sb_inodesize + \
@@ -710,7 +712,10 @@
 	 (mp)->m_sb.sb_sectsize + \
 	 XFS_FSB_TO_B((mp), 1) + \
 	 MAX((__uint16_t)XFS_FSB_TO_B((mp), 1), XFS_INODE_CLUSTER_SIZE(mp)) + \
-	 (128 * 5))
+	 (128 * 5) + \
+	  (128 * (2 + XFS_IALLOC_BLOCKS(mp) + XFS_IN_MAXLEVELS(mp) + \
+	   XFS_ALLOCFREE_LOG_COUNT(mp, 1))))
+
 
 #define	XFS_IFREE_LOG_RES(mp)	((mp)->m_reservations.tr_ifree)
 
@@ -918,6 +923,7 @@
 #define	XFS_DEFAULT_LOG_COUNT		1
 #define	XFS_DEFAULT_PERM_LOG_COUNT	2
 #define	XFS_ITRUNCATE_LOG_COUNT		2
+#define XFS_INACTIVE_LOG_COUNT		2
 #define	XFS_CREATE_LOG_COUNT		2
 #define	XFS_MKDIR_LOG_COUNT		3
 #define	XFS_SYMLINK_LOG_COUNT		3
@@ -991,6 +997,8 @@
 void		xfs_trans_bhold_until_committed(xfs_trans_t *, struct xfs_buf *);
 void		xfs_trans_binval(xfs_trans_t *, struct xfs_buf *);
 void		xfs_trans_inode_buf(xfs_trans_t *, struct xfs_buf *);
+void		xfs_trans_inode_buf(xfs_trans_t *, struct xfs_buf *);
+void		xfs_trans_stale_inode_buf(xfs_trans_t *, struct xfs_buf *);
 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 *,
diff -Nru a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c
--- a/fs/xfs/xfs_trans_buf.c	Wed Oct 15 00:46:35 2003
+++ b/fs/xfs/xfs_trans_buf.c	Wed Oct 15 00:46:35 2003
@@ -931,6 +931,35 @@
 	bip->bli_format.blf_flags |= XFS_BLI_INODE_BUF;
 }
 
+/*
+ * This call is used to indicate that the buffer is going to
+ * be staled and was an inode buffer. This means it gets
+ * special processing during unpin - where any inodes 
+ * associated with the buffer should be removed from ail.
+ * There is also special processing during recovery,
+ * any replay of the inodes in the buffer needs to be
+ * prevented as the buffer may have been reused.
+ */
+void
+xfs_trans_stale_inode_buf(
+	xfs_trans_t	*tp,
+	xfs_buf_t	*bp)
+{
+	xfs_buf_log_item_t	*bip;
+
+	ASSERT(XFS_BUF_ISBUSY(bp));
+	ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp);
+	ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL);
+
+	bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
+	ASSERT(atomic_read(&bip->bli_refcount) > 0);
+
+	bip->bli_flags |= XFS_BLI_STALE_INODE;
+	bip->bli_item.li_cb = (void(*)(xfs_buf_t*,xfs_log_item_t*))
+		xfs_buf_iodone;
+}
+
+
 
 /*
  * Mark the buffer as being one which contains newly allocated
@@ -954,7 +983,6 @@
 
 	bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
 	ASSERT(atomic_read(&bip->bli_refcount) > 0);
-	ASSERT(!(bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF));
 
 	bip->bli_flags |= XFS_BLI_INODE_ALLOC_BUF;
 }
diff -Nru a/fs/xfs/xfs_types.h b/fs/xfs/xfs_types.h
--- a/fs/xfs/xfs_types.h	Wed Oct 15 00:46:36 2003
+++ b/fs/xfs/xfs_types.h	Wed Oct 15 00:46:36 2003
@@ -75,8 +75,6 @@
 #error BITS_PER_LONG must be 32 or 64
 #endif
 
-#endif	/* __KERNEL__ */
-
 /*
  * Some types are conditional depending on the target system.
  * XFS_BIG_BLKNOS needs block layer disk addresses to be 64 bits.
@@ -95,6 +93,8 @@
 # define XFS_BIG_INUMS	0
 #endif
 
+#endif	/* __KERNEL__ */
+
 typedef __uint32_t	xfs_agblock_t;	/* blockno in alloc. group */
 typedef	__uint32_t	xfs_extlen_t;	/* extent length in blocks */
 typedef	__uint32_t	xfs_agnumber_t;	/* allocation group number */
@@ -197,4 +197,4 @@
 	XFS_BTNUM_MAX
 } xfs_btnum_t;
 
-#endif	/* !__XFS_TYPES_H */
+#endif	/* __XFS_TYPES_H__ */
diff -Nru a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c
--- a/fs/xfs/xfs_vfsops.c	Wed Oct 15 00:46:36 2003
+++ b/fs/xfs/xfs_vfsops.c	Wed Oct 15 00:46:36 2003
@@ -225,7 +225,7 @@
 		/*
 		 * At this point the superblock has not been read
 		 * in, therefore we do not know the block size.
-		 * Before, the mount call ends we will convert
+		 * Before the mount call ends we will convert
 		 * these to FSBs.
 		 */
 		mp->m_dalign = ap->sunit;
@@ -298,6 +298,8 @@
 		mp->m_flags |= XFS_MOUNT_DFLT_IOSIZE;
 		mp->m_readio_log = mp->m_writeio_log = ap->iosizelog;
 	}
+	if (ap->flags & XFSMNT_IDELETE)
+		mp->m_flags |= XFS_MOUNT_IDELETE;
 
 	/*
 	 * no recovery flag requires a read-only mount
@@ -603,6 +605,7 @@
 	struct vfs	*vfsp = bhvtovfs(bdp);
 	xfs_mount_t	*mp = XFS_BHVTOM(bdp);
 	int		pincount, error;
+	int		count = 0;
 
 	if (args->flags & XFSMNT_NOATIME)
 		mp->m_flags |= XFS_MOUNT_NOATIME;
@@ -617,11 +620,19 @@
 		pagebuf_delwri_flush(mp->m_ddev_targp, 0, NULL);
 		xfs_finish_reclaim_all(mp, 0);
 
+		/* This loop must run at least twice.
+		 * The first instance of the loop will flush
+		 * most meta data but that will generate more
+		 * meta data (typically directory updates).
+		 * Which then must be flushed and logged before
+		 * we can write the unmount record.
+		 */ 
 		do {
 			VFS_SYNC(vfsp, REMOUNT_READONLY_FLAGS, NULL, error);
 			pagebuf_delwri_flush(mp->m_ddev_targp, PBDF_WAIT,
 								&pincount);
-		} while (pincount);
+			if(0 == pincount) { delay(50); count++; }
+		} while (count < 2);
 
 		/* Ok now write out an unmount record */
 		xfs_log_unmount_write(mp);
@@ -1588,6 +1599,7 @@
 #define MNTOPT_NOLOGFLUSH   "nologflush"   /* don't hard flush on log writes */
 #define MNTOPT_OSYNCISOSYNC "osyncisosync" /* o_sync is REALLY o_sync */
 #define MNTOPT_64BITINODE   "inode64"  /* inodes can be allocated anywhere */
+#define MNTOPT_IKEEP	"ikeep"		/* free empty inode clusters */
 
 
 int
@@ -1602,6 +1614,8 @@
 	int			dsunit, dswidth, vol_dsunit, vol_dswidth;
 	int			iosize;
 
+	args->flags |= XFSMNT_IDELETE; /* default to on */
+
 	if (!options)
 		return 0;
 
@@ -1706,6 +1720,8 @@
 			args->flags |= XFSMNT_NOUUID;
 		} else if (!strcmp(this_char, MNTOPT_NOLOGFLUSH)) {
 			args->flags |= XFSMNT_NOLOGFLUSH;
+		} else if (!strcmp(this_char, MNTOPT_IKEEP)) {
+			args->flags &= ~XFSMNT_IDELETE;
 		} else if (!strcmp(this_char, "osyncisdsync")) {
 			/* no-op, this is now the default */
 printk("XFS: osyncisdsync is now the default, option is deprecated.\n");
diff -Nru a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
--- a/fs/xfs/xfs_vnodeops.c	Wed Oct 15 00:46:38 2003
+++ b/fs/xfs/xfs_vnodeops.c	Wed Oct 15 00:46:38 2003
@@ -78,7 +78,7 @@
 #define SYMLINK_MAPS 2
 
 extern int xfs_ioctl(bhv_desc_t *, struct inode *, struct file *,
-			unsigned int, unsigned long);
+			int, unsigned int, unsigned long);
 
 
 /*
@@ -470,15 +470,15 @@
 		if (mask & XFS_AT_MODE) {
 			mode_t m = 0;
 
-			if ((vap->va_mode & ISUID) && !file_owner)
-				m |= ISUID;
-			if ((vap->va_mode & ISGID) &&
+			if ((vap->va_mode & S_ISUID) && !file_owner)
+				m |= S_ISUID;
+			if ((vap->va_mode & S_ISGID) &&
 			    !in_group_p((gid_t)ip->i_d.di_gid))
-				m |= ISGID;
+				m |= S_ISGID;
 #if 0
 			/* Linux allows this, Irix doesn't. */
-			if ((vap->va_mode & ISVTX) && vp->v_type != VDIR)
-				m |= ISVTX;
+			if ((vap->va_mode & S_ISVTX) && vp->v_type != VDIR)
+				m |= S_ISVTX;
 #endif
 			if (m && !capable(CAP_FSETID))
 				vap->va_mode &= ~m;
@@ -755,8 +755,8 @@
 	 * Change file access modes.
 	 */
 	if (mask & XFS_AT_MODE) {
-		ip->i_d.di_mode &= IFMT;
-		ip->i_d.di_mode |= vap->va_mode & ~IFMT;
+		ip->i_d.di_mode &= S_IFMT;
+		ip->i_d.di_mode |= vap->va_mode & ~S_IFMT;
 
 		xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE);
 		timeflags |= XFS_ICHGTIME_CHG;
@@ -776,9 +776,9 @@
 		 * The set-user-ID and set-group-ID bits of a file will be
 		 * cleared upon successful return from chown()
 		 */
-		if ((ip->i_d.di_mode & (ISUID|ISGID)) &&
+		if ((ip->i_d.di_mode & (S_ISUID|S_ISGID)) &&
 		    !capable(CAP_FSETID)) {
-			ip->i_d.di_mode &= ~(ISUID|ISGID);
+			ip->i_d.di_mode &= ~(S_ISUID|S_ISGID);
 		}
 
 		/*
@@ -992,6 +992,7 @@
 xfs_readlink(
 	bhv_desc_t	*bdp,
 	uio_t		*uiop,
+	int		ioflags,
 	cred_t		*credp)
 {
 	xfs_inode_t     *ip;
@@ -1019,7 +1020,7 @@
 
 	xfs_ilock(ip, XFS_ILOCK_SHARED);
 
-	ASSERT((ip->i_d.di_mode & IFMT) == IFLNK);
+	ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFLNK);
 
 	offset = uiop->uio_offset;
 	count = uiop->uio_resid;
@@ -1033,7 +1034,7 @@
 		goto error_return;
 	}
 
-	if (!(uiop->uio_fmode & FINVIS)) {
+	if (!(ioflags & IO_INVIS)) {
 		xfs_ichgtime(ip, XFS_ICHGTIME_ACC);
 	}
 
@@ -1595,8 +1596,7 @@
 STATIC int
 xfs_inactive_attrs(
 	xfs_inode_t	*ip,
-	xfs_trans_t	**tpp,
-	int		*commitflags)
+	xfs_trans_t	**tpp)
 {
 	xfs_trans_t	*tp;
 	int		error;
@@ -1606,9 +1606,8 @@
 	tp = *tpp;
 	mp = ip->i_mount;
 	ASSERT(ip->i_d.di_forkoff != 0);
-	xfs_trans_commit(tp, *commitflags, NULL);
+	xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
 	xfs_iunlock(ip, XFS_ILOCK_EXCL);
-	*commitflags = 0;
 
 	error = xfs_attr_inactive(ip);
 	if (error) {
@@ -1620,8 +1619,8 @@
 	tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
 	error = xfs_trans_reserve(tp, 0,
 				  XFS_IFREE_LOG_RES(mp),
-				  0, 0,
-				  XFS_DEFAULT_LOG_COUNT);
+				  0, XFS_TRANS_PERM_LOG_RES,
+				  XFS_INACTIVE_LOG_COUNT);
 	if (error) {
 		ASSERT(XFS_FORCED_SHUTDOWN(mp));
 		xfs_trans_cancel(tp, 0);
@@ -1664,7 +1663,7 @@
 	mp = ip->i_mount;
 
 	if (ip->i_d.di_nlink != 0) {
-		if ((((ip->i_d.di_mode & IFMT) == IFREG) &&
+		if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) &&
 		     ((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0)) &&
 		     (ip->i_df.if_flags & XFS_IFEXTENTS))  &&
 		    (!(ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC|XFS_DIFLAG_APPEND)))) {
@@ -1694,10 +1693,12 @@
 {
 	xfs_inode_t	*ip;
 	vnode_t		*vp;
+	xfs_bmap_free_t	free_list; 
+	xfs_fsblock_t	first_block;
+	int		committed;
 	xfs_trans_t	*tp;
 	xfs_mount_t	*mp;
 	int		error;
-	int		commit_flags;
 	int		truncate;
 
 	vp = BHV_TO_VNODE(bdp);
@@ -1723,7 +1724,7 @@
 	 */
 	truncate = ((ip->i_d.di_nlink == 0) &&
 	    ((ip->i_d.di_size != 0) || (ip->i_d.di_nextents > 0)) &&
-	    ((ip->i_d.di_mode & IFMT) == IFREG));
+	    ((ip->i_d.di_mode & S_IFMT) == S_IFREG));
 
 	mp = ip->i_mount;
 
@@ -1739,7 +1740,7 @@
 		goto out;
 
 	if (ip->i_d.di_nlink != 0) {
-		if ((((ip->i_d.di_mode & IFMT) == IFREG) &&
+		if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) &&
 		     ((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0)) &&
 		     (ip->i_df.if_flags & XFS_IFEXTENTS))  &&
 		    (!(ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC|XFS_DIFLAG_APPEND)) ||
@@ -1795,14 +1796,14 @@
 		 */
 		error = xfs_itruncate_finish(&tp, ip, 0, XFS_DATA_FORK,
 				(!(mp->m_flags & XFS_MOUNT_WSYNC) ? 1 : 0));
-		commit_flags = XFS_TRANS_RELEASE_LOG_RES;
 
 		if (error) {
-			xfs_trans_cancel(tp, commit_flags | XFS_TRANS_ABORT);
+			xfs_trans_cancel(tp,
+				XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
 			xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
 			return (VN_INACTIVE_CACHE);
 		}
-	} else if ((ip->i_d.di_mode & IFMT) == IFLNK) {
+	} else if ((ip->i_d.di_mode & S_IFMT) == S_IFLNK) {
 
 		/*
 		 * If we get an error while cleaning up a
@@ -1819,13 +1820,11 @@
 
 		xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
 		xfs_trans_ihold(tp, ip);
-		commit_flags = XFS_TRANS_RELEASE_LOG_RES;
-
 	} else {
 		error = xfs_trans_reserve(tp, 0,
 					  XFS_IFREE_LOG_RES(mp),
-					  0, 0,
-					  XFS_DEFAULT_LOG_COUNT);
+					  0, XFS_TRANS_PERM_LOG_RES,
+					  XFS_INACTIVE_LOG_COUNT);
 		if (error) {
 			ASSERT(XFS_FORCED_SHUTDOWN(mp));
 			xfs_trans_cancel(tp, 0);
@@ -1835,7 +1834,6 @@
 		xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
 		xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
 		xfs_trans_ihold(tp, ip);
-		commit_flags = 0;
 	}
 
 	/*
@@ -1846,7 +1844,7 @@
 	 * because we can't use it for xfs_attr_inactive().
 	 */
 	if (ip->i_d.di_anextents > 0) {
-		error = xfs_inactive_attrs(ip, &tp, &commit_flags);
+		error = xfs_inactive_attrs(ip, &tp);
 		/*
 		 * If we got an error, the transaction is already
 		 * cancelled, and the inode is unlocked. Just get out.
@@ -1860,7 +1858,8 @@
 	/*
 	 * Free the inode.
 	 */
-	error = xfs_ifree(tp, ip);
+	XFS_BMAP_INIT(&free_list, &first_block);
+	error = xfs_ifree(tp, ip, &free_list);
 	if (error) {
 		/*
 		 * If we fail to free the inode, shut down.  The cancel
@@ -1873,7 +1872,7 @@
 				error, mp->m_fsname);
 			xfs_force_shutdown(mp, XFS_METADATA_IO_ERROR);
 		}
-		xfs_trans_cancel(tp, commit_flags | XFS_TRANS_ABORT);
+		xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
 	} else {
 		/*
 		 * Credit the quota account(s). The inode is gone.
@@ -1884,7 +1883,9 @@
 		 * Just ignore errors at this point.  There is
 		 * nothing we can do except to try to keep going.
 		 */
-		(void) xfs_trans_commit(tp, commit_flags, NULL);
+		(void) xfs_bmap_finish(&tp,  &free_list, first_block,
+				       &committed);
+		(void) xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
 	}
 	/*
 	 * Release the dquots held by inode, if any.
@@ -3508,7 +3509,7 @@
 	/*
 	 * Allocate an inode for the symlink.
 	 */
-	error = xfs_dir_ialloc(&tp, dp, IFLNK | (vap->va_mode&~IFMT),
+	error = xfs_dir_ialloc(&tp, dp, S_IFLNK | (vap->va_mode&~S_IFMT),
 			       1, 0, credp, prid, resblks > 0, &ip, NULL);
 	if (error) {
 		if (error == ENOSPC)
@@ -3891,7 +3892,7 @@
 	ASSERT(!VN_MAPPED(vp));
 	ip = XFS_BHVTOI(bdp);
 
-	if ((ip->i_d.di_mode & IFMT) == IFREG) {
+	if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) {
 		if (ip->i_d.di_size > 0) {
 			/*
 			 * Flush and invalidate any data left around that is
@@ -4597,7 +4598,7 @@
 
 	xfs_ilock(ip, XFS_ILOCK_SHARED);
 
-	if ((error = xfs_iaccess(ip, IWRITE, credp))) {
+	if ((error = xfs_iaccess(ip, S_IWUSR, credp))) {
 		xfs_iunlock(ip, XFS_ILOCK_SHARED);
 		return error;
 	}
@@ -4704,17 +4705,17 @@
 	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
 	xfs_trans_ihold(tp, ip);
 
-	ip->i_d.di_mode &= ~ISUID;
+	ip->i_d.di_mode &= ~S_ISUID;
 
 	/*
 	 * Note that we don't have to worry about mandatory
 	 * file locking being disabled here because we only
-	 * clear the ISGID bit if the Group execute bit is
+	 * clear the S_ISGID bit if the Group execute bit is
 	 * on, but if it was on then mandatory locking wouldn't
 	 * have been enabled.
 	 */
-	if (ip->i_d.di_mode & (IEXEC >> 3))
-		ip->i_d.di_mode &= ~ISGID;
+	if (ip->i_d.di_mode & S_IXGRP)
+		ip->i_d.di_mode &= ~S_ISGID;
 
 	xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
 
diff -Nru a/fs/xfs/xfsidbg.c b/fs/xfs/xfsidbg.c
--- a/fs/xfs/xfsidbg.c	Wed Oct 15 00:46:37 2003
+++ b/fs/xfs/xfsidbg.c	Wed Oct 15 00:46:37 2003
@@ -2643,6 +2643,7 @@
 		"stale",	/* 0x4 */
 		"logged",	/* 0x8 */
 		"ialloc",	/* 0x10 */
+		"inode_stale",  /* 0x20 */
 		0
 		};
 	static char *blf_flags[] = {
@@ -4811,6 +4812,7 @@
 		"uiosize",	/* XFS_IUIOSZ */
 		"quiesce",	/* XFS_IQUIESCE */
 		"reclaim",	/* XFS_IRECLAIM */
+		"stale",	/* XFS_ISTALE */
 		NULL
 	};
 
diff -Nru a/include/acpi/acconfig.h b/include/acpi/acconfig.h
--- a/include/acpi/acconfig.h	Wed Oct 15 00:46:37 2003
+++ b/include/acpi/acconfig.h	Wed Oct 15 00:46:37 2003
@@ -64,7 +64,7 @@
 
 /* Version string */
 
-#define ACPI_CA_VERSION                 0x20030918
+#define ACPI_CA_VERSION                 0x20031002
 
 /* Maximum objects in the various object caches */
 
diff -Nru a/include/acpi/acexcep.h b/include/acpi/acexcep.h
--- a/include/acpi/acexcep.h	Wed Oct 15 00:46:35 2003
+++ b/include/acpi/acexcep.h	Wed Oct 15 00:46:35 2003
@@ -163,6 +163,7 @@
 #define AE_AML_NO_RESOURCE_END_TAG      (acpi_status) (0x001E | AE_CODE_AML)
 #define AE_AML_BAD_RESOURCE_VALUE       (acpi_status) (0x001F | AE_CODE_AML)
 #define AE_AML_CIRCULAR_REFERENCE       (acpi_status) (0x0020 | AE_CODE_AML)
+#define AE_AML_BAD_RESOURCE_LENGTH      (acpi_status) (0x0021 | AE_CODE_AML)
 
 #define AE_CODE_AML_MAX                 0x0020
 
@@ -280,7 +281,8 @@
 	"AE_AML_ALIGNMENT",
 	"AE_AML_NO_RESOURCE_END_TAG",
 	"AE_AML_BAD_RESOURCE_VALUE",
-	"AE_AML_CIRCULAR_REFERENCE"
+	"AE_AML_CIRCULAR_REFERENCE",
+	"AE_AML_BAD_RESOURCE_LENGTH"
 };
 
 char const   *acpi_gbl_exception_names_ctrl[] =
diff -Nru a/include/acpi/actbl.h b/include/acpi/actbl.h
--- a/include/acpi/actbl.h	Wed Oct 15 00:46:36 2003
+++ b/include/acpi/actbl.h	Wed Oct 15 00:46:36 2003
@@ -65,16 +65,6 @@
 
 #define GL_OWNED                0x02        /* Ownership of global lock is bit 1 */
 
-/* values of Mapic.Model */
-
-#define DUAL_PIC                0
-#define MULTIPLE_APIC           1
-
-/* values of Type in struct apic_header */
-
-#define APIC_PROC               0
-#define APIC_IO                 1
-
 
 /*
  * Common table types.  The base code can remain
@@ -89,8 +79,10 @@
 #pragma pack(1)
 
 /*
- * Architecture-independent tables
- * The architecture dependent tables are in separate files
+ * ACPI Version-independent tables
+ *
+ * NOTE: The tables that are specific to ACPI versions (1.0, 2.0, etc.)
+ * are in separate files.
  */
 struct rsdp_descriptor         /* Root System Descriptor Pointer */
 {
@@ -106,20 +98,6 @@
 };
 
 
-struct acpi_table_header         /* ACPI common table header */
-{
-	char                            signature [4];          /* ACPI signature (4 ASCII characters) */
-	u32                             length;                 /* Length of table, in bytes, including header */
-	u8                              revision;               /* ACPI Specification minor version # */
-	u8                              checksum;               /* To make sum of entire table == 0 */
-	char                            oem_id [6];             /* OEM identification */
-	char                            oem_table_id [8];       /* OEM table identification */
-	u32                             oem_revision;           /* OEM revision number */
-	char                            asl_compiler_id [4];    /* ASL compiler vendor ID */
-	u32                             asl_compiler_revision;  /* ASL compiler revision number */
-};
-
-
 struct acpi_common_facs          /* Common FACS for internal use */
 {
 	u32                             *global_lock;
@@ -128,68 +106,196 @@
 };
 
 
-struct apic_table
+#define ACPI_TABLE_HEADER_DEF   /* ACPI common table header */ \
+	char                            signature [4];          /* ACPI signature (4 ASCII characters) */\
+	u32                             length;                 /* Length of table, in bytes, including header */\
+	u8                              revision;               /* ACPI Specification minor version # */\
+	u8                              checksum;               /* To make sum of entire table == 0 */\
+	char                            oem_id [6];             /* OEM identification */\
+	char                            oem_table_id [8];       /* OEM table identification */\
+	u32                             oem_revision;           /* OEM revision number */\
+	char                            asl_compiler_id [4];    /* ASL compiler vendor ID */\
+	u32                             asl_compiler_revision;  /* ASL compiler revision number */
+
+
+struct acpi_table_header         /* ACPI common table header */
 {
-	struct acpi_table_header        header;                 /* ACPI table header */
-	u32                             local_apic_address;     /* Physical address for accessing local APICs */
-	u32                             PCATcompat      : 1;    /* a one indicates system also has dual 8259s */
-	u32                             reserved1       : 31;
+	ACPI_TABLE_HEADER_DEF
 };
 
 
-struct apic_header
+/*
+ * MADT values and structures
+ */
+
+/* Values for MADT PCATCompat */
+
+#define DUAL_PIC                0
+#define MULTIPLE_APIC           1
+
+
+/* Master MADT */
+
+struct multiple_apic_table
 {
-	u8                              type;                   /* APIC type.  Either APIC_PROC or APIC_IO */
-	u8                              length;                 /* Length of APIC structure */
+	ACPI_TABLE_HEADER_DEF                           /* ACPI common table header */
+	u32                             local_apic_address;     /* Physical address of local APIC */
+	u32                             PCATcompat      : 1;    /* A one indicates system also has dual 8259s */
+	u32                             reserved1       : 31;
 };
 
 
-struct processor_apic
+/* Values for Type in APIC_HEADER_DEF */
+
+#define APIC_PROCESSOR          0
+#define APIC_IO                 1
+#define APIC_XRUPT_OVERRIDE     2
+#define APIC_NMI                3
+#define APIC_LOCAL_NMI          4
+#define APIC_ADDRESS_OVERRIDE   5
+#define APIC_IO_SAPIC           6
+#define APIC_LOCAL_SAPIC        7
+#define APIC_XRUPT_SOURCE       8
+#define APIC_RESERVED           9           /* 9 and greater are reserved */
+
+/*
+ * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE)
+ */
+#define APIC_HEADER_DEF                     /* Common APIC sub-structure header */\
+	u8                              type; \
+	u8                              length;
+
+/* Values for MPS INTI flags */
+
+#define POLARITY_CONFORMS       0
+#define POLARITY_ACTIVE_HIGH    1
+#define POLARITY_RESERVED       2
+#define POLARITY_ACTIVE_LOW     3
+
+#define TRIGGER_CONFORMS        0
+#define TRIGGER_EDGE            1
+#define TRIGGER_RESERVED        2
+#define TRIGGER_LEVEL           3
+
+/* Common flag definitions */
+
+#define MPS_INTI_FLAGS \
+	u16                             polarity        : 2;    /* Polarity of APIC I/O input signals */\
+	u16                             trigger_mode    : 2;    /* Trigger mode of APIC input signals */\
+	u16                             reserved1       : 12;   /* Reserved, must be zero */
+
+#define LOCAL_APIC_FLAGS \
+	u32                             processor_enabled: 1;   /* Processor is usable if set */\
+	u32                             reserved2       : 31;   /* Reserved, must be zero */
+
+/* Sub-structures for MADT */
+
+struct madt_processor_apic
 {
-	struct apic_header              header;
-	u8                              processor_apic_id;      /* ACPI processor id */
+	APIC_HEADER_DEF
+	u8                              processor_id;           /* ACPI processor id */
 	u8                              local_apic_id;          /* Processor's local APIC id */
-	u32                             processor_enabled: 1;   /* Processor is usable if set */
-	u32                             reserved1       : 31;
+	LOCAL_APIC_FLAGS
 };
 
-
-struct io_apic
+struct madt_io_apic
 {
-	struct apic_header              header;
+	APIC_HEADER_DEF
 	u8                              io_apic_id;             /* I/O APIC ID */
 	u8                              reserved;               /* Reserved - must be zero */
-	u32                             io_apic_address;        /* APIC's physical address */
-	u32                             vector;                 /* Interrupt vector index where INTI
+	u32                             address;                /* APIC physical address */
+	u32                             interrupt;              /* Global system interrupt where INTI
 			  * lines start */
 };
 
+struct madt_interrupt_override
+{
+	APIC_HEADER_DEF
+	u8                              bus;                    /* 0 - ISA */
+	u8                              source;                 /* Interrupt source (IRQ) */
+	u32                             interrupt;              /* Global system interrupt */
+	MPS_INTI_FLAGS
+};
+
+struct madt_nmi_source
+{
+	APIC_HEADER_DEF
+	MPS_INTI_FLAGS
+	u32                             interrupt;              /* Global system interrupt */
+};
+
+struct madt_local_apic_nmi
+{
+	APIC_HEADER_DEF
+	u8                              processor_id;           /* ACPI processor id */
+	MPS_INTI_FLAGS
+	u8                              lint;                   /* LINTn to which NMI is connected */
+};
+
+struct madt_address_override
+{
+	APIC_HEADER_DEF
+	u16                             reserved;               /* Reserved - must be zero */
+	u32                             address;                /* APIC physical address */
+};
+
+struct madt_io_sapic
+{
+	APIC_HEADER_DEF
+	u8                              io_sapic_id;            /* I/O SAPIC ID */
+	u8                              reserved;               /* Reserved - must be zero */
+	u32                             interrupt_base;         /* Glocal interrupt for SAPIC start */
+	u64                             address;                /* SAPIC physical address */
+};
+
+struct madt_local_sapic
+{
+	APIC_HEADER_DEF
+	u8                              processor_id;           /* ACPI processor id */
+	u8                              local_sapic_id;         /* SAPIC ID */
+	u8                              local_sapic_eid;        /* SAPIC EID */
+	u8                              reserved [3];           /* Reserved - must be zero */
+	LOCAL_APIC_FLAGS
+};
+
+struct madt_interrupt_source
+{
+	APIC_HEADER_DEF
+	MPS_INTI_FLAGS
+	u8                              interrupt_type;         /* 1=PMI, 2=INIT, 3=corrected */
+	u8                              processor_id;           /* Processor ID */
+	u8                              processor_eid;          /* Processor EID */
+	u8                              io_sapic_vector;        /* Vector value for PMI interrupts */
+	u32                             interrupt;              /* Global system interrupt */
+	u32                             reserved;               /* Reserved - must be zero */
+};
 
-/*
- *  IA64 TBD:  Add SAPIC Tables
- */
 
 /*
- *  IA64 TBD:   Modify Smart Battery Description to comply with ACPI IA64
- *              extensions.
+ * Smart Battery
  */
-struct smart_battery_description_table
+struct smart_battery_table
 {
-	struct acpi_table_header        header;
+	ACPI_TABLE_HEADER_DEF
 	u32                             warning_level;
 	u32                             low_level;
 	u32                             critical_level;
 };
 
-struct hpet_description_table
+
+/*
+ * High performance timer
+ */
+struct hpet_table
 {
-	struct acpi_table_header        header;
+	ACPI_TABLE_HEADER_DEF
 	u32                             hardware_id;
-	u32                             base_address[3];
+	u32                             base_address [3];
 	u8                              hpet_number;
 	u16                             clock_tick;
 	u8                              attributes;
 };
+
 #pragma pack()
 
 
@@ -227,9 +333,10 @@
 
 
 /*
- * Get the architecture-specific tables
+ * Get the ACPI version-specific tables
  */
 #include "actbl1.h"   /* Acpi 1.0 table definitions */
 #include "actbl2.h"   /* Acpi 2.0 table definitions */
+
 
 #endif /* __ACTBL_H__ */
diff -Nru a/include/acpi/actbl1.h b/include/acpi/actbl1.h
--- a/include/acpi/actbl1.h	Wed Oct 15 00:46:36 2003
+++ b/include/acpi/actbl1.h	Wed Oct 15 00:46:36 2003
@@ -51,7 +51,7 @@
  */
 struct rsdt_descriptor_rev1
 {
-	struct acpi_table_header        header;                 /* ACPI Table header */
+	ACPI_TABLE_HEADER_DEF                           /* ACPI common table header */
 	u32                             table_offset_entry [1]; /* Array of pointers to other */
 			 /* ACPI tables */
 };
@@ -78,7 +78,7 @@
  */
 struct fadt_descriptor_rev1
 {
-	struct acpi_table_header        header;                 /* ACPI Table header */
+	ACPI_TABLE_HEADER_DEF                           /* ACPI common table header */
 	u32                             firmware_ctrl;          /* Physical address of FACS */
 	u32                             dsdt;                   /* Physical address of DSDT */
 	u8                              model;                  /* System Interrupt Model */
diff -Nru a/include/acpi/actbl2.h b/include/acpi/actbl2.h
--- a/include/acpi/actbl2.h	Wed Oct 15 00:46:37 2003
+++ b/include/acpi/actbl2.h	Wed Oct 15 00:46:37 2003
@@ -71,7 +71,7 @@
  */
 struct rsdt_descriptor_rev2
 {
-	struct acpi_table_header        header;                 /* ACPI table header */
+	ACPI_TABLE_HEADER_DEF                           /* ACPI common table header */
 	u32                             table_offset_entry [1]; /* Array of pointers to  */
 			 /* ACPI table headers */
 };
@@ -82,7 +82,7 @@
  */
 struct xsdt_descriptor_rev2
 {
-	struct acpi_table_header        header;                 /* ACPI table header */
+	ACPI_TABLE_HEADER_DEF                           /* ACPI common table header */
 	u64                             table_offset_entry [1]; /* Array of pointers to  */
 			 /* ACPI table headers */
 };
@@ -124,7 +124,7 @@
  */
 struct fadt_descriptor_rev2
 {
-	struct acpi_table_header        header;             /* ACPI table header */
+	ACPI_TABLE_HEADER_DEF                       /* ACPI common table header */
 	u32                             V1_firmware_ctrl;   /* 32-bit physical address of FACS */
 	u32                             V1_dsdt;            /* 32-bit physical address of DSDT */
 	u8                              reserved1;          /* System Interrupt Model isn't used in ACPI 2.0*/
@@ -192,6 +192,19 @@
 	struct acpi_generic_address     xpm_tmr_blk;        /* Extended Power Mgt Timer Ctrl Reg Blk address */
 	struct acpi_generic_address     xgpe0_blk;          /* Extended General Purpose acpi_event 0 Reg Blk address */
 	struct acpi_generic_address     xgpe1_blk;          /* Extended General Purpose acpi_event 1 Reg Blk address */
+};
+
+
+/* Embedded Controller */
+
+struct ec_boot_resources
+{
+	ACPI_TABLE_HEADER_DEF
+	struct acpi_generic_address     ec_control;         /* Address of EC command/status register */
+	struct acpi_generic_address     ec_data;            /* Address of EC data register */
+	u32                             uid;                /* Unique ID - must be same as the EC _UID method */
+	u8                              gpe_bit;            /* The GPE for the EC */
+	u8                              ec_id[1];           /* Full namepath of the EC in the ACPI namespace */
 };
 
 
diff -Nru a/include/acpi/actypes.h b/include/acpi/actypes.h
--- a/include/acpi/actypes.h	Wed Oct 15 00:46:37 2003
+++ b/include/acpi/actypes.h	Wed Oct 15 00:46:37 2003
@@ -207,6 +207,7 @@
 /*
  * Miscellaneous common types
  */
+typedef u16                                     UINT16_BIT;
 typedef u32                                     UINT32_BIT;
 typedef acpi_native_uint                        ACPI_PTRDIFF;
 
diff -Nru a/include/asm-i386/div64.h b/include/asm-i386/div64.h
--- a/include/asm-i386/div64.h	Wed Oct 15 00:46:35 2003
+++ b/include/asm-i386/div64.h	Wed Oct 15 00:46:35 2003
@@ -14,14 +14,15 @@
  * convention" on x86.
  */
 #define do_div(n,base) ({ \
-	unsigned long __upper, __low, __high, __mod; \
+	unsigned long __upper, __low, __high, __mod, __base; \
+	__base = (base); \
 	asm("":"=a" (__low), "=d" (__high):"A" (n)); \
 	__upper = __high; \
 	if (__high) { \
-		__upper = __high % (base); \
-		__high = __high / (base); \
+		__upper = __high % (__base); \
+		__high = __high / (__base); \
 	} \
-	asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (base), "0" (__low), "1" (__upper)); \
+	asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (__base), "0" (__low), "1" (__upper)); \
 	asm("":"=A" (n):"a" (__low),"d" (__high)); \
 	__mod; \
 })
diff -Nru a/include/asm-i386/processor.h b/include/asm-i386/processor.h
--- a/include/asm-i386/processor.h	Wed Oct 15 00:46:35 2003
+++ b/include/asm-i386/processor.h	Wed Oct 15 00:46:35 2003
@@ -585,12 +585,12 @@
 
 /* Prefetch instructions for Pentium III and AMD Athlon */
 /* It's not worth to care about 3dnow! prefetches for the K6
-   because they are microcoded there and very slow. */
+   because they are microcoded there and very slow.
+   However we don't do prefetches for pre XP Athlons currently
+   That should be fixed. */
 #define ARCH_HAS_PREFETCH
 extern inline void prefetch(const void *x)
 {
-	if (cpu_data[0].x86_vendor == X86_VENDOR_AMD)
-		return;		/* Some athlons fault if the address is bad */
 	alternative_input(ASM_NOP4,
 			  "prefetchnta (%1)",
 			  X86_FEATURE_XMM,
diff -Nru a/include/asm-ia64/meminit.h b/include/asm-ia64/meminit.h
--- a/include/asm-ia64/meminit.h	Wed Oct 15 00:46:36 2003
+++ b/include/asm-ia64/meminit.h	Wed Oct 15 00:46:36 2003
@@ -7,6 +7,8 @@
  * for more details.
  */
 
+#include <linux/config.h>
+
 /*
  * Entries defined so far:
  * 	- boot param structure itself
@@ -32,10 +34,27 @@
 extern void find_initrd (void);
 extern int filter_rsvd_memory (unsigned long start, unsigned long end, void *arg);
 
+/*
+ * For rounding an address to the next IA64_GRANULE_SIZE or order
+ */
+#define GRANULEROUNDDOWN(n)	((n) & ~(IA64_GRANULE_SIZE-1))
+#define GRANULEROUNDUP(n)	(((n)+IA64_GRANULE_SIZE-1) & ~(IA64_GRANULE_SIZE-1))
+#define ORDERROUNDDOWN(n)	((n) & ~((PAGE_SIZE<<MAX_ORDER)-1))
+
 #ifdef CONFIG_DISCONTIGMEM
-extern void call_pernode_memory (unsigned long start, unsigned long end, void *arg);
+  extern void call_pernode_memory (unsigned long start, unsigned long len, void *func);
+#else
+# define call_pernode_memory(start, len, func)	(*func)(start, len, 0)
 #endif
 
 #define IGNORE_PFN0	1	/* XXX fix me: ignore pfn 0 until TLB miss handler is updated... */
+
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+# define LARGE_GAP	0x40000000 /* Use virtual mem map if hole is > than this */
+  extern unsigned long vmalloc_end;
+  extern struct page *vmem_map;
+  extern int find_largest_hole (u64 start, u64 end, void *arg);
+  extern int create_mem_map_page_table (u64 start, u64 end, void *arg);
+#endif
 
 #endif /* meminit_h */
diff -Nru a/include/asm-ia64/mmzone.h b/include/asm-ia64/mmzone.h
--- a/include/asm-ia64/mmzone.h	Wed Oct 15 00:46:38 2003
+++ b/include/asm-ia64/mmzone.h	Wed Oct 15 00:46:38 2003
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 2000 Silicon Graphics, Inc.  All rights reserved.
+ * Copyright (c) 2000,2003 Silicon Graphics, Inc.  All rights reserved.
  * Copyright (c) 2002 NEC Corp.
  * Copyright (c) 2002 Erich Focht <efocht@ess.nec.de>
  * Copyright (c) 2002 Kimio Suganuma <k-suganuma@da.jp.nec.com>
@@ -12,148 +12,26 @@
 #define _ASM_IA64_MMZONE_H
 
 #include <linux/config.h>
-#include <linux/init.h>
-
-/*
- * Given a kaddr, find the base mem_map address for the start of the mem_map
- * entries for the bank containing the kaddr.
- */
-#define BANK_MEM_MAP_BASE(kaddr) local_node_data->bank_mem_map_base[BANK_MEM_MAP_INDEX(kaddr)]
-
-/*
- * Given a kaddr, this macro return the relative map number 
- * within the bank.
- */
-#define BANK_MAP_NR(kaddr) 	(BANK_OFFSET(kaddr) >> PAGE_SHIFT)
-
-/*
- * Given a pte, this macro returns a pointer to the page struct for the pte.
- */
-#define pte_page(pte)	virt_to_page(PAGE_OFFSET | (pte_val(pte)&_PFN_MASK))
-
-/*
- * Determine if a kaddr is a valid memory address of memory that
- * actually exists. 
- *
- * The check consists of 2 parts:
- *	- verify that the address is a region 7 address & does not 
- *	  contain any bits that preclude it from being a valid platform
- *	  memory address
- *	- verify that the chunk actually exists.
- *
- * Note that IO addresses are NOT considered valid addresses.
- *
- * Note, many platforms can simply check if kaddr exceeds a specific size.  
- *	(However, this won't work on SGI platforms since IO space is embedded 
- * 	within the range of valid memory addresses & nodes have holes in the 
- *	address range between banks). 
- */
-#define kern_addr_valid(kaddr)		({long _kav=(long)(kaddr);	\
-					VALID_MEM_KADDR(_kav);})
-
-/*
- * Given a kaddr, return a pointer to the page struct for the page.
- * If the kaddr does not represent RAM memory that potentially exists, return
- * a pointer the page struct for max_mapnr. IO addresses will
- * return the page for max_nr. Addresses in unpopulated RAM banks may
- * return undefined results OR may panic the system.
- *
- */
-#define virt_to_page(kaddr)	({long _kvtp=(long)(kaddr);	\
-				(VALID_MEM_KADDR(_kvtp))	\
-					? BANK_MEM_MAP_BASE(_kvtp) + BANK_MAP_NR(_kvtp)	\
-					: NULL;})
-
-/*
- * Given a page struct entry, return the physical address that the page struct represents.
- * Since IA64 has all memory in the DMA zone, the following works:
- */
-#define page_to_phys(page)	__pa(page_address(page))
-
-#define node_mem_map(nid)	(NODE_DATA(nid)->node_mem_map)
-
-#define node_localnr(pfn, nid)	((pfn) - NODE_DATA(nid)->node_start_pfn)
-
-#define pfn_to_page(pfn)	(struct page *)(node_mem_map(pfn_to_nid(pfn)) + node_localnr(pfn, pfn_to_nid(pfn)))
-
-#define pfn_to_nid(pfn)		 local_node_data->node_id_map[(pfn << PAGE_SHIFT) >> BANKSHIFT]
-
-#define page_to_pfn(page)	(long)((page - page_zone(page)->zone_mem_map) + page_zone(page)->zone_start_pfn)
+#include <asm/page.h>
+#include <asm/meminit.h>
 
+#ifdef CONFIG_DISCONTIGMEM
 
-/*
- * pfn_valid should be made as fast as possible, and the current definition
- * is valid for machines that are NUMA, but still contiguous, which is what
- * is currently supported. A more generalised, but slower definition would
- * be something like this - mbligh:
- * ( pfn_to_pgdat(pfn) && (pfn < node_end_pfn(pfn_to_nid(pfn))) )
- */
-#define pfn_valid(pfn)          (pfn < max_low_pfn)
-extern unsigned long max_low_pfn;
-
-
-#if defined(CONFIG_IA64_DIG)
-
-/*
- * Platform definitions for DIG platform with contiguous memory.
- */
-#define MAX_PHYSNODE_ID	8		/* Maximum node number +1 */
-#define MAX_PHYS_MEMORY	(1UL << 40)	/* 1 TB */
-
-/*
- * Bank definitions.
- * Configurable settings for DIG: 512MB/bank:  16GB/node,
- *                               2048MB/bank:  64GB/node,
- *                               8192MB/bank: 256GB/node.
- */
-#define NR_BANKS_PER_NODE	32
-#if defined(CONFIG_IA64_NODESIZE_16GB)
-# define BANKSHIFT		29
-#elif defined(CONFIG_IA64_NODESIZE_64GB)
-# define BANKSHIFT		31
-#elif defined(CONFIG_IA64_NODESIZE_256GB)
-# define BANKSHIFT		33
-#else
-# error Unsupported bank and nodesize!
+#ifdef CONFIG_IA64_DIG /* DIG systems are small */
+# define MAX_PHYSNODE_ID	8
+# define NR_NODES		8
+# define NR_MEMBLKS		(NR_NODES * 32)
+#else /* sn2 is the biggest case, so we use that if !DIG */
+# define MAX_PHYSNODE_ID	2048
+# define NR_NODES		256
+# define NR_MEMBLKS		(NR_NODES)
 #endif
-#define BANKSIZE		(1UL << BANKSHIFT)
 
-#elif defined(CONFIG_IA64_SGI_SN2)
-
-/*
- * SGI SN2 discontig definitions
- */
-#define MAX_PHYSNODE_ID	2048	/* 2048 node ids (also called nasid) */
-#define MAX_PHYS_MEMORY	(1UL << 49)
-
-#define NR_BANKS_PER_NODE	4
-#define BANKSHIFT		38
-#define SN2_NODE_SIZE		(64UL*1024*1024*1024)	/* 64GB per node */
-#define BANKSIZE		(SN2_NODE_SIZE/NR_BANKS_PER_NODE)
-
-#endif /* CONFIG_IA64_DIG */
-
-#if defined(CONFIG_IA64_DIG) || defined (CONFIG_IA64_SGI_SN2)
-/* Common defines for both platforms */
-#include <asm/numnodes.h>
-#define BANK_OFFSET(addr)	((unsigned long)(addr) & (BANKSIZE-1))
-#define NR_BANKS		(NR_BANKS_PER_NODE * (1 << NODES_SHIFT))
-#define NR_MEMBLKS		(NR_BANKS)
-
-/*
- * VALID_MEM_KADDR returns a boolean to indicate if a kaddr is
- * potentially a valid cacheable identity mapped RAM memory address.
- * Note that the RAM may or may not actually be present!!
- */
-#define VALID_MEM_KADDR(kaddr)	1
-
-/*
- * Given a nodeid & a bank number, find the address of the mem_map
- * entry for the first page of the bank.
- */
-#define BANK_MEM_MAP_INDEX(kaddr) \
-	(((unsigned long)(kaddr) & (MAX_PHYS_MEMORY-1)) >> BANKSHIFT)
+extern unsigned long max_low_pfn;
 
-#endif /* CONFIG_IA64_DIG || CONFIG_IA64_SGI_SN2 */
+#define pfn_valid(pfn)		(((pfn) < max_low_pfn) && ia64_pfn_valid(pfn))
+#define page_to_pfn(page)	((unsigned long) (page - vmem_map))
+#define pfn_to_page(pfn)	(vmem_map + (pfn))
 
+#endif /* CONFIG_DISCONTIGMEM */
 #endif /* _ASM_IA64_MMZONE_H */
diff -Nru a/include/asm-ia64/nodedata.h b/include/asm-ia64/nodedata.h
--- a/include/asm-ia64/nodedata.h	Wed Oct 15 00:46:37 2003
+++ b/include/asm-ia64/nodedata.h	Wed Oct 15 00:46:37 2003
@@ -11,9 +11,14 @@
 #ifndef _ASM_IA64_NODEDATA_H
 #define _ASM_IA64_NODEDATA_H
 
+#include <linux/config.h>
 #include <linux/numa.h>
+
+#include <asm/percpu.h>
 #include <asm/mmzone.h>
 
+#ifdef CONFIG_DISCONTIGMEM
+
 /*
  * Node Data. One of these structures is located on each node of a NUMA system.
  */
@@ -22,10 +27,7 @@
 struct ia64_node_data {
 	short			active_cpu_count;
 	short			node;
-	struct pglist_data	*pg_data_ptrs[MAX_NUMNODES];
-	struct page		*bank_mem_map_base[NR_BANKS];
-	struct ia64_node_data	*node_data_ptrs[MAX_NUMNODES];
-	short			node_id_map[NR_BANKS];
+	struct pglist_data	*pg_data_ptrs[NR_NODES];
 };
 
 
@@ -34,41 +36,17 @@
  */
 #define local_node_data		(local_cpu_data->node_data)
 
-
-/*
- * Return a pointer to the node_data structure for the specified node.
- */
-#define node_data(node)	(local_node_data->node_data_ptrs[node])
-
-/*
- * Get a pointer to the node_id/node_data for the current cpu.
- *    (boot time only)
- */
-extern int boot_get_local_nodeid(void);
-extern struct ia64_node_data *get_node_data_ptr(void);
-
 /*
  * Given a node id, return a pointer to the pg_data_t for the node.
- * The following 2 macros are similar. 
  *
  * NODE_DATA 	- should be used in all code not related to system
  *		  initialization. It uses pernode data structures to minimize
  *		  offnode memory references. However, these structure are not 
  *		  present during boot. This macro can be used once cpu_init
  *		  completes.
- *
- * BOOT_NODE_DATA
- *		- should be used during system initialization 
- *		  prior to freeing __initdata. It does not depend on the percpu
- *		  area being present.
- *
- * NOTE:   The names of these macros are misleading but are difficult to change
- *	   since they are used in generic linux & on other architecures.
  */
 #define NODE_DATA(nid)		(local_node_data->pg_data_ptrs[nid])
-#define BOOT_NODE_DATA(nid)	boot_get_pg_data_ptr((long)(nid))
 
-struct pglist_data;
-extern struct pglist_data * __init boot_get_pg_data_ptr(long);
+#endif /* CONFIG_DISCONTIGMEM */
 
 #endif /* _ASM_IA64_NODEDATA_H */
diff -Nru a/include/asm-ia64/numa.h b/include/asm-ia64/numa.h
--- a/include/asm-ia64/numa.h	Wed Oct 15 00:46:36 2003
+++ b/include/asm-ia64/numa.h	Wed Oct 15 00:46:36 2003
@@ -4,7 +4,7 @@
  * for more details.
  *
  * This file contains NUMA specific prototypes and definitions.
- * 
+ *
  * 2002/08/05 Erich Focht <efocht@ess.nec.de>
  *
  */
@@ -12,12 +12,17 @@
 #define _ASM_IA64_NUMA_H
 
 #include <linux/config.h>
-#include <linux/cpumask.h>
 
 #ifdef CONFIG_NUMA
 
-#include <linux/numa.h>
 #include <linux/cache.h>
+#include <linux/cache.h>
+#include <linux/cpumask.h>
+#include <linux/numa.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+
+#include <asm/mmzone.h>
 
 extern volatile char cpu_to_node_map[NR_CPUS] __cacheline_aligned;
 extern volatile cpumask_t node_to_cpu_mask[MAX_NUMNODES] __cacheline_aligned;
@@ -60,6 +65,10 @@
 extern int paddr_to_nid(unsigned long paddr);
 
 #define local_nodeid (cpu_to_node_map[smp_processor_id()])
+
+#else /* !CONFIG_NUMA */
+
+#define paddr_to_nid(addr)	0
 
 #endif /* CONFIG_NUMA */
 
diff -Nru a/include/asm-ia64/page.h b/include/asm-ia64/page.h
--- a/include/asm-ia64/page.h	Wed Oct 15 00:46:36 2003
+++ b/include/asm-ia64/page.h	Wed Oct 15 00:46:36 2003
@@ -94,18 +94,20 @@
 
 #define virt_addr_valid(kaddr)	pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
 
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+extern int ia64_pfn_valid (unsigned long pfn);
+#else
+# define ia64_pfn_valid(pfn) 1
+#endif
+
 #ifndef CONFIG_DISCONTIGMEM
-# ifdef CONFIG_VIRTUAL_MEM_MAP
-   extern int ia64_pfn_valid (unsigned long pfn);
-#  define pfn_valid(pfn)	(((pfn) < max_mapnr) && ia64_pfn_valid(pfn))
-# else
-#  define pfn_valid(pfn)	((pfn) < max_mapnr)
-# endif
-#define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
+#define pfn_valid(pfn)		(((pfn) < max_mapnr) && ia64_pfn_valid(pfn))
 #define page_to_pfn(page)	((unsigned long) (page - mem_map))
 #define pfn_to_page(pfn)	(mem_map + (pfn))
+#endif /* CONFIG_DISCONTIGMEM */
+
 #define page_to_phys(page)	(page_to_pfn(page) << PAGE_SHIFT)
-#endif
+#define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
 
 typedef union ia64_va {
 	struct {
diff -Nru a/include/asm-ia64/percpu.h b/include/asm-ia64/percpu.h
--- a/include/asm-ia64/percpu.h	Wed Oct 15 00:46:37 2003
+++ b/include/asm-ia64/percpu.h	Wed Oct 15 00:46:37 2003
@@ -46,11 +46,13 @@
 
 extern void percpu_modcopy(void *pcpudst, const void *src, unsigned long size);
 extern void setup_per_cpu_areas (void);
+extern void *per_cpu_init(void);
 
 #else /* ! SMP */
 
 #define per_cpu(var, cpu)			((void)cpu, per_cpu__##var)
 #define __get_cpu_var(var)			per_cpu__##var
+#define per_cpu_init()				(__phys_per_cpu_start)
 
 #endif	/* SMP */
 
diff -Nru a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h
--- a/include/asm-ia64/pgtable.h	Wed Oct 15 00:46:36 2003
+++ b/include/asm-ia64/pgtable.h	Wed Oct 15 00:46:36 2003
@@ -174,7 +174,6 @@
 	return (addr & (local_cpu_data->unimpl_pa_mask)) == 0;
 }
 
-#ifndef CONFIG_DISCONTIGMEM
 /*
  * kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel
  * memory.  For the return value to be meaningful, ADDR must be >=
@@ -190,7 +189,6 @@
  */
 #define kern_addr_valid(addr)	(1)
 
-#endif
 
 /*
  * Now come the defines and routines to manage and access the three-level
@@ -240,10 +238,8 @@
 #define pte_none(pte) 			(!pte_val(pte))
 #define pte_present(pte)		(pte_val(pte) & (_PAGE_P | _PAGE_PROTNONE))
 #define pte_clear(pte)			(pte_val(*(pte)) = 0UL)
-#ifndef CONFIG_DISCONTIGMEM
 /* pte_page() returns the "struct page *" corresponding to the PTE: */
 #define pte_page(pte)			virt_to_page(((pte_val(pte) & _PFN_MASK) + PAGE_OFFSET))
-#endif
 
 #define pmd_none(pmd)			(!pmd_val(pmd))
 #define pmd_bad(pmd)			(!ia64_phys_addr_valid(pmd_val(pmd)))
diff -Nru a/include/asm-ia64/sn/nodepda.h b/include/asm-ia64/sn/nodepda.h
--- a/include/asm-ia64/sn/nodepda.h	Wed Oct 15 00:46:36 2003
+++ b/include/asm-ia64/sn/nodepda.h	Wed Oct 15 00:46:36 2003
@@ -128,7 +128,7 @@
  * Check if given a compact node id the corresponding node has all the
  * cpus disabled. 
  */
-#define is_headless_node(cnode)		(!any_online_cpu(node_to_cpumask(cnode)))
+#define is_headless_node(cnode)		(!node_to_cpu_mask[cnode])
 
 /*
  * Check if given a node vertex handle the corresponding node has all the
diff -Nru a/include/asm-ia64/uaccess.h b/include/asm-ia64/uaccess.h
--- a/include/asm-ia64/uaccess.h	Wed Oct 15 00:46:36 2003
+++ b/include/asm-ia64/uaccess.h	Wed Oct 15 00:46:36 2003
@@ -408,11 +408,7 @@
 extern void handle_exception (struct pt_regs *regs, const struct exception_table_entry *e);
 extern const struct exception_table_entry *search_exception_tables (unsigned long addr);
 
-#ifdef GAS_HAS_LOCAL_TAGS
 # define SEARCH_EXCEPTION_TABLE(regs) search_exception_tables(regs->cr_iip + ia64_psr(regs)->ri)
-#else
-# define SEARCH_EXCEPTION_TABLE(regs) search_exception_tables(regs->cr_iip)
-#endif
 
 static inline int
 done_with_exception (struct pt_regs *regs)
diff -Nru a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h
--- a/include/asm-ia64/unistd.h	Wed Oct 15 00:46:36 2003
+++ b/include/asm-ia64/unistd.h	Wed Oct 15 00:46:36 2003
@@ -237,17 +237,17 @@
 #define __NR_epoll_wait			1245
 #define __NR_restart_syscall		1246
 #define __NR_semtimedop			1247
-#define __NR_sys_timer_create		1248
-#define __NR_sys_timer_settime		1249
-#define __NR_sys_timer_gettime		1250
-#define __NR_sys_timer_getoverrun	1251
-#define __NR_sys_timer_delete		1252
-#define __NR_sys_clock_settime		1253
-#define __NR_sys_clock_gettime		1254
-#define __NR_sys_clock_getres		1255
-#define __NR_sys_clock_nanosleep	1256
-#define __NR_sys_fstatfs64		1257
-#define __NR_sys_statfs64		1258
+#define __NR_timer_create		1248
+#define __NR_timer_settime		1249
+#define __NR_timer_gettime		1250
+#define __NR_timer_getoverrun		1251
+#define __NR_timer_delete		1252
+#define __NR_clock_settime		1253
+#define __NR_clock_gettime		1254
+#define __NR_clock_getres		1255
+#define __NR_clock_nanosleep		1256
+#define __NR_fstatfs64			1257
+#define __NR_statfs64			1258
 
 #ifdef __KERNEL__
 
diff -Nru a/include/asm-ppc/mpc10x.h b/include/asm-ppc/mpc10x.h
--- a/include/asm-ppc/mpc10x.h	Wed Oct 15 00:46:37 2003
+++ b/include/asm-ppc/mpc10x.h	Wed Oct 15 00:46:37 2003
@@ -121,7 +121,7 @@
 #define MPC10X_MCTLR_EXT_MEM_START_2	0x8c	/* Banks 4-7 */
 
 #define MPC10X_MCTLR_MEM_END_1		0x90	/* Banks 0-3 */
-#define MPC10X_MCTLR_MEM_END_2i		0x94	/* Banks 4-7 */
+#define MPC10X_MCTLR_MEM_END_2		0x94	/* Banks 4-7 */
 #define MPC10X_MCTLR_EXT_MEM_END_1	0x98	/* Banks 0-3 */
 #define MPC10X_MCTLR_EXT_MEM_END_2	0x9c	/* Banks 4-7 */
 
diff -Nru a/include/asm-ppc/reg.h b/include/asm-ppc/reg.h
--- a/include/asm-ppc/reg.h	Wed Oct 15 00:46:37 2003
+++ b/include/asm-ppc/reg.h	Wed Oct 15 00:46:37 2003
@@ -87,6 +87,10 @@
 #define SPRN_CTR	0x009	/* Count Register */
 #define SPRN_DABR	0x3F5	/* Data Address Breakpoint Register */
 #define SPRN_DAR	0x013	/* Data Address Register */
+#define SPRN_TBRL	0x10C	/* Time Base Read Lower Register (user, R/O) */
+#define SPRN_TBRU	0x10D	/* Time Base Read Upper Register (user, R/O) */
+#define SPRN_TBWL	0x11C	/* Time Base Lower Register (super, R/W) */
+#define SPRN_TBWU	0x11D	/* Time Base Upper Register (super, R/W) */
 #define SPRN_DBAT0L	0x219	/* Data BAT 0 Lower Register */
 #define SPRN_DBAT0U	0x218	/* Data BAT 0 Upper Register */
 #define SPRN_DBAT1L	0x21B	/* Data BAT 1 Lower Register */
@@ -397,6 +401,10 @@
 #define THRM2	SPRN_THRM2	/* Thermal Management Register 2 */
 #define THRM3	SPRN_THRM3	/* Thermal Management Register 3 */
 #define XER	SPRN_XER
+#define TBRL	SPRN_TBRL	/* Time Base Read Lower Register */
+#define TBRU	SPRN_TBRU	/* Time Base Read Upper Register */
+#define TBWL	SPRN_TBWL	/* Time Base Write Lower Register */
+#define TBWU	SPRN_TBWU	/* Time Base Write Upper Register */
 
 /* Processor Version Register */
 
diff -Nru a/include/asm-ppc/reg_booke.h b/include/asm-ppc/reg_booke.h
--- a/include/asm-ppc/reg_booke.h	Wed Oct 15 00:46:37 2003
+++ b/include/asm-ppc/reg_booke.h	Wed Oct 15 00:46:37 2003
@@ -59,14 +59,10 @@
 #define SPRN_SPRG5R	0x105	/* Special Purpose Register General 5 Read */
 #define SPRN_SPRG6R	0x106	/* Special Purpose Register General 6 Read */
 #define SPRN_SPRG7R	0x107	/* Special Purpose Register General 7 Read */
-#define SPRN_TBRL	0x10C	/* Time Base Read Lower Register (user, R/O) */
-#define SPRN_TBRU	0x10D	/* Time Base Read Upper Register (user, R/O) */
 #define SPRN_SPRG4W	0x114	/* Special Purpose Register General 4 Write */
 #define SPRN_SPRG5W	0x115	/* Special Purpose Register General 5 Write */
 #define SPRN_SPRG6W	0x116	/* Special Purpose Register General 6 Write */
 #define SPRN_SPRG7W	0x117	/* Special Purpose Register General 7 Write */
-#define SPRN_TBWL	0x11C	/* Time Base Lower Register (super, R/W) */
-#define SPRN_TBWU	0x11D	/* Time Base Upper Register (super, R/W) */
 #define SPRN_DBCR2	0x136	/* Debug Control Register 2 */
 #define SPRN_IAC3	0x13A	/* Instruction Address Compare 3 */
 #define SPRN_IAC4	0x13B	/* Instruction Address Compare 4 */
@@ -252,10 +248,6 @@
 #define SPRG5W	SPRN_SPRG5W
 #define SPRG6W	SPRN_SPRG6W
 #define SPRG7W	SPRN_SPRG7W
-#define TBRL	SPRN_TBRL	/* Time Base Read Lower Register */
-#define TBRU	SPRN_TBRU	/* Time Base Read Upper Register */
-#define TBWL	SPRN_TBWL	/* Time Base Write Lower Register */
-#define TBWU	SPRN_TBWU	/* Time Base Write Upper Register */
 
 /*
  * The IBM-403 is an even more odd special case, as it is much
diff -Nru a/include/asm-sparc64/uaccess.h b/include/asm-sparc64/uaccess.h
--- a/include/asm-sparc64/uaccess.h	Wed Oct 15 00:46:36 2003
+++ b/include/asm-sparc64/uaccess.h	Wed Oct 15 00:46:36 2003
@@ -263,9 +263,10 @@
 #define copy_to_user __copy_to_user
 #define copy_in_user __copy_in_user
 
+extern unsigned long __bzero_noasi(void *, unsigned long);
+
 static inline unsigned long __clear_user(void __user *addr, unsigned long size)
 {
-	extern unsigned long __bzero_noasi(void *addr, unsigned long size);
 	
 	return __bzero_noasi((void *) addr, size);
 }
diff -Nru a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h
--- a/include/asm-x86_64/proto.h	Wed Oct 15 00:46:37 2003
+++ b/include/asm-x86_64/proto.h	Wed Oct 15 00:46:37 2003
@@ -70,7 +70,9 @@
 extern int map_syscall32(struct mm_struct *mm, unsigned long address);
 extern char *syscall32_page;
 
-void setup_node_bootmem(int nodeid, unsigned long start, unsigned long end);
+extern void setup_node_bootmem(int nodeid, unsigned long start, unsigned long end);
+
+extern void check_ioapic(void);
 
 extern unsigned long max_mapnr;
 extern unsigned long end_pfn; 
@@ -81,6 +83,10 @@
 extern int using_apic_timer;
 extern int disable_apic;
 extern unsigned cpu_khz;
+extern int ioapic_force;
+extern int skip_ioapic_setup;
+extern int acpi_ht;
+extern int acpi_disabled;
 
 extern int fallback_aper_order;
 extern int fallback_aper_force;
diff -Nru a/include/asm-x86_64/suspend.h b/include/asm-x86_64/suspend.h
--- a/include/asm-x86_64/suspend.h	Wed Oct 15 00:46:36 2003
+++ b/include/asm-x86_64/suspend.h	Wed Oct 15 00:46:36 2003
@@ -1,14 +1,15 @@
 /*
- * Copyright 2001-2002 Pavel Machek <pavel@suse.cz>
+ * Copyright 2001-2003 Pavel Machek <pavel@suse.cz>
  * Based on code
  * Copyright 2001 Patrick Mochel <mochel@osdl.org>
  */
 #include <asm/desc.h>
 #include <asm/i387.h>
 
-static inline void
+static inline int
 arch_prepare_suspend(void)
 {
+	return 0;
 }
 
 /* Image of the saved processor state. If you touch this, fix acpi_wakeup.S. */
diff -Nru a/include/linux/device.h b/include/linux/device.h
--- a/include/linux/device.h	Wed Oct 15 00:46:37 2003
+++ b/include/linux/device.h	Wed Oct 15 00:46:37 2003
@@ -254,6 +254,7 @@
 	struct list_head children;
 	struct device 	* parent;
 
+	struct completion * complete;	/* Notification for freeing device. */
 	struct kobject kobj;
 	char	bus_id[BUS_ID_SIZE];	/* position on parent bus */
 
@@ -301,6 +302,7 @@
  */
 extern int device_register(struct device * dev);
 extern void device_unregister(struct device * dev);
+extern void device_unregister_wait(struct device * dev);
 extern void device_initialize(struct device * dev);
 extern int device_add(struct device * dev);
 extern void device_del(struct device * dev);
diff -Nru a/include/linux/ethtool.h b/include/linux/ethtool.h
--- a/include/linux/ethtool.h	Wed Oct 15 00:46:36 2003
+++ b/include/linux/ethtool.h	Wed Oct 15 00:46:36 2003
@@ -307,14 +307,14 @@
  *
  * get_eeprom:
  *	Should fill in the magic field.  Don't need to check len for zero
- *	or wraparound but must check offset + len < size.  Fill in the data
- *	argument with the eeprom values from offset to offset + len.  Update
- *	len to the amount read.  Returns an error or zero.
+ *	or wraparound.  Fill in the data argument with the eeprom values
+ *	from offset to offset + len.  Update len to the amount read.
+ *	Returns an error or zero.
  *
  * set_eeprom:
  *	Should validate the magic field.  Don't need to check len for zero
- *	or wraparound but must check offset + len < size.  Update len to
- *	the amount written.  Returns an error or zero.
+ *	or wraparound.  Update len to the amount written.  Returns an error
+ *	or zero.
  */
 struct ethtool_ops {
 	int	(*get_settings)(struct net_device *, struct ethtool_cmd *);
@@ -328,6 +328,7 @@
 	void	(*set_msglevel)(struct net_device *, u32);
 	int	(*nway_reset)(struct net_device *);
 	u32	(*get_link)(struct net_device *);
+	int	(*get_eeprom_len)(struct net_device *);
 	int	(*get_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);
 	int	(*set_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);
 	int	(*get_coalesce)(struct net_device *, struct ethtool_coalesce *);
diff -Nru a/include/linux/ioport.h b/include/linux/ioport.h
--- a/include/linux/ioport.h	Wed Oct 15 00:46:36 2003
+++ b/include/linux/ioport.h	Wed Oct 15 00:46:36 2003
@@ -90,6 +90,7 @@
 
 extern int request_resource(struct resource *root, struct resource *new);
 extern int release_resource(struct resource *new);
+extern int insert_resource(struct resource *parent, struct resource *new);
 extern int allocate_resource(struct resource *root, struct resource *new,
 			     unsigned long size,
 			     unsigned long min, unsigned long max,
diff -Nru a/include/linux/ipmi_msgdefs.h b/include/linux/ipmi_msgdefs.h
--- a/include/linux/ipmi_msgdefs.h	Wed Oct 15 00:46:37 2003
+++ b/include/linux/ipmi_msgdefs.h	Wed Oct 15 00:46:37 2003
@@ -37,22 +37,32 @@
 /* Various definitions for IPMI messages used by almost everything in
    the IPMI stack. */
 
-#define IPMI_NETFN_APP_REQUEST	0x06
-#define IPMI_NETFN_APP_RESPONSE	0x07
+/* NetFNs and commands used inside the IPMI stack. */
 
-#define IPMI_BMC_SLAVE_ADDR	0x20
+#define IPMI_NETFN_SENSOR_EVENT_REQUEST		0x04
+#define IPMI_NETFN_SENSOR_EVENT_RESPONSE	0x05
+#define IPMI_GET_EVENT_RECEIVER_CMD	0x01
 
+#define IPMI_NETFN_APP_REQUEST			0x06
+#define IPMI_NETFN_APP_RESPONSE			0x07
 #define IPMI_GET_DEVICE_ID_CMD		0x01
-
 #define IPMI_CLEAR_MSG_FLAGS_CMD	0x30
 #define IPMI_GET_MSG_FLAGS_CMD		0x31
 #define IPMI_SEND_MSG_CMD		0x34
 #define IPMI_GET_MSG_CMD		0x33
-
 #define IPMI_SET_BMC_GLOBAL_ENABLES_CMD	0x2e
 #define IPMI_GET_BMC_GLOBAL_ENABLES_CMD	0x2f
 #define IPMI_READ_EVENT_MSG_BUFFER_CMD	0x35
 
+#define IPMI_NETFN_STORAGE_REQUEST		0x0a
+#define IPMI_NETFN_STORAGE_RESPONSE		0x0b
+#define IPMI_ADD_SEL_ENTRY_CMD		0x44
+
+/* The default slave address */
+#define IPMI_BMC_SLAVE_ADDR	0x20
+
 #define IPMI_MAX_MSG_LENGTH	80
+
+#define IPMI_CC_NO_ERROR	0
 
 #endif /* __LINUX_IPMI_MSGDEFS_H */
diff -Nru a/include/linux/jffs2.h b/include/linux/jffs2.h
--- a/include/linux/jffs2.h	Wed Oct 15 00:46:37 2003
+++ b/include/linux/jffs2.h	Wed Oct 15 00:46:37 2003
@@ -1,14 +1,14 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in the 
  * jffs2 directory.
  *
- * $Id: jffs2.h,v 1.30 2003/02/15 00:15:22 dwmw2 Exp $
+ * $Id: jffs2.h,v 1.31 2003/10/04 08:33:05 dwmw2 Exp $
  *
  */
 
diff -Nru a/include/linux/jffs2_fs_sb.h b/include/linux/jffs2_fs_sb.h
--- a/include/linux/jffs2_fs_sb.h	Wed Oct 15 00:46:35 2003
+++ b/include/linux/jffs2_fs_sb.h	Wed Oct 15 00:46:35 2003
@@ -1,4 +1,4 @@
-/* $Id: jffs2_fs_sb.h,v 1.37 2003/01/17 16:04:44 dwmw2 Exp $ */
+/* $Id: jffs2_fs_sb.h,v 1.45 2003/10/08 11:46:27 dwmw2 Exp $ */
 
 #ifndef _JFFS2_FS_SB
 #define _JFFS2_FS_SB
@@ -15,6 +15,8 @@
 #define JFFS2_SB_FLAG_RO 1
 #define JFFS2_SB_FLAG_MOUNTING 2
 
+struct jffs2_inodirty;
+
 /* A struct for the overall file system control.  Pointers to
    jffs2_sb_info structs are named `c' in the source code.  
    Nee jffs_control
@@ -52,6 +54,15 @@
 	uint32_t nr_free_blocks;
 	uint32_t nr_erasing_blocks;
 
+	/* Number of free blocks there must be before we... */
+	uint8_t resv_blocks_write;	/* ... allow a normal filesystem write */
+	uint8_t resv_blocks_deletion;	/* ... allow a normal filesystem deletion */
+	uint8_t resv_blocks_gctrigger;	/* ... wake up the GC thread */
+	uint8_t resv_blocks_gcbad;	/* ... pick a block from the bad_list to GC */
+	uint8_t resv_blocks_gcmerge;	/* ... merge pages when garbage collecting */
+
+	uint32_t nospc_dirty_size;
+
 	uint32_t nr_blocks;
 	struct jffs2_eraseblock *blocks;	/* The whole array of blocks. Used for getting blocks 
 						 * from the offset (blocks[ofs / sector_size]) */
@@ -84,13 +95,20 @@
 	   to an obsoleted node. I don't like this. Alternatives welcomed. */
 	struct semaphore erase_free_sem;
 
+#ifdef CONFIG_JFFS2_FS_NAND
 	/* Write-behind buffer for NAND flash */
 	unsigned char *wbuf;
 	uint32_t wbuf_ofs;
 	uint32_t wbuf_len;
 	uint32_t wbuf_pagesize;
-	struct work_struct wbuf_task;		/* task for timed wbuf flush */
-	struct timer_list wbuf_timer;		/* timer for flushing wbuf */
+	struct jffs2_inodirty *wbuf_inodes;
+
+	/* Information about out-of-band area usage... */
+	struct nand_oobinfo *oobinfo;
+	uint32_t badblock_pos;
+	uint32_t fsdata_pos;
+	uint32_t fsdata_len;
+#endif
 
 	/* OS-private pointer for getting back to master superblock info */
 	void *os_priv;
diff -Nru a/include/linux/netfilter_bridge/ebt_among.h b/include/linux/netfilter_bridge/ebt_among.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/netfilter_bridge/ebt_among.h	Wed Oct 15 00:46:38 2003
@@ -0,0 +1,65 @@
+#ifndef __LINUX_BRIDGE_EBT_AMONG_H
+#define __LINUX_BRIDGE_EBT_AMONG_H
+
+#define EBT_AMONG_DST 0x01
+#define EBT_AMONG_SRC 0x02
+
+/* Grzegorz Borowiak <grzes@gnu.univ.gda.pl> 2003
+ * 
+ * Write-once-read-many hash table, used for checking if a given
+ * MAC address belongs to a set or not and possibly for checking
+ * if it is related with a given IPv4 address.
+ *
+ * The hash value of an address is its last byte.
+ * 
+ * In real-world ethernet addresses, values of the last byte are
+ * evenly distributed and there is no need to consider other bytes.
+ * It would only slow the routines down.
+ *
+ * For MAC address comparison speedup reasons, we introduce a trick.
+ * MAC address is mapped onto an array of two 32-bit integers.
+ * This pair of integers is compared with MAC addresses in the
+ * hash table, which are stored also in form of pairs of integers
+ * (in `cmp' array). This is quick as it requires only two elementary
+ * number comparisons in worst case. Further, we take advantage of
+ * fact that entropy of 3 last bytes of address is larger than entropy
+ * of 3 first bytes. So first we compare 4 last bytes of addresses and
+ * if they are the same we compare 2 first.
+ *
+ * Yes, it is a memory overhead, but in 2003 AD, who cares?
+ */
+
+struct ebt_mac_wormhash_tuple
+{
+	uint32_t cmp[2];
+	uint32_t ip;
+};
+
+struct ebt_mac_wormhash
+{
+	int table[257];
+	int poolsize;
+	struct ebt_mac_wormhash_tuple pool[0];
+};
+
+#define ebt_mac_wormhash_size(x) ((x) ? sizeof(struct ebt_mac_wormhash) \
+		+ (x)->poolsize * sizeof(struct ebt_mac_wormhash_tuple) : 0)
+
+struct ebt_among_info
+{
+	int wh_dst_ofs;
+	int wh_src_ofs;
+	int bitmask;
+};
+
+#define EBT_AMONG_DST_NEG 0x1
+#define EBT_AMONG_SRC_NEG 0x2
+
+#define ebt_among_wh_dst(x) ((x)->wh_dst_ofs ? \
+	(struct ebt_mac_wormhash*)((char*)(x) + (x)->wh_dst_ofs) : NULL)
+#define ebt_among_wh_src(x) ((x)->wh_src_ofs ? \
+	(struct ebt_mac_wormhash*)((char*)(x) + (x)->wh_src_ofs) : NULL)
+
+#define EBT_AMONG_MATCH "among"
+
+#endif
diff -Nru a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
--- a/include/linux/nfs_fs.h	Wed Oct 15 00:46:36 2003
+++ b/include/linux/nfs_fs.h	Wed Oct 15 00:46:36 2003
@@ -264,7 +264,7 @@
 /*
  * linux/fs/nfs/direct.c
  */
-extern int nfs_direct_IO(int, struct file *, const struct iovec *, loff_t,
+extern int nfs_direct_IO(int, struct kiocb *, const struct iovec *, loff_t,
 			unsigned long);
 
 /*
diff -Nru a/include/linux/nfs_page.h b/include/linux/nfs_page.h
--- a/include/linux/nfs_page.h	Wed Oct 15 00:46:35 2003
+++ b/include/linux/nfs_page.h	Wed Oct 15 00:46:35 2003
@@ -47,7 +47,6 @@
 					    unsigned int, unsigned int);
 extern	void nfs_clear_request(struct nfs_page *req);
 extern	void nfs_release_request(struct nfs_page *req);
-extern	void nfs_release_list(struct list_head *list);
 
 
 extern	void nfs_list_add_request(struct nfs_page *, struct list_head *);
@@ -57,7 +56,6 @@
 extern	int nfs_coalesce_requests(struct list_head *, struct list_head *,
 				  unsigned int);
 extern  int nfs_wait_on_request(struct nfs_page *);
-extern	int nfs_wait_for_reads(struct list_head *);
 
 extern	spinlock_t nfs_wreq_lock;
 
diff -Nru a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
--- a/include/linux/nfs_xdr.h	Wed Oct 15 00:46:37 2003
+++ b/include/linux/nfs_xdr.h	Wed Oct 15 00:46:37 2003
@@ -639,8 +639,7 @@
 	int	(*readlink)(struct inode *, struct page *);
 	int	(*read)    (struct nfs_read_data *, struct file *);
 	int	(*write)   (struct nfs_write_data *, struct file *);
-	int	(*commit)  (struct inode *, struct nfs_fattr *,
-			    unsigned long, unsigned int);
+	int	(*commit)  (struct nfs_write_data *, struct file *);
 	struct inode *	(*create)  (struct inode *, struct qstr *,
 			    struct iattr *, int);
 	int	(*remove)  (struct inode *, struct qstr *);
diff -Nru a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h	Wed Oct 15 00:46:35 2003
+++ b/include/linux/sched.h	Wed Oct 15 00:46:35 2003
@@ -264,15 +264,6 @@
 
 	/* thread group stop support, overloads group_exit_code too */
 	int			group_stop_count;
-
-	/* job control IDs */
-	pid_t pgrp;
-	pid_t tty_old_pgrp;
-	pid_t session;
-	/* boolean value for session group leader */
-	int leader;
-
-	struct tty_struct *tty; /* NULL if no tty */
 };
 
 /*
@@ -375,7 +366,12 @@
 	unsigned long personality;
 	int did_exec:1;
 	pid_t pid;
+	pid_t __pgrp;		/* Accessed via process_group() */
+	pid_t tty_old_pgrp;
+	pid_t session;
 	pid_t tgid;
+	/* boolean value for session group leader */
+	int leader;
 	/* 
 	 * pointers to (original) parent process, youngest child, younger sibling,
 	 * older sibling, respectively.  (p->father can be replaced with 
@@ -419,6 +415,7 @@
 	char comm[16];
 /* file system info */
 	int link_count, total_link_count;
+	struct tty_struct *tty; /* NULL if no tty */
 /* ipc stuff */
 	struct sysv_sem sysvsem;
 /* CPU-specific state of this task */
@@ -471,22 +468,7 @@
 
 static inline pid_t process_group(struct task_struct *tsk)
 {
-	return tsk->signal->pgrp;
-}
-
-static inline pid_t process_session(struct task_struct *tsk)
-{
-	return tsk->signal->session;
-}
-
-static inline int process_session_leader(struct task_struct *tsk)
-{
-	return tsk->signal->leader;
-}
-
-static inline struct tty_struct *process_tty(struct task_struct *tsk)
-{
-	return tsk->signal->tty;
+	return tsk->group_leader->__pgrp;
 }
 
 extern void __put_task_struct(struct task_struct *tsk);
@@ -559,6 +541,16 @@
 	unsigned long stack[INIT_THREAD_SIZE/sizeof(long)];
 };
 
+#ifndef __HAVE_ARCH_KSTACK_END
+static inline int kstack_end(void *addr)
+{
+	/* Reliable end of stack detection:
+	 * Some APM bios versions misalign the stack
+	 */
+	return !(((unsigned long)addr+sizeof(void*)-1) & (THREAD_SIZE-sizeof(void*)));
+}
+#endif
+
 extern union thread_union init_thread_union;
 extern struct task_struct init_task;
 
@@ -594,6 +586,19 @@
 extern void flush_signals(struct task_struct *);
 extern void flush_signal_handlers(struct task_struct *, int force_default);
 extern int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info);
+
+static inline int dequeue_signal_lock(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&tsk->sighand->siglock, flags);
+	ret = dequeue_signal(tsk, mask, info);
+	spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
+
+	return ret;
+}	
+
 extern void block_all_signals(int (*notifier)(void *priv), void *priv,
 			      sigset_t *mask);
 extern void unblock_all_signals(void);
@@ -691,6 +696,7 @@
 extern void reparent_to_init(void);
 extern void daemonize(const char *, ...);
 extern int allow_signal(int);
+extern int disallow_signal(int);
 extern task_t *child_reaper;
 
 extern int do_execve(char *, char __user * __user *, char __user * __user *, struct pt_regs *);
diff -Nru a/include/linux/suspend.h b/include/linux/suspend.h
--- a/include/linux/suspend.h	Wed Oct 15 00:46:36 2003
+++ b/include/linux/suspend.h	Wed Oct 15 00:46:36 2003
@@ -47,12 +47,6 @@
 
 extern unsigned int nr_copy_pages __nosavedata;
 extern suspend_pagedir_t *pagedir_nosave __nosavedata;
-
-/* Communication between acpi and arch/i386/suspend.c */
-
-extern void do_suspend_lowlevel(int resume);
-extern void do_suspend_lowlevel_s4bios(int resume);
-
 #endif /* CONFIG_PM */
 
 #ifdef CONFIG_SOFTWARE_SUSPEND
diff -Nru a/include/media/saa7146_vv.h b/include/media/saa7146_vv.h
--- a/include/media/saa7146_vv.h	Wed Oct 15 00:46:35 2003
+++ b/include/media/saa7146_vv.h	Wed Oct 15 00:46:35 2003
@@ -150,6 +150,7 @@
 
 /* flags */
 #define SAA7146_EXT_SWAP_ODD_EVEN       0x1     /* needs odd/even fields swapped */
+#define SAA7146_USE_PORT_B_FOR_VBI	0x2     /* use input port b for vbi hardware bug workaround */
 
 struct saa7146_ext_vv
 {
diff -Nru a/include/net/syncppp.h b/include/net/syncppp.h
--- a/include/net/syncppp.h	Wed Oct 15 00:46:36 2003
+++ b/include/net/syncppp.h	Wed Oct 15 00:46:36 2003
@@ -59,8 +59,9 @@
 
 static inline struct sppp *sppp_of(struct net_device *dev) 
 {
-	struct ppp_device *ppp = dev->priv;
-	return &ppp->sppp;
+	struct ppp_device **ppp = dev->priv;
+	BUG_ON((*ppp)->dev != dev);
+	return &(*ppp)->sppp;
 }
 
 #define PP_KEEPALIVE    0x01    /* use keepalive protocol */
diff -Nru a/include/sound/pcm_oss.h b/include/sound/pcm_oss.h
--- a/include/sound/pcm_oss.h	Wed Oct 15 00:46:37 2003
+++ b/include/sound/pcm_oss.h	Wed Oct 15 00:46:37 2003
@@ -50,6 +50,7 @@
 	unsigned int maxfrags;
 	unsigned int subdivision;		/* requested subdivision */
 	size_t period_bytes;			/* requested period size */
+	size_t period_ptr;			/* actual write pointer to period */
 	unsigned int periods;
 	size_t buffer_bytes;			/* requested buffer size */
 	size_t bytes;				/* total # bytes processed */
diff -Nru a/include/sound/rawmidi.h b/include/sound/rawmidi.h
--- a/include/sound/rawmidi.h	Wed Oct 15 00:46:37 2003
+++ b/include/sound/rawmidi.h	Wed Oct 15 00:46:37 2003
@@ -46,6 +46,7 @@
 #define SNDRV_RAWMIDI_LFLG_INPUT	(1<<1)
 #define SNDRV_RAWMIDI_LFLG_OPEN		(3<<0)
 #define SNDRV_RAWMIDI_LFLG_APPEND	(1<<2)
+#define	SNDRV_RAWMIDI_LFLG_NOOPENLOCK	(1<<3)
 
 typedef struct _snd_rawmidi_runtime snd_rawmidi_runtime_t;
 typedef struct _snd_rawmidi_substream snd_rawmidi_substream_t;
diff -Nru a/kernel/acct.c b/kernel/acct.c
--- a/kernel/acct.c	Wed Oct 15 00:46:37 2003
+++ b/kernel/acct.c	Wed Oct 15 00:46:37 2003
@@ -343,7 +343,7 @@
 	/* we really need to bite the bullet and change layout */
 	ac.ac_uid = current->uid;
 	ac.ac_gid = current->gid;
-	ac.ac_tty = process_tty(current) ? old_encode_dev(tty_devnum(process_tty(current))) : 0;
+	ac.ac_tty = current->tty ? old_encode_dev(tty_devnum(current->tty)) : 0;
 
 	ac.ac_flag = 0;
 	if (current->flags & PF_FORKNOEXEC)
diff -Nru a/kernel/exit.c b/kernel/exit.c
--- a/kernel/exit.c	Wed Oct 15 00:46:37 2003
+++ b/kernel/exit.c	Wed Oct 15 00:46:37 2003
@@ -119,13 +119,13 @@
 
 	read_lock(&tasklist_lock);
 	for_each_task_pid(pgrp, PIDTYPE_PGID, p, l, pid)
-		if (process_session(p) > 0) {
-			sid = process_session(p);
+		if (p->session > 0) {
+			sid = p->session;
 			goto out;
 		}
 	p = find_task_by_pid(pgrp);
 	if (p)
-		sid = process_session(p);
+		sid = p->session;
 out:
 	read_unlock(&tasklist_lock);
 	
@@ -153,7 +153,7 @@
 				|| p->real_parent->pid == 1)
 			continue;
 		if (process_group(p->real_parent) != pgrp
-			    && process_session(p->real_parent) == process_session(p)) {
+			    && p->real_parent->session == p->session) {
 			ret = 0;
 			break;
 		}
@@ -242,14 +242,14 @@
 {
 	struct task_struct *curr = current;
 
-	if (process_session(curr) != session) {
+	if (curr->session != session) {
 		detach_pid(curr, PIDTYPE_SID);
-		curr->signal->session = session;
+		curr->session = session;
 		attach_pid(curr, PIDTYPE_SID, session);
 	}
 	if (process_group(curr) != pgrp) {
 		detach_pid(curr, PIDTYPE_PGID);
-		curr->signal->pgrp = pgrp;
+		curr->group_leader->__pgrp = pgrp;
 		attach_pid(curr, PIDTYPE_PGID, pgrp);
 	}
 }
@@ -273,6 +273,13 @@
 
 	spin_lock_irq(&current->sighand->siglock);
 	sigdelset(&current->blocked, sig);
+	if (!current->mm) {
+		/* Kernel threads handle their own signals.
+		   Let the signal code know it'll be handled, so
+		   that they don't get converted to SIGKILL or
+		   just silently dropped */
+		current->sighand->action[(sig)-1].sa.sa_handler = (void *)2;
+	}
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 	return 0;
@@ -280,6 +287,20 @@
 
 EXPORT_SYMBOL(allow_signal);
 
+int disallow_signal(int sig)
+{
+	if (sig < 1 || sig > _NSIG)
+		return -EINVAL;
+
+	spin_lock_irq(&current->sighand->siglock);
+	sigaddset(&current->blocked, sig);
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+	return 0;
+}
+
+EXPORT_SYMBOL(disallow_signal);
+
 /*
  *	Put all the gunge required to become a kernel thread without
  *	attached user resources in one place where it belongs.
@@ -303,7 +324,7 @@
 	exit_mm(current);
 
 	set_special_pids(1, 1);
-	current->signal->tty = NULL;
+	current->tty = NULL;
 
 	/* Block and flush all signals */
 	sigfillset(&blocked);
@@ -515,7 +536,7 @@
 	 * outside, so the child pgrp is now orphaned.
 	 */
 	if ((process_group(p) != process_group(father)) &&
-	    (process_session(p) == process_session(father))) {
+	    (p->session == father->session)) {
 		int pgrp = process_group(p);
 
 		if (will_become_orphaned_pgrp(pgrp, NULL) && has_stopped_jobs(pgrp)) {
@@ -625,7 +646,7 @@
 	t = tsk->real_parent;
 	
 	if ((process_group(t) != process_group(tsk)) &&
-	    (process_session(t) == process_session(tsk)) &&
+	    (t->session == tsk->session) &&
 	    will_become_orphaned_pgrp(process_group(tsk), tsk) &&
 	    has_stopped_jobs(process_group(tsk))) {
 		__kill_pg_info(SIGHUP, (void *)1, process_group(tsk));
@@ -720,7 +741,7 @@
 	exit_itimers(tsk);
 	exit_thread();
 
-	if (process_session_leader(tsk))
+	if (tsk->leader)
 		disassociate_ctty(1);
 
 	module_put(tsk->thread_info->exec_domain->module);
diff -Nru a/kernel/fork.c b/kernel/fork.c
--- a/kernel/fork.c	Wed Oct 15 00:46:35 2003
+++ b/kernel/fork.c	Wed Oct 15 00:46:35 2003
@@ -743,12 +743,6 @@
 	sig->curr_target = NULL;
 	init_sigpending(&sig->shared_pending);
 
-	sig->tty = process_tty(current);
-	sig->pgrp = process_group(current);
-	sig->session = process_session(current);
-	sig->leader = 0;	/* session leadership doesn't inherit */
-	sig->tty_old_pgrp = 0;
-
 	return 0;
 }
 
@@ -795,9 +789,7 @@
 	 * Thread groups must share signals as well, and detached threads
 	 * can only be started up within the thread group.
 	 */
-	if ((clone_flags & CLONE_THREAD) &&
-		(clone_flags & (CLONE_SIGHAND|CLONE_DETACHED)) !=
-			(CLONE_SIGHAND|CLONE_DETACHED))
+	if ((clone_flags & CLONE_THREAD) && !(clone_flags & CLONE_SIGHAND))
 		return ERR_PTR(-EINVAL);
 
 	/*
@@ -902,6 +894,8 @@
 	init_timer(&p->real_timer);
 	p->real_timer.data = (unsigned long) p;
 
+	p->leader = 0;		/* session leadership doesn't inherit */
+	p->tty_old_pgrp = 0;
 	p->utime = p->stime = 0;
 	p->cutime = p->cstime = 0;
 	p->array = NULL;
@@ -1046,7 +1040,7 @@
 	if (thread_group_leader(p)) {
 		attach_pid(p, PIDTYPE_TGID, p->tgid);
 		attach_pid(p, PIDTYPE_PGID, process_group(p));
-		attach_pid(p, PIDTYPE_SID, process_session(p));
+		attach_pid(p, PIDTYPE_SID, p->session);
 		if (p->pid)
 			__get_cpu_var(process_counts)++;
 	} else
diff -Nru a/kernel/futex.c b/kernel/futex.c
--- a/kernel/futex.c	Wed Oct 15 00:46:36 2003
+++ b/kernel/futex.c	Wed Oct 15 00:46:36 2003
@@ -45,6 +45,9 @@
  * Futexes are matched on equal values of this key.
  * The key type depends on whether it's a shared or private mapping.
  * Don't rearrange members without looking at hash_futex().
+ *
+ * offset is aligned to a multiple of sizeof(u32) (== 4) by definition.
+ * We set bit 0 to indicate if it's an inode-based key.
  */
 union futex_key {
 	struct {
@@ -66,12 +69,20 @@
 
 /*
  * We use this hashed waitqueue instead of a normal wait_queue_t, so
- * we can wake only the relevant ones (hashed queues may be shared):
+ * we can wake only the relevant ones (hashed queues may be shared).
+ *
+ * A futex_q has a woken state, just like tasks have TASK_RUNNING.
+ * It is considered woken when list_empty(&q->list) || q->lock_ptr == 0.
+ * The order of wakup is always to make the first condition true, then
+ * wake up q->waiters, then make the second condition true.
  */
 struct futex_q {
 	struct list_head list;
 	wait_queue_head_t waiters;
 
+	/* Which hash list lock to use. */
+	spinlock_t *lock_ptr;
+
 	/* Key which the futex is hashed on. */
 	union futex_key key;
 
@@ -124,8 +135,7 @@
  * Returns: 0, or negative error code.
  * The key words are stored in *key on success.
  *
- * Should be called with &current->mm->mmap_sem,
- * but NOT &futex_lock or &current->mm->page_table_lock.
+ * Should be called with &current->mm->mmap_sem but NOT any spinlocks.
  */
 static int get_futex_key(unsigned long uaddr, union futex_key *key)
 {
@@ -172,9 +182,10 @@
 	}
 
 	/*
-	 * Linear mappings are also simple.
+	 * Linear file mappings are also simple.
 	 */
 	key->shared.inode = vma->vm_file->f_dentry->d_inode;
+	key->both.offset++; /* Bit 0 of offset indicates inode-based key. */
 	if (likely(!(vma->vm_flags & VM_NONLINEAR))) {
 		key->shared.pgoff = (((uaddr - vma->vm_start) >> PAGE_SHIFT)
 				     + vma->vm_pgoff);
@@ -214,16 +225,68 @@
 	return err;
 }
 
+/*
+ * Take a reference to the resource addressed by a key.
+ * Can be called while holding spinlocks.
+ *
+ * NOTE: mmap_sem MUST be held between get_futex_key() and calling this
+ * function, if it is called at all.  mmap_sem keeps key->shared.inode valid.
+ */
+static inline void get_key_refs(union futex_key *key)
+{
+	if (key->both.ptr != 0) {
+		if (key->both.offset & 1)
+			atomic_inc(&key->shared.inode->i_count);
+		else
+			atomic_inc(&key->private.mm->mm_count);
+	}
+}
+
+/*
+ * Drop a reference to the resource addressed by a key.
+ * The hash bucket spinlock must not be held.
+ */
+static inline void drop_key_refs(union futex_key *key)
+{
+	if (key->both.ptr != 0) {
+		if (key->both.offset & 1)
+			iput(key->shared.inode);
+		else
+			mmdrop(key->private.mm);
+	}
+}
+
+/*
+ * The hash bucket lock must be held when this is called.
+ * Afterwards, the futex_q must not be accessed.
+ */
+static inline void wake_futex(struct futex_q *q)
+{
+	list_del_init(&q->list);
+	if (q->filp)
+		send_sigio(&q->filp->f_owner, q->fd, POLL_IN);
+	/*
+	 * The lock in wake_up_all() is a crucial memory barrier after the
+	 * list_del_init() and also before assigning to q->lock_ptr.
+	 */
+	wake_up_all(&q->waiters);
+	/*
+	 * The waiting task can free the futex_q as soon as this is written,
+	 * without taking any locks.  This must come last.
+	 */
+	q->lock_ptr = 0;
+}
 
 /*
  * Wake up all waiters hashed on the physical page that is mapped
  * to this virtual address:
  */
-static int futex_wake(unsigned long uaddr, int num)
+static int futex_wake(unsigned long uaddr, int nr_wake)
 {
-	struct list_head *i, *next, *head;
-	struct futex_hash_bucket *bh;
 	union futex_key key;
+	struct futex_hash_bucket *bh;
+	struct list_head *head;
+	struct futex_q *this, *next;
 	int ret;
 
 	down_read(&current->mm->mmap_sem);
@@ -236,21 +299,15 @@
 	spin_lock(&bh->lock);
 	head = &bh->chain;
 
-	list_for_each_safe(i, next, head) {
-		struct futex_q *this = list_entry(i, struct futex_q, list);
-
+	list_for_each_entry_safe(this, next, head, list) {
 		if (match_futex (&this->key, &key)) {
-			list_del_init(i);
-			wake_up_all(&this->waiters);
-			if (this->filp)
-				send_sigio(&this->filp->f_owner, this->fd, POLL_IN);
-			ret++;
-			if (ret >= num)
+			wake_futex(this);
+			if (++ret >= nr_wake)
 				break;
 		}
 	}
-	spin_unlock(&bh->lock);
 
+	spin_unlock(&bh->lock);
 out:
 	up_read(&current->mm->mmap_sem);
 	return ret;
@@ -263,10 +320,11 @@
 static int futex_requeue(unsigned long uaddr1, unsigned long uaddr2,
 				int nr_wake, int nr_requeue)
 {
-	struct list_head *i, *next, *head1, *head2;
-	struct futex_hash_bucket *bh1, *bh2;
 	union futex_key key1, key2;
-	int ret;
+	struct futex_hash_bucket *bh1, *bh2;
+	struct list_head *head1;
+	struct futex_q *this, *next;
+	int ret, drop_count = 0;
 
 	down_read(&current->mm->mmap_sem);
 
@@ -279,78 +337,107 @@
 
 	bh1 = hash_futex(&key1);
 	bh2 = hash_futex(&key2);
-	if (bh1 < bh2) {
+
+	if (bh1 < bh2)
+		spin_lock(&bh1->lock);
+	spin_lock(&bh2->lock);
+	if (bh1 > bh2)
 		spin_lock(&bh1->lock);
-		spin_lock(&bh2->lock);
-	} else {
-		spin_lock(&bh2->lock);
-		if (bh1 > bh2)
-			spin_lock(&bh1->lock);
-	}
-	head1 = &bh1->chain;
-	head2 = &bh2->chain;
 
-	list_for_each_safe(i, next, head1) {
-		struct futex_q *this = list_entry(i, struct futex_q, list);
+	head1 = &bh1->chain;
+	list_for_each_entry_safe(this, next, head1, list) {
+		if (!match_futex (&this->key, &key1))
+			continue;
+		if (++ret <= nr_wake) {
+			wake_futex(this);
+		} else {
+			list_move_tail(&this->list, &bh2->chain);
+			this->lock_ptr = &bh2->lock;
+			this->key = key2;
+			get_key_refs(&key2);
+			drop_count++;
 
-		if (match_futex (&this->key, &key1)) {
-			list_del_init(i);
-			if (++ret <= nr_wake) {
-				wake_up_all(&this->waiters);
-				if (this->filp)
-					send_sigio(&this->filp->f_owner,
-							this->fd, POLL_IN);
-			} else {
-				list_add_tail(i, head2);
-				this->key = key2;
-				if (ret - nr_wake >= nr_requeue)
-					break;
-				/* Make sure to stop if key1 == key2 */
-				if (head1 == head2 && head1 != next)
-					head1 = i;
-			}
+			if (ret - nr_wake >= nr_requeue)
+				break;
+			/* Make sure to stop if key1 == key2 */
+			if (head1 == &bh2->chain && head1 != &next->list)
+				head1 = &this->list;
 		}
 	}
-	if (bh1 < bh2) {
-		spin_unlock(&bh2->lock);
-		spin_unlock(&bh1->lock);
-	} else {
-		if (bh1 > bh2)
-			spin_unlock(&bh1->lock);
+
+	spin_unlock(&bh1->lock);
+	if (bh1 != bh2)
 		spin_unlock(&bh2->lock);
-	}
+
+	/* drop_key_refs() must be called outside the spinlocks. */
+	while (--drop_count >= 0)
+		drop_key_refs(&key1);
+
 out:
 	up_read(&current->mm->mmap_sem);
 	return ret;
 }
 
-static inline void queue_me(struct futex_q *q, union futex_key *key,
-			    int fd, struct file *filp)
+/*
+ * queue_me and unqueue_me must be called as a pair, each
+ * exactly once.  They are called with the hashed spinlock held.
+ */
+
+/* The key must be already stored in q->key. */
+static inline void queue_me(struct futex_q *q, int fd, struct file *filp)
 {
-	struct futex_hash_bucket *bh = hash_futex(key);
-	struct list_head *head = &bh->chain;
+	struct futex_hash_bucket *bh;
 
-	q->key = *key;
 	q->fd = fd;
 	q->filp = filp;
 
+	init_waitqueue_head(&q->waiters);
+
+	get_key_refs(&q->key);
+	bh = hash_futex(&q->key);
+	q->lock_ptr = &bh->lock;
+
 	spin_lock(&bh->lock);
-	list_add_tail(&q->list, head);
+	list_add_tail(&q->list, &bh->chain);
 	spin_unlock(&bh->lock);
 }
 
 /* Return 1 if we were still queued (ie. 0 means we were woken) */
-static inline int unqueue_me(struct futex_q *q)
+static int unqueue_me(struct futex_q *q)
 {
-	struct futex_hash_bucket *bh = hash_futex(&q->key);
 	int ret = 0;
+	spinlock_t *lock_ptr;
 
-	spin_lock(&bh->lock);
-	if (!list_empty(&q->list)) {
-		list_del(&q->list);
-		ret = 1;
+	/* In the common case we don't take the spinlock, which is nice. */
+ retry:
+	lock_ptr = q->lock_ptr;
+	if (lock_ptr != 0) {
+		spin_lock(lock_ptr);
+		/*
+		 * q->lock_ptr can change between reading it and
+		 * spin_lock(), causing us to take the wrong lock.  This
+		 * corrects the race condition.
+		 *
+		 * Reasoning goes like this: if we have the wrong lock,
+		 * q->lock_ptr must have changed (maybe several times)
+		 * between reading it and the spin_lock().  It can
+		 * change again after the spin_lock() but only if it was
+		 * already changed before the spin_lock().  It cannot,
+		 * however, change back to the original value.  Therefore
+		 * we can detect whether we acquired the correct lock.
+		 */
+		if (unlikely(lock_ptr != q->lock_ptr)) {
+			spin_unlock(lock_ptr);
+			goto retry;
+		}
+		if (likely(!list_empty(&q->list))) {
+			list_del(&q->list);
+			ret = 1;
+		}
+		spin_unlock(lock_ptr);
 	}
-	spin_unlock(&bh->lock);
+
+	drop_key_refs(&q->key);
 	return ret;
 }
 
@@ -358,19 +445,15 @@
 {
 	DECLARE_WAITQUEUE(wait, current);
 	int ret, curval;
-	union futex_key key;
 	struct futex_q q;
-	struct futex_hash_bucket *bh = NULL;
-
-	init_waitqueue_head(&q.waiters);
 
 	down_read(&current->mm->mmap_sem);
 
-	ret = get_futex_key(uaddr, &key);
+	ret = get_futex_key(uaddr, &q.key);
 	if (unlikely(ret != 0))
 		goto out_release_sem;
 
-	queue_me(&q, &key, -1, NULL);
+	queue_me(&q, -1, NULL);
 
 	/*
 	 * Access the page after the futex is queued.
@@ -400,23 +483,17 @@
 	 * rely on the futex_wake() code removing us from hash when it
 	 * wakes us up.
 	 */
-	add_wait_queue(&q.waiters, &wait);
-	bh = hash_futex(&key);
-	spin_lock(&bh->lock);
-	set_current_state(TASK_INTERRUPTIBLE);
-
-	if (unlikely(list_empty(&q.list))) {
-		/*
-		 * We were woken already.
-		 */
-		spin_unlock(&bh->lock);
-		set_current_state(TASK_RUNNING);
-		return 0;
-	}
 
-	spin_unlock(&bh->lock);
-	time = schedule_timeout(time);
-	set_current_state(TASK_RUNNING);
+	/* add_wait_queue is the barrier after __set_current_state. */
+	__set_current_state(TASK_INTERRUPTIBLE);
+	add_wait_queue(&q.waiters, &wait);
+	/*
+	 * !list_empty() is safe here without any lock.
+	 * q.lock_ptr != 0 is not safe, because of ordering against wakeup.
+	 */
+	if (likely(!list_empty(&q.list)))
+		time = schedule_timeout(time);
+	__set_current_state(TASK_RUNNING);
 
 	/*
 	 * NOTE: we don't remove ourselves from the waitqueue because
@@ -446,7 +523,7 @@
 	struct futex_q *q = filp->private_data;
 
 	unqueue_me(q);
-	kfree(filp->private_data);
+	kfree(q);
 	return 0;
 }
 
@@ -455,14 +532,16 @@
 			       struct poll_table_struct *wait)
 {
 	struct futex_q *q = filp->private_data;
-	struct futex_hash_bucket *bh = hash_futex(&q->key);
 	int ret = 0;
 
 	poll_wait(filp, &q->waiters, wait);
-	spin_lock(&bh->lock);
+
+	/*
+	 * list_empty() is safe here without any lock.
+	 * q->lock_ptr != 0 is not safe, because of ordering against wakeup.
+	 */
 	if (list_empty(&q->list))
 		ret = POLLIN | POLLRDNORM;
-	spin_unlock(&bh->lock);
 
 	return ret;
 }
@@ -472,12 +551,13 @@
 	.poll		= futex_poll,
 };
 
-/* Signal allows caller to avoid the race which would occur if they
-   set the sigio stuff up afterwards. */
+/*
+ * Signal allows caller to avoid the race which would occur if they
+ * set the sigio stuff up afterwards.
+ */
 static int futex_fd(unsigned long uaddr, int signal)
 {
 	struct futex_q *q;
-	union futex_key key;
 	struct file *filp;
 	int ret, err;
 
@@ -500,7 +580,7 @@
 
 	if (signal) {
 		int err;
-		err = f_setown(filp, current->tgid, 1);
+		err = f_setown(filp, current->pid, 1);
 		if (err < 0) {
 			put_unused_fd(ret);
 			put_filp(filp);
@@ -519,20 +599,24 @@
 	}
 
 	down_read(&current->mm->mmap_sem);
-	err = get_futex_key(uaddr, &key);
-	up_read(&current->mm->mmap_sem);
+	err = get_futex_key(uaddr, &q->key);
 
 	if (unlikely(err != 0)) {
+		up_read(&current->mm->mmap_sem);
 		put_unused_fd(ret);
 		put_filp(filp);
 		kfree(q);
 		return err;
 	}
 
-	init_waitqueue_head(&q->waiters);
+	/*
+	 * queue_me() must be called before releasing mmap_sem, because
+	 * key->shared.inode needs to be referenced while holding it.
+	 */
 	filp->private_data = q;
 
-	queue_me(q, &key, ret, filp);
+	queue_me(q, ret, filp);
+	up_read(&current->mm->mmap_sem);
 
 	/* Now we map fd to filp, so userspace can access it */
 	fd_install(ret, filp);
diff -Nru a/kernel/module.c b/kernel/module.c
--- a/kernel/module.c	Wed Oct 15 00:46:37 2003
+++ b/kernel/module.c	Wed Oct 15 00:46:37 2003
@@ -485,6 +485,7 @@
 	set_cpus_allowed(current, cpumask_of_cpu((int)(long)cpu));
 
 	/* Ack: we are alive */
+	mb(); /* Theoretically the ack = 0 might not be on this CPU yet. */
 	atomic_inc(&stopref_thread_ack);
 
 	/* Simple state machine */
@@ -493,11 +494,13 @@
 			local_irq_disable();
 			irqs_disabled = 1;
 			/* Ack: irqs disabled. */
+			mb(); /* Must read state first. */
 			atomic_inc(&stopref_thread_ack);
 		} else if (stopref_state == STOPREF_PREPARE && !prepared) {
 			/* Everyone is in place, hold CPU. */
 			preempt_disable();
 			prepared = 1;
+			mb(); /* Must read state first. */
 			atomic_inc(&stopref_thread_ack);
 		}
 		if (irqs_disabled || prepared)
@@ -507,6 +510,7 @@
 	}
 
 	/* Ack: we are exiting. */
+	mb(); /* Must read state first. */
 	atomic_inc(&stopref_thread_ack);
 
 	if (irqs_disabled)
diff -Nru a/kernel/pid.c b/kernel/pid.c
--- a/kernel/pid.c	Wed Oct 15 00:46:37 2003
+++ b/kernel/pid.c	Wed Oct 15 00:46:37 2003
@@ -253,14 +253,14 @@
 
 	attach_pid(thread, PIDTYPE_PID, thread->pid);
 	attach_pid(thread, PIDTYPE_TGID, thread->tgid);
-	attach_pid(thread, PIDTYPE_PGID, thread->signal->pgrp);
-	attach_pid(thread, PIDTYPE_SID, thread->signal->session);
+	attach_pid(thread, PIDTYPE_PGID, leader->__pgrp);
+	attach_pid(thread, PIDTYPE_SID, thread->session);
 	list_add_tail(&thread->tasks, &init_task.tasks);
 
 	attach_pid(leader, PIDTYPE_PID, leader->pid);
 	attach_pid(leader, PIDTYPE_TGID, leader->tgid);
-	attach_pid(leader, PIDTYPE_PGID, leader->signal->pgrp);
-	attach_pid(leader, PIDTYPE_SID, leader->signal->session);
+	attach_pid(leader, PIDTYPE_PGID, leader->__pgrp);
+	attach_pid(leader, PIDTYPE_SID, leader->session);
 }
 
 /*
diff -Nru a/kernel/power/disk.c b/kernel/power/disk.c
--- a/kernel/power/disk.c	Wed Oct 15 00:46:35 2003
+++ b/kernel/power/disk.c	Wed Oct 15 00:46:35 2003
@@ -4,7 +4,7 @@
  * Copyright (c) 2003 Patrick Mochel
  * Copyright (c) 2003 Open Source Development Lab
  *
- * This file is release under the GPLv2
+ * This file is released under the GPLv2.
  *
  */
 
diff -Nru a/kernel/power/pmdisk.c b/kernel/power/pmdisk.c
--- a/kernel/power/pmdisk.c	Wed Oct 15 00:46:37 2003
+++ b/kernel/power/pmdisk.c	Wed Oct 15 00:46:37 2003
@@ -448,7 +448,7 @@
 
 
 /**
- *	copy_pages - Atmoically snapshot memory.
+ *	copy_pages - Atomically snapshot memory.
  *
  *	Iterate over all the pages in the system and copy each one 
  *	into its corresponding location in the pagedir.
diff -Nru a/kernel/power/swsusp.c b/kernel/power/swsusp.c
--- a/kernel/power/swsusp.c	Wed Oct 15 00:46:36 2003
+++ b/kernel/power/swsusp.c	Wed Oct 15 00:46:36 2003
@@ -5,7 +5,9 @@
  * machine suspend feature using pretty near only high-level routines
  *
  * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu>
- * Copyright (C) 1998,2001,2002 Pavel Machek <pavel@suse.cz>
+ * Copyright (C) 1998,2001-2003 Pavel Machek <pavel@suse.cz>
+ *
+ * This file is released under the GPLv2.
  *
  * I'd like to thank the following people for their work:
  * 
@@ -273,6 +275,17 @@
 	swap_list_unlock();
 }
 
+/**
+ *    write_suspend_image - Write entire image to disk.
+ *
+ *    After writing suspend signature to the disk, suspend may no
+ *    longer fail: we have ready-to-run image in swap, and rollback
+ *    would happen on next reboot -- corrupting data.
+ *
+ *    Note: The buffer we allocate to use to write the suspend header is
+ *    not freed; its not needed since system is going down anyway
+ *    (plus it causes oops and I'm lazy^H^H^H^Htoo busy).
+ */
 static int write_suspend_image(void)
 {
 	int i;
@@ -282,6 +295,9 @@
 	unsigned long address;
 	struct page *page;
 
+	if (!buffer)
+		return -ENOMEM;
+
 	printk( "Writing data to swap (%d pages): ", nr_copy_pages );
 	for (i=0; i<nr_copy_pages; i++) {
 		if (!(i%100))
@@ -344,7 +360,6 @@
 	printk( "|\n" );
 
 	MDELAY(1000);
-	free_page((unsigned long) buffer);
 	return 0;
 }
 
@@ -681,7 +696,10 @@
 
 static void do_software_suspend(void)
 {
-	arch_prepare_suspend();
+	if (arch_prepare_suspend()) {
+		printk("%sArchitecture failed to prepare\n", name_suspend);
+		return;
+	}		
 	if (pm_prepare_console())
 		printk( "%sCan't allocate a console... proceeding\n", name_suspend);
 	if (!prepare_suspend_processes()) {
@@ -1031,28 +1049,34 @@
 	return error;
 }
 
-/*
- * Called from init kernel_thread.
- * We check if we have an image and if so we try to resume
+/**
+ *	software_resume - Resume from a saved image.
+ *
+ *	Called as a late_initcall (so all devices are discovered and 
+ *	initialized), we call swsusp to see if we have a saved image or not.
+ *	If so, we quiesce devices, then restore the saved image. We will 
+ *	return above (in pm_suspend_disk() ) if everything goes well. 
+ *	Otherwise, we fail gracefully and return to the normally 
+ *	scheduled program.
+ *
  */
-
-void software_resume(void)
+static int __init software_resume(void)
 {
 	if (num_online_cpus() > 1) {
 		printk(KERN_WARNING "Software Suspend has malfunctioning SMP support. Disabled :(\n");	
-		return;
+		return -EINVAL;
 	}
 	/* We enable the possibility of machine suspend */
 	software_suspend_enabled = 1;
 	if (!resume_status)
-		return;
+		return 0;
 
 	printk( "%s", name_resume );
 	if (resume_status == NORESUME) {
 		if(resume_file[0])
 			read_suspend_image(resume_file, 1);
 		printk( "disabled\n" );
-		return;
+		return 0;
 	}
 	MDELAY(1000);
 
@@ -1061,7 +1085,7 @@
 
 	if (!resume_file[0] && resume_status == RESUME_SPECIFIED) {
 		printk( "suspension device unspecified\n" );
-		return;
+		return -EINVAL;
 	}
 
 	printk( "resuming from %s\n", resume_file);
@@ -1072,8 +1096,10 @@
 
 read_failure:
 	pm_restore_console();
-	return;
+	return 0;
 }
+
+late_initcall(software_resume);
 
 static int __init resume_setup(char *str)
 {
diff -Nru a/kernel/resource.c b/kernel/resource.c
--- a/kernel/resource.c	Wed Oct 15 00:46:37 2003
+++ b/kernel/resource.c	Wed Oct 15 00:46:37 2003
@@ -279,6 +279,67 @@
 
 EXPORT_SYMBOL(allocate_resource);
 
+/**
+ * insert_resource - Inserts a resource in the resource tree
+ * @parent: parent of the new resource
+ * @new: new resource to insert
+ *
+ * Returns 0 on success, -EBUSY if the resource can't be inserted.
+ *
+ * This function is equivalent of request_resource when no
+ * conflict happens. If a conflict happens, and the conflicting
+ * resources entirely fit within the range of the new resource,
+ * then the new resource is inserted and the conflicting resources
+ * become childs of the new resource. 
+ */
+int insert_resource(struct resource *parent, struct resource *new)
+{
+	int result = 0;
+	struct resource *first, *next;
+
+	write_lock(&resource_lock);
+	first = __request_resource(parent, new);
+	if (!first)
+		goto out;
+
+	result = -EBUSY;
+	if (first == parent)
+		goto out;
+
+	for (next = first; next->sibling; next = next->sibling)
+		if (next->sibling->start > new->end)
+			break;
+
+	/* existing resource overlaps end of new resource */
+	if (next->end > new->end)
+		goto out;
+
+	result = 0;
+
+	new->parent = parent;
+	new->sibling = next->sibling;
+	new->child = first;
+
+	next->sibling = NULL;
+	for (next = first; next; next = next->sibling)
+		next->parent = new;
+
+	if (parent->child == first) {
+		parent->child = new;
+	} else {
+		next = parent->child;
+		while (next->sibling != first)
+			next = next->sibling;
+		next->sibling = new;
+	}
+
+ out:
+	write_unlock(&resource_lock);
+	return result;
+}
+
+EXPORT_SYMBOL(insert_resource);
+
 /*
  * This is compatibility stuff for IO resources.
  *
diff -Nru a/kernel/signal.c b/kernel/signal.c
--- a/kernel/signal.c	Wed Oct 15 00:46:36 2003
+++ b/kernel/signal.c	Wed Oct 15 00:46:36 2003
@@ -593,8 +593,7 @@
 	error = -EPERM;
 	if ((!info || ((unsigned long)info != 1 &&
 			(unsigned long)info != 2 && SI_FROMUSER(info)))
-	    && ((sig != SIGCONT) ||
-		(process_session(current) != process_session(t)))
+	    && ((sig != SIGCONT) || (current->session != t->session))
 	    && (current->euid ^ t->suid) && (current->euid ^ t->uid)
 	    && (current->uid ^ t->suid) && (current->uid ^ t->uid)
 	    && !capable(CAP_KILL))
@@ -1103,7 +1102,7 @@
 	retval = -ESRCH;
 	read_lock(&tasklist_lock);
 	for_each_task_pid(sid, PIDTYPE_SID, p, l, pid) {
-		if (!process_session_leader(p))
+		if (!p->leader)
 			continue;
 		err = group_send_sig_info(sig, info, p);
 		if (retval)
diff -Nru a/kernel/sys.c b/kernel/sys.c
--- a/kernel/sys.c	Wed Oct 15 00:46:35 2003
+++ b/kernel/sys.c	Wed Oct 15 00:46:35 2003
@@ -969,7 +969,7 @@
 
 	if (p->parent == current || p->real_parent == current) {
 		err = -EPERM;
-		if (process_session(p) != process_session(current))
+		if (p->session != current->session)
 			goto out;
 		err = -EACCES;
 		if (p->did_exec)
@@ -981,7 +981,7 @@
 	}
 
 	err = -EPERM;
-	if (process_session_leader(p))
+	if (p->leader)
 		goto out;
 
 	if (pgid != pid) {
@@ -990,7 +990,7 @@
 		struct list_head *l;
 
 		for_each_task_pid(pgid, PIDTYPE_PGID, p, l, pid)
-			if (process_session(p) == process_session(current))
+			if (p->session == current->session)
 				goto ok_pgid;
 		goto out;
 	}
@@ -1002,7 +1002,7 @@
 
 	if (process_group(p) != pgid) {
 		detach_pid(p, PIDTYPE_PGID);
-		p->signal->pgrp = pgid;
+		p->group_leader->__pgrp = pgid;
 		attach_pid(p, PIDTYPE_PGID, pgid);
 	}
 
@@ -1044,7 +1044,7 @@
 asmlinkage long sys_getsid(pid_t pid)
 {
 	if (!pid) {
-		return process_session(current);
+		return current->session;
 	} else {
 		int retval;
 		struct task_struct *p;
@@ -1056,7 +1056,7 @@
 		if(p) {
 			retval = security_task_getsid(p);
 			if (!retval)
-				retval = process_session(p);
+				retval = p->session;
 		}
 		read_unlock(&tasklist_lock);
 		return retval;
@@ -1077,10 +1077,10 @@
 	if (pid)
 		goto out;
 
-	current->signal->leader = 1;
+	current->leader = 1;
 	__set_special_pids(current->pid, current->pid);
-	current->signal->tty = NULL;
-	current->signal->tty_old_pgrp = 0;
+	current->tty = NULL;
+	current->tty_old_pgrp = 0;
 	err = process_group(current);
 out:
 	write_unlock_irq(&tasklist_lock);
diff -Nru a/kernel/timer.c b/kernel/timer.c
--- a/kernel/timer.c	Wed Oct 15 00:46:37 2003
+++ b/kernel/timer.c	Wed Oct 15 00:46:37 2003
@@ -418,8 +418,9 @@
  			data = timer->data;
 
 			list_del(&timer->entry);
-			timer->base = NULL;
 			set_running_timer(base, timer);
+			smp_wmb();
+			timer->base = NULL;
 			spin_unlock_irq(&base->lock);
 			fn(data);
 			spin_lock_irq(&base->lock);
diff -Nru a/lib/kobject.c b/lib/kobject.c
--- a/lib/kobject.c	Wed Oct 15 00:46:37 2003
+++ b/lib/kobject.c	Wed Oct 15 00:46:37 2003
@@ -331,6 +331,7 @@
 	int limit = KOBJ_NAME_LEN;
 	int need;
 	va_list args;
+	char * name;
 
 	va_start(args,fmt);
 	/* 
@@ -338,25 +339,33 @@
 	 */
 	need = vsnprintf(kobj->name,limit,fmt,args);
 	if (need < limit) 
-		kobj->k_name = kobj->name;
+		name = kobj->name;
 	else {
 		/* 
 		 * Need more space? Allocate it and try again 
 		 */
-		kobj->k_name = kmalloc(need,GFP_KERNEL);
-		if (!kobj->k_name) {
+		name = kmalloc(need,GFP_KERNEL);
+		if (!name) {
 			error = -ENOMEM;
 			goto Done;
 		}
 		limit = need;
-		need = vsnprintf(kobj->k_name,limit,fmt,args);
+		need = vsnprintf(name,limit,fmt,args);
 
 		/* Still? Give up. */
 		if (need > limit) {
-			kfree(kobj->k_name);
+			kfree(name);
 			error = -EFAULT;
+			goto Done;
 		}
 	}
+
+	/* Free the old name, if necessary. */
+	if (kobj->k_name && kobj->k_name != kobj->name)
+		kfree(kobj->k_name);
+
+	/* Now, set the new name */
+	kobj->k_name = name;
  Done:
 	va_end(args);
 	return error;
@@ -627,6 +636,8 @@
 EXPORT_SYMBOL(kobject_get);
 EXPORT_SYMBOL(kobject_put);
 
+EXPORT_SYMBOL(kset_register);
+EXPORT_SYMBOL(kset_unregister);
 EXPORT_SYMBOL(kset_find_obj);
 
 EXPORT_SYMBOL(subsystem_init);
diff -Nru a/mm/mlock.c b/mm/mlock.c
--- a/mm/mlock.c	Wed Oct 15 00:46:35 2003
+++ b/mm/mlock.c	Wed Oct 15 00:46:35 2003
@@ -154,9 +154,9 @@
 		newflags = vma->vm_flags | VM_LOCKED;
 		if (!(flags & MCL_CURRENT))
 			newflags &= ~VM_LOCKED;
-		error = mlock_fixup(vma, vma->vm_start, vma->vm_end, newflags);
-		if (error)
-			break;
+
+		/* Ignore errors */
+		mlock_fixup(vma, vma->vm_start, vma->vm_end, newflags);
 	}
 	return error;
 }
diff -Nru a/mm/page-writeback.c b/mm/page-writeback.c
--- a/mm/page-writeback.c	Wed Oct 15 00:46:37 2003
+++ b/mm/page-writeback.c	Wed Oct 15 00:46:37 2003
@@ -549,6 +549,7 @@
 	unlock_page(page);
 	return ret;
 }
+EXPORT_SYMBOL(set_page_dirty_lock);
 
 /*
  * Clear a page's dirty flag, while caring for dirty memory accounting. 
diff -Nru a/mm/slab.c b/mm/slab.c
--- a/mm/slab.c	Wed Oct 15 00:46:37 2003
+++ b/mm/slab.c	Wed Oct 15 00:46:37 2003
@@ -862,7 +862,7 @@
 		unsigned long *sptr = &caller;
 		unsigned long svalue;
 
-		while (((long) sptr & (THREAD_SIZE-1)) != 0) {
+		while (!kstack_end(sptr)) {
 			svalue = *sptr++;
 			if (kernel_text_address(svalue)) {
 				*addr++=svalue;
diff -Nru a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
--- a/net/8021q/vlan_dev.c	Wed Oct 15 00:46:37 2003
+++ b/net/8021q/vlan_dev.c	Wed Oct 15 00:46:37 2003
@@ -76,7 +76,7 @@
 	if (VLAN_DEV_INFO(skb->dev)->flags & 1) {
 		if (skb_shared(skb) || skb_cloned(skb)) {
 			struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC);
-			kfree(skb);
+			kfree_skb(skb);
 			skb = nskb;
 		}
 		if (skb) {
diff -Nru a/net/atm/clip.c b/net/atm/clip.c
--- a/net/atm/clip.c	Wed Oct 15 00:46:38 2003
+++ b/net/atm/clip.c	Wed Oct 15 00:46:38 2003
@@ -24,10 +24,8 @@
 #include <linux/if.h> /* for IFF_UP */
 #include <linux/inetdevice.h>
 #include <linux/bitops.h>
-#ifdef CONFIG_PROC_FS
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
-#endif
 #include <net/route.h> /* for struct rtable and routing */
 #include <net/icmp.h> /* icmp_send */
 #include <asm/param.h> /* for HZ */
diff -Nru a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig
--- a/net/bridge/netfilter/Kconfig	Wed Oct 15 00:46:36 2003
+++ b/net/bridge/netfilter/Kconfig	Wed Oct 15 00:46:36 2003
@@ -55,6 +55,16 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config BRIDGE_EBT_AMONG
+	tristate "ebt: among filter support"
+	depends on BRIDGE_NF_EBTABLES
+	help
+	  This option adds the among match, which allows matching the MAC source
+	  and/or destination address on a list of addresses. Optionally,
+	  MAC/IP address pairs can be matched, f.e. for anti-spoofing rules.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config BRIDGE_EBT_ARP
 	tristate "ebt: ARP filter support"
 	depends on BRIDGE_NF_EBTABLES
diff -Nru a/net/bridge/netfilter/Makefile b/net/bridge/netfilter/Makefile
--- a/net/bridge/netfilter/Makefile	Wed Oct 15 00:46:37 2003
+++ b/net/bridge/netfilter/Makefile	Wed Oct 15 00:46:37 2003
@@ -11,6 +11,7 @@
 
 #matches
 obj-$(CONFIG_BRIDGE_EBT_802_3) += ebt_802_3.o
+obj-$(CONFIG_BRIDGE_EBT_AMONG) += ebt_among.o
 obj-$(CONFIG_BRIDGE_EBT_ARP) += ebt_arp.o
 obj-$(CONFIG_BRIDGE_EBT_IP) += ebt_ip.o
 obj-$(CONFIG_BRIDGE_EBT_LIMIT) += ebt_limit.o
diff -Nru a/net/bridge/netfilter/ebt_among.c b/net/bridge/netfilter/ebt_among.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/bridge/netfilter/ebt_among.c	Wed Oct 15 00:46:38 2003
@@ -0,0 +1,215 @@
+/*
+ *  ebt_among
+ *
+ *	Authors:
+ *	Grzegorz Borowiak <grzes@gnu.univ.gda.pl>
+ *
+ *  August, 2003
+ *
+ */
+
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_among.h>
+#include <linux/ip.h>
+#include <linux/if_arp.h>
+#include <linux/module.h>
+
+static int ebt_mac_wormhash_contains(const struct ebt_mac_wormhash *wh,
+				     const char *mac, uint32_t ip)
+{
+	/* You may be puzzled as to how this code works.
+	 * Some tricks were used, refer to 
+	 * 	include/linux/netfilter_bridge/ebt_among.h
+	 * as there you can find a solution of this mystery.
+	 */
+	const struct ebt_mac_wormhash_tuple *p;
+	int start, limit, i;
+	uint32_t cmp[2] = { 0, 0 };
+	int key = (const unsigned char) mac[5];
+
+	memcpy(((char *) cmp) + 2, mac, 6);
+	start = wh->table[key];
+	limit = wh->table[key + 1];
+	if (ip) {
+		for (i = start; i < limit; i++) {
+			p = &wh->pool[i];
+			if (cmp[1] == p->cmp[1] && cmp[0] == p->cmp[0]) {
+				if (p->ip == 0 || p->ip == ip) {
+					return 1;
+				}
+			}
+		}
+	} else {
+		for (i = start; i < limit; i++) {
+			p = &wh->pool[i];
+			if (cmp[1] == p->cmp[1] && cmp[0] == p->cmp[0]) {
+				if (p->ip == 0) {
+					return 1;
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+static int ebt_mac_wormhash_check_integrity(const struct ebt_mac_wormhash
+					    *wh)
+{
+	int i;
+
+	for (i = 0; i < 256; i++) {
+		if (wh->table[i] > wh->table[i + 1])
+			return -0x100 - i;
+		if (wh->table[i] < 0)
+			return -0x200 - i;
+		if (wh->table[i] > wh->poolsize)
+			return -0x300 - i;
+	}
+	if (wh->table[256] > wh->poolsize)
+		return -0xc00;
+	return 0;
+}
+
+static int get_ip_dst(const struct sk_buff *skb, uint32_t *addr)
+{
+	if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_IP)) {
+		struct iphdr iph;
+
+		if (skb_copy_bits(skb, 0, &iph, sizeof(iph)))
+			return -1;
+		*addr = iph.daddr;
+	} else if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) {
+		struct arphdr arph;
+
+		if (skb_copy_bits(skb, 0, &arph, sizeof(arph)) ||
+		    arph.ar_pln != sizeof(uint32_t) || arph.ar_hln != ETH_ALEN)
+			return -1;
+		if (skb_copy_bits(skb, sizeof(struct arphdr) +
+		    2 * ETH_ALEN + sizeof(uint32_t), addr, sizeof(uint32_t)))
+			return -1;
+	}
+	return 0;
+}
+
+static int get_ip_src(const struct sk_buff *skb, uint32_t *addr)
+{
+	if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_IP)) {
+		struct iphdr iph;
+
+		if (skb_copy_bits(skb, 0, &iph, sizeof(iph)))
+			return -1;
+		*addr = iph.saddr;
+	} else if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) {
+		struct arphdr arph;
+
+		if (skb_copy_bits(skb, 0, &arph, sizeof(arph)) ||
+		    arph.ar_pln != sizeof(uint32_t) || arph.ar_hln != ETH_ALEN)
+			return -1;
+		if (skb_copy_bits(skb, sizeof(struct arphdr) +
+		    ETH_ALEN, addr, sizeof(uint32_t)))
+			return -1;
+	}
+	return 0;
+}
+
+static int ebt_filter_among(const struct sk_buff *skb,
+			    const struct net_device *in,
+			    const struct net_device *out, const void *data,
+			    unsigned int datalen)
+{
+	struct ebt_among_info *info = (struct ebt_among_info *) data;
+	const char *dmac, *smac;
+	const struct ebt_mac_wormhash *wh_dst, *wh_src;
+	uint32_t dip = 0, sip = 0;
+
+	wh_dst = ebt_among_wh_dst(info);
+	wh_src = ebt_among_wh_src(info);
+
+	if (wh_src) {
+		smac = skb->mac.ethernet->h_source;
+		if (get_ip_src(skb, &sip))
+			return EBT_NOMATCH;
+		if (!(info->bitmask & EBT_AMONG_SRC_NEG)) {
+			/* we match only if it contains */
+			if (!ebt_mac_wormhash_contains(wh_src, smac, sip))
+				return EBT_NOMATCH;
+		} else {
+			/* we match only if it DOES NOT contain */
+			if (ebt_mac_wormhash_contains(wh_src, smac, sip))
+				return EBT_NOMATCH;
+		}
+	}
+
+	if (wh_dst) {
+		dmac = skb->mac.ethernet->h_dest;
+		if (get_ip_dst(skb, &dip))
+			return EBT_NOMATCH;
+		if (!(info->bitmask & EBT_AMONG_DST_NEG)) {
+			/* we match only if it contains */
+			if (!ebt_mac_wormhash_contains(wh_dst, dmac, dip))
+				return EBT_NOMATCH;
+		} else {
+			/* we match only if it DOES NOT contain */
+			if (ebt_mac_wormhash_contains(wh_dst, dmac, dip))
+				return EBT_NOMATCH;
+		}
+	}
+
+	return EBT_MATCH;
+}
+
+static int ebt_among_check(const char *tablename, unsigned int hookmask,
+			   const struct ebt_entry *e, void *data,
+			   unsigned int datalen)
+{
+	struct ebt_among_info *info = (struct ebt_among_info *) data;
+	int expected_length = sizeof(struct ebt_among_info);
+	const struct ebt_mac_wormhash *wh_dst, *wh_src;
+	int err;
+
+	wh_dst = ebt_among_wh_dst(info);
+	wh_src = ebt_among_wh_src(info);
+	expected_length += ebt_mac_wormhash_size(wh_dst);
+	expected_length += ebt_mac_wormhash_size(wh_src);
+
+	if (datalen != EBT_ALIGN(expected_length)) {
+		printk(KERN_WARNING
+		       "ebtables: among: wrong size: %d"
+		       "against expected %d, rounded to %d\n",
+		       datalen, expected_length,
+		       EBT_ALIGN(expected_length));
+		return -EINVAL;
+	}
+	if (wh_dst && (err = ebt_mac_wormhash_check_integrity(wh_dst))) {
+		printk(KERN_WARNING
+		       "ebtables: among: dst integrity fail: %x\n", -err);
+		return -EINVAL;
+	}
+	if (wh_src && (err = ebt_mac_wormhash_check_integrity(wh_src))) {
+		printk(KERN_WARNING
+		       "ebtables: among: src integrity fail: %x\n", -err);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static struct ebt_match filter_among = {
+	.name		= EBT_AMONG_MATCH, 
+	.match		= ebt_filter_among, 
+	.check		= ebt_among_check,
+	.me		= THIS_MODULE,
+};
+
+static int __init init(void)
+{
+	return ebt_register_match(&filter_among);
+}
+
+static void __exit fini(void)
+{
+	ebt_unregister_match(&filter_among);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff -Nru a/net/core/ethtool.c b/net/core/ethtool.c
--- a/net/core/ethtool.c	Wed Oct 15 00:46:36 2003
+++ b/net/core/ethtool.c	Wed Oct 15 00:46:36 2003
@@ -122,7 +122,8 @@
 		info.n_stats = ops->get_stats_count(dev);
 	if (ops->get_regs_len)
 		info.regdump_len = ops->get_regs_len(dev);
-	/* XXX: eeprom? */
+	if (ops->get_eeprom_len)
+		info.eedump_len = ops->get_eeprom_len(dev);
 
 	if (copy_to_user(useraddr, &info, sizeof(info)))
 		return -EFAULT;
@@ -245,29 +246,34 @@
 static int ethtool_get_eeprom(struct net_device *dev, void *useraddr)
 {
 	struct ethtool_eeprom eeprom;
+	struct ethtool_ops *ops = dev->ethtool_ops;
 	u8 *data;
-	int len, ret;
+	int ret;
 
-	if (!dev->ethtool_ops->get_eeprom)
+	if (!ops->get_eeprom || !ops->get_eeprom_len)
 		return -EOPNOTSUPP;
 
 	if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
 		return -EFAULT;
 
-	len = eeprom.len;
 	/* Check for wrap and zero */
-	if (eeprom.offset + len <= eeprom.offset)
+	if (eeprom.offset + eeprom.len <= eeprom.offset)
+		return -EINVAL;
+
+	/* Check for exceeding total eeprom len */
+	if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev))
 		return -EINVAL;
 
-	data = kmalloc(len, GFP_USER);
+	data = kmalloc(eeprom.len, GFP_USER);
 	if (!data)
 		return -ENOMEM;
 
-	if (copy_from_user(data, useraddr + sizeof(eeprom), len))
-		return -EFAULT;
+	ret = -EFAULT;
+	if (copy_from_user(data, useraddr + sizeof(eeprom), eeprom.len))
+		goto out;
 
-	ret = dev->ethtool_ops->get_eeprom(dev, &eeprom, data);
-	if (!ret)
+	ret = ops->get_eeprom(dev, &eeprom, data);
+	if (ret)
 		goto out;
 
 	ret = -EFAULT;
@@ -285,32 +291,37 @@
 static int ethtool_set_eeprom(struct net_device *dev, void *useraddr)
 {
 	struct ethtool_eeprom eeprom;
+	struct ethtool_ops *ops = dev->ethtool_ops;
 	u8 *data;
-	int len, ret;
+	int ret;
 
-	if (!dev->ethtool_ops->set_eeprom)
+	if (!ops->set_eeprom || !ops->get_eeprom_len)
 		return -EOPNOTSUPP;
 
 	if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
 		return -EFAULT;
 
-	len = eeprom.len;
 	/* Check for wrap and zero */
-	if (eeprom.offset + len <= eeprom.offset)
+	if (eeprom.offset + eeprom.len <= eeprom.offset)
+		return -EINVAL;
+
+	/* Check for exceeding total eeprom len */
+	if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev))
 		return -EINVAL;
 
-	data = kmalloc(len, GFP_USER);
+	data = kmalloc(eeprom.len, GFP_USER);
 	if (!data)
 		return -ENOMEM;
 
-	if (copy_from_user(data, useraddr + sizeof(eeprom), len))
-		return -EFAULT;
+	ret = -EFAULT;
+	if (copy_from_user(data, useraddr + sizeof(eeprom), eeprom.len))
+		goto out;
 
-	ret = dev->ethtool_ops->set_eeprom(dev, &eeprom, data);
+	ret = ops->set_eeprom(dev, &eeprom, data);
 	if (ret)
 		goto out;
 
-	if (copy_to_user(useraddr + sizeof(eeprom), data, len))
+	if (copy_to_user(useraddr + sizeof(eeprom), data, eeprom.len))
 		ret = -EFAULT;
 
  out:
diff -Nru a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
--- a/net/ipv4/ip_output.c	Wed Oct 15 00:46:38 2003
+++ b/net/ipv4/ip_output.c	Wed Oct 15 00:46:38 2003
@@ -412,6 +412,7 @@
 #endif
 #ifdef CONFIG_NETFILTER
 	to->nfmark = from->nfmark;
+	to->nfcache = from->nfcache;
 	/* Connection association is same as pre-frag packet */
 	to->nfct = from->nfct;
 	nf_conntrack_get(to->nfct);
diff -Nru a/net/ipv4/ipip.c b/net/ipv4/ipip.c
--- a/net/ipv4/ipip.c	Wed Oct 15 00:46:38 2003
+++ b/net/ipv4/ipip.c	Wed Oct 15 00:46:38 2003
@@ -475,11 +475,6 @@
 		goto out;
 
 	iph = skb->nh.iph;
-	skb->mac.raw = skb->nh.raw;
-	skb->nh.raw = skb->data;
-	memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
-	skb->protocol = htons(ETH_P_IP);
-	skb->pkt_type = PACKET_HOST;
 
 	read_lock(&ipip_lock);
 	if ((tunnel = ipip_tunnel_lookup(iph->saddr, iph->daddr)) != NULL) {
@@ -487,6 +482,12 @@
 			kfree_skb(skb);
 			return 0;
 		}
+
+		skb->mac.raw = skb->nh.raw;
+		skb->nh.raw = skb->data;
+		memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
+		skb->protocol = htons(ETH_P_IP);
+		skb->pkt_type = PACKET_HOST;
 
 		tunnel->stat.rx_packets++;
 		tunnel->stat.rx_bytes += skb->len;
diff -Nru a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
--- a/net/ipv4/ipvs/ip_vs_core.c	Wed Oct 15 00:46:35 2003
+++ b/net/ipv4/ipvs/ip_vs_core.c	Wed Oct 15 00:46:35 2003
@@ -1044,7 +1044,7 @@
 	/* increase its packet counter and check if it is needed
 	   to be synchronized */
 	atomic_inc(&cp->in_pkts);
-	if (ip_vs_sync_state == IP_VS_STATE_MASTER &&
+	if ((ip_vs_sync_state & IP_VS_STATE_MASTER) &&
 	    (cp->protocol != IPPROTO_TCP ||
 	     cp->state == IP_VS_TCP_S_ESTABLISHED) &&
 	    (atomic_read(&cp->in_pkts) % sysctl_ip_vs_sync_threshold[1]
diff -Nru a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
--- a/net/ipv4/ipvs/ip_vs_ctl.c	Wed Oct 15 00:46:37 2003
+++ b/net/ipv4/ipvs/ip_vs_ctl.c	Wed Oct 15 00:46:37 2003
@@ -650,6 +650,15 @@
 }
 
 
+static void
+ip_vs_zero_stats(struct ip_vs_stats *stats)
+{
+	spin_lock_bh(&stats->lock);
+	memset(stats, 0, (char *)&stats->lock - (char *)stats);
+	spin_unlock_bh(&stats->lock);
+	ip_vs_zero_estimator(stats);
+}
+
 /*
  *	Update a destination in the given service
  */
@@ -689,6 +698,7 @@
 	} else {
 		if (dest->svc != svc) {
 			__ip_vs_unbind_svc(dest);
+			ip_vs_zero_stats(&dest->stats);
 			__ip_vs_bind_svc(dest, svc);
 		}
 	}
@@ -1276,7 +1286,7 @@
 	 * Flush the service table hashed by fwmark
 	 */
 	for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
-		list_for_each_entry_safe(svc, nxt, 
+		list_for_each_entry_safe(svc, nxt,
 					 &ip_vs_svc_fwm_table[idx], f_list) {
 			write_lock_bh(&__ip_vs_svc_lock);
 			ip_vs_svc_unhash(svc);
@@ -1296,15 +1306,6 @@
 /*
  *	Zero counters in a service or all services
  */
-static void
-ip_vs_zero_stats(struct ip_vs_stats *stats)
-{
-	spin_lock_bh(&stats->lock);
-	memset(stats, 0, (char *)&stats->lock - (char *)stats);
-	spin_unlock_bh(&stats->lock);
-	ip_vs_zero_estimator(stats);
-}
-
 static int ip_vs_zero_service(struct ip_vs_service *svc)
 {
 	struct ip_vs_dest *dest;
@@ -1550,10 +1551,10 @@
 	++*pos;
 	if (v == SEQ_START_TOKEN)
 		return ip_vs_info_array(seq,0);
-	
+
 	svc = v;
 	iter = seq->private;
-	
+
 	if (iter->table == ip_vs_svc_table) {
 		/* next service in table hashed by protocol */
 		if ((e = svc->s_list.next) != &ip_vs_svc_table[iter->bucket])
@@ -1579,7 +1580,7 @@
  scan_fwmark:
 	while (++iter->bucket < IP_VS_SVC_TAB_SIZE) {
 		list_for_each_entry(svc, &ip_vs_svc_fwm_table[iter->bucket],
-				    f_list) 
+				    f_list)
 			return svc;
 	}
 
@@ -1607,7 +1608,7 @@
 		const struct ip_vs_iter *iter = seq->private;
 		const struct ip_vs_dest *dest;
 
-		if (iter->table == ip_vs_svc_table) 
+		if (iter->table == ip_vs_svc_table)
 			seq_printf(seq, "%s  %08X:%04X %s ",
 				   ip_vs_proto_name(svc->protocol),
 				   ntohl(svc->addr),
@@ -1625,7 +1626,7 @@
 			seq_putc(seq, '\n');
 
 		list_for_each_entry(dest, &svc->destinations, n_list) {
-			seq_printf(seq, 
+			seq_printf(seq,
 				   "  -> %08X:%04X      %-7s %-6d %-10d %-10d\n",
 				   ntohl(dest->addr), ntohs(dest->port),
 				   ip_vs_fwd_name(atomic_read(&dest->conn_flags)),
@@ -1686,7 +1687,7 @@
 /*               01234567 01234567 01234567 0123456701234567 0123456701234567 */
 	seq_puts(seq,
 		 "   Total Incoming Outgoing         Incoming         Outgoing\n");
-	seq_printf(seq, 	   
+	seq_printf(seq,
 		   "   Conns  Packets  Packets            Bytes            Bytes\n");
 
 	spin_lock_bh(&ip_vs_stats.lock);
diff -Nru a/net/ipv4/netfilter/ipt_limit.c b/net/ipv4/netfilter/ipt_limit.c
--- a/net/ipv4/netfilter/ipt_limit.c	Wed Oct 15 00:46:35 2003
+++ b/net/ipv4/netfilter/ipt_limit.c	Wed Oct 15 00:46:35 2003
@@ -38,12 +38,23 @@
 
    See Alexey's formal explanation in net/sched/sch_tbf.c.
 
-   To avoid underflow, we multiply by 128 (ie. you get 128 credits per
-   jiffy).  Hence a cost of 2^32-1, means one pass per 32768 seconds
-   at 1024HZ (or one every 9 hours).  A cost of 1 means 12800 passes
-   per second at 100HZ.  */
+   To get the maxmum range, we multiply by this factor (ie. you get N
+   credits per jiffy).  We want to allow a rate as low as 1 per day
+   (slowest userspace tool allows), which means
+   CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32. ie. */
+#define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24))
+
+/* Repeated shift and or gives us all 1s, final shift and add 1 gives
+ * us the power of 2 below the theoretical max, so GCC simply does a
+ * shift. */
+#define _POW2_BELOW2(x) ((x)|((x)>>1))
+#define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2))
+#define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4))
+#define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8))
+#define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16))
+#define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1)
 
-#define CREDITS_PER_JIFFY 128
+#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
 
 static int
 ipt_limit_match(const struct sk_buff *skb,
@@ -99,7 +110,7 @@
 	/* Check for overflow. */
 	if (r->burst == 0
 	    || user2credits(r->avg * r->burst) < user2credits(r->avg)) {
-		printk("Call rusty: overflow in ipt_limit: %u/%u\n",
+		printk("Overflow in ipt_limit, try lower: %u/%u\n",
 		       r->avg, r->burst);
 		return 0;
 	}
diff -Nru a/net/ipv4/netfilter/ipt_owner.c b/net/ipv4/netfilter/ipt_owner.c
--- a/net/ipv4/netfilter/ipt_owner.c	Wed Oct 15 00:46:37 2003
+++ b/net/ipv4/netfilter/ipt_owner.c	Wed Oct 15 00:46:37 2003
@@ -90,7 +90,7 @@
 	read_lock(&tasklist_lock);
 	do_each_thread(g, p) {
 		struct files_struct *files;
-		if (process_session(p) != sid)
+		if (p->session != sid)
 			continue;
 
 		task_lock(p);
diff -Nru a/net/ipv6/netfilter/ip6t_owner.c b/net/ipv6/netfilter/ip6t_owner.c
--- a/net/ipv6/netfilter/ip6t_owner.c	Wed Oct 15 00:46:37 2003
+++ b/net/ipv6/netfilter/ip6t_owner.c	Wed Oct 15 00:46:37 2003
@@ -56,7 +56,7 @@
 	read_lock(&tasklist_lock);
 	do_each_thread(g, p) {
 		struct files_struct *files;
-		if (process_session(p) != sid)
+		if (p->session != sid)
 			continue;
 
 		task_lock(p);
diff -Nru a/net/ipx/ipx_proc.c b/net/ipx/ipx_proc.c
--- a/net/ipx/ipx_proc.c	Wed Oct 15 00:46:35 2003
+++ b/net/ipx/ipx_proc.c	Wed Oct 15 00:46:35 2003
@@ -5,8 +5,8 @@
  */
 
 #include <linux/config.h>
-#ifdef CONFIG_PROC_FS
 #include <linux/init.h>
+#ifdef CONFIG_PROC_FS
 #include <linux/proc_fs.h>
 #include <linux/spinlock.h>
 #include <linux/seq_file.h>
diff -Nru a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
--- a/net/sunrpc/clnt.c	Wed Oct 15 00:46:36 2003
+++ b/net/sunrpc/clnt.c	Wed Oct 15 00:46:36 2003
@@ -961,19 +961,19 @@
 	case RPC_SUCCESS:
 		return p;
 	case RPC_PROG_UNAVAIL:
-		printk(KERN_WARNING "RPC: %4d call_verify: program %u is unsupported by server %s\n",
-				task->tk_pid, (unsigned int)task->tk_client->cl_prog,
+		printk(KERN_WARNING "RPC: call_verify: program %u is unsupported by server %s\n",
+				(unsigned int)task->tk_client->cl_prog,
 				task->tk_client->cl_server);
 		goto out_eio;
 	case RPC_PROG_MISMATCH:
-		printk(KERN_WARNING "RPC: %4d call_verify: program %u, version %u unsupported by server %s\n",
-				task->tk_pid, (unsigned int)task->tk_client->cl_prog,
+		printk(KERN_WARNING "RPC: call_verify: program %u, version %u unsupported by server %s\n",
+				(unsigned int)task->tk_client->cl_prog,
 				(unsigned int)task->tk_client->cl_vers,
 				task->tk_client->cl_server);
 		goto out_eio;
 	case RPC_PROC_UNAVAIL:
-		printk(KERN_WARNING "RPC: %4d call_verify: proc %p unsupported by program %u, version %u on server %s\n",
-				task->tk_pid, task->tk_msg.rpc_proc,
+		printk(KERN_WARNING "RPC: call_verify: proc %p unsupported by program %u, version %u on server %s\n",
+				task->tk_msg.rpc_proc,
 				task->tk_client->cl_prog,
 				task->tk_client->cl_vers,
 				task->tk_client->cl_server);
diff -Nru a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
--- a/net/sunrpc/xdr.c	Wed Oct 15 00:46:37 2003
+++ b/net/sunrpc/xdr.c	Wed Oct 15 00:46:37 2003
@@ -715,6 +715,7 @@
 	struct xdr_buf *buf = xdr->buf;
 	struct iovec *iov;
 	ssize_t shift;
+	int padding;
 
 	/* Realign pages to current pointer position */
 	iov  = buf->head;
@@ -723,10 +724,10 @@
 		xdr_shrink_bufhead(buf, shift);
 
 	/* Truncate page data and move it into the tail */
-	len = XDR_QUADLEN(len) << 2;
 	if (buf->page_len > len)
 		xdr_shrink_pagelen(buf, buf->page_len - len);
+	padding = (XDR_QUADLEN(len) << 2) - len;
 	xdr->iov = iov = buf->tail;
-	xdr->p = (uint32_t *)iov->iov_base;
+	xdr->p = (uint32_t *)((char *)iov->iov_base + padding);
 	xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len);
 }
diff -Nru a/sound/core/control.c b/sound/core/control.c
--- a/sound/core/control.c	Wed Oct 15 00:46:36 2003
+++ b/sound/core/control.c	Wed Oct 15 00:46:36 2003
@@ -822,10 +822,9 @@
 			}
 			init_waitqueue_entry(&wait, current);
 			add_wait_queue(&ctl->change_sleep, &wait);
-			spin_unlock_irq(&ctl->read_lock);
 			set_current_state(TASK_INTERRUPTIBLE);
+			spin_unlock_irq(&ctl->read_lock);
 			schedule();
-			set_current_state(TASK_RUNNING);
 			remove_wait_queue(&ctl->change_sleep, &wait);
 			if (signal_pending(current))
 				return result > 0 ? result : -ERESTARTSYS;
diff -Nru a/sound/core/hwdep.c b/sound/core/hwdep.c
--- a/sound/core/hwdep.c	Wed Oct 15 00:46:35 2003
+++ b/sound/core/hwdep.c	Wed Oct 15 00:46:35 2003
@@ -129,13 +129,14 @@
 		} else
 			break;
 		set_current_state(TASK_INTERRUPTIBLE);
+		up(&hw->open_mutex);
 		schedule();
+		down(&hw->open_mutex);
 		if (signal_pending(current)) {
 			err = -ERESTARTSYS;
 			break;
 		}
 	}
-	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&hw->open_wait, &wait);
 	if (err >= 0) {
 		err = snd_card_file_add(hw->card, file);
diff -Nru a/sound/core/init.c b/sound/core/init.c
--- a/sound/core/init.c	Wed Oct 15 00:46:36 2003
+++ b/sound/core/init.c	Wed Oct 15 00:46:36 2003
@@ -697,8 +697,8 @@
 		}
 		if (file && (file->f_flags & O_NONBLOCK))
 			return -EAGAIN;
-		snd_power_unlock(card);
 		set_current_state(TASK_UNINTERRUPTIBLE);
+		snd_power_unlock(card);
 		schedule_timeout(30 * HZ);
 		snd_power_lock(card);
 	}
diff -Nru a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
--- a/sound/core/oss/pcm_oss.c	Wed Oct 15 00:46:37 2003
+++ b/sound/core/oss/pcm_oss.c	Wed Oct 15 00:46:37 2003
@@ -142,7 +142,7 @@
 	case AFMT_U16_LE:	return SNDRV_PCM_FORMAT_U16_LE;
 	case AFMT_U16_BE:	return SNDRV_PCM_FORMAT_U16_BE;
 	case AFMT_MPEG:		return SNDRV_PCM_FORMAT_MPEG;
-	default:			return SNDRV_PCM_FORMAT_U8;
+	default:		return SNDRV_PCM_FORMAT_U8;
 	}
 }
 
@@ -554,6 +554,7 @@
 	}
 	runtime->oss.prepare = 0;
 	runtime->oss.prev_hw_ptr_interrupt = 0;
+	runtime->oss.period_ptr = 0;
 
 	return 0;
 }
@@ -818,6 +819,8 @@
 					return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
 				runtime->oss.bytes += tmp;
 				runtime->oss.buffer_used = 0;
+				runtime->oss.period_ptr += tmp;
+				runtime->oss.period_ptr %= runtime->oss.period_bytes;
 			}
 		} else {
 			tmp = snd_pcm_oss_write2(substream, (char *)buf, runtime->oss.period_bytes, 0);
@@ -941,6 +944,7 @@
 {
 	snd_pcm_runtime_t *runtime;
 	ssize_t result = 0;
+	long res;
 	wait_queue_t wait;
 
 	runtime = substream->runtime;
@@ -957,12 +961,23 @@
 			break;
 		result = 0;
 		set_current_state(TASK_INTERRUPTIBLE);
-		schedule();
+		snd_pcm_stream_lock_irq(substream);
+		res = runtime->status->state;
+		snd_pcm_stream_unlock_irq(substream);
+		if (res != SNDRV_PCM_STATE_RUNNING) {
+			set_current_state(TASK_RUNNING);
+			break;
+		}
+		res = schedule_timeout(10 * HZ);
 		if (signal_pending(current)) {
 			result = -ERESTARTSYS;
 			break;
 		}
-		set_current_state(TASK_RUNNING);
+		if (res == 0) {
+			snd_printk(KERN_ERR "OSS sync error - DMA timeout\n");
+			result = -EIO;
+			break;
+		}
 	}
 	remove_wait_queue(&runtime->sleep, &wait);
 	return result;
@@ -974,31 +989,44 @@
 	unsigned int saved_f_flags;
 	snd_pcm_substream_t *substream;
 	snd_pcm_runtime_t *runtime;
-	size_t size;
+	snd_pcm_format_t format;
+	unsigned long width;
+	size_t size, size1;
 
 	substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
 	if (substream != NULL) {
 		if ((err = snd_pcm_oss_make_ready(substream)) < 0)
 			return err;
 		runtime = substream->runtime;
+		format = snd_pcm_oss_format_from(runtime->oss.format);
+		width = snd_pcm_format_physical_width(format);
 		if (runtime->oss.buffer_used > 0) {
-			snd_pcm_format_set_silence(runtime->format,
+			size = (8 * (runtime->oss.period_bytes - runtime->oss.buffer_used) + 7) / width;
+			snd_pcm_format_set_silence(format,
 						   runtime->oss.buffer + runtime->oss.buffer_used,
-						   bytes_to_samples(runtime, runtime->oss.period_bytes - runtime->oss.buffer_used));
+						   size);
 			err = snd_pcm_oss_sync1(substream, runtime->oss.period_bytes);
 			if (err < 0)
 				return err;
+		} else if (runtime->oss.period_ptr > 0) {
+			size = runtime->oss.period_bytes - runtime->oss.period_ptr;
+			snd_pcm_format_set_silence(format,
+						   runtime->oss.buffer,
+						   size * 8 / width);
+			err = snd_pcm_oss_sync1(substream, size);
+			if (err < 0)
+				return err;
 		}
-		size = runtime->control->appl_ptr % runtime->period_size;
-		if (size > 0) {
-			size = runtime->period_size - size;
-                        size *= runtime->channels;
-			snd_pcm_format_set_silence(runtime->format,
+		size = runtime->oss.period_bytes;
+		size1 = frames_to_bytes(runtime, runtime->period_size);
+		while (size < size1) {
+			snd_pcm_format_set_silence(format,
 						   runtime->oss.buffer,
-						   size);
-			err = snd_pcm_oss_sync1(substream, samples_to_bytes(runtime, size));
+						   (8 * runtime->oss.period_bytes + 7) / width);
+			err = snd_pcm_oss_sync1(substream, runtime->oss.period_bytes);
 			if (err < 0)
 				return err;
+			size += runtime->oss.period_bytes;
 		}
 		saved_f_flags = substream->ffile->f_flags;
 		substream->ffile->f_flags &= ~O_NONBLOCK;
@@ -1786,7 +1814,6 @@
 			break;
 		}
 	}
-	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&pcm->open_wait, &wait);
 	up(&pcm->open_mutex);
 	if (err < 0)
diff -Nru a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
--- a/sound/core/pcm_lib.c	Wed Oct 15 00:46:36 2003
+++ b/sound/core/pcm_lib.c	Wed Oct 15 00:46:36 2003
@@ -2106,11 +2106,11 @@
 			init_waitqueue_entry(&wait, current);
 			add_wait_queue(&runtime->sleep, &wait);
 			while (1) {
-				set_current_state(TASK_INTERRUPTIBLE);
 				if (signal_pending(current)) {
 					state = SIGNALED;
 					break;
 				}
+				set_current_state(TASK_INTERRUPTIBLE);
 				snd_pcm_stream_unlock_irq(substream);
 				tout = schedule_timeout(10 * HZ);
 				snd_pcm_stream_lock_irq(substream);
@@ -2139,7 +2139,6 @@
 				}
 			}
 		       _end_loop:
-			set_current_state(TASK_RUNNING);
 			remove_wait_queue(&runtime->sleep, &wait);
 
 			switch (state) {
@@ -2401,11 +2400,11 @@
 			init_waitqueue_entry(&wait, current);
 			add_wait_queue(&runtime->sleep, &wait);
 			while (1) {
-				set_current_state(TASK_INTERRUPTIBLE);
 				if (signal_pending(current)) {
 					state = SIGNALED;
 					break;
 				}
+				set_current_state(TASK_INTERRUPTIBLE);
 				snd_pcm_stream_unlock_irq(substream);
 				tout = schedule_timeout(10 * HZ);
 				snd_pcm_stream_lock_irq(substream);
@@ -2435,7 +2434,6 @@
 				}
 			}
 		       _end_loop:
-			set_current_state(TASK_RUNNING);
 			remove_wait_queue(&runtime->sleep, &wait);
 
 			switch (state) {
diff -Nru a/sound/core/pcm_native.c b/sound/core/pcm_native.c
--- a/sound/core/pcm_native.c	Wed Oct 15 00:46:36 2003
+++ b/sound/core/pcm_native.c	Wed Oct 15 00:46:36 2003
@@ -1237,11 +1237,11 @@
 	add_wait_queue(&runtime->sleep, &wait);
 	while (1) {
 		long tout;
-		set_current_state(TASK_INTERRUPTIBLE);
 		if (signal_pending(current)) {
 			state = SIGNALED;
 			break;
 		}
+		set_current_state(TASK_INTERRUPTIBLE);
 		snd_pcm_stream_unlock_irq(substream);
 		tout = schedule_timeout(10 * HZ);
 		snd_pcm_stream_lock_irq(substream);
@@ -1254,7 +1254,6 @@
 			break;
 		}
 	}
-	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&runtime->sleep, &wait);
 
 	switch (state) {
@@ -1961,12 +1960,11 @@
 	}
 	init_waitqueue_entry(&wait, current);
 	add_wait_queue(&pcm->open_wait, &wait);
+	down(&pcm->open_mutex);
 	while (1) {
-		down(&pcm->open_mutex);
 		err = snd_pcm_open_file(file, pcm, device >= SNDRV_MINOR_PCM_CAPTURE ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK, &pcm_file);
 		if (err >= 0)
 			break;
-		up(&pcm->open_mutex);
 		if (err == -EAGAIN) {
 			if (file->f_flags & O_NONBLOCK) {
 				err = -EBUSY;
@@ -1975,13 +1973,14 @@
 		} else
 			break;
 		set_current_state(TASK_INTERRUPTIBLE);
+		up(&pcm->open_mutex);
 		schedule();
+		down(&pcm->open_mutex);
 		if (signal_pending(current)) {
 			err = -ERESTARTSYS;
 			break;
 		}
 	}
-	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&pcm->open_wait, &wait);
 	if (err < 0)
 		goto __error;
diff -Nru a/sound/core/rawmidi.c b/sound/core/rawmidi.c
--- a/sound/core/rawmidi.c	Wed Oct 15 00:46:36 2003
+++ b/sound/core/rawmidi.c	Wed Oct 15 00:46:36 2003
@@ -191,7 +191,8 @@
 		err = -EFAULT;
 		goto __error1;
 	}
-	down(&rmidi->open_mutex);
+	if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
+		down(&rmidi->open_mutex);
 	if (mode & SNDRV_RAWMIDI_LFLG_INPUT) {
 		if (!(rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT)) {
 			err = -ENXIO;
@@ -320,7 +321,8 @@
 	} else {
 		soutput = NULL;
 	}
-	up(&rmidi->open_mutex);
+	if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
+		up(&rmidi->open_mutex);
 	if (rfile) {
 		rfile->rmidi = rmidi;
 		rfile->input = sinput;
@@ -338,7 +340,8 @@
 		kfree(output);
 	}
 	module_put(rmidi->card->module);
-	up(&rmidi->open_mutex);
+	if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
+		up(&rmidi->open_mutex);
       __error1:
 	return err;
 }
@@ -392,6 +395,7 @@
 	fflags = snd_rawmidi_file_flags(file);
 	if ((file->f_flags & O_APPEND) || maj != CONFIG_SND_MAJOR) /* OSS emul? */
 		fflags |= SNDRV_RAWMIDI_LFLG_APPEND;
+	fflags |= SNDRV_RAWMIDI_LFLG_NOOPENLOCK;
 	rawmidi_file = snd_magic_kmalloc(snd_rawmidi_file_t, 0, GFP_KERNEL);
 	if (rawmidi_file == NULL) {
 		snd_card_file_remove(card, file);
@@ -399,6 +403,7 @@
 	}
 	init_waitqueue_entry(&wait, current);
 	add_wait_queue(&rmidi->open_wait, &wait);
+	down(&rmidi->open_mutex);
 	while (1) {
 		subdevice = -1;
 		down_read(&card->controls_rwsem);
@@ -421,7 +426,9 @@
 		} else
 			break;
 		set_current_state(TASK_INTERRUPTIBLE);
+		up(&rmidi->open_mutex);
 		schedule();
+		down(&rmidi->open_mutex);
 		if (signal_pending(current)) {
 			err = -ERESTARTSYS;
 			break;
@@ -433,7 +440,6 @@
 	if (rawmidi_file->output && rawmidi_file->output->runtime)
 		rawmidi_file->output->runtime->oss = (maj == SOUND_MAJOR);
 #endif
-	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&rmidi->open_wait, &wait);
 	if (err >= 0) {
 		file->private_data = rawmidi_file;
@@ -441,6 +447,7 @@
 		snd_card_file_remove(card, file);
 		snd_magic_kfree(rawmidi_file);
 	}
+	up(&rmidi->open_mutex);
 	return err;
 }
 
@@ -950,10 +957,9 @@
 			}
 			init_waitqueue_entry(&wait, current);
 			add_wait_queue(&runtime->sleep, &wait);
-			spin_unlock_irq(&runtime->lock);
 			set_current_state(TASK_INTERRUPTIBLE);
+			spin_unlock_irq(&runtime->lock);
 			schedule();
-			set_current_state(TASK_RUNNING);
 			remove_wait_queue(&runtime->sleep, &wait);
 			if (signal_pending(current))
 				return result > 0 ? result : -ERESTARTSYS;
@@ -1179,8 +1185,8 @@
 			}
 			init_waitqueue_entry(&wait, current);
 			add_wait_queue(&runtime->sleep, &wait);
-			spin_unlock_irq(&runtime->lock);
 			set_current_state(TASK_INTERRUPTIBLE);
+			spin_unlock_irq(&runtime->lock);
 			timeout = schedule_timeout(30 * HZ);
 			remove_wait_queue(&runtime->sleep, &wait);
 			if (signal_pending(current))
@@ -1206,8 +1212,8 @@
 			unsigned int last_avail = runtime->avail;
 			init_waitqueue_entry(&wait, current);
 			add_wait_queue(&runtime->sleep, &wait);
-			spin_unlock_irq(&runtime->lock);
 			set_current_state(TASK_INTERRUPTIBLE);
+			spin_unlock_irq(&runtime->lock);
 			timeout = schedule_timeout(30 * HZ);
 			remove_wait_queue(&runtime->sleep, &wait);
 			if (signal_pending(current))
diff -Nru a/sound/core/seq/seq_lock.c b/sound/core/seq/seq_lock.c
--- a/sound/core/seq/seq_lock.c	Wed Oct 15 00:46:36 2003
+++ b/sound/core/seq/seq_lock.c	Wed Oct 15 00:46:36 2003
@@ -25,44 +25,6 @@
 
 #if defined(CONFIG_SMP) || defined(CONFIG_SND_DEBUG)
 
-#if 0 /* NOT USED */
-/* (interruptible) sleep_on during the specified spinlock */
-void snd_seq_sleep_in_lock(wait_queue_head_t *p, spinlock_t *lock)
-{
-	wait_queue_t wait;
-
-	set_current_state(TASK_INTERRUPTIBLE);
-	init_waitqueue_entry(&wait, current);
-
-	add_wait_queue(p, &wait);
-
-	spin_unlock(lock);
-	schedule();
-	spin_lock_irq(lock);
-
-	remove_wait_queue(p, &wait);
-}
-
-/* (interruptible) sleep_on with timeout during the specified spinlock */
-long snd_seq_sleep_timeout_in_lock(wait_queue_head_t *p, spinlock_t *lock, long timeout)
-{
-	wait_queue_t wait;
-
-	set_current_state(TASK_INTERRUPTIBLE);
-	init_waitqueue_entry(&wait, current);
-
-	add_wait_queue(p, &wait);
-
-	spin_unlock(lock);
-	timeout = schedule_timeout(timeout);
-	spin_lock_irq(lock);
-
-	remove_wait_queue(p, &wait);
-
-	return timeout;
-}
-#endif /* NOT USED */
-
 /* wait until all locks are released */
 void snd_use_lock_sync_helper(snd_use_lock_t *lockp, const char *file, int line)
 {
diff -Nru a/sound/core/timer.c b/sound/core/timer.c
--- a/sound/core/timer.c	Wed Oct 15 00:46:37 2003
+++ b/sound/core/timer.c	Wed Oct 15 00:46:37 2003
@@ -1678,7 +1678,6 @@
 			spin_lock_irq(&tu->qlock);
 
 			remove_wait_queue(&tu->qchange_sleep, &wait);
-			set_current_state(TASK_RUNNING);
 
 			if (signal_pending(current)) {
 				err = -ERESTARTSYS;
diff -Nru a/sound/drivers/dummy.c b/sound/drivers/dummy.c
--- a/sound/drivers/dummy.c	Wed Oct 15 00:46:37 2003
+++ b/sound/drivers/dummy.c	Wed Oct 15 00:46:37 2003
@@ -41,6 +41,20 @@
 #define MAX_PCM_SUBSTREAMS	16
 #define MAX_MIDI_DEVICES	2
 
+#if 0 /* emu10k1 emulation */
+#define MAX_BUFFER_SIZE		(128 * 1024)
+static int emu10k1_playback_constraints(snd_pcm_runtime_t *runtime)
+{
+	int err;
+	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
+		return err;
+	if ((err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX)) < 0)
+		return err;
+	return 0;
+}
+#define add_playback_constraints emu10k1_playback_constraints
+#endif
+
 #if 0 /* RME9652 emulation */
 #define MAX_BUFFER_SIZE		(26 * 64 * 1024)
 #define USE_FORMATS		SNDRV_PCM_FMTBIT_S32_LE
@@ -102,6 +116,12 @@
 #ifndef USE_PERIODS_MAX
 #define USE_PERIODS_MAX 	1024
 #endif
+#ifndef add_playback_constraints
+#define add_playback_constraints(x) 0
+#endif
+#ifndef add_capture_constraints
+#define add_capture_constraints(x) 0
+#endif
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
@@ -325,6 +345,7 @@
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	snd_card_dummy_pcm_t *dpcm;
+	int err;
 
 	dpcm = snd_magic_kcalloc(snd_card_dummy_pcm_t, 0, GFP_KERNEL);
 	if (dpcm == NULL)
@@ -347,6 +368,11 @@
 	}
 	if (substream->pcm->device & 2)
 		runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID);
+	if ((err = add_playback_constraints(runtime)) < 0) {
+		snd_magic_kfree(dpcm);
+		return err;
+	}
+
 	return 0;
 }
 
@@ -354,6 +380,7 @@
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	snd_card_dummy_pcm_t *dpcm;
+	int err;
 
 	dpcm = snd_magic_kcalloc(snd_card_dummy_pcm_t, 0, GFP_KERNEL);
 	if (dpcm == NULL)
@@ -377,6 +404,11 @@
 	}
 	if (substream->pcm->device & 2)
 		runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID);
+	if ((err = add_capture_constraints(runtime)) < 0) {
+		snd_magic_kfree(dpcm);
+		return err;
+	}
+
 	return 0;
 }
 
diff -Nru a/sound/isa/sb/emu8000_patch.c b/sound/isa/sb/emu8000_patch.c
--- a/sound/isa/sb/emu8000_patch.c	Wed Oct 15 00:46:36 2003
+++ b/sound/isa/sb/emu8000_patch.c	Wed Oct 15 00:46:36 2003
@@ -233,11 +233,7 @@
 		/* we may take too long time in this loop.
 		 * so give controls back to kernel if needed.
 		 */
-		if (need_resched()) {
-			if (current->state != TASK_RUNNING)
-				set_current_state(TASK_RUNNING);
-			schedule();
-		}
+		cond_resched();
 
 		if (i == sp->v.loopend &&
 		    (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP)))
diff -Nru a/sound/isa/sb/emu8000_pcm.c b/sound/isa/sb/emu8000_pcm.c
--- a/sound/isa/sb/emu8000_pcm.c	Wed Oct 15 00:46:38 2003
+++ b/sound/isa/sb/emu8000_pcm.c	Wed Oct 15 00:46:38 2003
@@ -424,13 +424,9 @@
  */
 #define CHECK_SCHEDULER() \
 do { \
-	if (need_resched()) {\
-		if (current->state != TASK_RUNNING)\
-			set_current_state(TASK_RUNNING);\
-		schedule();\
-		if (signal_pending(current))\
-			return -EAGAIN;\
-	}\
+	cond_resched();\
+	if (signal_pending(current))\
+		return -EAGAIN;\
 } while (0)
 
 
diff -Nru a/sound/pci/Kconfig b/sound/pci/Kconfig
--- a/sound/pci/Kconfig	Wed Oct 15 00:46:36 2003
+++ b/sound/pci/Kconfig	Wed Oct 15 00:46:36 2003
@@ -32,7 +32,6 @@
 config SND_CS4281
 	tristate "Cirrus Logic (Sound Fusion) CS4281"
 	depends on SND
-	select GAMEPORT
 	help
 	  Say 'Y' or 'M' to include support for Cirrus Logic CS4281.
 
@@ -86,7 +85,6 @@
 config SND_TRIDENT
 	tristate "Trident 4D-Wave DX/NX; SiS 7018"
 	depends on SND
-	select GAMEPORT
 	help
 	  Say 'Y' or 'M' to include support for Trident 4D-Wave DX/NX and
 	  SiS 7018 soundcards.
@@ -114,14 +112,12 @@
 config SND_ENS1370
 	tristate "(Creative) Ensoniq AudioPCI 1370"
 	depends on SND
-	select GAMEPORT
 	help
 	  Say 'Y' or 'M' to include support for Ensoniq AudioPCI ES1370.
 
 config SND_ENS1371
 	tristate "(Creative) Ensoniq AudioPCI 1371/1373"
 	depends on SND
-	select GAMEPORT
 	help
 	  Say 'Y' or 'M' to include support for Ensoniq AudioPCI ES1371 and
 	  Sound Blaster PCI 64 or 128 soundcards.
@@ -129,7 +125,6 @@
 config SND_ES1938
 	tristate "ESS ES1938/1946/1969 (Solo-1)"
 	depends on SND
-	select GAMEPORT
 	help
 	  Say 'Y' or 'M' to include support for ESS Solo-1 (ES1938, ES1946, ES1969)
 	  soundcard.
@@ -180,7 +175,6 @@
 config SND_SONICVIBES
 	tristate "S3 SonicVibes"
 	depends on SND
-	select GAMEPORT
 	help
 	  Say 'Y' or 'M' to include support for S3 SonicVibes based soundcards.
 
diff -Nru a/sound/pci/via82xx.c b/sound/pci/via82xx.c
--- a/sound/pci/via82xx.c	Wed Oct 15 00:46:37 2003
+++ b/sound/pci/via82xx.c	Wed Oct 15 00:46:37 2003
@@ -2038,16 +2038,17 @@
 				break;
 			}
 		}
-		if (dxs_support[dev] == VIA_DXS_AUTO)
-			dxs_support[dev] = check_dxs_list(pci);
-		/* force to use VIA8233 or 8233A model according to
-		 * dxs_support module option
-		 */
-		if (dxs_support[dev] == VIA_DXS_DISABLE)
-			chip_type = TYPE_VIA8233A;
-		else
-			chip_type = TYPE_VIA8233;
-
+		if (chip_type != TYPE_VIA8233A) {
+			if (dxs_support[dev] == VIA_DXS_AUTO)
+				dxs_support[dev] = check_dxs_list(pci);
+			/* force to use VIA8233 or 8233A model according to
+			 * dxs_support module option
+			 */
+			if (dxs_support[dev] == VIA_DXS_DISABLE)
+				chip_type = TYPE_VIA8233A;
+			else
+				chip_type = TYPE_VIA8233;
+		}
 		if (chip_type == TYPE_VIA8233A)
 			strcpy(card->driver, "VIA8233A");
 		else
diff -Nru a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c
--- a/sound/pci/vx222/vx222_ops.c	Wed Oct 15 00:46:35 2003
+++ b/sound/pci/vx222/vx222_ops.c	Wed Oct 15 00:46:35 2003
@@ -378,11 +378,7 @@
 		if (put_xilinx_data(chip, port, 8, data) < 0)
 			return -EINVAL;
 		/* don't take too much time in this loop... */
-		if (need_resched()) {
-			if (current->state != TASK_RUNNING)
-				set_current_state(TASK_RUNNING);
-			schedule();
-		}
+		cond_resched();
 	}
 	put_xilinx_data(chip, port, 4, 0xff); /* end signature */
 
diff -Nru a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
--- a/sound/usb/usbmixer.c	Wed Oct 15 00:46:36 2003
+++ b/sound/usb/usbmixer.c	Wed Oct 15 00:46:36 2003
@@ -1358,16 +1358,16 @@
 		return -EINVAL;
 	}
 
+	for (i = 0; i < num_ins; i++) {
+		if ((err = parse_audio_unit(state, desc[5 + i])) < 0)
+			return err;
+	}
+
 	if (num_ins == 1) /* only one ? nonsense! */
 		return 0;
 
 	if (check_ignored_ctl(state, unitid, 0))
 		return 0;
-
-	for (i = 0; i < num_ins; i++) {
-		if ((err = parse_audio_unit(state, desc[5 + i])) < 0)
-			return err;
-	}
 
 	cval = snd_magic_kcalloc(usb_mixer_elem_info_t, 0, GFP_KERNEL);
 	if (! cval) {
