]> git.neil.brown.name Git - history.git/commitdiff
Import 2.1.56 2.1.56
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:13:54 +0000 (15:13 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:13:54 +0000 (15:13 -0500)
60 files changed:
CREDITS
Documentation/00-INDEX
Documentation/Changes
Documentation/devices.tex
Documentation/devices.txt
Documentation/parport.txt
Documentation/stallion.txt
Makefile
arch/i386/defconfig
drivers/block/README.fd
drivers/block/floppy.c
drivers/block/ide-probe.c
drivers/block/ide.h
drivers/char/istallion.c
drivers/char/lp.c
drivers/char/pcwd.c
drivers/char/stallion.c
drivers/char/tty_io.c
drivers/misc/Makefile
drivers/misc/parport_pc.c
drivers/misc/parport_share.c
drivers/pnp/parport_probe.c
drivers/scsi/Config.in
drivers/scsi/eata.c
drivers/scsi/eata.h
drivers/scsi/sr_vendor.c
drivers/scsi/u14-34f.c
drivers/scsi/u14-34f.h
drivers/sound/soundcard.c
fs/Makefile
fs/affs/dir.c
fs/bad_inode.c [new file with mode: 0644]
fs/buffer.c
fs/dcache.c
fs/ext2/fsync.c
fs/fcntl.c
fs/lockd/clntlock.c
fs/locks.c
fs/namei.c
fs/nfs/write.c
fs/smbfs/dir.c
fs/smbfs/file.c
fs/smbfs/inode.c
fs/smbfs/proc.c
fs/smbfs/sock.c
include/linux/dcache.h
include/linux/fs.h
include/linux/minix_fs.h
include/linux/smb_fs.h
include/linux/smb_fs_i.h
include/linux/smbno.h
include/linux/sysv_fs.h
kernel/exit.c
mm/filemap.c
net/ipv4/arp.c
net/ipv4/tcp_output.c
net/sunrpc/clnt.c
net/sunrpc/sched.c
net/sunrpc/svcsock.c
net/sunrpc/xprt.c

diff --git a/CREDITS b/CREDITS
index fa7c007505659d27840755b6fcb696754c979e08..7a380d5ac69620bd401e750916734f1a6d60dee5 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -42,7 +42,7 @@ D: VFS fixes (new notify_change in particular)
 D: Moving all VFS access checks into the file systems
 S: MIT Room E15-341
 S: 20 Ames Street
-S: Cambridge, Massachusetts  02139
+S: Cambridge, Massachusetts 02139
 S: USA
 
 N: John Aycock
@@ -86,7 +86,7 @@ E: james.banks@caldera.com
 D: TLAN network driver
 S: Caldera, Inc.
 S: 633 South 550 East
-S: Provo, UT 84606
+S: Provo, Utah 84606
 S: USA
 
 N: Peter Bauer
@@ -115,9 +115,9 @@ S: USA
 
 N: Randolph Bentson
 E: bentson@grieg.seaslug.org
-D: author of driver for Cyclom-Y and Cyclades-Z async mux
-P: 1024/39ED5729 5C A8 7A F4 B2 7A D1 3E  B5 3B 81 CF 47 30 11 71
 W: http://www.aa.net/~bentson/
+P: 1024/39ED5729 5C A8 7A F4 B2 7A D1 3E  B5 3B 81 CF 47 30 11 71
+D: Author of driver for Cyclom-Y and Cyclades-Z async mux
 S: 2322 37th Ave SW
 S: Seattle, Washington 98126-2010
 S: USA
@@ -221,7 +221,7 @@ S: 3674 Oakwood Terrace #201
 S: Fremont, California 94536
 S: USA
 
-N: Chih-Jen Chang     
+N: Chih-Jen Chang
 E: chihjenc@scf.usc.edu
 E: chihjen@iis.sinica.edu.tw
 D: IGMP(Internet Group Management Protocol) version 2
@@ -266,11 +266,6 @@ E: alan@lxorguk.ukuu.org.uk (linux related - except big patches)
 E: iialan@www.uk.linux.org (linux.org.uk/big patches)
 E: alan@cymru.net (commercial CymruNET stuff)
 E: Alan.Cox@linux.org (if others fail)
-S: CymruNet Limited
-S: The Innovation Centre
-S: Singleton Park
-S: Swansea, SA2 8PP
-S: Wales, UK
 D: NET2Debugged/NET3 author
 D: Network layer debugging
 D: Initial AX.25 & IPX releases
@@ -278,6 +273,11 @@ D: Original Linux netatalk patches.
 D: Current 3c501 hacker. >>More 3c501 info/tricks wanted<<.
 D: Watchdog timer drivers
 D: Linux/SMP
+S: CymruNet Limited
+S: The Innovation Centre
+S: Singleton Park
+S: Swansea, SA2 8PP
+S: Wales, United Kingdom
 
 N: Laurence Culhane
 E: loz@holmes.demon.co.uk
@@ -299,12 +299,12 @@ S: The Netherlands
 
 N: David Davies
 E: davies@wanton.lkg.dec.com
-S: Digital Equipment Corporation
-S: 550 King Street
-S: Littleton, MA 01460
-S: U.S.A.
 D: Network driver author - depca, ewrk3 and de4x5
 D: Wrote shared interrupt support
+S: Digital Equipment Corporation
+S: 550 King Street
+S: Littleton, Massachusetts 01460
+S: USA
 
 N: Wayne Davison
 E: davison@borland.com
@@ -319,12 +319,10 @@ D: ax25-utils maintainer.
 
 N: Todd J. Derr
 E: tjd@fore.com
-D: x86 VESA console blanking enhancements
-D: maintainer of dual-monitor patches for 1.0+
-D: MouseMan driver for selection
-S: Fore Systems, Inc.
-S: 5800 Corporate Drive
-S: Pittsburgh, Pennsylvania 15237-5829
+W: http://www.wordsmith.org/~tjd
+D: Random console hacks and other miscellaneous stuff
+S: 3000 FORE Drive
+S: Warrendale, Pennsylvania 15086
 S: USA
 
 N: Eddie C. Dost
@@ -341,7 +339,7 @@ W: http://www.cs.nmt.edu/~cort/
 D: PowerPC PReP port
 S: Computer Science Department
 S: New Mexico Tech
-S: Socorro NM 87801
+S: Socorro, New Mexico 87801
 S: USA
 
 N: Thomas Dunbar
@@ -486,15 +484,6 @@ N: Philip Gladstone
 E: philip@raptor.com
 D: Kernel / timekeeping stuff
 
-N: Michael A. Griffith
-E: grif@cs.ucr.edu
-W: http://www.cs.ucr.edu/~grif
-D: Loopback speedup, qlogic scsi hacking, VT_LOCKSWITCH
-S: Department of Computer Science
-S: University of California, Riverside
-S: Riverside, California  92521-0304
-S: USA
-
 N: Dmitry S. Gorodchanin
 E: begemot@bgm.rosprint.net
 D: RISCom/8 driver, misc kernel fixes.
@@ -516,7 +505,16 @@ N: John E. Gotts
 E: jgotts@engin.umich.edu
 D: kernel hacker
 S: 8124 Constitution Apt. 7
-S: Sterling Heights, Michigan  48313
+S: Sterling Heights, Michigan 48313
+S: USA
+
+N: Michael A. Griffith
+E: grif@cs.ucr.edu
+W: http://www.cs.ucr.edu/~grif
+D: Loopback speedup, qlogic scsi hacking, VT_LOCKSWITCH
+S: Department of Computer Science
+S: University of California, Riverside
+S: Riverside, California 92521-0304
 S: USA
 
 N: Grant Guenther
@@ -655,7 +653,7 @@ N: Christopher Horn
 E: chorn@warwick.net
 D: Miscellaneous sysctl hacks
 S: 36 Mudtown Road
-S: Wantage, NJ 07461
+S: Wantage, New Jersey 07461
 S: USA
 
 N: Miguel de Icaza Amozurrutia
@@ -813,8 +811,8 @@ S: Germany
 
 N: Jaroslav Kysela
 E: perex@jcu.cz
-D: Original Author and Maintainer for HP 10/100 Mbit Network Adapters
 W: http://www.pf.jcu.cz/~perex
+D: Original Author and Maintainer for HP 10/100 Mbit Network Adapters
 S: Unix Centre of Pedagogical Faculty, University of South Bohemia
 
 N: Bas Laarhoven
@@ -864,13 +862,13 @@ E: beans@bucket.ualr.edu
 D: Promised to send money if I would put his name in the source tree.
 S: PO Box 371
 S: North Little Rock, Arkansas 72115
-S: US
+S: USA
 
 N: Siegfried "Frieder" Loeffler (dg1sek)
 E: floeff@tunix.mathematik.uni-stuttgart.de, fl@LF.net
 W: http://www.mathematik.uni-stuttgart.de/~floeff
 D: Busmaster driver for HP 10/100 Mbit Network Adapters
-S: University of Stuttgart, Germany  and
+S: University of Stuttgart, Germany and
 S: Ecole Nationale Superieure des Telecommunications, Paris
 
 N: Martin von Loewis
@@ -890,7 +888,7 @@ N: Warner Losh
 E: imp@village.org
 D: Linux/MIPS Deskstation support, Provided OI/OB for Linux
 S: 8786 Niwot Rd
-S: Niwot, CO 80503
+S: Niwot, Colorado 80503
 S: USA
 
 N: H.J. Lu
@@ -920,20 +918,28 @@ N: Peter MacDonald
 D: SLS distribution
 D: Initial implementation of VC's, pty's and select()
 
+N: Pavel Machek
+E: pavel@atrey.karlin.mff.cuni.cz
+D: Softcursor for vga, hypertech cdrom support, vcsa bugfix
+S: Volkova 1131
+S: 198 00 Praha 9
+S: Czech Republic
+
 N: Paul Mackerras
 E: paulus@cs.anu.edu.au
 D: Linux port for PCI Power Macintosh
 S: Dept. of Computer Science
 S: Australian National University
 S: Canberra  ACT  0200
-S: AUSTRALIA
+S: Australia
 
-N: Pavel Machek
-E: pavel@atrey.karlin.mff.cuni.cz
-D: Softcursor for vga, hypertech cdrom support, vcsa bugfix
-S: Volkova 1131
-S: 198 00 Praha 9
-S: Czech Republic
+N: Pat Mackinlay
+E: pat@it.com.au
+D: 8 bit XT hard disk driver
+D: Miscellaneous ST0x, TMC-8xx and other SCSI hacking
+S: 25 McMillan Street
+S: Victoria Park 6100
+S: Australia
 
 N: James B. MacLean
 E: macleajb@ednet.ns.ca
@@ -944,14 +950,6 @@ S: PO BOX 220, HFX. CENTRAL
 S: Halifax, Nova Scotia
 S: Canada B3J 3C8
 
-N: Pat Mackinlay
-E: pat@it.com.au
-D: 8 bit XT hard disk driver
-D: Miscellaneous ST0x, TMC-8xx and other SCSI hacking
-S: 25 McMillan Street
-S: Victoria Park 6100
-S: Australia
-
 N: Martin Mares
 E: mj@k332.feld.cvut.cz
 W: http://atrey.karlin.mff.cuni.cz/~mj/
@@ -965,6 +963,9 @@ S: Czech Republic
 
 N: John A. Martin
 E: jam@acm.org
+W: http://linux.wauug.org/~jam/
+P: 1024/04456D53 9D A3 6C 6B 88 80 8A 61  D7 06 22 4F 95 40 CE D2
+P: 1024/3B986635 5A61 7EE6 9E20 51FB 59FB  2DA5 3E18 DD55 3B98 6635
 D: FSSTND contributor
 D: Credit file compilator
 
@@ -983,7 +984,7 @@ W: http://www.invlogic.com/~mmclagan
 D: DLCI/FRAD drivers for Sangoma SDLAs
 S: Innovative Logic Corp
 S: P.O. Box 1068
-S: Laurel, M 20732
+S: Laurel, Maryland 20732
 S: USA
 
 N: Bradley McLean
@@ -1017,7 +1018,7 @@ P: 1024/31455639 B7 99 BD B8 00 17 BD 46  C1 15 B8 AB 87 BC 25 FA
 D: IP Masquerading work and minor fixes
 S: Planet Online
 S: The White House, Melbourne Street, LEEDS
-S: LS2  7PS,   UK
+S: LS2 7PS, United Kingdom
 
 N: Craig Metz
 E: cmetz@inner.net
@@ -1050,8 +1051,9 @@ S: East Brunswick, New Jersey 08816
 S: USA
 
 N: Rick Miller
-E: rick@digalogsys.com
-D: Original Linux Device Registrar (Major/minor numbers), au-play, bwBASIC
+E: rdmiller@execpc.com
+D: Original Linux Device Registrar (Major/minor numbers)
+D: au-play, bwBASIC
 S: S78 W16203 Woods Road
 S: Muskego, Wisconsin 53150
 S: USA
@@ -1084,7 +1086,7 @@ N: David Mosberger-Tang
 E: davidm@azstarnet.com
 D: Linux/Alpha
 S: 2552 E. Copper Street
-S: Tucson, AZ 85716-2406
+S: Tucson, Arizona 85716-2406
 S: USA
 
 N: Ian A. Murdock
@@ -1146,6 +1148,10 @@ N: Greg Page
 E: greg@caldera.com
 D: IPX development and support
 
+N: David Parsons
+E: orc@pell.chi.il.us
+D: improved memory detection code.
+
 N: Barak A. Pearlmutter
 E: bap@cs.unm.edu
 W: http://www.cs.unm.edu/~bap/
@@ -1154,13 +1160,9 @@ D: Author of mark-and-sweep GC integrated by Alan Cox
 S: Computer Science Department
 S: FEC 313
 S: University of New Mexico
-S: Albuquerque, N 87131
+S: Albuquerque, New Mexico 87131
 S: USA
 
-N: David Parsons
-E: orc@pell.chi.il.us
-D: improved memory detection code.
-
 N: Avery Pennarun
 E: apenwarr@bond.net
 D: ARCnet driver
@@ -1242,7 +1244,7 @@ E: roadcapw@cfw.com
 W: http://www.cfw.com/~roadcapw
 D: Author of menu based configuration tool, Menuconfig.
 S: 1407 Broad Street
-S: Waynesboro, Virginia  22980
+S: Waynesboro, Virginia 22980
 S: USA
 
 N: Andrew J. Robinson
@@ -1335,7 +1337,7 @@ W: http://www.-i-Connect.Net/~shimon
 D: SCSI debugging
 D: Maintainer of the Debian Kernel packages
 S: 14355 SW Allen Blvd., Suite #140
-S: Beaverton, OR 97008
+S: Beaverton, Oregon 97008
 S: USA
 
 N: Mike Shaver
@@ -1400,7 +1402,7 @@ N: Leo Spiekman
 E: leo@netlabs.net
 W: http://www.netlabs.net/hp/leo/
 D: Optics Storage 8000AT cdrom driver
-S: Cliffwood, NJ 07721
+S: Cliffwood, New Jersey 07721
 S: USA
 
 N: Henrik Storner
@@ -1472,7 +1474,7 @@ E: winni@xpilot.org
 W: http://www.shop.de/~winni/
 D: German HOWTO, Crash-Kurs Linux (German, 100 comprehensive pages)
 D: CD-Writing HOWTO, various mini-HOWTOs
-D: one-week tutorials on Linux twice a year (free of charge)
+D: One-week tutorials on Linux twice a year (free of charge)
 D: Linux-Workshop Köln (aka LUG Cologne, Germany), Installfests
 S: Tacitusstr. 6
 S: D-50968 Köln
@@ -1611,7 +1613,7 @@ S: Dr. Greg Wettstein, Ph.D.
 S: Oncology Research Division Computing Facility
 S: Roger Maris Cancer Center
 S: 820 4th St. N.
-S: Fargo, North Dakota  58122
+S: Fargo, North Dakota 58122
 S: USA
 
 N: Steven Whitehouse
index 86a2391ea7e3d78df28d2497ada564ecc107468d..c1c171f2bfa239a02b0fe9c815b9fb9b0befda24 100644 (file)
@@ -68,6 +68,8 @@ nfsroot.txt
        - short guide on setting up a diskless box with NFS root filesystem
 oops-tracing.txt
        - how to decode those nasty internal kernel error dump messages.
+parport.txt
+       - how to use the parallel-port driver.
 ramdisk.txt
        - short guide on how to set up and use the RAM disk.
 riscom8.txt
index 8cabe2d381eac5cecb923ed59bcf88e9bbcfa162..b00bd197d9b0f80e48304c247b9e3de3190c4c8a 100644 (file)
@@ -26,10 +26,7 @@ HTML-ized shopping list.
 http://www.datanet.hu/generations/linux/Changes2.html is an
 English-language HTML version.
 
-   Also, don't forget http://www.linuxhq.com/ for all your Linux kernel
-needs.
-
-Last updated: July 22. 1997
+Last updated: September 13. 1997
 Current Author: Chris Ricker (gt1355b@prism.gatech.edu).
 
 Current Minimal Requirements
@@ -39,22 +36,21 @@ Current Minimal Requirements
 encountered a bug!  If you're unsure what version you're currently
 running, the suggested command should tell you.
 
-- Kernel modules        modutils-2.1.42         ; insmod -V
-- Gnu C                 2.7.2.1                 ; gcc --version
+- Kernel modules        modutils-2.1.55         ; insmod -V
+- Gnu C                 2.7.2.3                 ; gcc --version
 - Binutils              2.8.1.0.1               ; ld -v
-- Linux C Library       5.4.33                  ; ls -l /lib/libc.so.*
-- Dynamic Linker (ld.so) 1.9.2                   ; ldd -v
-- Linux C++ Library     2.7.2.1                 ; ls -l /usr/lib/libg++.so.*
-- Procps                1.01                    ; ps --version
+- Linux C Library       5.4.38                  ; ls -l /lib/libc.so.*
+- Dynamic Linker (ld.so) 1.9.5                   ; ldd -v
+- Linux C++ Library     2.7.2.8                 ; ls -l /usr/lib/libg++.so.*
+- Procps                1.2                    ; ps --version
 - Procinfo               0.11                    ; procinfo -v
-- Mount                  2.6g                    ; mount --version
+- Mount                  2.6h                    ; mount --version
 - Net-tools              1.41                    ; hostname -V
 - Loadlin                1.6a
 - Sh-utils               1.16                    ; expr --v
-- Autofs                 0.3.7                   ; automount --version
+- Autofs                 0.3.11                   ; automount --version
 - NFS                    0.4.21                  ; showmount --version
 - Bash                   1.14.7                  ; bash -version
-- Smbfs                  2.1.0
 
 Upgrade notes
 *************
@@ -80,15 +76,16 @@ accordingly.
    For modules to work, you need to be running libc-5.4.x or greater.
 Since updates to libc fix other problems as well (security flaws, for
 example) and since 5.4.7 is missing a few needed symbols, try to get
-the latest 5.4.x you can.  Currently, libc-5.4.33 is the latest public
+the latest 5.4.x you can.  Currently, libc-5.4.38 is the latest public
 release.
 
    If you upgrade to libc-5.4.x, you also have to upgrade your dynamic
-linker (ld.so) to at least 1.9.2, or all sorts of weirdness will
-happen.  Actually, ld.so-1.8.2 and later will work, but 1.9.2 is widely
+linker (ld.so) to at least 1.9.5, or all sorts of weirdness will
+happen.  Actually, ld.so-1.8.2 and later will work, but 1.9.5 is widely
 available, so if you need to upgrade, use it.  If you get a release
 later than 1.8.5, avoid 1.8.10 as it introduces a few bugs that are
-fixed in later releases.
+fixed in later releases.  Please make sure you don't install ld.so-2.x
+unless you're running glibc2 / libc6.
 
    If you upgrade to libc-5.4.x, you may also need to upgrade ypbind if
 you're using NIS.
@@ -96,7 +93,7 @@ you're using NIS.
 Modules
 =======
 
-   You need to upgrade to modutils-2.1.42 for kernels 2.1.42 and later.
+   You need to upgrade to modutils-2.1.55 for kernels 2.1.55 and later.
 This version will also work with 2.0.x kernels.
 
 Binutils
@@ -110,7 +107,7 @@ Gnu C
 =====
 
    You need at least GCC 2.7.2 to compile the kernel.  If you're
-upgrading from an earlier release, you might as well get GCC 2.7.2.1,
+upgrading from an earlier release, you might as well get GCC 2.7.2.3,
 the latest public release.  If you already have GCC 2.7.2 on your
 system, you don't have to upgrade just so the kernel will work (though
 feel free to upgrade if you want the gcc bug fixes).
@@ -146,24 +143,17 @@ Memory
 ======
 
    As of 2.1.41, the format of /proc/meminfo has changed.  This broke
-many memory utils, which have to be upgraded.  Get the new procinfo and
-procps (which, AFAIK, is not yet available) to fix this.  Until you
-upgrade, programs which read /proc/meminfo will seg-fault or give an
-error.  There is an unofficial update to 1.12.2 available that fixes
-most problems.
+many memory utils, which have to be upgraded.  Get the new procps-1.2
+and you should be set.
 
 Mount and network file systems
 ==============================
 
    The NFS code in the kernel is currently being revised, resulting in
 much-improved performance.  As a result, you'll need to upgrade mount
-to a 2.6 release.  Also, amd is being phased out in favor of the much
-better autofs.  You'll also have to get the appropriate utils to use
-autofs as well as the new NFS utils.
-
-The smbfs code is also being revised. This results in an incompatible
-mount interface. See the README of smbfs-2.1.0 or later for a
-description of the new mount command.
+to a recent 2.6 release.  Also, amd is being phased out in favor of the
+much better autofs.  You'll also have to get the appropriate utils to
+use autofs as well as the new NFS utils.
 
 RPM
 ===
@@ -223,55 +213,53 @@ ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.8.1.0.1
 Gnu C
 =====
 
-The 2.7.2.1 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/gcc-2.7.2.1.bin.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/gcc-2.7.2.1.bin.tar.gz
+The 2.7.2.3 release:
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/gcc-2.7.2.3.bin.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/gcc-2.7.2.3.bin.tar.gz
 Installation notes:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.gcc-2.7.2.1
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.gcc-2.7.2.1
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.gcc-2.7.2.3
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.gcc-2.7.2.3
 
 Linux C Library
 ===============
 
-The 5.4.33 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/libc-5.4.33.bin.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.4.33.bin.tar.gz
-Installation notes for 5.4.33:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.libc-5.4.33
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.4.33
+The 5.4.38 release:
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/libc-5.4.38.bin.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.4.38.bin.tar.gz
+Installation notes for 5.4.38:
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.libc-5.4.38
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.4.38
 
 Linux C++ Library
 =================
 
-The 2.7.2.1 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/libg++-2.7.2.1.bin.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/libg++-2.7.2.1.bin.tar.gz
+The 2.7.2.8 release:
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/libg++-2.7.2.8.bin.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/libg++-2.7.2.8.bin.tar.gz
 Installation notes:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.libg++-2.7.2.1
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.libg++-2.7.2.1
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.libg++-2.7.2.8
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.libg++-2.7.2.8
 
 Dynamic Linker
 ==============
 
-The 1.9.2 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/ld.so-1.9.2.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/ld.so-1.9.2.tar.gz
+The 1.9.5 release:
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/ld.so-1.9.5.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/ld.so-1.9.5.tar.gz
 
 Modules utilities
 =================
 
-The 2.1.42 release:
-ftp://ftp.redhat.com/pub/alphabits/modutils-2.1.42.tar.gz
-ftp://ftp.kernel.org/pub/linux/kernel/v2.1/modutils-2.1.42.tar.gz
+The 2.1.55 release:
+ftp://ftp.redhat.com/pub/alphabits/modutils/modutils-2.1.55.tar.gz
+ftp://ftp.kernel.org/pub/linux/kernel/v2.1/modutils-2.1.55.tar.gz
 
 Procps utilities
 ================
 
-The 1.01 release:
-ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.01.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/system/status/ps/procps-1.01.tgz
-The unofficial 1.12.2 release:
-ftp://ftp.debian.org/pub/debian/hamm/hamm/source/base/procps_1.12.2.tar.gz
+The 1.2 release:
+ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.2.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/system/status/ps/procps-1.2.tgz
 
 Procinfo utilities
 ==================
@@ -316,14 +304,14 @@ ftp://prep.ai.mit.edu/pub/gnu/sh-utils-1.16.tar.gz
 Mount
 =====
 
-The 2.6g release:
-ftp://ftp.win.tue.nl/pub/linux/util/mount-2.6g.tar.gz
+The 2.6h release:
+ftp://ftp.win.tue.nl/pub/linux/util/mount-2.6h.tar.gz
 
 Autofs
 ======
 
-The 0.3.7 release:
-ftp://ftp.kernel.org/pub/linux/daemons/autofs/autofs-0.3.7.tar.gz
+The 0.3.11 release:
+ftp://ftp.kernel.org/pub/linux/daemons/autofs/autofs-0.3.11.tar.gz
 
 NFS
 ===
@@ -335,7 +323,7 @@ ftp://linux.nrao.edu/pub/people/okir/linux-nfs-0.4.21.tar.gz
 Net-tools
 =========
 
-The 0.41 release:
+The 1.41 release:
 ftp://ftp.london.uk.eu.org/pub/ipv6/net-tools-1.41.tar.gz
 ftp://ftp.cs-ipv6.lancs.ac.uk/pub/Code/Linux/Net_Tools/net-tools-1.41.tar.gz
 
index f9aa0294d87a98aa5a54d5c2b6506feec3f5155d..37bdfae0b93bbeeb842aab974793426536ad98f1 100644 (file)
@@ -47,7 +47,7 @@ foo \kill}%
 %
 \title{{\bf Linux Allocated Devices}}
 \author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$}
-\date{Last revised: September 5, 1997}
+\date{Last revised: September 11, 1997}
 \maketitle
 %
 \noindent
@@ -57,8 +57,9 @@ is a registry of allocated major device numbers, as well as the
 recommended {\file /dev} directory nodes for these devices.
 
 The latest version of this list is included with the Linux kernel
-sources in \LaTeX\ and ASCII form.  In case of discrepancy, the
-\LaTeX\ version is authoritative.
+sources in \LaTeX\ and ASCII form.  It is also available separate from
+{\url ftp://ftp.kernel.org/pub/linux/docs/device-list/}.  In case of
+discrepancy, the \LaTeX\ version is authoritative.
 
 This document is included by reference into the Linux Filesystem
 Standard (FSSTND).  The FSSTND is available from
@@ -66,10 +67,10 @@ Standard (FSSTND).  The FSSTND is available from
 
 To have a major number allocated, or a minor number in situations
 where that applies (e.g.\ busmice), please contact me with the
-appropriate device information.  I *very* much appreciate if you send
-me a device description in the same format as the ones already in this
-file.  Also, if you have additional information regarding any of the
-devices listed below, or if I have made a mistake, I would greatly
+appropriate device information.  I {\em very\/} much appreciate if you
+send me a device description in the same format as the ones already in
+this file.  Also, if you have additional information regarding any of
+the devices listed below, or if I have made a mistake, I would greatly
 appreciate a note.
 
 NOTE: When sending me mail, {\em please\/} include the word ``device''
@@ -176,6 +177,7 @@ reply.
 \major{43}{}{char }{isdn4linux virtual modem}
 \major{  }{}{block}{Network block devices}
 \major{44}{}{char }{isdn4linux virtual modem -- alternate devices}
+\major{  }{}{block}{Flash Translation Layer (FTL) filesystems}
 \major{45}{}{char }{isdn4linux ISDN BRI driver}
 \major{46}{}{char }{Comtrol Rocketport serial card}
 \major{47}{}{char }{Comtrol Rocketport serial card -- alternate devices}
@@ -218,7 +220,8 @@ reply.
 \major{87}{}{char }{Sony Control-A1 stereo control bus}
 \major{88}{}{char }{COMX synchronous serial card}
 \major{89}{}{char }{I$^2$C bus interface}
-\major{90}{--119}{}{Unallocated}
+\major{90}{}{char }{Memory Technology Device (RAM, ROM, Flash)}
+\major{91}{--119}{}{Unallocated}
 \major{120}{--127}{}{Local/experimental use}
 \major{128}{--239}{}{Unallocated}
 \major{240}{--254}{}{Local/experimental use}
@@ -1094,8 +1097,20 @@ net, implementing block device in userland etc.
        \minor{0}{/dev/cui0}{Callout device corresponding to {\file ttyI0}}
        \minordots
        \minor{63}{/dev/cui63}{Callout device corresponding to {\file ttyI63}}
+\\
+\major{  }{}{block}{Flash Translation Layer (FTL) filesystems}
+        \minor{0}{/dev/ftla}{FTL on first Memory Technology Device}
+        \minor{16}{/dev/ftlb}{FTL on second Memory Technology Device}
+        \minor{32}{/dev/ftlc}{FTL on third Memory Technology Device}
+        \minordots
+        \minor{240}{/dev/ftlp}{FTL on 16th Memory Technology Device}
 \end{devicelist}
 
+\noindent
+Partitions are handled in the same way as for IDE disks (see major
+number 3) expect that the partition limit is 15 rather than 63 per
+disk (same as SCSI.)
+
 \begin{devicelist}
 \major{45}{}{char }{isdn4linux ISDN BRI driver}
        \minor{0}{/dev/isdn0}{First virtual B channel raw data}
@@ -1482,7 +1497,16 @@ on {\url http://home.pages.de/~videotext/\/}.
 \end{devicelist}
 
 \begin{devicelist}
-\major{90}{--119}{}{Unallocated}
+\major{90}{}{char }{Memory Technology Device (RAM, ROM, Flash)}
+        \minor{0}{/dev/mtd0}{First MTD (rw)}
+        \minor{1}{/dev/mtdr0}{First MTD (ro)}
+        \minordots
+        \minor{30}{/dev/mtd15}{16th MTD (rw)}
+        \minor{31}{/dev/mtdr15}{16th MTD (ro)}
+\end{devicelist}
+
+\begin{devicelist}
+\major{91}{--119}{}{Unallocated}
 \end{devicelist}
 
 \begin{devicelist}
index c9697e262343c7e2a3d39a4c6040367df8c97f1c..4c390293b086c3eea87cfa868e6eecb4e29012f7 100644 (file)
@@ -1,7 +1,7 @@
                       LINUX ALLOCATED DEVICES
             Maintained by H. Peter Anvin <hpa@zytor.com>
 
-                  Last revised: September 5, 1997
+                  Last revised: September 11, 1997
 
 This list is the successor to Rick Miller's Linux Device List, which
 he stopped maintaining when he got busy with other things in 1993.  It
@@ -9,12 +9,13 @@ is a registry of allocated major device numbers, as well as the
 recommended /dev directory nodes for these devices.
 
 The latest version of this list is included with the Linux kernel
-sources in LaTeX and ASCII form.  In case of discrepancy, the LaTeX
-version is authoritative.
+sources in LaTeX and ASCII form.  It is also available separately from
+ftp://ftp.kernel.org/pub/linux/docs/device-list/.  In case of
+discrepancy, the LaTeX version is authoritative.
 
 This document is included by reference into the Linux Filesystem
-Standard (FSSTND).  The FSSTND is available via FTP from
-tsx-11.mit.edu in the directory /pub/linux/docs/linux-standards/fsstnd.
+Standard (FSSTND).  The FSSTND is available from
+ftp://tsx-11.mit.edu/pub/linux/docs/linux-standards/fsstnd/.
 
 To have a major number allocated, or a minor number in situations
 where that applies (e.g. busmice), please contact me with the
@@ -748,6 +749,16 @@ reply.
                  0 = /dev/cui0         Callout device corresponding to ttyI0
                      ...
                 63 = /dev/cui63        Callout device corresponding to ttyI63
+    block      Flash Translatio Layer (FTL) filesystems
+                 0 = /dev/ftla         FTL on first Memory Technology Device
+                16 = /dev/ftlb         FTL on second Memory Technology Device
+                32 = /dev/ftlc         FTL on third Memory Technology Device
+                     ...
+               240 = /dev/ftlp         FTL on 16th Memory Technology Device 
+
+               Partitions are handled in the same way as for IDE
+               disks (see major number 3) expect that the partition
+               limit is 15 rather than 63 per disk (same as SCSI.)
 
  45 char       isdn4linux ISDN BRI driver
                  0 = /dev/isdn0        First virtual B channel raw data
@@ -1042,7 +1053,14 @@ reply.
                  1 = /dev/i2c1         Second I2C adapter
                    ...
 
- 90-119                UNALLOCATED
+ 90 char       Memory Technology Device (RAM, ROM, Flash)
+                 0 = /dev/mtd0         First MTD (rw)
+                 1 = /dev/mtdr0        First MTD (ro)
+                   ...
+                30 = /dev/mtd15        16th MTD (rw)
+                31 = /dev/mtdr15       16th MTD (ro)
+
+ 91-119                UNALLOCATED
 
 120-127                LOCAL/EXPERIMENTAL USE
 
index 17a659e55538fd669ac59d2826587890f6a38483..aa9f3ca45ae953f229c3703577c20645180e0513 100644 (file)
@@ -6,12 +6,61 @@ You can pass parameters to the parport code to override its automatic
 detection of your hardware.  This is particularly useful if you want
 to use IRQs, since in general these can't be autoprobed successfully.
 
+The parport code is split into two parts: generic (which deals with
+port-sharing) and architecture-dependent (which deals with actually
+using the port).
+
+Parport as modules
+==================
+
 If you load the parport code as a module, say
 
-       # insmod parport.o io=0x378,0x278 irq=7,5
+       # insmod parport.o
+
+to load the generic parport code.  You then must load the
+architecture-dependent code with (for example):
+
+       # insmod parport_pc.o io=0x378,0x278 irq=7,5
+
+to tell the parport code that you want two PC-style ports, one at
+0x378 using IRQ 7, and one at 0x278 using IRQ 5.  Currently, PC-style
+(parport_pc) and ARC onboard (parport_arc) parallel ports are
+supported.
+
+Kerneld
+-------
+
+If you use kerneld, you will find it useful to edit /etc/conf.modules.
+Here is an example of the lines that need to be added:
+
+       alias parport_lowlevel parport_pc
+       options parport_pc io=0x378,0x278 irq=7,5
+
+Kerneld, in conjunction with parport, will automatically load
+parport_pc whenever a parallel port device driver (such as lp) is
+loaded.
+
+Parport probe [optional]
+-------------
 
-to tell the parport code that you want two ports, one at 0x378 using
-IRQ 7, and one at 0x278 using IRQ 5. 
+Once the architecture-dependent part of the parport code is loaded
+into the kernel, you insert the parport_probe module with:
+
+       # insmod parport_probe.o
+
+This will perform an IEEE1284 probe of any attached devices and log a
+message similar to:
+
+       parport0: Printer, BJC-210 (Canon)
+
+Additionally, if you use kerneld, you can add to /etc/conf.modules the
+following lines, to have the probe happen automatically:
+
+       post-install parport modprobe parport_probe
+       pre-remove parport modprobe -r parport_probe
+
+Parport, but not as modules
+===========================
 
 If you compile the parport code into the kernel, then you can use
 kernel boot parameters to get the same effect.  Add something like the
@@ -20,12 +69,15 @@ following to your LILO command line:
        parport=0x378,7 parport=0x278,5
 
 You can have many `parport=...' statements, one for each port you want
-to add.  Adding `parport=0' or just `parport=' to the command-line
-will disable parport support entirely.
+to add.  Adding `parport=0' to the kernel command-line will disable
+parport support entirely.
+
+Device drivers
+==============
 
 Once the parport code is initialised, you can attach device drivers to
-ports.  Normally this happens automatically; if the lp driver is
-loaded it will create one lp device for each port found.  You can
+specific ports.  Normally this happens automatically; if the lp driver
+is loaded it will create one lp device for each port found.  You can
 override this, though, by using parameters either when you load the lp
 driver:
 
@@ -57,3 +109,8 @@ Also:
  * If your BIOS allows you to engage "ECP mode", you may find that
    your port's IRQ can be autoprobed, without having to specify any 
    parameters.
+
+
+--
+Philip.Blundell@pobox.com
+tim@cyberelk.demon.co.uk
index e838de545fc86e3bd6f0d4bd93436ee25e9b8eba..73d31f7bdbe40728041e09e0598410765bbc1923 100644 (file)
@@ -4,8 +4,8 @@ Stallion Multiport Serial Driver Readme
 
 Copyright (C) 1994-1997,  Stallion Technologies (support@stallion.oz.au).
 
-Version:   5.3.2
-Date:      11FEB97
+Version:   5.3.4
+Date:      15SEP97
 
 
 
index 24d65bc41d2f1c5782350467d3c6650ab374e5d2..f381407a4f578820e62295ef61c3063df79abb17 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 55
+SUBLEVEL = 56
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
 
index 93f300de7a695225990898d2bdf79285e1117f4d..d4118f63ffccbe6e9f3b15d15588582d5d69a18f 100644 (file)
@@ -178,6 +178,7 @@ CONFIG_EEXPRESS_PRO100=y
 # CONFIG_NET_RADIO is not set
 # CONFIG_SLIP is not set
 # CONFIG_TR is not set
+# CONFIG_WAN_DRIVERS is not set
 # CONFIG_LAPBETHER is not set
 # CONFIG_X25_ASY is not set
 
index 3ceb16c0bedad3a2f5865b54b51c44f8cc7bc375..d05120c59f0c352a5b259216f9f411d9b47dcf4b 100644 (file)
@@ -179,6 +179,13 @@ floppy=fifo
        Uses a less noisy way to clear the disk change line (which
        doesn't involve seeks). Implied by daring.
 
+ floppy=<nr>,irq
+       Sets the floppy IRQ to <nr> instead of 6
+
+ floppy=<nr>,dma
+       Sets the floppy DMA channel to <nr> instead of 2
+
+
 Supporting utilities and additional documentation:
 ==================================================
 
index fbceed0962cd323e75719c1ee9b0d386eabf6d90..2d30343df8d1d5cba9a16c088216ca54d0030d04 100644 (file)
@@ -3866,6 +3866,9 @@ static struct param_table {
        { "all_drives", 0, &allowed_drive_mask, 0xff, 0 }, /* obsolete */
        { "asus_pci", 0, &allowed_drive_mask, 0x33, 0},
 
+       { "irq", 0, &FLOPPY_IRQ, 6, 0 },
+       { "dma", 0, &FLOPPY_DMA, 2, 0 },
+
        { "daring", daring, 0, 1, 0},
 
        { "two_fdc",  0, &FDC2, 0x370, 0 },
index 25b3d54fa1a76c8dc2460ac5426540a162ea6acc..ddaf1b0c6a501e1175073a65445bf89bfb9aab75 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide-probe.c    Version 1.01  Jan  26, 1997
+ *  linux/drivers/block/ide-probe.c    Version 1.02  Jul  29, 1997
  *
  *  Copyright (C) 1994-1996  Linus Torvalds & authors (see below)
  */
@@ -38,6 +38,8 @@
  *
  * Version 1.00                move drive probing code from ide.c to ide-probe.c
  * Version 1.01                fix compilation problem for m68k
+ * Version 1.02                increase WAIT_PIDENTIFY to avoid CD-ROM locking at boot
+ *                     by Andrea Arcangeli <arcangeli@mbox.queen.it>
  */
 
 #undef REALLY_SLOW_IO          /* most systems can safely undef this */
index 2f60115a33bf1df1b5edfaa3b2037eb6609c65cd..5c69eb353774c48e23aff0a2cb9e1968f0387ec7 100644 (file)
@@ -158,7 +158,8 @@ typedef unsigned char       byte;   /* used everywhere */
 #else
 #define WAIT_READY     (3*HZ/100)      /* 30msec - should be instantaneous */
 #endif /* CONFIG_APM */
-#define WAIT_PIDENTIFY (1*HZ)  /* 1sec   - should be less than 3ms (?) */
+#define WAIT_PIDENTIFY (10*HZ) /* 10sec  - should be less than 3ms (?)
+                                           if all ATAPI CD is closed at boot */
 #define WAIT_WORSTCASE (30*HZ) /* 30sec  - worst case when spinning up */
 #define WAIT_CMD       (10*HZ) /* 10sec  - maximum wait for an IRQ to happen */
 #define WAIT_MIN_SLEEP (2*HZ/100)      /* 20msec - minimum sleep time */
index 270159480516b1722631a2b14f5171797d0327a1..f18d25d9abb684d81329287568e8ee9bd0fbdd47 100644 (file)
@@ -129,8 +129,7 @@ typedef struct {
 } stlconf_t;
 
 static stlconf_t       stli_brdconf[] = {
-       /*{ BRD_ECP, 0x2a0, 0, 0xcc000, 0, 0 },*/
-       { BRD_ECP, 0x2b0, 0, 0xcc000, 0, 0 },
+       { BRD_ECP, 0x2a0, 0, 0xcc000, 0, 0 },
 };
 
 static int     stli_nrbrds = sizeof(stli_brdconf) / sizeof(stlconf_t);
@@ -168,7 +167,7 @@ static int  stli_nrbrds = sizeof(stli_brdconf) / sizeof(stlconf_t);
  *     all the local structures required by a serial tty driver.
  */
 static char    *stli_drvname = "Stallion Intelligent Multiport Serial Driver";
-static char    *stli_drvversion = "5.3.2";
+static char    *stli_drvversion = "5.3.4";
 static char    *stli_serialname = "ttyE";
 static char    *stli_calloutname = "cue";
 
@@ -447,6 +446,7 @@ int         stli_eisaprobe = STLI_EISAPROBE;
 #define        ECH_PNLSTATUS   2
 #define        ECH_PNL16PORT   0x20
 #define        ECH_PNLIDMASK   0x07
+#define        ECH_PNLXPID     0x40
 #define        ECH_PNLINTRPEND 0x80
 
 /*
@@ -542,12 +542,12 @@ static void       stli_flushbuffer(struct tty_struct *tty);
 static void    stli_hangup(struct tty_struct *tty);
 
 static inline int stli_initbrds(void);
-static int     stli_brdinit(stlibrd_t *brdp);
 static inline int stli_initecp(stlibrd_t *brdp);
 static inline int stli_initonb(stlibrd_t *brdp);
-static int     stli_eisamemprobe(stlibrd_t *brdp);
 static inline int stli_findeisabrds(void);
 static inline int stli_initports(stlibrd_t *brdp);
+static int     stli_eisamemprobe(stlibrd_t *brdp);
+static int     stli_brdinit(stlibrd_t *brdp);
 static int     stli_startbrd(stlibrd_t *brdp);
 static long    stli_memread(struct inode *ip, struct file *fp, char *buf, unsigned long count);
 static long    stli_memwrite(struct inode *ip, struct file *fp, const char *buf, unsigned long count);
@@ -3341,7 +3341,7 @@ static inline int stli_initecp(stlibrd_t *brdp)
        cdkecpsig_t     sig;
        cdkecpsig_t     *sigsp;
        unsigned int    status, nxtid;
-       int             panelnr;
+       int             panelnr, nrports;
 
 #if DEBUG
        printk("stli_initecp(brdp=%x)\n", (int) brdp);
@@ -3448,16 +3448,13 @@ static inline int stli_initecp(stlibrd_t *brdp)
                status = sig.panelid[nxtid];
                if ((status & ECH_PNLIDMASK) != nxtid)
                        break;
-               if (status & ECH_PNL16PORT) {
-                       brdp->panels[panelnr] = 16;
-                       brdp->nrports += 16;
-                       nxtid += 2;
-               } else {
-                       brdp->panels[panelnr] = 8;
-                       brdp->nrports += 8;
-                       nxtid++;
-               }
                brdp->panelids[panelnr] = status;
+               nrports = (status & ECH_PNL16PORT) ? 16 : 8;
+               if ((nrports == 16) && ((status & ECH_PNLXPID) == 0))
+                       nxtid++;
+               brdp->panels[panelnr] = nrports;
+               brdp->nrports += nrports;
+               nxtid++;
                brdp->nrpanels++;
        }
 
index c84f0846cf8f86d231457ed7f52f337e157c65f6..49a6c65dbfe0b762ab60e301eb70f54dab6f4884 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/fcntl.h>
 #include <linux/delay.h>
 
+#include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -103,7 +104,13 @@ static int lp_reset(int minor)
        return r_str(minor);
 }
 
-static inline int lp_char_polled(char lpchar, int minor)
+static inline int must_use_polling(int minor)
+{
+       return lp_table[minor].dev->port->irq == PARPORT_IRQ_NONE ||
+                      lp_table[minor].dev->port->devices->next;
+}
+
+static inline int lp_char(char lpchar, int minor, int use_polling)
 {
        int status;
        unsigned int wait = 0;
@@ -115,12 +122,13 @@ static inline int lp_char_polled(char lpchar, int minor)
                count++;
                if (need_resched)
                        lp_schedule (minor);
-       } while (!LP_READY(minor, status) && count < LP_CHAR(minor));
+       } while (((use_polling && !LP_READY(minor, status)) || 
+                (!use_polling && !(status & LP_PBUSY))) &&
+                (count < LP_CHAR(minor)));
 
-       if (count == LP_CHAR(minor)) {
+       if (count == LP_CHAR(minor) ||
+           (!use_polling && !LP_CAREFUL_READY(minor, status)))
                return 0;
-               /* we timed out, and the character was /not/ printed */
-       }
        w_dtr(minor, lpchar);
        stats = &LP_STAT(minor);
        stats->chars++;
@@ -150,50 +158,6 @@ static inline int lp_char_polled(char lpchar, int minor)
        return 1;
 }
 
-static inline int lp_char_interrupt(char lpchar, int minor)
-{
-       unsigned int wait;
-       unsigned long count = 0;
-       unsigned char status;
-       struct lp_stats *stats;
-
-       do {
-               if(need_resched)
-                       lp_schedule (minor);
-               if ((status = r_str(minor)) & LP_PBUSY) {
-                       if (!LP_CAREFUL_READY(minor, status))
-                               return 0;
-                       w_dtr(minor, lpchar);
-                       stats = &LP_STAT(minor);
-                       stats->chars++;
-                       /* must wait before taking strobe high, and after taking strobe
-                          low, according spec.  Some printers need it, others don't. */
-                       wait = 0;
-                       while (wait != LP_WAIT(minor)) /* FIXME: should be */
-                               wait++;                /* a udelay ()      */
-                       /* control port takes strobe high */
-                       w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE);
-                       while (wait)
-                               wait--; /* FIXME: should be a udelay() */
-                       /* take strobe low */
-                       w_ctr(minor, LP_PSELECP | LP_PINITP);
-                       /* update waittime statistics */
-                       if (count) {
-                               if (count > stats->maxwait)
-                                       stats->maxwait = count;
-                               count *= 256;
-                               wait = (count > stats->meanwait) ? count - stats->meanwait :
-                                   stats->meanwait - count;
-                               stats->meanwait = (255 * stats->meanwait + count + 128) / 256;
-                               stats->mdev = ((127 * stats->mdev) + wait + 64) / 128;
-                       }
-                       return 1;
-               }
-       } while (count++ < LP_CHAR(minor));
-
-       return 0;
-}
-
 static void lp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        struct parport *pb = (struct parport *) dev_id;
@@ -204,7 +168,16 @@ static void lp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                wake_up(&lp_dev->lp_wait_q);
 }
 
-static inline int lp_write_interrupt(unsigned int minor, const char *buf, int count)
+static void lp_error(int minor)
+{
+       if (must_use_polling(minor)) {
+               current->state = TASK_INTERRUPTIBLE;
+               current->timeout = jiffies + LP_TIMEOUT_POLLED;
+               lp_schedule (minor);
+       }
+}
+
+static inline int lp_write_buf(unsigned int minor, const char *buf, int count)
 {
        unsigned long copy_size;
        unsigned long total_bytes_written = 0;
@@ -223,7 +196,7 @@ static inline int lp_write_interrupt(unsigned int minor, const char *buf, int co
                copy_from_user(lp->lp_buffer, buf, copy_size);
 
                while (copy_size) {
-                       if (lp_char_interrupt(lp->lp_buffer[bytes_written], minor)) {
+                       if (lp_char(lp->lp_buffer[bytes_written], minor, must_use_polling(minor))) {
                                --copy_size;
                                ++bytes_written;
                                lp_table[minor].runchars++;
@@ -236,32 +209,48 @@ static inline int lp_write_interrupt(unsigned int minor, const char *buf, int co
                                        printk(KERN_INFO "lp%d out of paper\n", minor);
                                        if (LP_F(minor) & LP_ABORT)
                                                return rc ? rc : -ENOSPC;
+                                       lp_error(minor);
                                } else if (!(status & LP_PSELECD)) {
                                        printk(KERN_INFO "lp%d off-line\n", minor);
                                        if (LP_F(minor) & LP_ABORT)
                                                return rc ? rc : -EIO;
+                                       lp_error(minor);
                                } else if (!(status & LP_PERRORP)) {
                                        printk(KERN_ERR "lp%d printer error\n", minor);
                                        if (LP_F(minor) & LP_ABORT)
                                                return rc ? rc : -EIO;
+                                       lp_error(minor);
                                }
+
                                LP_STAT(minor).sleeps++;
-                               cli();
-                               enable_irq(lp->dev->port->irq);
-                               w_ctr(minor, LP_PSELECP|LP_PINITP|LP_PINTEN);
-                               status = r_str(minor);
-                               if ((!(status & LP_PACK) || (status & LP_PBUSY))
-                                   && LP_CAREFUL_READY(minor, status)) {
+
+                               if (must_use_polling(minor)) {
+#ifdef LP_DEBUG
+                                       printk(KERN_DEBUG "lp%d sleeping at %d characters for %d jiffies\n", minor, lp_table[minor].runchars, LP_TIME(minor));
+#endif
+                                       lp_table[minor].runchars = 0;
+                                       current->state = TASK_INTERRUPTIBLE;
+                                       current->timeout = jiffies + LP_TIME(minor);
+                                       lp_schedule (minor);
+                               } else {
+                                       cli();
+                                       enable_irq(lp->dev->port->irq);
+                                       w_ctr(minor, LP_PSELECP|LP_PINITP|LP_PINTEN);
+                                       status = r_str(minor);
+                                       if ((!(status & LP_PACK) || (status & LP_PBUSY))
+                                           && LP_CAREFUL_READY(minor, status)) {
+                                               w_ctr(minor, LP_PSELECP | LP_PINITP);
+                                               sti();
+                                               continue;
+                                       }
+                                       lp_table[minor].runchars = 0;
+                                       current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
+                                       interruptible_sleep_on(&lp->lp_wait_q);
+
                                        w_ctr(minor, LP_PSELECP | LP_PINITP);
                                        sti();
-                                       continue;
                                }
-                               lp_table[minor].runchars = 0;
-                               current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
-                               interruptible_sleep_on(&lp->lp_wait_q);
 
-                               w_ctr(minor, LP_PSELECP | LP_PINITP);
-                               sti();
                                if (current->signal & ~current->blocked) {
                                        if (total_bytes_written + bytes_written)
                                                return total_bytes_written + bytes_written;
@@ -280,72 +269,6 @@ static inline int lp_write_interrupt(unsigned int minor, const char *buf, int co
        return total_bytes_written;
 }
 
-static inline int lp_write_polled(unsigned int minor, const char *buf, int count)
-{
-       int  retval, status;
-       char c;
-       const char *temp;
-
-       temp = buf;
-       while (count > 0) {
-               get_user(c, temp);
-               retval = lp_char_polled(c, minor);
-               /* only update counting vars if character was printed */
-               if (retval) {
-                       count--; temp++;
-                       lp_table[minor].runchars++;
-               } else { /* if printer timed out */
-                       if (lp_table[minor].runchars > LP_STAT(minor).maxrun)
-                                LP_STAT(minor).maxrun = lp_table[minor].runchars;
-                       status = r_str(minor);
-
-                       if (status & LP_POUTPA) {
-                               printk(KERN_INFO "lp%d out of paper\n", minor);
-                               if(LP_F(minor) & LP_ABORT)
-                                       return temp-buf?temp-buf:-ENOSPC;
-                               current->state = TASK_INTERRUPTIBLE;
-                               current->timeout = jiffies + LP_TIMEOUT_POLLED;
-                               lp_schedule (minor);
-                       } else
-                       if (!(status & LP_PSELECD)) {
-                               printk(KERN_INFO "lp%d off-line\n", minor);
-                               if(LP_F(minor) & LP_ABORT)
-                                       return temp-buf?temp-buf:-EIO;
-                               current->state = TASK_INTERRUPTIBLE;
-                               current->timeout = jiffies + LP_TIMEOUT_POLLED;
-                               lp_schedule (minor);
-                       } else
-                       /* not offline or out of paper. on fire? */
-                       if (!(status & LP_PERRORP)) {
-                               printk(KERN_ERR "lp%d on fire\n", minor);
-                               if(LP_F(minor) & LP_ABORT)
-                                       return temp-buf?temp-buf:-EIO;
-                               current->state = TASK_INTERRUPTIBLE;
-                               current->timeout = jiffies + LP_TIMEOUT_POLLED;
-                               lp_schedule (minor);
-                       }
-
-                       /* check for signals before going to sleep */
-                       if (current->signal & ~current->blocked) {
-                               if (temp != buf)
-                                       return temp-buf;
-                               else
-                                       return -EINTR;
-                       }
-                       LP_STAT(minor).sleeps++;
-#ifdef LP_DEBUG
-                       printk(KERN_DEBUG "lp%d sleeping at %d characters for %d jiffies\n",
-                               minor,lp_table[minor].runchars, LP_TIME(minor));
-#endif
-                       lp_table[minor].runchars=0;
-                       current->state = TASK_INTERRUPTIBLE;
-                       current->timeout = jiffies + LP_TIME(minor);
-                       lp_schedule (minor);
-               }
-       }
-       return temp-buf;
-}
-
 static long lp_write(struct inode * inode, struct file * file,
        const char * buf, unsigned long count)
 {
@@ -362,10 +285,7 @@ static long lp_write(struct inode * inode, struct file * file,
         */
        lp_parport_claim (minor);
 
-       if (LP_IRQ(minor) > 0)
-               retv = lp_write_interrupt(minor, buf, count);
-       else
-               retv = lp_write_polled(minor, buf, count);
+       retv = lp_write_buf(minor, buf, count);
  
        lp_parport_release (minor);
        return retv;
@@ -431,7 +351,7 @@ static long lp_read(struct inode * inode, struct file * file,
                        udelay(50);
                        counter++;
                        if (need_resched)
-                               lp_schedule (minor);
+                               schedule ();
                } while ( (status == 0x40) && (counter < 20) );
                if ( counter == 20 ) { /* Timeout */
 #ifdef LP_READ_DEBUG
@@ -450,7 +370,7 @@ static long lp_read(struct inode * inode, struct file * file,
                        udelay(20);
                        counter++;
                        if (need_resched)
-                               lp_schedule (minor);
+                               schedule ();
                } while ( (status == 0) && (counter < 20) );
                if (counter == 20) { /* Timeout */
 #ifdef LP_READ_DEBUG
@@ -466,7 +386,7 @@ static long lp_read(struct inode * inode, struct file * file,
                        }
                        current->state=TASK_INTERRUPTIBLE;
                        current->timeout=jiffies + LP_TIME(minor);
-                       lp_schedule (minor);
+                       schedule ();
                }
                counter=0;
                if (( i & 1) != 0) {
@@ -516,12 +436,10 @@ static int lp_open(struct inode * inode, struct file * file)
                        return -EIO;
                }
        }
-       if (LP_IRQ(minor) > 0) {
-               lp_table[minor].lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
-               if (!lp_table[minor].lp_buffer) {
-                       MOD_DEC_USE_COUNT;
-                       return -ENOMEM;
-               }
+       lp_table[minor].lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
+       if (!lp_table[minor].lp_buffer) {
+               MOD_DEC_USE_COUNT;
+               return -ENOMEM;
        }
        LP_F(minor) |= LP_BUSY;
        return 0;
@@ -530,12 +448,9 @@ static int lp_open(struct inode * inode, struct file * file)
 static int lp_release(struct inode * inode, struct file * file)
 {
        unsigned int minor = MINOR(inode->i_rdev);
-       unsigned int irq;
 
-       if ((irq = LP_IRQ(minor)) != PARPORT_IRQ_NONE) {
-               kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
-               lp_table[minor].lp_buffer = NULL;
-       }
+       kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
+       lp_table[minor].lp_buffer = NULL;
        LP_F(minor) &= ~LP_BUSY;
        MOD_DEC_USE_COUNT;
        return 0;
index 9a77783b366518dfa04febe1600e7ed015eb9f00..2f8a5a75bffe5f41fcae9de4876f9892e395669f 100644 (file)
@@ -28,6 +28,7 @@
  *              drivers to panic the system if it's overheating at bootup.
  * 961118      Changed some verbiage on some of the output, tidied up
  *             code bits, and added compatibility to 2.1.x.
+ * 970912       Enabled board on open and disable on close.
  */
 
 #include <linux/module.h>
@@ -209,9 +210,6 @@ static void pcwd_send_heartbeat(void)
 {
        int wdrst_stat;
 
-       if (!is_open)
-               return;
-
        wdrst_stat = inb_p(current_readport);
        wdrst_stat &= 0x0F;
 
@@ -373,7 +371,13 @@ static long pcwd_write(struct inode *inode, struct file *file, const char *buf,
 
 static int pcwd_open(struct inode *ino, struct file *filep)
 {
+       if (is_open)
+               return -EIO;
        MOD_INC_USE_COUNT;
+       /*  Enable the port  */
+       if (revision == PCWD_REVISION_C)
+               outb_p(0x00, current_readport + 3);
+       is_open = 1;
        return(0);
 }
 
@@ -397,7 +401,15 @@ static long pcwd_read(struct inode *inode, struct file *file, char *buf,
 
 static int pcwd_close(struct inode *ino, struct file *filep)
 {
+       is_open = 0;
        MOD_DEC_USE_COUNT;
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+       /*  Disable the board  */
+       if (revision == PCWD_REVISION_C) {
+               outb_p(0xA5, current_readport + 3);
+               outb_p(0xA5, current_readport + 3);
+       }
+#endif
        return 0;
 }
 
@@ -531,8 +543,6 @@ __initfunc(int pcwatchdog_init(void))
        }
 #endif
 
-       is_open = 1;
-
 #ifdef PCWD_BLIND
        current_readport = PCWD_BLIND;
 #endif
@@ -571,6 +581,11 @@ __initfunc(int pcwatchdog_init(void))
 #ifdef MODULE
 void cleanup_module(void)
 {
+       /*  Disable the board  */
+       if (revision == PCWD_REVISION_C) {
+               outb_p(0xA5, current_readport + 3);
+               outb_p(0xA5, current_readport + 3);
+       }
        misc_deregister(&pcwd_miscdev);
        if (supports_temp)
                misc_deregister(&temp_miscdev);
index 184a2104049ba3d6011351d48f64ac591d5ceabc..1ec03230b0b5cebb5b3fa875add0fef834aeacf7 100644 (file)
@@ -102,8 +102,7 @@ typedef struct {
 } stlconf_t;
 
 static stlconf_t       stl_brdconf[] = {
-       /*{ BRD_EASYIO, 0x2a0, 0, 0, 10, 0 },*/
-       { BRD_ECH, 0x2a0, 0x280, 0, 15, 0 },
+       { BRD_EASYIO, 0x2a0, 0, 0, 10, 0 },
 };
 
 static int     stl_nrbrds = sizeof(stl_brdconf) / sizeof(stlconf_t);
@@ -141,7 +140,7 @@ static int  stl_nrbrds = sizeof(stl_brdconf) / sizeof(stlconf_t);
  *     all the local structures required by a serial tty driver.
  */
 static char    *stl_drvname = "Stallion Multiport Serial Driver";
-static char    *stl_drvversion = "5.3.2";
+static char    *stl_drvversion = "5.3.4";
 static char    *stl_serialname = "ttyE";
 static char    *stl_calloutname = "cue";
 
@@ -391,9 +390,9 @@ static void stl_hangup(struct tty_struct *tty);
 static int     stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
 
 static inline int stl_initbrds(void);
-static int     stl_brdinit(stlbrd_t *brdp);
 static inline int stl_initeio(stlbrd_t *brdp);
 static inline int stl_initech(stlbrd_t *brdp);
+static int     stl_brdinit(stlbrd_t *brdp);
 static int     stl_initports(stlbrd_t *brdp, stlpanel_t *panelp);
 static int     stl_mapirq(int irq);
 static void    stl_getserial(stlport_t *portp, struct serial_struct *sp);
@@ -436,7 +435,8 @@ static void stl_cd1400disableintrs(stlport_t *portp);
 static void    stl_cd1400sendbreak(stlport_t *portp, long len);
 static void    stl_cd1400flowctrl(stlport_t *portp, int state);
 static void    stl_cd1400flush(stlport_t *portp);
-static void    stl_cd1400intr(stlpanel_t *panelp, unsigned int iobase);
+static void    stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase);
+static void    stl_cd1400echintr(stlpanel_t *panelp, unsigned int iobase);
 static void    stl_cd1400txisr(stlpanel_t *panelp, int ioaddr);
 static void    stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr);
 static void    stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr);
@@ -519,7 +519,7 @@ static uart_t stl_cd1400uart = {
        stl_cd1400sendbreak,
        stl_cd1400flowctrl,
        stl_cd1400flush,
-       stl_cd1400intr
+       stl_cd1400eiointr
 };
 
 /*
@@ -1912,7 +1912,7 @@ static inline int stl_initeio(stlbrd_t *brdp)
                panelp->isr = stl_sc26198intr;
        } else {
                panelp->uartp = (void *) &stl_cd1400uart;
-               panelp->isr = stl_cd1400intr;
+               panelp->isr = stl_cd1400eiointr;
        }
 
        brdp->panels[0] = panelp;
@@ -2053,10 +2053,8 @@ static inline int stl_initech(stlbrd_t *brdp)
                        }
                } else {
                        panelp->uartp = (void *) &stl_cd1400uart;
-                       panelp->isr = stl_cd1400intr;
+                       panelp->isr = stl_cd1400echintr;
                        if (status & ECH_PNL16PORT) {
-                               if ((brdp->nrports + 16) > 32)
-                                       break;
                                panelp->nrports = 16;
                                panelp->ackmask = 0x80;
                                if (brdp->brdtype != BRD_ECHPCI)
@@ -3214,18 +3212,48 @@ static void stl_cd1400flush(stlport_t *portp)
        restore_flags(flags);
 }
 
+/*****************************************************************************/
+
+/*
+ *     Interrupt service routine for cd1400 EasyIO boards.
+ */
+
+static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase)
+{
+       unsigned char   svrtype;
+
+#if DEBUG
+       printk("stl_cd1400eiointr(panelp=%x,iobase=%x)\n", (int) panelp, iobase);
+#endif
+
+       outb(SVRR, iobase);
+       svrtype = inb(iobase + EREG_DATA);
+       if (panelp->nrports > 4) {
+               outb((SVRR + 0x80), iobase);
+               svrtype |= inb(iobase + EREG_DATA);
+       }
+
+       if (svrtype & SVRR_RX)
+               stl_cd1400rxisr(panelp, iobase);
+       if (svrtype & SVRR_TX)
+               stl_cd1400txisr(panelp, iobase);
+       if (svrtype & SVRR_MDM)
+               stl_cd1400mdmisr(panelp, iobase);
+}
+
+
 /*****************************************************************************/
 
 /*
  *     Interrupt service routine for cd1400 panels.
  */
 
-static void stl_cd1400intr(stlpanel_t *panelp, unsigned int iobase)
+static void stl_cd1400echintr(stlpanel_t *panelp, unsigned int iobase)
 {
        unsigned char   svrtype;
 
 #if DEBUG
-       printk("stl_cd1400intr(panelp=%x,iobase=%x)\n", (int) panelp, iobase);
+       printk("stl_cd1400echintr(panelp=%x,iobase=%x)\n", (int) panelp, iobase);
 #endif
 
        outb(SVRR, iobase);
@@ -3562,7 +3590,7 @@ static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp)
  *     Check that each chip is present and started up OK.
  */
        chipmask = 0;
-       nrchips = panelp->nrports / SC26198_PORTS;
+       nrchips = (panelp->nrports + 4) / SC26198_PORTS;
        if (brdp->brdtype == BRD_ECHPCI)
                outb(panelp->pagenr, brdp->ioctrl);
 
@@ -3778,7 +3806,7 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp)
        stl_sc26198setreg(portp, IMR, 0);
        stl_sc26198updatereg(portp, MR0, mr0);
        stl_sc26198updatereg(portp, MR1, mr1);
-       stl_sc26198setreg(portp, CCR, CR_RXERRBLOCK);
+       stl_sc26198setreg(portp, SCCR, CR_RXERRBLOCK);
        stl_sc26198updatereg(portp, MR2, mr2);
        stl_sc26198updatereg(portp, IOPIOR,
                ((stl_sc26198getreg(portp, IOPIOR) & ~IPR_CHANGEMASK) | iopr));
@@ -3792,7 +3820,7 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp)
        stl_sc26198setreg(portp, XOFFCR, tiosp->c_cc[VSTOP]);
 
        ipr = stl_sc26198getreg(portp, IPR);
-       if (ipr & MSVR1_DCD)
+       if (ipr & IPR_DCD)
                portp->sigs &= ~TIOCM_CD;
        else
                portp->sigs |= TIOCM_CD;
@@ -4120,7 +4148,7 @@ static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase)
        outb(0, (iobase + 1));
 
        iack = inb(iobase + XP_IACK);
-       portp = panelp->ports[(iack & IVR_CHANMASK)];
+       portp = panelp->ports[(iack & IVR_CHANMASK) + ((iobase & 0x4) << 1)];
 
        if (iack & IVR_RXDATA)
                stl_sc26198rxisr(portp, iack);
@@ -4178,7 +4206,7 @@ static void stl_sc26198txisr(stlport_t *portp)
                len = MIN(len, SC26198_TXFIFOSIZE);
                portp->stats.txtotal += len;
                stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail));
-               outb((GTXFIFO | portp->uartaddr), (ioaddr + XP_ADDR));
+               outb(GTXFIFO, (ioaddr + XP_ADDR));
                outsb((ioaddr + XP_DATA), tail, stlen);
                len -= stlen;
                tail += stlen;
@@ -4215,21 +4243,21 @@ static void stl_sc26198rxisr(stlport_t *portp, unsigned int iack)
 
        tty = portp->tty;
        ioaddr = portp->ioaddr;
-       outb((GIBCR | portp->uartaddr), (ioaddr + XP_ADDR));
+       outb(GIBCR, (ioaddr + XP_ADDR));
        len = inb(ioaddr + XP_DATA) + 1;
 
        if ((iack & IVR_TYPEMASK) == IVR_RXDATA) {
                if ((tty == (struct tty_struct *) NULL) ||
                    (tty->flip.char_buf_ptr == (char *) NULL) ||
                    ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) {
-                       outb((GRXFIFO | portp->uartaddr), (ioaddr + XP_ADDR));
+                       outb(GRXFIFO, (ioaddr + XP_ADDR));
                        insb((ioaddr + XP_DATA), &stl_unwanted[0], len);
                        portp->stats.rxlost += len;
                        portp->stats.rxtotal += len;
                } else {
                        len = MIN(len, buflen);
                        if (len > 0) {
-                               outb((GRXFIFO | portp->uartaddr), (ioaddr + XP_ADDR));
+                               outb(GRXFIFO, (ioaddr + XP_ADDR));
                                insb((ioaddr + XP_DATA), tty->flip.char_buf_ptr, len);
                                memset(tty->flip.flag_buf_ptr, 0, len);
                                tty->flip.flag_buf_ptr += len;
@@ -4342,7 +4370,7 @@ static void stl_sc26198rxbadchars(stlport_t *portp)
        stl_sc26198setreg(portp, MR1, (mr1 & ~MR1_ERRBLOCK));
 
        while ((status = stl_sc26198getreg(portp, SR)) & SR_RXRDY) {
-               stl_sc26198setreg(portp, CCR, CR_CLEARRXERR);
+               stl_sc26198setreg(portp, SCCR, CR_CLEARRXERR);
                ch = stl_sc26198getreg(portp, RXFIFO);
                stl_sc26198rxbadch(portp, status, ch);
        }
index c4e7e3391dc9ac7abd75474198858f1d89288513..2148a06a6c75cc1af8cd1a7d26d273afafab75f5 100644 (file)
@@ -1313,11 +1313,10 @@ static int tty_fasync(struct file * filp, int on)
        if (on) {
                if (!waitqueue_active(&tty->read_wait))
                        tty->minimum_to_wake = 1;
-               if (filp->f_owner == 0) {
-                       if (tty->pgrp)
-                               filp->f_owner = -tty->pgrp;
-                       else
-                               filp->f_owner = current->pid;
+               if (filp->f_owner.pid == 0) {
+                       filp->f_owner.pid = (-tty->pgrp) ? : current->pid;
+                       filp->f_owner.uid = current->uid;
+                       filp->f_owner.euid = current->euid;
                }
        } else {
                if (!tty->fasync && !waitqueue_active(&tty->read_wait))
index 9d568b2fdd423ed8588f1af4b85af71ac3f9d497..795df5697fe4ff00de2256280d1252f347bad9f9 100644 (file)
@@ -25,6 +25,10 @@ ifeq ($(CONFIG_PARPORT),y)
   endif
   ifeq ($(CONFIG_PARPORT_PC),y)
     LX_OBJS += parport_pc.o
+  else
+    ifeq ($(CONFIG_PARPORT_PC),m)
+      M_OBJS += parport_pc.o
+    endif
   endif
   LX_OBJS += parport_init.o
 else
index ae32bc91c2e97706bd6c91971cbf719f5866b4ae..477b350e34c851e46db431df690d03b4956f7ce4 100644 (file)
@@ -881,9 +881,9 @@ int parport_pc_init(int *io, int *irq, int *dma)
                } while (*io && (++i < PC_MAX_PORTS));
        } else {
                /* Probe all the likely ports. */
+               count += probe_one_port(0x3bc, PARPORT_IRQ_AUTO, PARPORT_DMA_AUTO);
                count += probe_one_port(0x378, PARPORT_IRQ_AUTO, PARPORT_DMA_AUTO);
                count += probe_one_port(0x278, PARPORT_IRQ_AUTO, PARPORT_DMA_AUTO);
-               count += probe_one_port(0x3bc, PARPORT_IRQ_AUTO, PARPORT_DMA_AUTO);
        }
        return count;
 }
index e4c58370fa536f5090a507aaff85ed69fac56917..6d518d28450e100718c0f20f22c40647d6a76dad 100644 (file)
@@ -33,9 +33,13 @@ static int portcount = 0;
 struct parport *parport_enumerate(void)
 {
 #ifdef CONFIG_KERNELD
-       if (portlist == NULL)
+       if (portlist == NULL) {
                request_module("parport_lowlevel");
-#endif
+#ifdef CONFIG_PNP_PARPORT_MODULE
+               request_module("parport_probe");
+#endif /* CONFIG_PNP_PARPORT_MODULE */
+       }
+#endif /* CONFIG_KERNELD */
        return portlist;
 }
 
index cd60a5058d50fb69749d76ac90694f0d1bc50dba..70aebe87482a65aa0b42ae970103c3d6aeb8d281 100644 (file)
@@ -84,13 +84,13 @@ static long read_polled(struct parport *port, char *buf,
        return count; 
 }
 
-static struct wait_queue *wait_q = NULL;
+static struct wait_queue *wait_q;
 
 static void wakeup(void *ref)
 {
        struct pardevice **dev = (struct pardevice **)ref;
        
-       if (!wait_q || parport_claim(*dev))
+       if (!waitqueue_active || parport_claim(*dev))
                return;
 
        wake_up(&wait_q);
@@ -108,10 +108,9 @@ int parport_probe(struct parport *port, char *buffer, int len)
                return -EINVAL;
        }
 
-       if (parport_claim(dev)) {
+       init_waitqueue (&wait_q);
+       if (parport_claim(dev))
                sleep_on(&wait_q);
-               wait_q = NULL;
-       }
 
        switch (parport_ieee1284_nibble_mode_ok(port, 4)) {
        case 1:
index a137680cbdbdd6bd689785633e87a36b34b87113..de7a65d6c5be84dd8411e3029f5e12d0cac627b7 100644 (file)
@@ -45,7 +45,7 @@ dep_tristate 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO $
 dep_tristate 'EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support' CONFIG_SCSI_EATA $CONFIG_SCSI
   if [ "$CONFIG_SCSI_EATA" != "n" ]; then
     bool '  enable tagged command queueing' CONFIG_SCSI_EATA_TAGGED_QUEUE
-    bool '  enable linked commands' CONFIG_SCSI_EATA_LINKED_COMMANDS
+    bool '  enable elevator sorting' CONFIG_SCSI_EATA_LINKED_COMMANDS
     int  '  maximum number of queued commands' CONFIG_SCSI_EATA_MAX_TAGS 16
   fi
 dep_tristate 'Future Domain 16xx SCSI/AHA 2920 support' CONFIG_SCSI_FUTURE_DOMAIN $CONFIG_SCSI
@@ -103,7 +103,7 @@ fi
 dep_tristate 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 $CONFIG_SCSI
 dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI
   if [ "$CONFIG_SCSI_U14_34F" != "n" ]; then
-    bool '  enable linked commands' CONFIG_SCSI_U14_34F_LINKED_COMMANDS
+    bool '  enable elevator sorting' CONFIG_SCSI_U14_34F_LINKED_COMMANDS
     int  '  maximum number of queued commands' CONFIG_SCSI_U14_34F_MAX_TAGS 8
   fi
 dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI
index cfff8bfa3cf936fdddcba076ee7649a6779e8606..aeda681c1a8055d5f7e41edfb7f5782277d956ea 100644 (file)
@@ -1,5 +1,14 @@
 /*
  *      eata.c - Low-level driver for EATA/DMA SCSI host adapters.
+ *   
+ *      12 Sep 1997 rev. 3.11 for linux 2.0.30 and 2.1.55
+ *          Use of udelay inside the wait loops to avoid timeout
+ *          problems with fast cpus.
+ *          Removed check about useless calls to the interrupt service
+ *          routine (reported on SMP systems only).
+ *          At initialization time "sorted/unsorted" is displayed instead
+ *          of "linked/unlinked" to reinforce the fact that "linking" is
+ *          nothing but "elevator sorting" in the actual implementation.
  *
  *      17 May 1997 rev. 3.10 for linux 2.0.30 and 2.1.38
  *          Use of serial_number_at_timeout in abort and reset processing.
@@ -283,6 +292,7 @@ MODULE_AUTHOR("Dario Ballabio");
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/byteorder.h>
@@ -323,6 +333,7 @@ struct proc_dir_entry proc_scsi_eata2x = {
 #undef  DEBUG_INTERRUPT
 #undef  DEBUG_STATISTICS
 #undef  DEBUG_RESET
+#undef  DEBUG_SMP
 
 #define MAX_ISA 4
 #define MAX_VESA 0 
@@ -351,7 +362,7 @@ struct proc_dir_entry proc_scsi_eata2x = {
 #define READY    5
 #define ABORTING 6
 #define NO_DMA  0xff
-#define MAXLOOP 200000
+#define MAXLOOP  10000
 #define TAG_MIXED    0
 #define TAG_SIMPLE   1
 #define TAG_HEAD     2
@@ -630,9 +641,9 @@ static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) {
 
       if (TLDEV(dev->type)) {
          if (linked_comm && dev->queue_depth > 2)
-            link_suffix = ", linked";
+            link_suffix = ", sorted";
          else
-            link_suffix = ", unlinked";
+            link_suffix = ", unsorted";
          }
 
       if (tagged_comm && dev->tagged_supported && TLDEV(dev->type)) {
@@ -656,8 +667,10 @@ static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) {
 
 static inline int wait_on_busy(unsigned int iobase, unsigned int loop) {
 
-   while (inb(iobase + REG_AUX_STATUS) & ABSY_ASSERTED)
+   while (inb(iobase + REG_AUX_STATUS) & ABSY_ASSERTED) {
+      udelay(1L);
       if (--loop == 0) return TRUE;
+      }
 
    return FALSE;
 }
@@ -683,8 +696,10 @@ static inline int read_pio(unsigned int iobase, ushort *start, ushort *end) {
 
    for (p = start; p <= end; p++) {
 
-      while (!(inb(iobase + REG_STATUS) & DRQ_ASSERTED)) 
+      while (!(inb(iobase + REG_STATUS) & DRQ_ASSERTED)) {
+         udelay(1L);
         if (--loop == 0) return TRUE;
+         }
 
       loop = MAXLOOP;
       *p = inw(iobase);
@@ -1416,7 +1431,7 @@ int eata2x_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
    HD(j)->in_reset = TRUE;
    sti();
    time = jiffies;
-   while ((jiffies - time) < HZ && limit++ < 100000000);
+   while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L);
    cli();
    printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
 
@@ -1831,9 +1846,11 @@ static void eata2x_interrupt_handler(int irq, void *dev_id,
 
    calls[irq]++;
 
+#if defined (DEBUG_SMP)
    if (total_loops == 0) 
      printk("%s: ihdlr, irq %d, no command completed, calls %d.\n",
            driver_name, irq, calls[irq]);
+#endif
 
    if (do_trace) printk("%s: ihdlr, exit, irq %d, calls %d.\n", 
                        driver_name, irq, calls[irq]);
index cba3914145590a73baed192419f19583cce427dc..8292ef5148065053973471a87861f886f9ab1fc2 100644 (file)
@@ -12,7 +12,7 @@ int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int eata2x_abort(Scsi_Cmnd *);
 int eata2x_reset(Scsi_Cmnd *, unsigned int);
 
-#define EATA_VERSION "3.10.00"
+#define EATA_VERSION "3.11.00"
 
 
 #define EATA {                                                 \
index a81e77d7a2cf98c1c1909cb2cc060c9ad0f1025b..e8f73f1b23524a64d897b77125b22692bb6c44f2 100644 (file)
  *              Some XA-Sector tweaking, required for older drives.
  *
  *   - SONY:   Detection and support of multisession CD's.
- *              added by Thomas Quinot <operator@melchior.cuivre.fdn.fr>
+ *              added by Thomas Quinot <thomas@cuivre.freenix.fr>
  *
- *   - PIONEER, HITACHI, PLEXTOR, MATSHITA, TEAC: known to work with SONY code.
+ *   - PIONEER, HITACHI, PLEXTOR, MATSHITA, TEAC, PHILIPS:
+ *             Known to work with SONY code.
  *
  *   - HP:     Much like SONY, but a little different... (Thomas)
  *              HP-Writers only ??? Maybe other CD-Writers work with this too ?
+ *             HP 6020 writers now supported.
  */
 
 #include <linux/errno.h>
 #define VENDOR_NEC             2
 #define VENDOR_TOSHIBA         3
 #define VENDOR_SONY_LIKE       4   /* much drives are Sony compatible */
-#define VENDOR_HP              5   /* HP Writers, others too ?? */
+#define VENDOR_HP_4020         5   /* HP 4xxx writers, others too ?? */
+#define VENDOR_HP_6020         6   /* HP 6020 writers */
+
+#define VENDOR_ID (scsi_CDs[minor].vendor)
 
 #if 0
 #define DEBUG
@@ -58,10 +63,13 @@ sr_vendor_init(int minor)
                
        if ((!strncmp(vendor,"HP",2) || !strncmp(vendor,"PHILIPS",7)) &&
            scsi_CDs[minor].device->type == TYPE_WORM) {
-               scsi_CDs[minor].vendor = VENDOR_HP;
+               if (!strncmp(model,"CD-Writer 6020",14))
+                    VENDOR_ID = VENDOR_HP_6020;
+                else
+                    VENDOR_ID = VENDOR_HP_4020;
 
        } else if (!strncmp (vendor, "NEC", 3)) {
-               scsi_CDs[minor].vendor = VENDOR_NEC;
+               VENDOR_ID = VENDOR_NEC;
                if (!strncmp (model,"CD-ROM DRIVE:25", 15)  ||
                    !strncmp (model,"CD-ROM DRIVE:36", 15)  ||
                    !strncmp (model,"CD-ROM DRIVE:83", 15)  ||
@@ -70,12 +78,12 @@ sr_vendor_init(int minor)
                        scsi_CDs[minor].cdi.mask |= CDC_MULTI_SESSION;
 
        } else if (!strncmp (vendor, "TOSHIBA", 7)) {
-               scsi_CDs[minor].vendor = VENDOR_TOSHIBA;
+               VENDOR_ID = VENDOR_TOSHIBA;
                
        } else {
-               /* most drives can handled like sony ones, so we take
+               /* most drives can handled like Sony ones, so we take
                 * it as default */
-               scsi_CDs[minor].vendor = VENDOR_SONY_LIKE;
+               VENDOR_ID = VENDOR_SONY_LIKE;
 #ifdef DEBUG
                printk(KERN_DEBUG
                       "sr: using \"Sony group\" multisession code\n");
@@ -128,7 +136,7 @@ sr_read_sector(int minor, int lba, int blksize, unsigned char *dest)
        unsigned char   cmd[12];    /* the scsi-command */
        int             rc, density;
 
-       density = (scsi_CDs[minor].vendor == VENDOR_TOSHIBA) ? 0x83 : 0;
+       density = (VENDOR_ID == VENDOR_TOSHIBA) ? 0x83 : 0;
 
        buffer = (unsigned char *) scsi_malloc(512);
        if (!buffer) return -ENOMEM;
@@ -177,7 +185,7 @@ int sr_cd_check(struct cdrom_device_info *cdi)
        no_multi = 0;         /* flag: the drive can't handle multisession */
        rc       = 0;
     
-       switch(scsi_CDs[minor].vendor) {
+       switch(VENDOR_ID) {
        
        case VENDOR_NEC:
                memset(cmd,0,12);
@@ -222,12 +230,16 @@ int sr_cd_check(struct cdrom_device_info *cdi)
                        sector -= CD_BLOCK_OFFSET;
                break;
 
-       case VENDOR_HP:
+       case VENDOR_HP_4020:
+               /* Fallthrough */
+       case VENDOR_HP_6020:
                cmd[0] = READ_TOC;
                cmd[1] = (scsi_CDs[minor].device->lun << 5);
-               cmd[8] = 0x04;
+               cmd[8] = (VENDOR_ID == VENDOR_HP_4020) ?
+                       0x04 : 0x0c;
                cmd[9] = 0x40;
-               rc = sr_do_ioctl(minor, cmd, buffer, 12);       
+               rc = sr_do_ioctl(minor, cmd, buffer,
+                   (VENDOR_ID == VENDOR_HP_4020) ? 0x04 : 0x0c);
                if (rc != 0) {
                        break;
                }
@@ -237,31 +249,23 @@ int sr_cd_check(struct cdrom_device_info *cdi)
                        break;
                }
 
-               cmd[0] = READ_TOC; /* Read TOC */
-               cmd[1] = (scsi_CDs[minor].device->lun << 5);
-               cmd[6] = rc & 0x7f;  /* number of last session */
-               cmd[8] = 0x0c;
-               cmd[9] = 0x40;
-               rc = sr_do_ioctl(minor, cmd, buffer, 12);       
-               if (rc != 0) {
-                       break;
+               if (VENDOR_ID == VENDOR_HP_4020) {
+                   cmd[0] = READ_TOC; /* Read TOC */
+                   cmd[1] = (scsi_CDs[minor].device->lun << 5);
+                   cmd[6] = rc & 0x7f;  /* number of last session */
+                   cmd[8] = 0x0c;
+                   cmd[9] = 0x40;
+                   rc = sr_do_ioctl(minor, cmd, buffer, 12);   
+                   if (rc != 0) {
+                           break;
+                   }
                }
 
-#undef STRICT_HP
-#ifdef STRICT_HP
-               sector = buffer[11] + (buffer[10] << 8) + (buffer[9] << 16);
-               /* HP documentation states that Logical Start Address is
-                  returned as three (!) bytes, and that buffer[8] is
-                  reserved. This is strange, because a LBA usually is
-                  4 bytes long. */
-#else
                sector = buffer[11] + (buffer[10] << 8) +
                        (buffer[9] << 16) + (buffer[8] << 24);
-#endif
                break;
 
        case VENDOR_SONY_LIKE:
-               /* Thomas QUINOT <thomas@melchior.cuivre.fdn.fr> */
                memset(cmd,0,12);
                cmd[0] = READ_TOC;
                cmd[1] = (scsi_CDs[minor].device->lun << 5);
@@ -293,7 +297,7 @@ int sr_cd_check(struct cdrom_device_info *cdi)
                /* should not happen */
                printk(KERN_WARNING
                       "sr: unknown vendor code (%i), not initialized ?\n",
-                      scsi_CDs[minor].vendor);
+                      VENDOR_ID);
                sector = 0;
                no_multi = 1;
                break;
index 6a0076ddeb93a9d204ffd72b57719e9892015f7e..fa980051a6510ecf30234d9ca2382f0056e81a89 100644 (file)
@@ -1,6 +1,15 @@
 /*
  *      u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
  *
+ *      12 Sep 1997 rev. 3.11 for linux 2.0.30 and 2.1.55
+ *          Use of udelay inside the wait loops to avoid timeout
+ *          problems with fast cpus.
+ *          Removed check about useless calls to the interrupt service
+ *          routine (reported on SMP systems only).
+ *          At initialization time "sorted/unsorted" is displayed instead
+ *          of "linked/unlinked" to reinforce the fact that "linking" is
+ *          nothing but "elevator sorting" in the actual implementation.
+ *
  *      17 May 1997 rev. 3.10 for linux 2.0.30 and 2.1.38
  *          Use of serial_number_at_timeout in abort and reset processing.
  *          Use of the __initfunc and __initdata macro in setup code.
@@ -269,6 +278,7 @@ MODULE_AUTHOR("Dario Ballabio");
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/byteorder.h>
@@ -321,6 +331,7 @@ struct proc_dir_entry proc_scsi_u14_34f = {
 #undef  DEBUG_INTERRUPT
 #undef  DEBUG_STATISTICS
 #undef  DEBUG_RESET
+#undef  DEBUG_SMP
 
 #define MAX_ISA 3
 #define MAX_VESA 1 
@@ -349,7 +360,7 @@ struct proc_dir_entry proc_scsi_u14_34f = {
 #define READY    5
 #define ABORTING 6
 #define NO_DMA  0xff
-#define MAXLOOP 200000
+#define MAXLOOP  10000
 
 #define REG_LCL_MASK      0
 #define REG_LCL_INTR      1
@@ -530,9 +541,9 @@ static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) {
 
       if (TLDEV(dev->type)) {
          if (linked_comm && dev->queue_depth > 2)
-            link_suffix = ", linked";
+            link_suffix = ", sorted";
          else
-            link_suffix = ", unlinked";
+            link_suffix = ", unsorted";
          }
 
       if (dev->tagged_supported && TLDEV(dev->type) && dev->tagged_queue)
@@ -551,8 +562,10 @@ static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) {
 
 static inline int wait_on_busy(unsigned int iobase, unsigned int loop) {
 
-   while (inb(iobase + REG_LCL_INTR) & BSY_ASSERTED)
+   while (inb(iobase + REG_LCL_INTR) & BSY_ASSERTED) {
+      udelay(1L);
       if (--loop == 0) return TRUE;
+      }
 
    return FALSE;
 }
@@ -588,7 +601,7 @@ static int board_inquiry(unsigned int j) {
 
    sti();
    time = jiffies;
-   while ((jiffies - time) < HZ && limit++ < 100000000);
+   while ((jiffies - time) < HZ && limit++ < 20000) udelay(100L);
    cli();
 
    if (cpp->adapter_status || HD(j)->cp_stat[0] != FREE) {
@@ -1195,7 +1208,7 @@ int u14_34f_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
    HD(j)->in_reset = TRUE;
    sti();
    time = jiffies;
-   while ((jiffies - time) < HZ && limit++ < 100000000);
+   while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L);
    cli();
    printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
 
@@ -1616,9 +1629,11 @@ static void u14_34f_interrupt_handler(int irq, void *dev_id,
 
    calls[irq]++;
 
+#if defined (DEBUG_SMP)
    if (total_loops == 0) 
      printk("%s: ihdlr, irq %d, no command completed, calls %d.\n",
            driver_name, irq, calls[irq]);
+#endif
 
    if (do_trace) printk("%s: ihdlr, exit, irq %d, calls %d.\n",
                        driver_name, irq, calls[irq]);
index 9381f7729421ddae5466e1daf1c31acdde9e0b65..004936393518b9c647be987a4aafa4a6ae8b33b1 100644 (file)
@@ -11,7 +11,7 @@ int u14_34f_abort(Scsi_Cmnd *);
 int u14_34f_reset(Scsi_Cmnd *, unsigned int);
 int u14_34f_biosparam(Disk *, kdev_t, int *);
 
-#define U14_34F_VERSION "3.10.00"
+#define U14_34F_VERSION "3.11.00"
 
 #define ULTRASTOR_14_34F {                                            \
                NULL, /* Ptr for modules */                           \
index f0b10464c6450e2832c276941fdc8456d40ab55e..450197a34224ff994b7eda8c2317fdec7f5c02e3 100644 (file)
@@ -138,8 +138,8 @@ sound_release (struct inode *inode, struct file *file)
   sound_release_sw (dev, &files[dev]);
 #ifdef MODULE
   MOD_DEC_USE_COUNT;
-  return 0;
 #endif
+  return 0;
 }
 
 static int
index fb9da7124295c4b4937ec98d45271f238bcab944..c4abd22494d8992e2bc567eabf1e5b33ad514df8 100644 (file)
@@ -13,7 +13,7 @@ O_TARGET := fs.o
 O_OBJS    = open.o read_write.o devices.o file_table.o buffer.o \
                super.o  block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
                ioctl.o readdir.o select.o fifo.o locks.o filesystems.o \
-               inode.o dcache.o attr.o $(BINFMTS) 
+               inode.o dcache.o attr.o bad_inode.o $(BINFMTS) 
 
 MOD_LIST_NAME := FS_MODULES
 ALL_SUB_DIRS = minix ext2 fat msdos vfat proc isofs nfs umsdos \
index e936e5bb56d26c651a3549567244a8a1e6e29efa..cfd05640ba3308259b215b28e84416bef7406b24 100644 (file)
@@ -82,7 +82,7 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
        struct buffer_head       *dir_bh;
        struct buffer_head       *fh_bh;
        struct inode             *dir;
-       struct inode             *inode = file->f_dentry->d_inode;
+       struct inode             *inode = filp->f_dentry->d_inode;
 
        pr_debug("AFFS: readdir(ino=%ld,f_pos=%lu)\n",inode->i_ino,filp->f_pos);
 
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
new file mode 100644 (file)
index 0000000..562a5d8
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ *  linux/fs/bad_inode.c
+ *
+ *  Copyright (C) 1997, Stephen Tweedie
+ *
+ *  Provide stub functions for unreadable inodes
+ */
+
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/sched.h>
+
+/*
+ * The follow_symlink operation must dput() the base.
+ */
+static struct dentry * bad_follow_link(struct inode * ino, struct dentry *base)
+{
+       dput(base);
+       return ERR_PTR(-EIO);
+}
+
+static int return_EIO()
+{
+       return -EIO;
+}
+
+#define EIO_ERROR ((void *) (return_EIO))
+
+static struct file_operations bad_file_ops =
+{
+       EIO_ERROR,              /* lseek */
+       EIO_ERROR,              /* read */
+       EIO_ERROR,              /* write */
+       EIO_ERROR,              /* readdir */
+       EIO_ERROR,              /* select */
+       EIO_ERROR,              /* ioctl */
+       EIO_ERROR,              /* mmap */
+       EIO_ERROR,              /* open */
+       EIO_ERROR,              /* release */
+       EIO_ERROR,              /* fsync */
+       EIO_ERROR,              /* fasync */
+       EIO_ERROR,              /* check_media_change */
+       EIO_ERROR               /* revalidate */
+};
+
+struct inode_operations bad_inode_ops =
+{
+       &bad_file_ops,          /* default file operations */
+       EIO_ERROR,              /* create */
+       EIO_ERROR,              /* lookup */
+       EIO_ERROR,              /* link */
+       EIO_ERROR,              /* unlink */
+       EIO_ERROR,              /* symlink */
+       EIO_ERROR,              /* mkdir */
+       EIO_ERROR,              /* rmdir */
+       EIO_ERROR,              /* mknod */
+       EIO_ERROR,              /* rename */
+       EIO_ERROR,              /* readlink */
+       bad_follow_link,        /* follow_link */
+       EIO_ERROR,              /* readpage */
+       EIO_ERROR,              /* writepage */
+       EIO_ERROR,              /* bmap */
+       EIO_ERROR,              /* truncate */
+       EIO_ERROR,              /* permission */
+       EIO_ERROR               /* smap */
+};
+
+
+/* 
+ * When a filesystem is unable to read an inode due to an I/O error in
+ * its read_inode() function, it can call make_bad_inode() to return a
+ * set of stubs which will return EIO errors as required. 
+ *
+ * We only need to do limited initialisation: all other fields are
+ * preinitialised to zero automatically.
+ */
+void make_bad_inode(struct inode * inode) 
+{
+       inode->i_mode = S_IFREG;
+       inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+       inode->i_op = &bad_inode_ops;   
+}
+
index 64e56fb90c55b2574fc0cdbcebea0b199ad83173..6025dcd31444fc2af64dd5ea65c1841557ca8195 100644 (file)
@@ -107,7 +107,7 @@ union bdflush_param{
                int dummy3;    /* unused */
        } b_un;
        unsigned int data[N_PARAM];
-} bdf_prm = {{60, 500, 64, 256, 15, 30*HZ, 5*HZ, 1884, 2}};
+} bdf_prm = {{40, 500, 64, 256, 15, 30*HZ, 5*HZ, 1884, 2}};
 
 /* These are the min and max parameter values that we will allow to be assigned */
 int bdflush_min[N_PARAM] = {  0,  10,    5,   25,  0,   100,   100, 1, 1};
@@ -320,7 +320,10 @@ asmlinkage int sys_fsync(unsigned int fd)
        if (!file->f_op || !file->f_op->fsync)
                goto out;
 
+       /* We need to protect against concurrent writers.. */
+       down(&inode->i_sem);
        err = file->f_op->fsync(file, file->f_dentry);
+       up(&inode->i_sem);
 
 out:
        unlock_kernel();
index 0fff8086d48190e4380e794a7f937c326b6800e5..600e5b0e3f8b739d60be62c78b915b2daa83602d 100644 (file)
@@ -179,7 +179,12 @@ struct dentry * d_alloc(struct dentry * parent, const struct qstr *name)
        dentry->d_count = 1;
        dentry->d_flags = 0;
        dentry->d_inode = NULL;
-       dentry->d_parent = dget(parent);
+       dentry->d_parent = NULL;
+       dentry->d_sb = NULL;
+       if (parent) {
+               dentry->d_parent = dget(parent);
+               dentry->d_sb = parent->d_sb;
+       }
        dentry->d_mounts = dentry;
        dentry->d_covers = dentry;
        INIT_LIST_HEAD(&dentry->d_hash);
@@ -214,6 +219,7 @@ struct dentry * d_alloc_root(struct inode * root_inode, struct dentry *old_root)
        if (root_inode) {
                res = d_alloc(NULL, &(const struct qstr) { "/", 1, 0 });
                if (res) {
+                       res->d_sb = root_inode->i_sb;
                        res->d_parent = res;
                        d_instantiate(res, root_inode);
                }
index 01f0ac99ea13720a98b991b9b243e49fdb6da20d..8a9bdf902de7fc2f87b9d053c563128a032fb015 100644 (file)
 static int sync_block (struct inode * inode, u32 * block, int wait)
 {
        struct buffer_head * bh;
-       int tmp;
        
        if (!*block)
                return 0;
-       tmp = *block;
        bh = get_hash_table (inode->i_dev, *block, blocksize);
        if (!bh)
                return 0;
-       if (*block != tmp) {
-               brelse (bh);
-               return 1;
-       }
        if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
                brelse (bh);
                return -1;
@@ -67,18 +61,12 @@ static int sync_block (struct inode * inode, u32 * block, int wait)
 static int sync_block_swab32 (struct inode * inode, u32 * block, int wait)
 {
        struct buffer_head * bh;
-       int tmp;
        
        if (!le32_to_cpu(*block))
                return 0;
-       tmp = le32_to_cpu(*block);
        bh = get_hash_table (inode->i_dev, le32_to_cpu(*block), blocksize);
        if (!bh)
                return 0;
-       if (le32_to_cpu(*block) != tmp) {
-               brelse (bh);
-               return 1;
-       }
        if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
                brelse (bh);
                return -1;
@@ -109,11 +97,6 @@ static int sync_iblock (struct inode * inode, u32 * iblock,
        if (rc)
                return rc;
        *bh = bread (inode->i_dev, tmp, blocksize);
-       if (tmp != *iblock) {
-               brelse (*bh);
-               *bh = NULL;
-               return 1;
-       }
        if (!*bh)
                return -1;
        return 0;
@@ -133,11 +116,6 @@ static int sync_iblock_swab32 (struct inode * inode, u32 * iblock,
        if (rc)
                return rc;
        *bh = bread (inode->i_dev, tmp, blocksize);
-       if (tmp != le32_to_cpu(*iblock)) {
-               brelse (*bh);
-               *bh = NULL;
-               return 1;
-       }
        if (!*bh)
                return -1;
        return 0;
@@ -153,8 +131,6 @@ static int sync_direct (struct inode * inode, int wait)
 
        for (i = 0; i < EXT2_NDIR_BLOCKS; i++) {
                rc = sync_block (inode, inode->u.ext2_i.i_data + i, wait);
-               if (rc > 0)
-                       break;
                if (rc)
                        err = rc;
        }
@@ -175,8 +151,6 @@ static int sync_indirect (struct inode * inode, u32 * iblock, int wait)
                rc = sync_block_swab32 (inode, 
                                        ((u32 *) ind_bh->b_data) + i,
                                        wait);
-               if (rc > 0)
-                       break;
                if (rc)
                        err = rc;
        }
@@ -199,8 +173,6 @@ static __inline__ int sync_indirect_swab32 (struct inode * inode, u32 * iblock,
                rc = sync_block_swab32 (inode, 
                                        ((u32 *) ind_bh->b_data) + i,
                                        wait);
-               if (rc > 0)
-                       break;
                if (rc)
                        err = rc;
        }
@@ -225,8 +197,6 @@ static int sync_dindirect (struct inode * inode, u32 * diblock, int wait)
                rc = sync_indirect_swab32 (inode,
                                           ((u32 *) dind_bh->b_data) + i,
                                           wait);
-               if (rc > 0)
-                       break;
                if (rc)
                        err = rc;
        }
@@ -249,8 +219,6 @@ static __inline__ int sync_dindirect_swab32 (struct inode * inode, u32 * diblock
                rc = sync_indirect_swab32 (inode,
                                           ((u32 *) dind_bh->b_data) + i,
                                           wait);
-               if (rc > 0)
-                       break;
                if (rc)
                        err = rc;
        }
@@ -275,8 +243,6 @@ static int sync_tindirect (struct inode * inode, u32 * tiblock, int wait)
                rc = sync_dindirect_swab32 (inode,
                                            ((u32 *) tind_bh->b_data) + i,
                                            wait);
-               if (rc > 0)
-                       break;
                if (rc)
                        err = rc;
        }
@@ -318,5 +284,5 @@ int ext2_sync_file(struct file * file, struct dentry *dentry)
        }
 skip:
        err |= ext2_sync_inode (inode);
-       return (err < 0) ? -EIO : 0;
+       return err ? -EIO : 0;
 }
index 8cef1e59ebe62037e413dfbd6f7c6dad6e8cdeb8..ce00e439f7794d442a8d7451b8d3e84b77aa5de2 100644 (file)
@@ -98,8 +98,6 @@ static int setfl(struct file * filp, unsigned long arg)
 asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {      
        struct file * filp;
-       struct task_struct *p;
-       int task_found = 0;
        long err = -EBADF;
 
        lock_kernel();
@@ -142,57 +140,13 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
                         * current syscall conventions, the only way
                         * to fix this will be in libc.
                         */
-                       err = filp->f_owner;
+                       err = filp->f_owner.pid;
                        break;
                case F_SETOWN:
-                       /*
-                        *      Add the security checks - AC. Without
-                        *      this there is a massive Linux security
-                        *      hole here - consider what happens if
-                        *      you do something like
-                        * 
-                        *              fcntl(0,F_SETOWN,some_root_process);
-                        *              getchar();
-                        * 
-                        *      and input a line!
-                        * 
-                        * BTW: Don't try this for fun. Several Unix
-                        *      systems I tried this on fall for the
-                        *      trick!
-                        * 
-                        * I had to fix this botch job as Linux
-                        *      kill_fasync asserts priv making it a
-                        *      free all user process killer!
-                        *
-                        * Changed to make the security checks more
-                        * liberal.  -- TYT
-                        */
-                       if (current->pgrp == -arg || current->pid == arg)
-                               goto fasync_ok;
-                       
-                       read_lock(&tasklist_lock);
-                       for_each_task(p) {
-                               if ((p->pid == arg) || (p->pid == -arg) || 
-                                   (p->pgrp == -arg)) {
-                                       task_found++;
-                                       err = -EPERM;
-                                       if ((p->session != current->session) &&
-                                           (p->uid != current->uid) &&
-                                           (p->euid != current->euid) &&
-                                           !suser()) {
-                                               read_unlock(&tasklist_lock);
-                                               goto out;
-                                       }
-                                       break;
-                               }
-                       }
-                       read_unlock(&tasklist_lock);
-                       err = -EINVAL;
-                       if ((task_found == 0) && !suser())
-                               break;
-               fasync_ok:
                        err = 0;
-                       filp->f_owner = arg;
+                       filp->f_owner.pid = arg;
+                       filp->f_owner.uid = current->uid;
+                       filp->f_owner.euid = current->euid;
                        if (S_ISSOCK (filp->f_dentry->d_inode->i_mode))
                                err = sock_fcntl (filp, F_SETOWN, arg);
                        break;
@@ -209,18 +163,40 @@ out:
        return err;
 }
 
+static void send_sigio(int pid, uid_t uid, uid_t euid)
+{
+       struct task_struct * p;
+
+       read_lock(&tasklist_lock);
+       for_each_task(p) {
+               int match = p->pid;
+               if (pid < 0)
+                       match = -p->pgrp;
+               if (pid != match)
+                       continue;
+               if (!euid &&
+                   (euid ^ p->suid) && (euid ^ p->uid) &&
+                   (uid ^ p->suid) && (uid ^ p->uid))
+                       continue;
+               p->signal |= 1 << (SIGIO-1);
+               if (p->state == TASK_INTERRUPTIBLE && (p->signal & ~p->blocked))
+                       wake_up_process(p);
+       }
+       read_unlock(&tasklist_lock);
+}
+
 void kill_fasync(struct fasync_struct *fa, int sig)
 {
        while (fa) {
+               struct fown_struct * fown;
                if (fa->magic != FASYNC_MAGIC) {
                        printk("kill_fasync: bad magic number in "
                               "fasync_struct!\n");
                        return;
                }
-               if (fa->fa_file->f_owner > 0)
-                       kill_proc(fa->fa_file->f_owner, sig, 1);
-               else
-                       kill_pg(-fa->fa_file->f_owner, sig, 1);
+               fown = &fa->fa_file->f_owner;
+               if (fown->pid)
+                       send_sigio(fown->pid, fown->uid, fown->euid);
                fa = fa->fa_next;
        }
 }
index 98814d220f4ed98c145a0c9da110266b2242639a..ad70f7b552fc7cea33c3d40716d389ed7c877762 100644 (file)
@@ -71,7 +71,7 @@ nlmclnt_block(struct nlm_host *host, struct file_lock *fl, u32 *statp)
         * nlmclnt_lock for an explanation.
         */
        current->timeout = jiffies + 30 * HZ;
-       interruptible_sleep_on(&block.b_wait);
+       sleep_on(&block.b_wait);
 
        for (head = &nlm_blocked; *head; head = &(*head)->b_next) {
                if (*head == &block) {
index 720cf98a8220e799c29677072d0c3abc3ea8e1bf..738fa0bcab09847390099d7b2053f5a3622c4480 100644 (file)
@@ -132,7 +132,9 @@ static int flock_lock_file(struct file *filp, struct file_lock *caller,
 static int posix_locks_deadlock(struct file_lock *caller,
                                struct file_lock *blocker);
 
-static struct file_lock *locks_alloc_lock(struct file_lock *fl);
+static struct file_lock *locks_empty_lock(void);
+static struct file_lock *locks_init_lock(struct file_lock *,
+                                        struct file_lock *);
 static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl);
 static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait);
 static char *lock_get_status(struct file_lock *fl, int id, char *pfx);
@@ -143,6 +145,15 @@ static void locks_wake_up_blocks(struct file_lock *blocker, unsigned int wait);
 
 struct file_lock *file_lock_table = NULL;
 
+/* Allocate a new lock, and initialize its fields from fl.
+ * The lock is not inserted into any lists until locks_insert_lock() or 
+ * locks_insert_block() are called.
+ */
+static inline struct file_lock *locks_alloc_lock(struct file_lock *fl)
+{
+       return locks_init_lock(locks_empty_lock(), fl);
+}
+
 /* Free lock not inserted in any queue.
  */
 static inline void locks_free_lock(struct file_lock *fl)
@@ -250,6 +261,7 @@ static void locks_wake_up_blocks(struct file_lock *blocker, unsigned int wait)
        struct file_lock *waiter;
 
        while ((waiter = blocker->fl_nextblock) != NULL) {
+               /* N.B. Is it possible for the notify function to block?? */
                if (waiter->fl_notify)
                        waiter->fl_notify(waiter);
                wake_up(&waiter->fl_wait);
@@ -330,6 +342,7 @@ int fcntl_getlk(unsigned int fd, struct flock *l)
                fl = posix_test_lock(filp, &file_lock);
        }
  
+       flock.l_type = F_UNLCK;
        if (fl != NULL) {
                flock.l_pid = fl->fl_pid;
                flock.l_start = fl->fl_start;
@@ -337,10 +350,7 @@ int fcntl_getlk(unsigned int fd, struct flock *l)
                        fl->fl_end - fl->fl_start + 1;
                flock.l_whence = 0;
                flock.l_type = fl->fl_type;
-               return (copy_to_user(l, &flock, sizeof(flock)) ? -EFAULT : 0);
-       } else {
-               flock.l_type = F_UNLCK;
-       }
+       }
   
        return (copy_to_user(l, &flock, sizeof(flock)) ? -EFAULT : 0);
 }
@@ -368,7 +378,12 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
 
        if (!(inode = dentry->d_inode))
                return -EINVAL;
-       
+       /*
+        * This might block, so we do it before checking the inode.
+        */
+       if (copy_from_user(&flock, l, sizeof(flock)))
+               return (-EFAULT);
+
        /* Don't allow mandatory locks on files that may be memory mapped
         * and shared.
         */
@@ -382,8 +397,6 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
                } while ((vma = vma->vm_next_share) != NULL);
        }
 
-       if (copy_from_user(&flock, l, sizeof(flock)))
-               return (-EFAULT);
        if (!posix_make_lock(filp, &file_lock, &flock))
                return (-EINVAL);
        
@@ -441,8 +454,8 @@ void locks_remove_locks(struct task_struct *task, struct file *filp)
         * close on that file.
         */
        inode = filp->f_dentry->d_inode;
+repeat:
        before = &inode->i_flock;
-
        while ((fl = *before) != NULL) {
                if (((fl->fl_flags & FL_POSIX) && (fl->fl_owner == task)) ||
                    ((fl->fl_flags & FL_FLOCK) && (fl->fl_file == filp) &&
@@ -453,11 +466,11 @@ void locks_remove_locks(struct task_struct *task, struct file *filp)
                                file_lock.fl_type = F_UNLCK;
                                filp->f_op->lock(filp, F_SETLK, &file_lock);
                                /* List may have changed: */
-                               before = &inode->i_flock;
+                               goto repeat;
                        }
-               } else {
-                       before = &fl->fl_next;
+                       continue;
                }
+               before = &fl->fl_next;
        }
 
        return;
@@ -762,16 +775,30 @@ static int flock_lock_file(struct file *filp, struct file_lock *caller,
                           unsigned int wait)
 {
        struct file_lock *fl;
-       struct file_lock *new_fl;
+       struct file_lock *new_fl = NULL;
        struct file_lock **before;
        struct inode * inode = filp->f_dentry->d_inode;
-       int change = 0;
+       int error, change;
+       int unlock = (caller->fl_type == F_UNLCK);
+
+       /*
+        * If we need a new lock, get it in advance to avoid races.
+        */
+       if (!unlock) {
+               error = -ENOLCK;
+               new_fl = locks_alloc_lock(caller);
+               if (!new_fl)
+                       goto out;
+       }
 
+       error = 0;
+search:
+       change = 0;
        before = &inode->i_flock;
        while (((fl = *before) != NULL) && (fl->fl_flags & FL_FLOCK)) {
                if (caller->fl_file == fl->fl_file) {
                        if (caller->fl_type == fl->fl_type)
-                               return (0);
+                               goto out;
                        change = 1;
                        break;
                }
@@ -780,44 +807,43 @@ static int flock_lock_file(struct file *filp, struct file_lock *caller,
        /* change means that we are changing the type of an existing lock, or
         * or else unlocking it.
         */
-       if (change)
-               locks_delete_lock(before, caller->fl_type != F_UNLCK);
-       if (caller->fl_type == F_UNLCK)
-               return (0);
-       if ((new_fl = locks_alloc_lock(caller)) == NULL)
-               return (-ENOLCK);
+       if (change) {
+               /* N.B. What if the wait argument is false? */
+               locks_delete_lock(before, !unlock);
+               /*
+                * If we waited, another lock may have been added ...
+                */
+               if (!unlock)
+                       goto search;
+       }
+       if (unlock)
+               goto out;
+
 repeat:
+       /* Check signals each time we start */
+       error = -ERESTARTSYS;
+       if (current->signal & ~current->blocked)
+               goto out;
        for (fl = inode->i_flock; (fl != NULL) && (fl->fl_flags & FL_FLOCK);
             fl = fl->fl_next) {
                if (!flock_locks_conflict(new_fl, fl))
                        continue;
-               if (!wait) {
-                       locks_free_lock(new_fl);
-                       return (-EAGAIN);
-               }
-               if (current->signal & ~current->blocked) {
-                       /* Note: new_fl is not in any queue at this
-                        * point, so we must use locks_free_lock()
-                        * instead of locks_delete_lock()
-                        *      Dmitry Gorodchanin 09/02/96.
-                        */
-                       locks_free_lock(new_fl);
-                       return (-ERESTARTSYS);
-               }
+               error = -EAGAIN;
+               if (!wait)
+                       goto out;
                locks_insert_block(fl, new_fl);
                interruptible_sleep_on(&new_fl->fl_wait);
                locks_delete_block(fl, new_fl);
-               if (current->signal & ~current->blocked) {
-                       /* Awakened by a signal. Free the new
-                        * lock and return an error.
-                        */
-                       locks_free_lock(new_fl);
-                       return (-ERESTARTSYS);
-               }
                goto repeat;
        }
        locks_insert_lock(&inode->i_flock, new_fl);
-       return (0);
+       new_fl = NULL;
+       error = 0;
+
+out:
+       if (new_fl)
+               locks_free_lock(new_fl);
+       return error;
 }
 
 /* Add a POSIX style lock to a file.
@@ -836,36 +862,51 @@ int posix_lock_file(struct file *filp, struct file_lock *caller,
                           unsigned int wait)
 {
        struct file_lock *fl;
-       struct file_lock *new_fl;
+       struct file_lock *new_fl, *new_fl2;
        struct file_lock *left = NULL;
        struct file_lock *right = NULL;
        struct file_lock **before;
        struct inode * inode = filp->f_dentry->d_inode;
-       int added = 0;
+       int error, added = 0;
+
+       /*
+        * We may need two file_lock structures for this operation,
+        * so we get them in advance to avoid races.
+        */
+       new_fl  = locks_empty_lock();
+       new_fl2 = locks_empty_lock();
+       error = -ENOLCK; /* "no luck" */
+       if (!(new_fl && new_fl2))
+               goto out;
 
        if (caller->fl_type != F_UNLCK) {
   repeat:
+               error = -ERESTARTSYS;
+               if (current->signal & ~current->blocked)
+                       goto out;
                for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
                        if (!(fl->fl_flags & FL_POSIX))
                                continue;
                        if (!posix_locks_conflict(caller, fl))
                                continue;
+                       error = -EAGAIN;
                        if (!wait)
-                               return (-EAGAIN);
-                       if (current->signal & ~current->blocked)
-                               return (-ERESTARTSYS);
+                               goto out;
+                       error = -EDEADLK;
                        if (posix_locks_deadlock(caller, fl))
-                               return (-EDEADLK);
+                               goto out;
                        locks_insert_block(fl, caller);
                        interruptible_sleep_on(&caller->fl_wait);
                        locks_delete_block(fl, caller);
-                       if (current->signal & ~current->blocked)
-                               return (-ERESTARTSYS);
                        goto repeat;
                }
        }
 
-       /* Find the first old lock with the same owner as the new lock.
+       /*
+        * We've allocated the new locks in advance, so there are no
+        * errors possible (and no blocking operations) from here on.
+        * 
+        * Find the first old lock with the same owner as the new lock.
         */
        
        before = &inode->i_flock;
@@ -958,25 +999,23 @@ int posix_lock_file(struct file *filp, struct file_lock *caller,
                before = &fl->fl_next;
        }
 
+       error = 0;
        if (!added) {
                if (caller->fl_type == F_UNLCK)
-                       return (0);
-               if ((new_fl = locks_alloc_lock(caller)) == NULL)
-                       return (-ENOLCK);
+                       goto out;
+               locks_init_lock(new_fl, caller);
                locks_insert_lock(before, new_fl);
+               new_fl = NULL;
        }
        if (right) {
                if (left == right) {
-                       /* The new lock breaks the old one in two pieces, so we
-                        * have to allocate one more lock (in this case, even
-                        * F_UNLCK may fail!).
+                       /* The new lock breaks the old one in two pieces,
+                        * so we have to use the second new lock (in this
+                        * case, even F_UNLCK may fail!).
                         */
-                       if ((left = locks_alloc_lock(right)) == NULL) {
-                               if (!added)
-                                       locks_delete_lock(before, 0);
-                               return (-ENOLCK);
-                       }
+                       left = locks_init_lock(new_fl2, right);
                        locks_insert_lock(before, left);
+                       new_fl2 = NULL;
                }
                right->fl_start = caller->fl_end + 1;
                locks_wake_up_blocks(right, 0);
@@ -985,35 +1024,48 @@ int posix_lock_file(struct file *filp, struct file_lock *caller,
                left->fl_end = caller->fl_start - 1;
                locks_wake_up_blocks(left, 0);
        }
-       return (0);
+out:
+       /*
+        * Free any unused locks.  (They haven't
+        * ever been used, so we use kfree().)
+        */
+       if (new_fl)
+               kfree(new_fl);
+       if (new_fl2)
+               kfree(new_fl2);
+       return error;
 }
 
-/* Allocate new lock.
- * Initialize its fields from fl. The lock is not inserted into any
- * lists until locks_insert_lock() or locks_insert_block() are called.
+/*
+ * Allocate an empty lock structure. We can use GFP_KERNEL now that
+ * all allocations are done in advance.
  */
-static struct file_lock *locks_alloc_lock(struct file_lock *fl)
+static struct file_lock *locks_empty_lock(void)
 {
-       struct file_lock *tmp;
-
        /* Okay, let's make a new file_lock structure... */
-       if ((tmp = (struct file_lock *)kmalloc(sizeof(struct file_lock),
-                                              GFP_ATOMIC)) == NULL)
-               return (tmp);
-
-       memset(tmp, 0, sizeof(*tmp));
-
-       tmp->fl_flags = fl->fl_flags;
-       tmp->fl_owner = fl->fl_owner;
-       tmp->fl_pid = fl->fl_pid;
-       tmp->fl_file = fl->fl_file;
-       tmp->fl_type = fl->fl_type;
-       tmp->fl_start = fl->fl_start;
-       tmp->fl_end = fl->fl_end;
-       tmp->fl_notify = fl->fl_notify;
-       tmp->fl_u = fl->fl_u;
-
-       return (tmp);
+       return ((struct file_lock *) kmalloc(sizeof(struct file_lock),
+                                               GFP_KERNEL));
+}
+
+/*
+ * Initialize a new lock from an existing file_lock structure.
+ */
+static struct file_lock *locks_init_lock(struct file_lock *new,
+                                        struct file_lock *fl)
+{
+       if (new) {
+               memset(new, 0, sizeof(*new));
+               new->fl_owner = fl->fl_owner;
+               new->fl_pid = fl->fl_pid;
+               new->fl_file = fl->fl_file;
+               new->fl_flags = fl->fl_flags;
+               new->fl_type = fl->fl_type;
+               new->fl_start = fl->fl_start;
+               new->fl_end = fl->fl_end;
+               new->fl_notify = fl->fl_notify;
+               new->fl_u = fl->fl_u;
+       }
+       return new;
 }
 
 /* Insert file lock fl into an inode's lock list at the position indicated
index 5aa6a54222735a840bb665f181367ef1adb41352..54714754d0bf5b4368fa7540757f0d9f3085029c 100644 (file)
@@ -593,8 +593,12 @@ struct dentry * open_namei(const char * pathname, int flag, int mode)
         * An append-only file must be opened in append mode for writing.
         */
        error = -EPERM;
-       if (IS_APPEND(inode) && ((flag & FMODE_WRITE) && !(flag & O_APPEND)))
-               goto exit;
+       if (IS_APPEND(inode)) {
+               if  ((flag & FMODE_WRITE) && !(flag & O_APPEND))
+                       goto exit;
+               if (flag & O_TRUNC)
+                       goto exit;
+       }
 
        if (flag & O_TRUNC) {
                error = get_write_access(inode);
index 449fc0d4e58f4bb358fb2c0c84c4d96cbdac7dea..ec5a1f7be6f9eeed37c5e3dd32a25c198a17278b 100644 (file)
 #include <linux/nfs_fs.h>
 #include <asm/uaccess.h>
 
+/*
+ * NOTE! We must NOT default to soft-mounting: that breaks too many
+ * programs that depend on POSIX behaviour of uninterruptible reads
+ * and writes.
+ *
+ * Until we have a per-mount soft/hard mount policy that we can honour
+ * we must default to hard mounting!
+ */
+#define IS_SOFT 0
+
 #define NFSDBG_FACILITY                NFSDBG_PAGECACHE
 
 static void                    nfs_wback_lock(struct rpc_task *task);
@@ -397,19 +407,24 @@ wait_on_write_request(struct nfs_wreq *req)
 {
        struct wait_queue       wait = { current, NULL };
        struct page             *page = req->wb_page;
+       int                     retval;
 
        add_wait_queue(&page->wait, &wait);
        atomic_inc(&page->count);
-repeat:
-       current->state = TASK_INTERRUPTIBLE;
-       if (PageLocked(page)) {
+       for (;;) {
+               current->state = IS_SOFT ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE;
+               retval = 0;
+               if (!PageLocked(page))
+                       break;
+               retval = -ERESTARTSYS;
+               if (IS_SOFT && signalled())
+                       break;
                schedule();
-               goto repeat;
        }
        remove_wait_queue(&page->wait, &wait);
        current->state = TASK_RUNNING;
        atomic_dec(&page->count);
-       return signalled()? -ERESTARTSYS : 0;
+       return retval;
 }
 
 /*
@@ -613,10 +628,13 @@ nfs_flush_dirty_pages(struct inode *inode, off_t offset, off_t len)
                                inode->i_dev, inode->i_ino, current->pid,
                                offset, len);
 
-       if (signalled())
+       if (IS_SOFT && signalled())
                nfs_cancel_dirty(inode, current->pid);
 
-       while (!signalled()) {
+       for (;;) {
+               if (IS_SOFT && signalled())
+                       return -ERESTARTSYS;
+
                /* Flush all pending writes for this pid and file region */
                last = nfs_flush_pages(inode, current->pid, offset, len, 0);
                if (last == NULL)
@@ -624,7 +642,7 @@ nfs_flush_dirty_pages(struct inode *inode, off_t offset, off_t len)
                wait_on_write_request(last);
        }
 
-       return signalled()? -ERESTARTSYS : 0;
+       return 0;
 }
 
 /*
index 2b0c4d1e287123a5b14dc5a68bcc670006aa2171..3196e90093a2285ef6e2d19b1c122be402cf2989 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 
+#define SMBFS_PARANOIA 1
+/* #define SMBFS_DEBUG_VERBOSE 1 */
+/* #define pr_debug printk */
+
+#define this_dir_cached(dir) ((dir->i_sb == c_sb) && (dir->i_ino == c_ino))
+
 static long
 smb_dir_read(struct inode *inode, struct file *filp,
             char *buf, unsigned long count);
@@ -69,6 +75,15 @@ struct inode_operations smb_dir_inode_operations =
        NULL                    /* smap */
 };
 
+static void smb_put_dentry(struct dentry *);
+static struct dentry_operations smbfs_dentry_operations =
+{
+       NULL,                   /* revalidate */
+       NULL,                   /* d_hash */
+       NULL,                   /* d_compare */
+       smb_put_dentry          /* d_delete */
+};
+
 static long
 smb_dir_read(struct inode *inode, struct file *filp, char *buf,
             unsigned long count)
@@ -76,166 +91,240 @@ smb_dir_read(struct inode *inode, struct file *filp, char *buf,
        return -EISDIR;
 }
 
+/*
+ * This is the callback from dput().  We close the file so that
+ * cached dentries don't keep the file open.
+ */
+void
+smb_put_dentry(struct dentry *dentry)
+{
+       struct inode *ino = dentry->d_inode;
+       if (ino)
+               smb_close(ino);
+}
+
+/* Static variables for the dir cache */
+static struct smb_dirent *c_entry = NULL;
+static struct super_block * c_sb = NULL;
 static unsigned long c_ino = 0;
-static kdev_t c_dev;
-static int c_size;
 static int c_seen_eof;
+static int c_size;
 static int c_last_returned_index;
-static struct smb_dirent *c_entry = NULL;
 
 static struct smb_dirent *
 smb_search_in_cache(struct inode *dir, unsigned long f_pos)
 {
        int i;
 
-       if ((dir->i_dev != c_dev) || (dir->i_ino != c_ino))
-       {
-               return NULL;
-       }
-       for (i = 0; i < c_size; i++)
-       {
-               if (f_pos == c_entry[i].f_pos)
+       if (this_dir_cached(dir))
+               for (i = 0; i < c_size; i++)
                {
-                       c_last_returned_index = i;
-                       return &(c_entry[i]);
+                       if (c_entry[i].f_pos < f_pos)
+                               continue;
+                       if (c_entry[i].f_pos == f_pos)
+                       {
+                               c_last_returned_index = i;
+                               return &(c_entry[i]);
+                       }
+                       break;
                }
-       }
        return NULL;
 }
 
+/*
+ * Compute the hash for a qstr ... move to include/linux/dcache.h?
+ */
+static unsigned int hash_it(const char * name, unsigned int len)
+{
+       unsigned long hash;
+       hash = init_name_hash();
+       while (len--)
+               hash = partial_name_hash(*name++, hash);
+       return end_name_hash(hash);
+}
+
+static struct semaphore refill_cache_sem = MUTEX;
+/*
+ * Called with the refill semaphore held.
+ */
 static int
 smb_refill_dir_cache(struct dentry *dentry, unsigned long f_pos)
 {
-       int result;
        struct inode *dir = dentry->d_inode;
-       static struct semaphore sem = MUTEX;
-       int i;
-       ino_t ino;
+       ino_t ino_start;
+       int i, result;
 
-       do
+       result = smb_proc_readdir(dentry, f_pos,
+                                       SMB_READDIR_CACHE_SIZE, c_entry);
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_refill_dir_cache: dir=%s/%s, pos=%lu, result=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, f_pos, result);
+#endif
+
+       if (result <= 0)
        {
-               down(&sem);
-               result = smb_proc_readdir(dentry, f_pos,
-                                         SMB_READDIR_CACHE_SIZE, c_entry);
+               /*
+                * If an error occurred, the cache may have been partially
+                * filled prior to failing, so we must invalidate.
+                * N.B. Might not need to for 0 return ... save cache?
+                */
+               c_sb = NULL;
+               c_ino = 0;
+               c_seen_eof = 0;
+               goto out;
+       }
 
-               if (result <= 0)
+       /* Suppose there are a multiple of cache entries? */
+       c_seen_eof = (result < SMB_READDIR_CACHE_SIZE);
+       c_sb = dir->i_sb;
+       c_ino = dir->i_ino;
+       c_size = result;
+       c_last_returned_index = 0; /* is this used? */
+
+       ino_start = smb_invent_inos(c_size);
+       /*
+        * If a dentry already exists, we have to give the cache entry
+        * the correct inode number.  This is needed for getcwd().
+        */
+       for (i = 0; i < c_size; i++)
+       {
+               struct dentry * new_dentry;
+               struct qstr qname;
+
+               c_entry[i].attr.f_ino = ino_start++;
+               qname.name = c_entry[i].name;
+               qname.len  = c_entry[i].len;
+               qname.hash = hash_it(qname.name, qname.len);
+               new_dentry = d_lookup(dentry, &qname);
+               if (new_dentry)
                {
-                       smb_invalid_dir_cache(dir->i_ino);
-                       up(&sem);
-                       return result;
+                       struct inode * inode = new_dentry->d_inode;
+                       if (inode)
+                               c_entry[i].attr.f_ino = inode->i_ino;
+                       dput(new_dentry);
                }
-               c_seen_eof = (result < SMB_READDIR_CACHE_SIZE);
-               c_dev = dir->i_dev;
-               c_ino = dir->i_ino;
-               c_size = result;
-               c_last_returned_index = 0;
-
-               ino = smb_invent_inos(c_size);
-
-               for (i = 0; i < c_size; i++)
-                       c_entry[i].attr.f_ino = ino++;
-
-               up(&sem);
        }
-       while ((c_dev != dir->i_dev) || (c_ino != dir->i_ino));
-
+out:
        return result;
 }
 
-static int smb_readdir(struct file *filp,
-           void *dirent, filldir_t filldir)
+static int 
+smb_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
        struct dentry *dentry = filp->f_dentry;
        struct inode *dir = dentry->d_inode;
-       int result, i = 0;
-       struct smb_dirent *entry = NULL;
+       struct smb_dirent *entry;
+       int result;
 
        pr_debug("smb_readdir: filp->f_pos = %d\n", (int) filp->f_pos);
        pr_debug("smb_readdir: dir->i_ino = %ld, c_ino = %ld\n",
                 dir->i_ino, c_ino);
 
+       result = -EBADF;
        if ((dir == NULL) || !S_ISDIR(dir->i_mode))
-       {
-               return -EBADF;
-       }
+               goto out;
+
+       /*
+        * Check whether the directory cache exists yet
+        */
        if (c_entry == NULL)
        {
-               i = sizeof(struct smb_dirent) * SMB_READDIR_CACHE_SIZE;
-               c_entry = (struct smb_dirent *) smb_vmalloc(i);
-               if (c_entry == NULL)
+               int size = sizeof(struct smb_dirent) * SMB_READDIR_CACHE_SIZE;
+               result = -ENOMEM;
+               entry = (struct smb_dirent *) smb_vmalloc(size);
+               /*
+                * Somebody else may have allocated the cache,
+                * so we check again to avoid a memory leak.
+                */
+               if (!c_entry)
                {
-                       return -ENOMEM;
+                       if (!entry)
+                               goto out;
+                       c_entry = entry;
+               } else if (entry) {
+                       printk("smb_readdir: cache already alloced!\n");
+                       smb_vfree(entry);
                }
        }
-       if (filp->f_pos == 0)
-       {
-               c_ino = 0;
-               c_dev = 0;
-               c_seen_eof = 0;
-
-               if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino) < 0)
-                       return 0;
 
-               filp->f_pos += 1;
-       }
-       if (filp->f_pos == 1)
+       result = 0;
+       switch ((unsigned int) filp->f_pos)
        {
-               if (filldir(dirent, "..", 2, filp->f_pos,
-                           filp->f_dentry->d_parent->d_inode->i_ino) < 0)
-                       return 0;
-
-               filp->f_pos += 1;
+       case 0:
+               if (filldir(dirent, ".", 1, 0, dir->i_ino) < 0)
+                       goto out;
+               filp->f_pos = 1;
+       case 1:
+               if (filldir(dirent, "..", 2, 1,
+                               dentry->d_parent->d_inode->i_ino) < 0)
+                       goto out;
+               filp->f_pos = 2;
        }
-       entry = smb_search_in_cache(dir, filp->f_pos);
 
+       /*
+        * Since filldir() could block if dirent is paged out,
+        * we hold the refill semaphore while using the cache.
+        * N.B. It's possible that the directory could change
+        * between calls to readdir ... what to do??
+        */
+       down(&refill_cache_sem);
+       entry = smb_search_in_cache(dir, filp->f_pos);
        if (entry == NULL)
        {
-               if (c_seen_eof)
+               /* Past the end of _this_ directory? */
+               if (this_dir_cached(dir) && c_seen_eof &&
+                   filp->f_pos == c_entry[c_size-1].f_pos + 1)
                {
-                       /* End of directory */
-                       return 0;
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_readdir: eof reached for %s/%s, c_size=%d, pos=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, c_size, (int) filp->f_pos);
+#endif
+                       goto up_and_out;
                }
                result = smb_refill_dir_cache(dentry, filp->f_pos);
                if (result <= 0)
-               {
-                       return result;
-               }
+                       goto up_and_out;
                entry = c_entry;
        }
+
        while (entry < &(c_entry[c_size]))
        {
-               ino_t ino = entry->attr.f_ino;
-
                pr_debug("smb_readdir: entry->name = %s\n", entry->name);
 
-               if (filldir(dirent, entry->name, strlen(entry->name),
-                           entry->f_pos, ino) < 0)
+               if (filldir(dirent, entry->name, entry->len, 
+                                   entry->f_pos, entry->attr.f_ino) < 0)
                        break;
-
-               if ((dir->i_dev != c_dev) || (dir->i_ino != c_ino)
-                   || (entry->f_pos != filp->f_pos))
-                       break;
-
+#if SMBFS_PARANOIA
+/* should never happen */
+if (!this_dir_cached(dir) || (entry->f_pos != filp->f_pos))
+printk("smb_readdir: cache changed!\n");
+#endif
                filp->f_pos += 1;
                entry += 1;
        }
-       return 0;
+       result = 0;
+
+up_and_out:
+       up(&refill_cache_sem);
+out:
+       return result;
 }
 
 void
 smb_init_dir_cache(void)
 {
-       c_ino = 0;
-       c_dev = 0;
        c_entry = NULL;
+       c_sb = NULL;
+       c_ino = 0;
+       c_seen_eof = 0;
 }
 
 void
-smb_invalid_dir_cache(unsigned long ino)
+smb_invalid_dir_cache(struct inode * dir)
 {
-       /* FIXME: check for dev as well */
-       if (ino == c_ino)
+       if (this_dir_cached(dir))
        {
+               c_sb = NULL;
                c_ino = 0;
                c_seen_eof = 0;
        }
@@ -246,6 +335,7 @@ smb_free_dir_cache(void)
 {
        if (c_entry != NULL)
        {
+               /* N.B. can this block?? */
                smb_vfree(c_entry);
        }
        c_entry = NULL;
@@ -256,106 +346,111 @@ smb_lookup(struct inode *dir, struct dentry *d_entry)
 {
        struct smb_fattr finfo;
        struct inode *inode;
-       int len = d_entry->d_name.len;
        int error;
 
-       if (!dir || !S_ISDIR(dir->i_mode)) {
-               printk("smb_lookup: inode is NULL or not a directory\n");
-               return -ENOENT;
-       }
-
-       if (len > SMB_MAXNAMELEN)
-               return -ENAMETOOLONG;
+       error = -ENAMETOOLONG;
+       if (d_entry->d_name.len > SMB_MAXNAMELEN)
+               goto out;
 
-       error = smb_proc_getattr(d_entry, &(d_entry->d_name), &finfo);
+       error = smb_proc_getattr(d_entry->d_parent, &(d_entry->d_name), &finfo);
+#if SMBFS_PARANOIA
+if (error && error != -ENOENT)
+printk("smb_lookup: find %s/%s failed, error=%d\n",
+d_entry->d_parent->d_name.name, d_entry->d_name.name, error);
+#endif
 
        inode = NULL;
-       if (!error) {
-               error = -ENOENT;
+       if (error == -ENOENT)
+               goto add_entry;
+       if (!error)
+       {
                finfo.f_ino = smb_invent_inos(1);
                inode = smb_iget(dir->i_sb, &finfo);
-               if (!inode)
-                       return -EACCES;
-       } else if (error != -ENOENT)
-               return error;
-
-       d_add(d_entry, inode);
-       return 0;
+               error = -EACCES;
+               if (inode)
+               {
+                       /* cache the dentry pointer */
+                       inode->u.smbfs_i.dentry = d_entry;
+       add_entry:
+                       d_entry->d_op = &smbfs_dentry_operations;
+                       d_add(d_entry, inode);
+                       error = 0;
+               }
+       }
+out:
+       return error;
 }
 
-static int smb_create(struct inode *dir, struct dentry *dentry, int mode)
+/*
+ * This code is common to all routines creating a new inode.
+ */
+static int
+smb_instantiate(struct inode *dir, struct dentry *dentry)
 {
        struct smb_fattr fattr;
-       struct inode *inode;
        int error;
 
-       if (!dir || !S_ISDIR(dir->i_mode))
+       smb_invalid_dir_cache(dir);
+
+       error = smb_proc_getattr(dentry->d_parent, &(dentry->d_name), &fattr);
+       if (!error)
        {
-               printk("smb_create: inode is NULL or not a directory\n");
-               return -ENOENT;
+               struct inode *inode;
+               error = -EACCES;
+               fattr.f_ino = smb_invent_inos(1);
+               inode = smb_iget(dir->i_sb, &fattr);
+               if (inode)
+               {
+                       /* cache the dentry pointer */
+                       inode->u.smbfs_i.dentry = dentry;
+                       d_instantiate(dentry, inode);
+                       error = 0;
+               }
        }
+       return error;
+}
 
-       if (dentry->d_name.len > SMB_MAXNAMELEN)
-               return -ENAMETOOLONG;
-
-       error = smb_proc_create(dentry, &(dentry->d_name), 0, CURRENT_TIME);
-       if (error < 0)
-               return error;
+/* N.B. Should the mode argument be put into the fattr? */
+static int
+smb_create(struct inode *dir, struct dentry *dentry, int mode)
+{
+       int error;
 
-       smb_invalid_dir_cache(dir->i_ino);
+       error = -ENAMETOOLONG;
+       if (dentry->d_name.len > SMB_MAXNAMELEN)
+               goto out;
 
        /* FIXME: In the CIFS create call we get the file in open
          * state. Currently we close it directly again, although this
         * is not necessary anymore. */
 
-       error = smb_proc_getattr(dentry, &(dentry->d_name), &fattr);
-       if (error < 0)
-               return error;
-
-       fattr.f_ino = smb_invent_inos(1);
-
-       inode = smb_iget(dir->i_sb, &fattr);
-       if (!inode)
-               return -EACCES;
-
-       d_instantiate(dentry, inode);
-       return 0;
+       error = smb_proc_create(dentry->d_parent, &(dentry->d_name), 
+                               0, CURRENT_TIME);
+       if (!error)
+       {
+               error = smb_instantiate(dir, dentry);
+       }
+out:
+       return error;
 }
 
+/* N.B. Should the mode argument be put into the fattr? */
 static int
 smb_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
-       struct smb_fattr fattr;
-       struct inode *inode;
        int error;
 
-       if (!dir || !S_ISDIR(dir->i_mode))
-       {
-               printk("smb_mkdir: inode is NULL or not a directory\n");
-               return -ENOENT;
-       }
-
+       error = -ENAMETOOLONG;
        if (dentry->d_name.len > SMB_MAXNAMELEN)
-               return -ENAMETOOLONG;
-
-       error = smb_proc_mkdir(dentry, &(dentry->d_name));
-       if (error)
-               return error;
-
-       smb_invalid_dir_cache(dir->i_ino);
+               goto out;
 
-       error = smb_proc_getattr(dentry, &(dentry->d_name), &fattr);
-       if (error < 0)
-               return error;
-
-       fattr.f_ino = smb_invent_inos(1);
-
-       inode = smb_iget(dir->i_sb, &fattr);
-       if (!inode)
-               return -EACCES;
-
-       d_instantiate(dentry, inode);
-       return 0;
+       error = smb_proc_mkdir(dentry->d_parent, &(dentry->d_name));
+       if (!error)
+       {
+               error = smb_instantiate(dir, dentry);
+       }
+out:
+       return error;
 }
 
 static int
@@ -363,21 +458,25 @@ smb_rmdir(struct inode *dir, struct dentry *dentry)
 {
        int error;
 
-       if (!dir || !S_ISDIR(dir->i_mode))
+       error = -ENAMETOOLONG;
+       if (dentry->d_name.len > NFS_MAXNAMLEN)
+               goto out;
+
+       /*
+        * Since the dentry is holding an inode, the file
+        * is in use, so we have to close it first.
+        */
+       if (dentry->d_inode)
+               smb_close(dentry->d_inode);
+       smb_invalid_dir_cache(dir);
+
+       error = smb_proc_rmdir(dentry->d_parent, &(dentry->d_name));
+       if (!error)
        {
-               printk("smb_rmdir: inode is NULL or not a directory\n");
-               return -ENOENT;
+               d_delete(dentry);
        }
-
-       if (dentry->d_name.len > NFS_MAXNAMLEN)
-               return -ENAMETOOLONG;
-
-       error = smb_proc_rmdir(dentry, &(dentry->d_name));
-       if (error)
-               return error;
-
-       d_delete(dentry);
-       return 0;
+out:
+       return error;
 }
 
 static int
@@ -385,64 +484,96 @@ smb_unlink(struct inode *dir, struct dentry *dentry)
 {
        int error;
 
-       if (!dir || !S_ISDIR(dir->i_mode))
+       error = -ENAMETOOLONG;
+       if (dentry->d_name.len > SMB_MAXNAMELEN)
+               goto out;
+
+       /*
+        * Since the dentry is holding an inode, the file
+        * is in use, so we have to close it first.
+        */
+       if (dentry->d_inode)
+               smb_close(dentry->d_inode);
+       smb_invalid_dir_cache(dir);
+
+       error = smb_proc_unlink(dentry->d_parent, &(dentry->d_name));
+       if (!error)
        {
-               printk("smb_unlink: inode is NULL or not a directory\n");
-               return -ENOENT;
+               d_delete(dentry);
        }
-
-       if (dentry->d_name.len > SMB_MAXNAMELEN)
-               return -ENAMETOOLONG;
-
-       error = smb_proc_unlink(dentry, &(dentry->d_name));
-       if (error)
-               return error;
-
-       smb_invalid_dir_cache(dir->i_ino);
-
-       d_delete(dentry);
-       return 0;
+out:
+       return error;
 }
 
-static int smb_rename(struct inode *old_dir, struct dentry *old_dentry,
-                     struct inode *new_dir, struct dentry *new_dentry)
+static int
+smb_rename(struct inode *old_dir, struct dentry *old_dentry,
+          struct inode *new_dir, struct dentry *new_dentry)
 {
        int error;
 
+       error = -ENOTDIR;
        if (!old_dir || !S_ISDIR(old_dir->i_mode))
        {
                printk("smb_rename: old inode is NULL or not a directory\n");
-               return -ENOENT;
+               goto out;
        }
 
        if (!new_dir || !S_ISDIR(new_dir->i_mode))
        {
                printk("smb_rename: new inode is NULL or not a directory\n");
-               return -ENOENT;
+               goto out;
        }
 
+       error = -ENAMETOOLONG;
        if (old_dentry->d_name.len > SMB_MAXNAMELEN ||
            new_dentry->d_name.len > SMB_MAXNAMELEN)
-               return -ENAMETOOLONG;
-
-       error = smb_proc_mv(old_dentry, &(old_dentry->d_name),
-                           new_dentry, &(new_dentry->d_name));
-
+               goto out;
+
+       /*
+        * Since the old and new dentries are holding the files open,
+        * we have to close the files first.
+        */
+       if (old_dentry->d_inode)
+               smb_close(old_dentry->d_inode);
+       if (new_dentry->d_inode)
+               smb_close(new_dentry->d_inode);
+
+       /* Assume success and invalidate now */
+       smb_invalid_dir_cache(old_dir);
+       smb_invalid_dir_cache(new_dir);
+
+       error = smb_proc_mv(old_dentry->d_parent, &(old_dentry->d_name),
+                           new_dentry->d_parent, &(new_dentry->d_name));
+       /*
+        * If the new file exists, attempt to delete it.
+        */
        if (error == -EEXIST)
        {
-               error = smb_proc_unlink(old_dentry, &(new_dentry->d_name));
-                                       
+#ifdef SMBFS_PARANOIA
+printk("smb_rename: existing file %s/%s, d_count=%d\n",
+new_dentry->d_parent->d_name.name, new_dentry->d_name.name, 
+new_dentry->d_count);
+#endif
+               error = smb_proc_unlink(new_dentry->d_parent, 
+                                       &(new_dentry->d_name));
+#ifdef SMBFS_PARANOIA
+printk("smb_rename: after unlink error=%d\n", error);
+#endif
                if (error)
-                       return error;
+                       goto out;
+               d_delete(new_dentry);
 
-               error = smb_proc_mv(old_dentry, &(old_dentry->d_name),
-                                   new_dentry, &(new_dentry->d_name));
+               error = smb_proc_mv(old_dentry->d_parent, &(old_dentry->d_name),
+                                   new_dentry->d_parent, &(new_dentry->d_name));
        }
 
-       if (error)
-               return error;
-
-       smb_invalid_dir_cache(old_dir->i_ino);
-       smb_invalid_dir_cache(new_dir->i_ino);
-       return 0;
+       /*
+        * Update the dcache
+        */
+       if (!error)
+       {
+               d_move(old_dentry, new_dentry);
+       }
+out:
+       return error;
 }
index cb1a0cd30c19851208f4798d216008170a8c410c..9653a7be6e3f2738c54aa801f11afacbad7a0117 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
+#define SMBFS_PARANOIA 1
+/* #define SMBFS_DEBUG_VERBOSE 1 */
+/* #define pr_debug printk */
+
 static inline int
 min(int a, int b)
 {
        return a < b ? a : b;
 }
 
-static int smb_fsync(struct file *file, struct dentry *dir)
+static int
+smb_fsync(struct file *file, struct dentry * dentry)
 {
+       printk("smb_fsync: sync file %s/%s\n", 
+               dentry->d_parent->d_name.name, dentry->d_name.name);
        return 0;
 }
 
@@ -38,6 +45,7 @@ smb_readpage_sync(struct inode *inode, struct page *page)
 {
        unsigned long offset = page->offset;
        char *buffer = (char *) page_address(page);
+       struct dentry * dentry = inode->u.smbfs_i.dentry;
        int rsize = SMB_SERVER(inode)->opt.max_xmit - (SMB_HEADER_LEN+15);
        int result, refresh = 0;
        int count = PAGE_SIZE;
@@ -45,14 +53,26 @@ smb_readpage_sync(struct inode *inode, struct page *page)
        pr_debug("SMB: smb_readpage_sync(%p)\n", page);
        clear_bit(PG_error, &page->flags);
 
-       result = smb_open(inode, O_RDONLY);
+       result = -EIO;
+       if (!dentry) {
+               printk("smb_readpage_sync: no dentry for inode %ld\n",
+                       inode->i_ino);
+               goto io_error;
+       }
+       result = smb_open(dentry, O_RDONLY);
        if (result < 0)
                goto io_error;
+       /* Should revalidate inode ... */
 
        do {
                if (count < rsize)
                        rsize = count;
 
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_readpage: reading %s/%s, offset=%ld, buffer=%p, size=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, offset, buffer, rsize);
+#endif
                result = smb_proc_read(inode, offset, rsize, buffer);
                if (result < 0)
                        goto io_error;
@@ -80,15 +100,17 @@ io_error:
 int
 smb_readpage(struct inode *inode, struct page *page)
 {
-       unsigned long   address;
-       int             error = -1;
+       int             error;
 
        pr_debug("SMB: smb_readpage %08lx\n", page_address(page));
+#ifdef SMBFS_PARANOIA
+       if (test_bit(PG_locked, &page->flags))
+               printk("smb_readpage: page already locked!\n");
+#endif
        set_bit(PG_locked, &page->flags);
-       address = page_address(page);
        atomic_inc(&page->count);
        error = smb_readpage_sync(inode, page);
-       free_page(address);
+       __free_page(page);
        return error;
 }
 
@@ -122,6 +144,11 @@ smb_writepage_sync(struct inode *inode, struct page *page,
                        clear_bit(PG_uptodate, &page->flags);
                        goto io_error;
                }
+               /* N.B. what if result < wsize?? */
+#ifdef SMBFS_PARANOIA
+if (result < wsize)
+printk("smb_writepage_sync: short write, wsize=%d, result=%d\n", wsize, result);
+#endif
                refresh = 1;
                buffer += wsize;
                offset += wsize;
@@ -134,6 +161,7 @@ io_error:
                smb_refresh_inode(inode);
 
        clear_bit(PG_locked, &page->flags);
+       wake_up(&page->wait);
        return written ? written : result;
 }
 
@@ -144,7 +172,17 @@ io_error:
 static int
 smb_writepage(struct inode *inode, struct page *page)
 {
-       return smb_writepage_sync(inode, page, 0, PAGE_SIZE);
+       int     result;
+
+#ifdef SMBFS_PARANOIA
+       if (test_bit(PG_locked, &page->flags))
+               printk("smb_writepage: page already locked!\n");
+#endif
+       set_bit(PG_locked, &page->flags);
+       atomic_inc(&page->count);
+       result = smb_writepage_sync(inode, page, 0, PAGE_SIZE);
+       __free_page(page);
+       return result;
 }
 
 static int
@@ -152,15 +190,35 @@ smb_updatepage(struct inode *inode, struct page *page, const char *buffer,
               unsigned long offset, unsigned int count, int sync)
 {
        u8              *page_addr;
+       int     result;
 
        pr_debug("SMB:      smb_updatepage(%x/%ld %d@%ld, sync=%d)\n",
                 inode->i_dev, inode->i_ino,
                 count, page->offset+offset, sync);
 
+#ifdef SMBFS_PARANOIA
+       if (test_bit(PG_locked, &page->flags))
+               printk("smb_updatepage: page already locked!\n");
+#endif
+       set_bit(PG_locked, &page->flags);
+       atomic_inc(&page->count);
+
        page_addr = (u8 *) page_address(page);
 
-       copy_from_user(page_addr + offset, buffer, count);
-       return smb_writepage_sync(inode, page, offset, count);
+       if (copy_from_user(page_addr + offset, buffer, count))
+               goto bad_fault;
+       result = smb_writepage_sync(inode, page, offset, count);
+out:
+       __free_page(page);
+       return result;
+
+bad_fault:
+       printk("smb_updatepage: fault at page=%p buffer=%p\n", page, buffer);
+       result = -EFAULT;
+       clear_bit(PG_uptodate, &page->flags);
+       clear_bit(PG_locked, &page->flags);
+       wake_up(&page->wait);
+       goto out;
 }
 
 static long
@@ -174,23 +232,26 @@ smb_file_read(struct inode * inode, struct file * file,
                 count, (unsigned long) file->f_pos);
 
        status = smb_revalidate_inode(inode);
-       if (status < 0)
-               return status;
-
-       return generic_file_read(inode, file, buf, count);
+       if (status >= 0)
+       {
+               status = generic_file_read(inode, file, buf, count);
+       }
+       return status;
 }
 
 static int
 smb_file_mmap(struct file * file, struct vm_area_struct * vma)
 {
+       struct dentry * dentry = file->f_dentry;
+       struct inode * inode = dentry->d_inode;
        int     status;
-       struct inode * inode = file->f_dentry->d_inode;
 
        status = smb_revalidate_inode(inode);
-       if (status < 0)
-               return status;
-
-       return generic_file_mmap(file, vma);
+       if (status >= 0)
+       {
+               status = generic_file_mmap(file, vma);
+       }
+       return status;
 }
 
 /* 
@@ -206,28 +267,34 @@ smb_file_write(struct inode *inode, struct file *file,
                 inode->i_dev, inode->i_ino, inode->i_count,
                 count, (unsigned long) file->f_pos);
 
+       result = -EINVAL;
        if (!inode) {
                printk("smb_file_write: inode = NULL\n");
-               return -EINVAL;
+               goto out;
        }
 
        result = smb_revalidate_inode(inode);
        if (result < 0)
-               return result;
+               goto out;
 
-       result = smb_open(inode, O_WRONLY);
+       result = smb_open(file->f_dentry, O_WRONLY);
        if (result < 0)
-               return result;
+               goto out;
 
+       result = -EINVAL;
        if (!S_ISREG(inode->i_mode)) {
                printk("smb_file_write: write to non-file, mode %07o\n",
                        inode->i_mode);
-               return -EINVAL;
+               goto out;
        }
-       if (count <= 0)
-               return 0;
 
-       return generic_file_write(inode, file, buf, count);
+       result = 0;
+       if (count > 0)
+       {
+               result = generic_file_write(inode, file, buf, count);
+       }
+out:
+       return result;
 }
 
 static struct file_operations smb_file_operations =
index edea049053686d0c55e801ad752709f029c49a3f..9203650e25deffc2ddbbaedb5f81b634feb02391 100644 (file)
@@ -26,6 +26,9 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
+#define SB_of(server) ((struct super_block *) ((char *)(server) - \
+       (unsigned long)(&((struct super_block *)0)->u.smbfs_sb)))
+
 extern int close_fp(struct file *filp);
 
 static void smb_put_inode(struct inode *);
@@ -81,6 +84,23 @@ smb_iget(struct super_block *sb, struct smb_fattr *fattr)
        return result;
 }
 
+static void
+smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr)
+{
+       inode->i_dev    = inode->i_sb->s_dev;
+       inode->i_mode   = fattr->f_mode;
+       inode->i_nlink  = fattr->f_nlink;
+       inode->i_uid    = fattr->f_uid;
+       inode->i_gid    = fattr->f_gid;
+       inode->i_rdev   = fattr->f_rdev;
+       inode->i_size   = fattr->f_size;
+       inode->i_mtime  = fattr->f_mtime;
+       inode->i_ctime  = fattr->f_ctime;
+       inode->i_atime  = fattr->f_atime;
+       inode->i_blksize= fattr->f_blksize;
+       inode->i_blocks = fattr->f_blocks;
+}
+
 static void
 smb_read_inode(struct inode *inode)
 {
@@ -92,18 +112,8 @@ smb_read_inode(struct inode *inode)
                printk("smb_read_inode called from invalid point\n");
                return;
        }
-       inode->i_mode = read_fattr->f_mode;
-       inode->i_nlink = read_fattr->f_nlink;
-       inode->i_uid = read_fattr->f_uid;
-       inode->i_gid = read_fattr->f_gid;
-       inode->i_rdev = read_fattr->f_rdev;
-       inode->i_size = read_fattr->f_size;
-       inode->i_mtime = read_fattr->f_mtime;
-       inode->i_ctime = read_fattr->f_ctime;
-       inode->i_atime = read_fattr->f_atime;
-       inode->i_blksize = read_fattr->f_blksize;
-       inode->i_blocks = read_fattr->f_blocks;
 
+       smb_set_inode_attr(inode, read_fattr);
        memset(&(inode->u.smbfs_i), 0, sizeof(inode->u.smbfs_i));
 
        if (S_ISREG(inode->i_mode))
@@ -114,39 +124,112 @@ smb_read_inode(struct inode *inode)
                inode->i_op = NULL;
 }
 
+/*
+ * This is called if the connection has gone bad ...
+ * try to kill off all the current inodes.
+ */
 void
 smb_invalidate_inodes(struct smb_sb_info *server)
 {
        printk("smb_invalidate_inodes\n");
+       shrink_dcache(); /* should shrink only this sb */
+       invalidate_inodes(SB_of(server));
 }
 
 int
-smb_revalidate_inode(struct inode *i)
+smb_revalidate_inode(struct inode *ino)
 {
+       struct dentry * dentry = ino->u.smbfs_i.dentry;
+       int error = 0;
+
        pr_debug("smb_revalidate_inode\n");
-       return 0;
+       if (!ino)
+               goto bad_no_inode;
+       dentry = ino->u.smbfs_i.dentry;
+#if 0
+       if (dentry)
+       {
+               printk("smb_revalidate: checking %s/%s\n",
+                       dentry->d_parent->d_name.name, dentry->d_name.name);
+       }
+#endif
+out:
+       return error;
+
+bad_no_inode:
+       printk("smb_revalidate: no inode!\n");
+       error = -EINVAL;
+       goto out;
 }
 
 int
-smb_refresh_inode(struct inode *i)
+smb_refresh_inode(struct inode *ino)
 {
+       struct dentry * dentry = ino->u.smbfs_i.dentry;
+       struct smb_fattr fattr;
+       int error;
+
        pr_debug("smb_refresh_inode\n");
-       return 0;
+       error = -EIO;
+       if (!dentry) {
+               printk("smb_refresh_inode: no dentry, can't refresh\n");
+               goto out;
+       }
+
+       /* N.B. Should check for changes of important fields! cf. NFS */
+       error = smb_proc_getattr(dentry->d_parent, &(dentry->d_name), &fattr);
+       if (!error)
+       {
+               smb_set_inode_attr(ino, &fattr);
+       }
+out:
+       return error;
 }
 
+/*
+ * This routine is called for every iput().
+ */
 static void
 smb_put_inode(struct inode *ino)
 {
+       struct dentry * dentry;
        pr_debug("smb_put_inode: count = %d\n", ino->i_count);
 
-       if (smb_close(ino))
-               printk("smbfs: could not close inode\n");
+       if (ino->i_count > 1) {
+               /*
+                * Check whether the dentry still holds this inode. 
+                * This looks scary, but should work ... d_inode is 
+                * cleared before iput() in the dcache. 
+                */
+               dentry = (struct dentry *) ino->u.smbfs_i.dentry;
+               if (dentry && dentry->d_inode != ino) {
+                       ino->u.smbfs_i.dentry = NULL;
+#if 1
+printk("smb_put_inode: cleared dentry for %s/%s (%ld), count=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, ino->i_ino, ino->i_count);
+#endif
+               }
+       } else {
+               /*
+                * Last use ... clear i_nlink to force
+                * smb_delete_inode to be called.
+               */
+               ino->i_nlink = 0;
+       }
 }
 
+/*
+ * This routine is called when i_nlink == 0 and i_count goes to 0.
+ * All blocking cleanup operations need to go here to avoid races.
+ */
 static void
-smb_delete_inode(struct inode *i)
+smb_delete_inode(struct inode *ino)
 {
        pr_debug("smb_delete_inode\n");
+       if (smb_close(ino))
+               printk("smb_delete_inode: could not close inode %ld\n",
+                       ino->i_ino);
+       clear_inode(ino);
 }
 
 static void
@@ -181,33 +264,20 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent)
        struct smb_fattr root;
        kdev_t dev = sb->s_dev;
        unsigned char *packet;
+       struct inode *root_inode;
+       struct dentry *dentry;
 
        MOD_INC_USE_COUNT;
 
-       if (!data) {
-               printk("smb_read_super: missing data argument\n");
-               sb->s_dev = 0;
-               MOD_DEC_USE_COUNT;
-               return NULL;
-       }
+       if (!data)
+               goto out_no_data;
                
        if (data->version != SMB_MOUNT_VERSION)
-       {
-               printk(KERN_ERR "smb_read_super: wrong data argument."
-                      " Recompile smbmount.\n");
-               sb->s_dev = 0;
-               MOD_DEC_USE_COUNT;
-               return NULL;
-       }
+               goto out_wrong_data;
 
        packet = smb_vmalloc(SMB_INITIAL_PACKET_SIZE);  
        if (!packet)
-       {
-               pr_debug("smb_read_super: could not alloc packet\n");
-               sb->s_dev = 0;
-               MOD_DEC_USE_COUNT;
-               return NULL;
-       }
+               goto out_no_mem;
 
        lock_super(sb);
 
@@ -222,7 +292,7 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent)
        sb->u.smbfs_sb.conn_pid = 0;
        sb->u.smbfs_sb.packet = packet;
        sb->u.smbfs_sb.packet_size = SMB_INITIAL_PACKET_SIZE;
-       sb->u.smbfs_sb.generation = 1;
+       sb->u.smbfs_sb.generation = 0;
 
        sb->u.smbfs_sb.m = *data;
        sb->u.smbfs_sb.m.file_mode = (sb->u.smbfs_sb.m.file_mode &
@@ -232,18 +302,38 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent)
 
        smb_init_root_dirent(&(sb->u.smbfs_sb), &root);
 
+       sb->s_root = NULL;
        unlock_super(sb);
 
-       sb->s_root = d_alloc_root(smb_iget(sb, &root), NULL);
-       if (!sb->s_root)
-       {
-               sb->s_dev = 0;
-               printk(KERN_ERR "smb_read_super: get root inode failed\n");
-               smb_vfree(sb->u.smbfs_sb.packet);
-               MOD_DEC_USE_COUNT;
-               return NULL;
-       }
+       root_inode = smb_iget(sb, &root);
+       if (!root_inode)
+               goto out_no_root;
+       dentry = d_alloc_root(root_inode, NULL);
+       if (!dentry)
+               goto out_no_root;
+       root_inode->u.smbfs_i.dentry = dentry;
+       sb->s_root = dentry;
        return sb;
+
+out_no_data:
+       printk("smb_read_super: missing data argument\n");
+       goto out;
+out_wrong_data:
+       printk(KERN_ERR "smb_read_super: wrong data argument."
+              " Recompile smbmount.\n");
+       goto out;
+out_no_mem:
+       pr_debug("smb_read_super: could not alloc packet\n");
+       goto out;
+out_no_root:
+       sb->s_dev = 0; /* iput() might block */
+       printk(KERN_ERR "smb_read_super: get root inode failed\n");
+       iput(root_inode);
+       smb_vfree(packet);
+out:
+       sb->s_dev = 0;
+       MOD_DEC_USE_COUNT;
+       return NULL;
 }
 
 static int
@@ -265,32 +355,46 @@ smb_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
 int
 smb_notify_change(struct inode *inode, struct iattr *attr)
 {
-       int error = 0;
+       struct dentry *dentry = inode->u.smbfs_i.dentry;
+       int error;
+
+       error = -EIO;
+       if (!dentry)
+       {
+               printk("smb_notify_change: no dentry for inode!\n");
+               goto out;
+       }
 
        if ((error = inode_change_ok(inode, attr)) < 0)
-               return error;
+               goto out;
 
+       error = -EPERM;
        if (((attr->ia_valid & ATTR_UID) &&
             (attr->ia_uid != SMB_SERVER(inode)->m.uid)))
-               return -EPERM;
+               goto out;
 
        if (((attr->ia_valid & ATTR_GID) &&
             (attr->ia_uid != SMB_SERVER(inode)->m.gid)))
-               return -EPERM;
+               goto out;
 
        if (((attr->ia_valid & ATTR_MODE) &&
        (attr->ia_mode & ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO))))
-               return -EPERM;
+               goto out;
+
+       /*
+        * Assume success and invalidate the parent's dir cache
+        */ 
+       smb_invalid_dir_cache(dentry->d_parent->d_inode);
 
        if ((attr->ia_valid & ATTR_SIZE) != 0)
        {
-               if ((error = smb_open(inode, O_WRONLY)) < 0)
-                       goto fail;
+               if ((error = smb_open(dentry, O_WRONLY)) < 0)
+                       goto out;
 
                if ((error = smb_proc_trunc(SMB_SERVER(inode),
                                            inode->u.smbfs_i.fileid,
                                            attr->ia_size)) < 0)
-                       goto fail;
+                       goto out;
        }
        if ((attr->ia_valid & (ATTR_CTIME | ATTR_MTIME | ATTR_ATIME)) != 0)
        {
@@ -300,37 +404,31 @@ smb_notify_change(struct inode *inode, struct iattr *attr)
                fattr.attr = 0;
                fattr.f_size = inode->i_size;
                fattr.f_blksize = inode->i_blksize;
+               fattr.f_ctime = inode->i_ctime;
+               fattr.f_mtime = inode->i_mtime;
+               fattr.f_atime = inode->i_atime;
 
                if ((attr->ia_valid & ATTR_CTIME) != 0)
                        fattr.f_ctime = attr->ia_ctime;
-               else
-                       fattr.f_ctime = inode->i_ctime;
 
                if ((attr->ia_valid & ATTR_MTIME) != 0)
                        fattr.f_mtime = attr->ia_mtime;
-               else
-                       fattr.f_mtime = inode->i_mtime;
 
                if ((attr->ia_valid & ATTR_ATIME) != 0)
                        fattr.f_atime = attr->ia_atime;
-               else
-                       fattr.f_atime = inode->i_atime;
 
-               if ((error = smb_proc_setattr(SMB_SERVER(inode),
-                                             inode, &fattr)) >= 0)
+               error = smb_proc_setattr(SMB_SERVER(inode), dentry, &fattr);
+               if (error >= 0)
                {
                        inode->i_ctime = fattr.f_ctime;
                        inode->i_mtime = fattr.f_mtime;
                        inode->i_atime = fattr.f_atime;
                }
        }
-      fail:
-/*     smb_invalid_dir_cache(smb_info_ino(SMB_INOP(inode)->dir));*/
-
+out:
        return error;
 }
 
-
 #ifdef DEBUG_SMB_MALLOC
 int smb_malloced;
 int smb_current_kmalloced;
index 248222af8f3ae3ae8b99a72d23f9aa60e566e934..57b4be6fbec16ce87c6f1ee254706c0084f8c8f1 100644 (file)
@@ -5,7 +5,6 @@
  *  Copyright (C) 1997 by Volker Lendecke
  *
  *  28/06/96 - Fixed long file name support (smb_proc_readdir_long) by Yuri Per
- *  04/09/97 - Fixed smb_d_path to be non-recursive by Riccardo Facchetti
  */
 
 #include <linux/config.h>
@@ -17,7 +16,6 @@
 #include <linux/malloc.h>
 #include <linux/stat.h>
 #include <linux/fcntl.h>
-#include <linux/dcache.h>
 
 #include <asm/uaccess.h>
 #include <asm/string.h>
 #define SMB_DIRINFO_SIZE 43
 #define SMB_STATUS_SIZE  21
 
+#define SMBFS_PARANOIA 1
+/* #define SMBFS_DEBUG_VERBOSE 1 */
+/* #define pr_debug printk */
+
 static int smb_request_ok(struct smb_sb_info *s, int command, int wct, int bcc);
+void smb_close_socket(struct smb_sb_info *);
 
 static inline int
 min(int a, int b)
@@ -81,36 +84,31 @@ smb_encode_smb_length(__u8 * p, __u32 len)
        return p + 4;
 }
 
-static int smb_d_path(struct dentry * entry, char * buffer)
+/*
+ * Return the server for the specified dentry
+ * N.B. Make this a #define in the smb header
+ */
+static struct smb_sb_info * server_from_dentry(struct dentry * dentry)
 {
-       char *page, *path, *buf = buffer;
-       int len = 0;
-
-       page = (char *) __get_free_page(GFP_KERNEL);
-
-       /*
-        * Get the path
-        */
-       path = d_path(entry, page, PAGE_SIZE);
+       return &dentry->d_sb->u.smbfs_sb;
+}
 
-       /*
-        * path is a string with a trailing '\0'
-        */
-       len = strlen(path);
+static int smb_d_path(struct dentry * entry, char * buf)
+{
+       if (IS_ROOT(entry)) {
+               *buf = '\\';
+               return 1;
+       } else {
+               int len = smb_d_path(entry->d_parent, buf);
 
-       /*
-        * Now encode it the DOSish way and copy it to the
-        * output buffer. No need to terminate output buffer
-        * with a trailing '\0'.
-        */
-       while (*path) {
-               *buf++ = ((*path != '/') ? *path : '\\');
-               path++;
+               buf += len;
+               if (len > 1) {
+                       *buf++ = '\\';
+                       len++;
+               }
+               memcpy(buf, entry->d_name.name, entry->d_name.len);
+               return len + entry->d_name.len;
        }
-
-       free_page((unsigned long) page);
-
-       return len;
 }
 
 static char *smb_encode_path(struct smb_sb_info *server, char *buf,
@@ -128,15 +126,6 @@ static char *smb_encode_path(struct smb_sb_info *server, char *buf,
                *buf++ = 0;
        }
 
-       /*
-        * XXX smb_d_path don't put the trailing '\0' in the buf.
-        * The problem may arise when (dir != NULL && name == NULL &&
-        * server->opt.protocol <= SMB_PROTOCOL_COREPLUS))
-        * because str_upper() rely on trailing '\0' for converting the
-        * start to upper chars. I don't know samba, so I suspect a bug but I
-        * don't want to do something stupid here.
-        * -Riccardo
-        */
        if (server->opt.protocol <= SMB_PROTOCOL_COREPLUS)
                str_upper(start);
 
@@ -308,11 +297,15 @@ smb_errno(int errcls, int error)
                        return EEXIST;
                case 87:
                        return 0;       /* Unknown error!! */
+               case 123:               /* Invalid name?? e.g. .tmp* */
+                       return ENOENT;
                        /* This next error seems to occur on an mv when
                         * the destination exists */
                case 183:
                        return EEXIST;
                default:
+                       printk("smb_errno: ERRDOS code %d, returning EIO\n",
+                               error);
                        return EIO;
        } else if (errcls == ERRSRV)
                switch (error)
@@ -326,6 +319,8 @@ smb_errno(int errcls, int error)
                case ERRaccess:
                        return EACCES;
                default:
+                       printk("smb_errno: ERRSRV code %d, returning EIO\n",
+                               error);
                        return EIO;
        } else if (errcls == ERRHRD)
                switch (error)
@@ -347,9 +342,14 @@ smb_errno(int errcls, int error)
                case ERRlock:
                        return EDEADLK;
                default:
+                       printk("smb_errno: ERRHRD code %d, returning EIO\n",
+                               error);
                        return EIO;
        } else if (errcls == ERRCMD)
+               {
+               printk("smb_errno: ERRCMD code %d, returning EIO\n", error);
                return EIO;
+               }
        return 0;
 }
 
@@ -374,6 +374,7 @@ static int
 smb_request_ok(struct smb_sb_info *s, int command, int wct, int bcc)
 {
        int result = 0;
+
        s->rcls = 0;
        s->err = 0;
 
@@ -396,86 +397,133 @@ smb_request_ok(struct smb_sb_info *s, int command, int wct, int bcc)
        return result;
 }
 
-/* smb_retry: This function should be called when smb_request_ok has
+/*
+ * smb_retry: This function should be called when smb_request_ok has
    indicated an error. If the error was indicated because the
    connection was killed, we try to reconnect. If smb_retry returns 0,
    the error was indicated for another reason, so a retry would not be
-   of any use. */
+   of any use.
+ * N.B. The server must be locked for this call.
+ */
 
 static int
 smb_retry(struct smb_sb_info *server)
 {
+       int result = 0;
+
        if (server->state != CONN_INVALID)
-       {
-               return 0;
-       }
-       if (server->sock_file != NULL)
-       {
-               close_fp(server->sock_file);
-               server->sock_file = NULL;
-       }
+               goto out;
+
+       smb_close_socket(server);
 
        if (server->conn_pid == 0)
        {
+               printk("smb_retry: no connection process\n");
                server->state = CONN_RETRIED;
-               return 0;
+               goto out;
        }
 
+       printk("smb_retry: signalling process %d\n", server->conn_pid);
        kill_proc(server->conn_pid, SIGUSR1, 0);
        server->conn_pid = 0;
 
+       /*
+        * Block here until we get a new connection.
+        * N.B. This needs to be fixed ... we should wait in an
+        * interruptible sleep for CONN_VALID.
+        */
+       printk("smb_retry: blocking for new connection\n");
        smb_lock_server(server);
 
-       if (server->sock_file != NULL)
+       if (server->state == CONN_VALID)
        {
-               server->state = CONN_VALID;
-               return 1;
+               printk("smb_retry: new connection pid=%d\n", server->conn_pid);
+               result = 1;
        }
-       return 0;
+out:
+       return result;
 }
 
+/*
+ * This is called with the server locked after a successful smb_newconn().
+ * It installs the new connection pid, sets server->state to CONN_VALID,
+ * and unlocks the server.
+ * N.B. The first call is made without locking the server -- need to fix!
+ */
 int
 smb_offerconn(struct smb_sb_info *server)
 {
+       int error;
+
+       error = -EACCES;
        if (!suser() && (current->uid != server->m.mounted_uid))
-       {
-               return -EACCES;
-       }
+               goto out;
+
        server->conn_pid = current->pid;
-       return 0;
+       server->state = CONN_VALID;
+       printk("smb_offerconn: state valid, pid=%d\n", server->conn_pid);
+       error = 0;
+
+       /*
+        * The initial call may be made without the server locked?
+        */
+out:
+       if (atomic_read(&server->sem.count) != 1)
+               smb_unlock_server(server);
+       else
+               printk("smb_offerconn: server not locked, count=%d\n",
+                       atomic_read(&server->sem.count));
+       return error;
 }
 
+/*
+ * This must be called with the server locked.
+ * N.B. The first call is made without locking the server -- need to fix!
+ */
 int
 smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt)
 {
        struct file *filp;
+       int error;
 
+       error = -EBADF;
        if (opt->fd >= NR_OPEN || !(filp = current->files->fd[opt->fd]))
-       {
-               return -EBADF;
-       }
+               goto out_unlock;
        if (!S_ISSOCK(filp->f_dentry->d_inode->i_mode))
-       {
-               return -EBADF;
-       }
+               goto out_unlock;
+       if (!S_ISSOCK(filp->f_dentry->d_inode->i_mode))
+               goto out_unlock;
+
+       error = -EACCES;
        if (!suser() && (current->uid != server->m.mounted_uid))
-       {
-               return -EACCES;
-       }
-       if (server->sock_file != NULL)
-       {
-               close_fp(server->sock_file);
-               server->sock_file = NULL;
-       }
+               goto out_unlock;
+
+       /*
+        * Make sure the old socket is closed
+        */
+       smb_close_socket(server);
+
        filp->f_count += 1;
        server->sock_file = filp;
        smb_catch_keepalive(server);
        server->opt = *opt;
        pr_debug("smb_newconn: protocol = %d\n", server->opt.protocol);
-       server->conn_pid = 0;
        server->generation += 1;
-       smb_unlock_server(server);
-       return 0;
+       error = 0;
+
+out:
+       return error;
+
+       /*
+        * Unlock now if an error occurred.
+        */
+out_unlock:
+       if (atomic_read(&server->sem.count) != 1)
+               smb_unlock_server(server);
+       else
+               printk("smb_newconn: server not locked, count=%d\n",
+                       atomic_read(&server->sem.count));
+       goto out;
 }
 
 /* smb_setup_header: We completely set up the packet. You only have to
@@ -528,17 +576,15 @@ smb_setup_bcc(struct smb_sb_info *server, __u8 * p)
                              SMB_HEADER_LEN + 2 * SMB_WCT(packet) - 2 + bcc);
 }
 
-
 /*
  * We're called with the server locked, and we leave it that way. We
  * try maximum permissions.
  */
 
 static int
-smb_proc_open(struct dentry *dir)
+smb_proc_open(struct smb_sb_info *server, struct dentry *dir)
 {
        struct inode *ino = dir->d_inode;
-       struct smb_sb_info *server = SMB_SERVER(ino);
        int error;
        char *p;
 
@@ -557,7 +603,7 @@ smb_proc_open(struct dentry *dir)
 
                if ((error != -EACCES) && (error != -ETXTBSY)
                    && (error != -EROFS))
-                       return error;
+                       goto out;
 
                p = smb_setup_header(server, SMBopen, 2, 0);
                WSET(server->packet, smb_vwv0, 0x40);   /* read only */
@@ -570,40 +616,56 @@ smb_proc_open(struct dentry *dir)
                {
                        if (smb_retry(server))
                                goto retry;
-
-                       return error;
+                       goto out;
                }
        }
        /* We should now have data in vwv[0..6]. */
 
        ino->u.smbfs_i.fileid = WVAL(server->packet, smb_vwv0);
-       ino->u.smbfs_i.attr = WVAL(server->packet, smb_vwv1);
+       ino->u.smbfs_i.attr   = WVAL(server->packet, smb_vwv1);
        ino->u.smbfs_i.access = WVAL(server->packet, smb_vwv6);
        ino->u.smbfs_i.access &= 3;
 
        ino->u.smbfs_i.open = server->generation;
 
        pr_debug("smb_proc_open: entry->access = %d\n", ino->u.smbfs_i.access);
-       return 0;
+out:
+       return error;
 }
 
 int
 smb_open(struct dentry *dir, int wish)
 {
-       struct inode *i=dir->d_inode;
-       struct smb_sb_info *server = SMB_SERVER(i);
-       int result = -EACCES;
+       struct inode *i = dir->d_inode;
+       int result;
 
-       smb_lock_server(server);
+       result = -EIO;
+       if (!i)
+       {
+               printk("smb_open: no inode for dentry %s/%s\n",
+                       dir->d_parent->d_name.name, dir->d_name.name);
+               goto out;
+       }
 
-       if (!smb_is_open(i)) {
-               int error = smb_proc_open(dir);
-               if (error) {
-                       smb_unlock_server(server);
-                       return error;
+       /*
+        * If the inode is already open, we don't need to lock the server.
+        */
+       if (!smb_is_open(i))
+       {
+               struct smb_sb_info *server = SMB_SERVER(i);
+               smb_lock_server(server);
+               result = smb_proc_open(server, dir);
+               smb_unlock_server(server);
+               if (result)
+               {
+                       printk("smb_open: %s/%s open failed, result=%d\n",
+                               dir->d_parent->d_name.name, dir->d_name.name,
+                               result);
+                       goto out;
                }
        }
 
+       result = -EACCES;
        if (((wish == O_RDONLY) && ((i->u.smbfs_i.access == O_RDONLY)
                                     || (i->u.smbfs_i.access == O_RDWR)))
            || ((wish == O_WRONLY) && ((i->u.smbfs_i.access == O_WRONLY)
@@ -611,7 +673,7 @@ smb_open(struct dentry *dir, int wish)
            || ((wish == O_RDWR) && (i->u.smbfs_i.access == O_RDWR)))
                result = 0;
 
-       smb_unlock_server(server);
+out:
        return result;
 }
 
@@ -625,24 +687,21 @@ static int smb_proc_close(struct smb_sb_info *server,
        DSET(server->packet, smb_vwv1, mtime);
        return smb_request_ok(server, SMBclose, 0, 0);
 }
-       
 
-int smb_close(struct dentry *dir)
+int
+smb_close(struct inode *ino)
 {
-       struct inode *ino = dir->d_inode;
-       struct smb_sb_info *server = SMB_SERVER(ino);
-       int result;
-
-       smb_lock_server(server);
+       int result = 0;
 
-       if (!smb_is_open(ino)) {
+       if (smb_is_open(ino))
+       {
+               struct smb_sb_info *server = SMB_SERVER(ino);
+               smb_lock_server(server);
+               result = smb_proc_close(server, ino->u.smbfs_i.fileid, 
+                                               ino->i_mtime);
                smb_unlock_server(server);
-               return 0;
+               ino->u.smbfs_i.open = 0;
        }
-
-       result = smb_proc_close(server, ino->u.smbfs_i.fileid, ino->i_mtime);
-       ino->u.smbfs_i.open = 0;
-       smb_unlock_server(server);
        return result;
 }
 
@@ -658,38 +717,49 @@ smb_proc_read(struct inode *ino, off_t offset, long count, char *data)
        struct smb_sb_info *server = SMB_SERVER(ino);
        __u16 returned_count, data_len;
        char *buf;
-       int error;
+       int result;
+       struct dentry * dentry;
+
+       if (!ino || !(dentry = ino->u.smbfs_i.dentry))
+       {
+               printk("smb_proc_read: no inode!\n");
+               return -EIO;
+       }
 
        smb_lock_server(server);
        smb_setup_header(server, SMBread, 5, 0);
-       buf = server->packet;
 
+       /* Achtung! Do not refer to the cached packet after the request! */
+       buf = server->packet;
        WSET(buf, smb_vwv0, ino->u.smbfs_i.fileid);
        WSET(buf, smb_vwv1, count);
        DSET(buf, smb_vwv2, offset);
        WSET(buf, smb_vwv4, 0);
 
-       if ((error = smb_request_ok(server, SMBread, 5, -1)) < 0)
-       {
-               smb_unlock_server(server);
-               return error;
-       }
-       returned_count = WVAL(buf, smb_vwv0);
+       result = smb_request_ok(server, SMBread, 5, -1);
+       if (result < 0)
+               goto out;
+#if 0
+printk("smb_proc_read: file %s/%s, result=%d, packet=%p\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, result, server->packet);
+#endif
+       returned_count = WVAL(server->packet, smb_vwv0);
 
        buf = SMB_BUF(server->packet);
        data_len = WVAL(buf, 1);
-
        memcpy(data, buf+3, data_len);
 
-       smb_unlock_server(server);
-
        if (returned_count != data_len)
        {
                printk(KERN_NOTICE "smb_proc_read: returned != data_len\n");
                printk(KERN_NOTICE "smb_proc_read: ret_c=%d, data_len=%d\n",
                       returned_count, data_len);
        }
-       return data_len;
+       result = data_len;
+
+out:
+       smb_unlock_server(server);
+       return result;
 }
 
 int
@@ -722,18 +792,17 @@ int
 smb_proc_create(struct dentry *dir, struct qstr *name,
                __u16 attr, time_t ctime)
 {
+       struct smb_sb_info *server;
        int error;
        char *p;
-       struct inode *i=dir->d_inode;
-       struct smb_sb_info *server = SMB_SERVER(i);
-       char *buf;
 
+       server = server_from_dentry(dir);
        smb_lock_server(server);
+
       retry:
-       buf = server->packet;
        p = smb_setup_header(server, SMBcreate, 3, 0);
-       WSET(buf, smb_vwv0, attr);
-       DSET(buf, smb_vwv1, utc2local(ctime));
+       WSET(server->packet, smb_vwv0, attr);
+       DSET(server->packet, smb_vwv1, utc2local(ctime));
        *p++ = 4;
        p = smb_encode_path(server, p, dir, name);
        smb_setup_bcc(server, p);
@@ -744,23 +813,25 @@ smb_proc_create(struct dentry *dir, struct qstr *name,
                {
                        goto retry;
                }
-               smb_unlock_server(server);
-               return error;
+               goto out;
        }
-       smb_proc_close(server, WVAL(buf, smb_vwv0), CURRENT_TIME);
-       smb_unlock_server(server);
+       smb_proc_close(server, WVAL(server->packet, smb_vwv0), CURRENT_TIME);
+       error = 0;
 
-       return 0;
+out:
+       smb_unlock_server(server);
+       return error;
 }
 
 int
 smb_proc_mv(struct dentry *odir, struct qstr *oname,
            struct dentry *ndir, struct qstr *nname)
 {
+       struct smb_sb_info *server;
        char *p;
-       struct smb_sb_info *server = SMB_SERVER(odir->d_inode);
        int result;
 
+       server = server_from_dentry(odir);
        smb_lock_server(server);
 
       retry:
@@ -786,10 +857,11 @@ smb_proc_mv(struct dentry *odir, struct qstr *oname,
 int
 smb_proc_mkdir(struct dentry *dir, struct qstr *name)
 {
+       struct smb_sb_info *server;
        char *p;
        int result;
-       struct smb_sb_info *server = SMB_SERVER(dir->d_inode);
 
+       server = server_from_dentry(dir);
        smb_lock_server(server);
 
       retry:
@@ -812,10 +884,11 @@ smb_proc_mkdir(struct dentry *dir, struct qstr *name)
 int
 smb_proc_rmdir(struct dentry *dir, struct qstr *name)
 {
+       struct smb_sb_info *server;
        char *p;
        int result;
-       struct smb_sb_info *server = SMB_SERVER(dir->d_inode);
 
+       server = server_from_dentry(dir);
        smb_lock_server(server);
 
       retry:
@@ -838,10 +911,11 @@ smb_proc_rmdir(struct dentry *dir, struct qstr *name)
 int
 smb_proc_unlink(struct dentry *dir, struct qstr *name)
 {
+       struct smb_sb_info *server;
        char *p;
-       struct smb_sb_info *server = SMB_SERVER(dir->d_inode);
        int result;
 
+       server = server_from_dentry(dir);
        smb_lock_server(server);
 
       retry:
@@ -907,22 +981,18 @@ smb_init_dirent(struct smb_sb_info *server, struct smb_fattr *fattr)
 static void
 smb_finish_dirent(struct smb_sb_info *server, struct smb_fattr *fattr)
 {
+       fattr->f_mode = server->m.file_mode;
        if (fattr->attr & aDIR)
        {
                fattr->f_mode = server->m.dir_mode;
                fattr->f_size = 512;
-       } else
-       {
-               fattr->f_mode = server->m.file_mode;
        }
 
+       fattr->f_blocks = 0; /* already set to zero? */
        if ((fattr->f_blksize != 0) && (fattr->f_size != 0))
        {
                fattr->f_blocks =
                    (fattr->f_size - 1) / fattr->f_blksize + 1;
-       } else
-       {
-               fattr->f_blocks = 0;
        }
        return;
 }
@@ -1007,13 +1077,13 @@ smb_proc_readdir_short(struct smb_sb_info *server, struct dentry *dir, int fpos,
        smb_lock_server(server);
 
       retry:
-       buf = server->packet;
        first = 1;
        total_count = 0;
        current_entry = entry;
 
        while (1)
        {
+               buf = server->packet;
                if (first == 1)
                {
                        p = smb_setup_header(server, SMBsearch, 2, 0);
@@ -1123,6 +1193,7 @@ smb_decode_long_dirent(struct smb_sb_info *server, char *p,
                       struct smb_dirent *entry, int level)
 {
        char *result;
+       unsigned int len;
 
        smb_init_dirent(server, &(entry->attr));
 
@@ -1130,20 +1201,24 @@ smb_decode_long_dirent(struct smb_sb_info *server, char *p,
        {
                /* We might add more levels later... */
        case 1:
-               entry->len = *(p+26);
-               strncpy(entry->name, p + 27, entry->len);
-               entry->name[entry->len] = '\0';
-               entry->attr.f_size = DVAL(p, 16);
-               entry->attr.attr = *(p+24);
-
                entry->attr.f_ctime = date_dos2unix(WVAL(p, 6), WVAL(p, 4));
                entry->attr.f_atime = date_dos2unix(WVAL(p, 10), WVAL(p, 8));
                entry->attr.f_mtime = date_dos2unix(WVAL(p, 14), WVAL(p, 12));
-               result = p + 28 + *(p+26);
+               entry->attr.f_size = DVAL(p, 16);
+               entry->attr.attr = *(p+24);
+               /*
+                * Achtung, lengths can go up to 255
+                */
+               len = *((unsigned char *) p + 26);
+               entry->len = len;
+               strncpy(entry->name, p + 27, len);
+               entry->name[len] = '\0';
+
+               result = p + 28 + len;
                break;
 
        default:
-               pr_debug("Unknown long filename format %d\n", level);
+               printk("smb_decode: Unknown long filename format %d\n", level);
                result = p + WVAL(p, 0);
        }
 
@@ -1160,6 +1235,7 @@ smb_decode_long_dirent(struct smb_sb_info *server, char *p,
        }
 
        smb_finish_dirent(server, &(entry->attr));
+
        return result;
 }
 
@@ -1173,7 +1249,7 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
 
        char *p;
        char *lastname;
-       int lastname_len;
+       unsigned lastname_len;
        int i;
        int first, entries, entries_seen;
 
@@ -1193,7 +1269,7 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
        int ff_dir_handle = 0;
        int loop_count = 0;
 
-       char param[SMB_MAXPATHLEN + 2 + 12];
+       char param[SMB_MAXPATHLEN + 2 + 12]; /* too long for the stack! */
        int mask_len;
        char *mask = &(param[12]);
 
@@ -1222,6 +1298,7 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
                {
                        printk(KERN_WARNING "smb_proc_readdir_long: "
                               "Looping in FIND_NEXT??\n");
+                       entries = -EIO;
                        break;
                }
                if (first != 0)
@@ -1268,15 +1345,23 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
                        {
                                goto retry;
                        }
-                       pr_debug("smb_proc_readdir_long: "
-                                "got error from trans2_request\n");
+#ifdef SMBFS_PARANOIA
+printk("smb_proc_readdir_long: trans2_request error=%d\n", result);
+#endif
+                       entries = result;
                        break;
                }
                if (server->rcls != 0)
-               {
-                       result = -EIO;
+               { 
+#ifdef SMBFS_PARANOIA
+printk("smb_proc_readdir_long: error, rcls=%d, err=%d\n",
+server->rcls, server->err);
+#endif
+                       /* Why isn't this considered an error? */
+                       /* entries = -EIO; */
                        break;
                }
+
                /* parse out some important return info */
                if (first != 0)
                {
@@ -1303,17 +1388,15 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
                lastname_len = 0;
                if (ff_lastname > 0)
                {
+                       ff_resume_key = 0;
+                       lastname = p + ff_lastname;
                        switch (info_level)
                        {
                        case 260:
-                               lastname = p + ff_lastname;
                                lastname_len = resp_data_len - ff_lastname;
-                               ff_resume_key = 0;
                                break;
                        case 1:
-                               lastname = p + ff_lastname + 1;
-                               lastname_len = *(p+ff_lastname);
-                               ff_resume_key = 0;
+                               lastname_len = *((unsigned char *) lastname++);
                                break;
                        }
                }
@@ -1345,11 +1428,12 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
                                entry->f_pos = entries_seen;
                                entries += 1;
                        }
-                       if (entries >= cache_size)
-                       {
-                               goto finished;
-                       }
                        entries_seen += 1;
+                       if (entries < cache_size)
+                               continue;
+
+                       /* cache is full */
+                       goto finished;
                }
 
                pr_debug("received %d entries (eos=%d resume=%d)\n",
@@ -1367,8 +1451,9 @@ int
 smb_proc_readdir(struct dentry *dir, int fpos,
                 int cache_size, struct smb_dirent *entry)
 {
-       struct smb_sb_info *server = SMB_SERVER(dir->d_inode);
+       struct smb_sb_info *server;
 
+       server = server_from_dentry(dir);
        if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
                return smb_proc_readdir_long(server, dir, fpos, cache_size,
                                             entry);
@@ -1378,18 +1463,15 @@ smb_proc_readdir(struct dentry *dir, int fpos,
 }
 
 static int
-smb_proc_getattr_core(struct dentry *dir, struct qstr *name,
-                     struct smb_fattr *attr)
+smb_proc_getattr_core(struct smb_sb_info *server, struct dentry *dir,
+                       struct qstr *name, struct smb_fattr *attr)
 {
        int result;
        char *p;
-       struct smb_sb_info *server = SMB_SERVER(dir->d_inode);
-       char *buf;
 
        smb_lock_server(server);
 
       retry:
-       buf = server->packet;
        p = smb_setup_header(server, SMBgetatr, 0, 0);
        *p++ = 4;
        p = smb_encode_path(server, p, dir, name);
@@ -1398,26 +1480,24 @@ smb_proc_getattr_core(struct dentry *dir, struct qstr *name,
        if ((result = smb_request_ok(server, SMBgetatr, 10, 0)) < 0)
        {
                if (smb_retry(server))
-               {
                        goto retry;
-               }
-               smb_unlock_server(server);
-               return result;
+               goto out;
        }
-       attr->attr = WVAL(buf, smb_vwv0);
-       attr->f_ctime = attr->f_atime =
-           attr->f_mtime = local2utc(DVAL(buf, smb_vwv1));
+       attr->attr   = WVAL(server->packet, smb_vwv0);
+       attr->f_ctime = attr->f_atime = attr->f_mtime = 
+            local2utc(DVAL(server->packet, smb_vwv1));
+       attr->f_size = DVAL(server->packet, smb_vwv3);
+       result = 0;
 
-       attr->f_size = DVAL(buf, smb_vwv3);
+out:
        smb_unlock_server(server);
-       return 0;
+       return result;
 }
 
 static int
-smb_proc_getattr_trans2(struct dentry *dir, struct qstr *name,
-                       struct smb_fattr *attr)
+smb_proc_getattr_trans2(struct smb_sb_info *server, struct dentry *dir,
+                       struct qstr *name, struct smb_fattr *attr)
 {
-       struct smb_sb_info *server = SMB_SERVER(dir->d_inode);
        char param[SMB_MAXPATHLEN + 20];
        char *p;
        int result;
@@ -1437,26 +1517,22 @@ smb_proc_getattr_trans2(struct dentry *dir, struct qstr *name,
                                    0, NULL, p - param, param,
                                    &resp_data_len, &resp_data,
                                    &resp_param_len, &resp_param);
-
        if (server->rcls != 0)
        {
-               smb_unlock_server(server);
-               return -smb_errno(server->rcls, server->err);
+               result = -smb_errno(server->rcls, server->err);
+               goto out;
        }
        if (result < 0)
        {
                if (smb_retry(server))
-               {
                        goto retry;
-               }
-               smb_unlock_server(server);
-               return result;
+               goto out;
        }
+       result = -ENOENT;
        if (resp_data_len < 22)
-       {
-               smb_unlock_server(server);
-               return -ENOENT;
-       }
+               goto out;
+
        attr->f_ctime = date_dos2unix(WVAL(resp_data, 2),
                                      WVAL(resp_data, 0));
        attr->f_atime = date_dos2unix(WVAL(resp_data, 6),
@@ -1465,24 +1541,28 @@ smb_proc_getattr_trans2(struct dentry *dir, struct qstr *name,
                                      WVAL(resp_data, 8));
        attr->f_size = DVAL(resp_data, 12);
        attr->attr = WVAL(resp_data, 20);
-       smb_unlock_server(server);
+       result = 0;
 
-       return 0;
+out:
+       smb_unlock_server(server);
+       return result;
 }
 
-int smb_proc_getattr(struct dentry *dir, struct qstr *name,
+int
+smb_proc_getattr(struct dentry *dir, struct qstr *name,
                     struct smb_fattr *fattr)
 {
-       struct smb_sb_info *server = SMB_SERVER(dir->d_inode);
-       int result = 0;
+       struct smb_sb_info *server;
+       int result = -1;
 
+       server = server_from_dentry(dir);
        smb_init_dirent(server, fattr);
 
        if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
-               result = smb_proc_getattr_trans2(dir, name, fattr);
+               result = smb_proc_getattr_trans2(server, dir, name, fattr);
 
-       if ((server->opt.protocol < SMB_PROTOCOL_LANMAN2) || (result < 0))
-               result = smb_proc_getattr_core(dir, name, fattr);
+       if (result < 0)
+               result = smb_proc_getattr_core(server, dir, name, fattr);
 
        smb_finish_dirent(server, fattr);
 
@@ -1571,12 +1651,12 @@ int
 smb_proc_setattr(struct smb_sb_info *server, struct dentry *dir,
                 struct smb_fattr *fattr)
 {
-       int result;
+       int result = -1;
 
        if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
                result = smb_proc_setattr_trans2(server, dir, fattr);
 
-       if ((server->opt.protocol < SMB_PROTOCOL_LANMAN2) || (result < 0))
+       if (result < 0)
                result = smb_proc_setattr_core(server, dir, fattr);
 
        return result;
@@ -1585,9 +1665,9 @@ smb_proc_setattr(struct smb_sb_info *server, struct dentry *dir,
 int
 smb_proc_dskattr(struct super_block *sb, struct statfs *attr)
 {
+       struct smb_sb_info *server = &(sb->u.smbfs_sb);
        int error;
        char *p;
-       struct smb_sb_info *server = &(sb->u.smbfs_sb);
 
        smb_lock_server(server);
 
@@ -1598,16 +1678,17 @@ smb_proc_dskattr(struct super_block *sb, struct statfs *attr)
        {
                if (smb_retry(server))
                        goto retry;
-
-               smb_unlock_server(server);
-               return error;
+               goto out;
        }
        p = SMB_VWV(server->packet);
        attr->f_bsize = WVAL(p, 2) * WVAL(p, 4);
        attr->f_blocks = WVAL(p, 0);
        attr->f_bavail = attr->f_bfree = WVAL(p, 6);
+       error = 0;
+
+out:
        smb_unlock_server(server);
-       return 0;
+       return error;
 }
 
 int
index 1687be10b79da13f97823f1766ed2537f310c0e4..aceca122b9e698a1d1f83552019935e4f39297c2 100644 (file)
 
 #include <asm/uaccess.h>
 
+#define SMBFS_PARANOIA 1
+/* #define SMBFS_DEBUG_VERBOSE 1 */
+
 #define _S(nr) (1<<((nr)-1))
 
 static int
-_recvfrom(struct socket *sock, unsigned char *ubuf, int size,
+_recvfrom(struct socket *socket, unsigned char *ubuf, int size,
          unsigned flags)
 {
        struct iovec iov;
@@ -43,14 +46,14 @@ _recvfrom(struct socket *sock, unsigned char *ubuf, int size,
        iov.iov_len = size;
        
        memset(&scm, 0,sizeof(scm));
-       size=sock->ops->recvmsg(sock, &msg, size, flags, &scm);
+       size=socket->ops->recvmsg(socket, &msg, size, flags, &scm);
        if(size>=0)
-               scm_recv(sock,&msg,&scm,flags);
+               scm_recv(socket,&msg,&scm,flags);
        return size;
 }
 
 static int
-_send(struct socket *sock, const void *buff, int len)
+_send(struct socket *socket, const void *buff, int len)
 {
        struct iovec iov;
        struct msghdr msg;
@@ -69,163 +72,199 @@ _send(struct socket *sock, const void *buff, int len)
 
        msg.msg_flags = 0;
 
-       err = scm_send(sock, &msg, &scm);
-        if (err < 0)
-                return err;
-       err = sock->ops->sendmsg(sock, &msg, len, &scm);
-       scm_destroy(&scm);
+       err = scm_send(socket, &msg, &scm);
+        if (err >= 0)
+       {
+               err = socket->ops->sendmsg(socket, &msg, len, &scm);
+               scm_destroy(&scm);
+       }
        return err;
 }
 
+/*
+ * N.B. What happens if we're in here when the socket closes??
+ */
 static void
 smb_data_callback(struct sock *sk, int len)
 {
-       struct socket *sock = sk->socket;
+       struct socket *socket = sk->socket;
+       unsigned char peek_buf[4];
+       int result;
+       unsigned long fs;
+
+       fs = get_fs();
+       set_fs(get_ds());
 
-       if (!sk->dead)
+       while (1)
        {
-               unsigned char peek_buf[4];
-               int result;
-               unsigned long fs;
+               if (sk->dead)
+               {
+                       printk("smb_data_callback: sock dead!\n");
+                       return;
+               }
+               result = _recvfrom(socket, (void *) peek_buf, 1,
+                                  MSG_PEEK | MSG_DONTWAIT);
+               if (result == -EAGAIN)
+                       break;
+               if (peek_buf[0] != 0x85)
+                       break;
 
-               fs = get_fs();
-               set_fs(get_ds());
+               /* got SESSION KEEP ALIVE */
+               result = _recvfrom(socket, (void *) peek_buf, 4,
+                                  MSG_DONTWAIT);
 
-               result = _recvfrom(sock, (void *) peek_buf, 1,
-                                  MSG_PEEK | MSG_DONTWAIT);
+               pr_debug("smb_data_callback: got SESSION KEEPALIVE\n");
 
-               while ((result != -EAGAIN) && (peek_buf[0] == 0x85))
-               {
-                       /* got SESSION KEEP ALIVE */
-                       result = _recvfrom(sock, (void *) peek_buf, 4,
-                                          MSG_DONTWAIT);
-
-                       pr_debug("smb_data_callback: got SESSION KEEPALIVE\n");
-
-                       if (result == -EAGAIN)
-                       {
-                               break;
-                       }
-                       result = _recvfrom(sock, (void *) peek_buf, 1,
-                                          MSG_PEEK | MSG_DONTWAIT);
-               }
-               set_fs(fs);
+               if (result == -EAGAIN)
+                       break;
+       }
+       set_fs(fs);
 
-               if (result != -EAGAIN)
-               {
-                       wake_up_interruptible(sk->sleep);
-               }
+       if (result != -EAGAIN)
+       {
+               wake_up_interruptible(sk->sleep);
        }
 }
 
-int
-smb_catch_keepalive(struct smb_sb_info *server)
+static struct socket *
+server_sock(struct smb_sb_info *server)
 {
        struct file *file;
        struct inode *inode;
-       struct socket *sock;
-       struct sock *sk;
 
-       if ((server == NULL)
-           || ((file = server->sock_file) == NULL)
-           || ((inode = file->f_dentry->d_inode) == NULL)
-           || (!S_ISSOCK(inode->i_mode)))
-       {
-               pr_debug("smb_catch_keepalive: did not get valid server!\n");
-               server->data_ready = NULL;
-               return -EINVAL;
-       }
-       sock = &(inode->u.socket_i);
+       if (server                              && 
+           (file = server->sock_file)          &&
+           (inode = file->f_dentry->d_inode)   && 
+           S_ISSOCK(inode->i_mode)             && 
+           inode->u.socket_i.type == SOCK_STREAM)
+               return &(inode->u.socket_i);
+       return NULL;
+}
 
-       if (sock->type != SOCK_STREAM)
+int
+smb_catch_keepalive(struct smb_sb_info *server)
+{
+       struct socket *socket;
+       struct sock *sk;
+       void *data_ready;
+       int error;
+
+       error = -EINVAL;
+       socket = server_sock(server);
+       if (!socket)
        {
-               pr_debug("smb_catch_keepalive: did not get SOCK_STREAM\n");
+               printk("smb_catch_keepalive: did not get valid server!\n");
                server->data_ready = NULL;
-               return -EINVAL;
+               goto out;
        }
-       sk = sock->sk;
 
+       sk = socket->sk;
        if (sk == NULL)
        {
                pr_debug("smb_catch_keepalive: sk == NULL");
                server->data_ready = NULL;
-               return -EINVAL;
+               goto out;
        }
        pr_debug("smb_catch_keepalive.: sk->d_r = %x, server->d_r = %x\n",
                 (unsigned int) (sk->data_ready),
                 (unsigned int) (server->data_ready));
 
-       if (sk->data_ready == smb_data_callback)
+       /*
+        * Install the callback atomically to avoid races ...
+        */
+       data_ready = xchg(&sk->data_ready, smb_data_callback);
+       if (data_ready != smb_data_callback)
        {
+               server->data_ready = data_ready;
+               error = 0;
+       } else
                printk(KERN_ERR "smb_catch_keepalive: already done\n");
-               return -EINVAL;
-       }
-       server->data_ready = sk->data_ready;
-       sk->data_ready = smb_data_callback;
-       return 0;
+out:
+       return error;
 }
 
 int
 smb_dont_catch_keepalive(struct smb_sb_info *server)
 {
-       struct file *file;
-       struct inode *inode;
-       struct socket *sock;
+       struct socket *socket;
        struct sock *sk;
+       void * data_ready;
+       int error;
 
-       if ((server == NULL)
-           || ((file = server->sock_file) == NULL)
-           || ((inode = file->f_dentry->d_inode) == NULL)
-           || (!S_ISSOCK(inode->i_mode)))
+       error = -EINVAL;
+       socket = server_sock(server);
+       if (!socket)
        {
-               printk("smb_dont_catch_keepalive: "
-                      "did not get valid server!\n");
-               return -EINVAL;
-       }
-       sock = &(inode->u.socket_i);
-
-       if (sock->type != SOCK_STREAM)
-       {
-               printk("smb_dont_catch_keepalive: did not get SOCK_STREAM\n");
-               return -EINVAL;
+               printk("smb_dont_catch_keepalive: did not get valid server!\n");
+               goto out;
        }
-       sk = sock->sk;
 
+       sk = socket->sk;
        if (sk == NULL)
        {
                printk("smb_dont_catch_keepalive: sk == NULL");
-               return -EINVAL;
+               goto out;
        }
+
+       /* Is this really an error?? */
        if (server->data_ready == NULL)
        {
                printk("smb_dont_catch_keepalive: "
                       "server->data_ready == NULL\n");
-               return -EINVAL;
-       }
-       if (sk->data_ready != smb_data_callback)
-       {
-               printk("smb_dont_catch_keepalive: "
-                      "sk->data_callback != smb_data_callback\n");
-               return -EINVAL;
+               goto out;
        }
        pr_debug("smb_dont_catch_keepalive: sk->d_r = %x, server->d_r = %x\n",
                 (unsigned int) (sk->data_ready),
                 (unsigned int) (server->data_ready));
 
-       sk->data_ready = server->data_ready;
+       /*
+        * Restore the original callback atomically to avoid races ...
+        */
+       data_ready = xchg(&sk->data_ready, server->data_ready);
        server->data_ready = NULL;
-       return 0;
+       if (data_ready != smb_data_callback)
+       {
+               printk("smb_dont_catch_keepalive: "
+                      "sk->data_callback != smb_data_callback\n");
+       }
+       error = 0;
+out:
+       return error;
+}
+
+/*
+ * Called with the server locked.
+ */
+void
+smb_close_socket(struct smb_sb_info *server)
+{
+       struct file * file = server->sock_file;
+
+       if (file)
+       {
+               struct socket * socket = server_sock(server);
+
+               printk("smb_close_socket: closing socket %p\n", socket);
+               /*
+                * We need a way to check for tasks running the callback!
+                */
+               if (socket->sk->data_ready == smb_data_callback)
+                       printk("smb_close_socket: still catching keepalives!\n");
+
+               server->sock_file = NULL;
+               close_fp(file);
+       }
 }
 
 static int
-smb_send_raw(struct socket *sock, unsigned char *source, int length)
+smb_send_raw(struct socket *socket, unsigned char *source, int length)
 {
        int result;
        int already_sent = 0;
 
        while (already_sent < length)
        {
-               result = _send(sock,
+               result = _send(socket,
                               (void *) (source + already_sent),
                               length - already_sent);
 
@@ -245,14 +284,14 @@ smb_send_raw(struct socket *sock, unsigned char *source, int length)
 }
 
 static int
-smb_receive_raw(struct socket *sock, unsigned char *target, int length)
+smb_receive_raw(struct socket *socket, unsigned char *target, int length)
 {
        int result;
        int already_read = 0;
 
        while (already_read < length)
        {
-               result = _recvfrom(sock,
+               result = _recvfrom(socket,
                                   (void *) (target + already_read),
                                   length - already_read, 0);
 
@@ -272,7 +311,7 @@ smb_receive_raw(struct socket *sock, unsigned char *target, int length)
 }
 
 static int
-smb_get_length(struct socket *sock, unsigned char *header)
+smb_get_length(struct socket *socket, unsigned char *header)
 {
        int result;
        unsigned char peek_buf[4];
@@ -281,7 +320,7 @@ smb_get_length(struct socket *sock, unsigned char *header)
       re_recv:
        fs = get_fs();
        set_fs(get_ds());
-       result = smb_receive_raw(sock, peek_buf, 4);
+       result = smb_receive_raw(socket, peek_buf, 4);
        set_fs(fs);
 
        if (result < 0)
@@ -312,21 +351,6 @@ smb_get_length(struct socket *sock, unsigned char *header)
        return smb_len(peek_buf);
 }
 
-static struct socket *
-server_sock(struct smb_sb_info *server)
-{
-       struct file *file;
-       struct inode *inode;
-
-       if (server == NULL)
-               return NULL;
-       if ((file = server->sock_file) == NULL)
-               return NULL;
-       if ((inode = file->f_dentry->d_inode) == NULL)
-               return NULL;
-       return &(inode->u.socket_i);
-}
-
 /*
  * smb_receive
  * fs points to the correct segment
@@ -334,12 +358,12 @@ server_sock(struct smb_sb_info *server)
 static int
 smb_receive(struct smb_sb_info *server)
 {
-       struct socket *sock = server_sock(server);
+       struct socket *socket = server_sock(server);
        int len;
        int result;
        unsigned char peek_buf[4];
 
-       len = smb_get_length(sock, peek_buf);
+       len = smb_get_length(socket, peek_buf);
 
        if (len < 0)
        {
@@ -352,6 +376,7 @@ smb_receive(struct smb_sb_info *server)
                pr_debug("smb_receive: Increase packet size from %d to %d\n",
                        server->packet_size, len + 4);
                smb_vfree(server->packet);
+               server->packet = 0;
                server->packet_size = 0;
                server->packet = smb_vmalloc(len + 4);
                if (server->packet == NULL)
@@ -361,7 +386,7 @@ smb_receive(struct smb_sb_info *server)
                server->packet_size = len + 4;
        }
        memcpy(server->packet, peek_buf, 4);
-       result = smb_receive_raw(sock, server->packet + 4, len);
+       result = smb_receive_raw(socket, server->packet + 4, len);
 
        if (result < 0)
        {
@@ -371,11 +396,10 @@ smb_receive(struct smb_sb_info *server)
        server->rcls = *(server->packet+9);
        server->err = WVAL(server->packet, 11);
 
-       if (server->rcls != 0)
-       {
-               pr_debug("smb_receive: rcls=%d, err=%d\n",
-                        server->rcls, server->err);
-       }
+#ifdef SMBFS_DEBUG_VERBOSE
+if (server->rcls != 0)
+printk("smb_receive: rcls=%d, err=%d\n", server->rcls, server->err);
+#endif
        return result;
 }
 
@@ -469,6 +493,13 @@ smb_receive_trans2(struct smb_sb_info *server,
                total_data = WVAL(inbuf, smb_tdrcnt);
                total_param = WVAL(inbuf, smb_tprcnt);
 
+#ifdef SMBFS_PARANOIA
+if ((data_len >= total_data || param_len >= total_param) &&
+   !(data_len >= total_data && param_len >= total_param))
+printk("smb_receive_trans2: dlen=%d, tdata=%d, plen=%d, tlen=%d\n",
+data_len, total_data, param_len, total_param);
+#endif
+               /* shouldn't this be an OR test? don't want to overrun */
                if ((data_len >= total_data) && (param_len >= total_param))
                {
                        break;
@@ -477,11 +508,9 @@ smb_receive_trans2(struct smb_sb_info *server,
                {
                        goto fail;
                }
+               result = -EIO;
                if (server->rcls != 0)
-               {
-                       result = -EIO;
                        goto fail;
-               }
        }
        *ldata = data_len;
        *lparam = param_len;
@@ -496,32 +525,33 @@ smb_receive_trans2(struct smb_sb_info *server,
        return result;
 }
 
+/*
+ * Called with the server locked
+ */
 int
 smb_request(struct smb_sb_info *server)
 {
        unsigned long old_mask;
        unsigned long fs;
        int len, result;
+       unsigned char *buffer;
 
-       unsigned char *buffer = (server == NULL) ? NULL : server->packet;
+       result = -EBADF;
+       if (!server) /* this can't happen */
+               goto bad_no_server;
+               
+       buffer = server->packet;
+       if (!buffer)
+               goto bad_no_packet;
 
-       if (buffer == NULL)
-       {
-               pr_debug("smb_request: Bad server!\n");
-               return -EBADF;
-       }
+       result = -EIO;
        if (server->state != CONN_VALID)
-       {
-               return -EIO;
-       }
+               goto bad_no_conn;
+
        if ((result = smb_dont_catch_keepalive(server)) != 0)
-       {
-               server->state = CONN_INVALID;
-               smb_invalidate_inodes(server);
-               return result;
-       }
-       len = smb_len(buffer) + 4;
+               goto bad_conn;
 
+       len = smb_len(buffer) + 4;
        pr_debug("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]);
 
        old_mask = current->blocked;
@@ -544,17 +574,31 @@ smb_request(struct smb_sb_info *server)
                int result2 = smb_catch_keepalive(server);
                if (result2 < 0)
                {
+                       printk("smb_request: catch keepalive failed\n");
                        result = result2;
                }
        }
        if (result < 0)
-       {
-               server->state = CONN_INVALID;
-               smb_invalidate_inodes(server);
-       }
-       pr_debug("smb_request: result = %d\n", result);
+               goto bad_conn;
 
+out:
+       pr_debug("smb_request: result = %d\n", result);
        return result;
+       
+bad_conn:
+       printk("smb_request: result %d, setting invalid\n", result);
+       server->state = CONN_INVALID;
+       smb_invalidate_inodes(server);
+       goto out;               
+bad_no_server:
+       printk("smb_request: no server!\n");
+       goto out;
+bad_no_packet:
+       printk("smb_request: no packet!\n");
+       goto out;
+bad_no_conn:
+       printk("smb_request: connection %d not valid!\n", server->state);
+       goto out;
 }
 
 #define ROUND_UP(x) (((x)+3) & ~3)
@@ -629,11 +673,11 @@ smb_send_trans2(struct smb_sb_info *server, __u16 trans2_command,
        iov[3].iov_len = ldata;
 
        err = scm_send(sock, &msg, &scm);
-        if (err < 0)
-                return err;
-       
-       err = sock->ops->sendmsg(sock, &msg, packet_length, &scm);
-       scm_destroy(&scm);
+        if (err >= 0)
+       {
+               err = sock->ops->sendmsg(sock, &msg, packet_length, &scm);
+               scm_destroy(&scm);
+       }
        return err;
 }
 
@@ -655,16 +699,19 @@ smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,
        pr_debug("smb_trans2_request: com=%d, ld=%d, lp=%d\n",
                 trans2_command, ldata, lparam);
 
+       /*
+        * These are initialized in smb_request_ok, but not here??
+        */
+       server->rcls = 0;
+       server->err = 0;
+
+       result = -EIO;
        if (server->state != CONN_VALID)
-       {
-               return -EIO;
-       }
+               goto out;
+
        if ((result = smb_dont_catch_keepalive(server)) != 0)
-       {
-               server->state = CONN_INVALID;
-               smb_invalidate_inodes(server);
-               return result;
-       }
+               goto bad_conn;
+
        old_mask = current->blocked;
        current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
        fs = get_fs();
@@ -691,11 +738,15 @@ smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,
                }
        }
        if (result < 0)
-       {
-               server->state = CONN_INVALID;
-               smb_invalidate_inodes(server);
-       }
+               goto bad_conn;
        pr_debug("smb_trans2_request: result = %d\n", result);
 
+out:
        return result;
+
+bad_conn:
+       printk("smb_trans2_request: connection bad, setting invalid\n");
+       server->state = CONN_INVALID;
+       smb_invalidate_inodes(server);
+       goto out;
 }
index 8238ce62376d95fc84690ac46b605b786d5f0909..ebdf22bfcdd0308db8554b311b5efaa4e7f78d02 100644 (file)
@@ -50,6 +50,7 @@ struct dentry {
        struct qstr d_name;
        unsigned long d_time;           /* used by d_revalidate */
        struct dentry_operations  *d_op;
+       struct super_block * d_sb;      /* The root of the dentry tree */
 };
 
 struct dentry_operations {
index c7c005ec3216ec77d0f253869113eac4072ac9e5..4fd14cf7aadfae44518ce05318240f8fbe2cd37d 100644 (file)
@@ -93,7 +93,7 @@ extern int max_files, nr_files;
 /*
  * Flags that can be altered by MS_REMOUNT
  */
-#define MS_RMT_MASK (MS_RDONLY|MS_MANDLOCK|MS_NOATIME)
+#define MS_RMT_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS|MS_MANDLOCK|MS_NOATIME)
 
 /*
  * Magic mount flag number. Has to be or-ed to the flag values.
@@ -367,6 +367,11 @@ static inline void mark_inode_dirty(struct inode *inode)
                __mark_inode_dirty(inode);
 }
 
+struct fown_struct {
+       int pid;                /* pid or -pgrp where SIGIO should be sent */
+       uid_t uid, euid;        /* uid/euid of process setting the owner */
+};
+
 struct file {
        struct file             *f_next, **f_pprev;
        struct dentry           *f_dentry;
@@ -375,9 +380,7 @@ struct file {
        loff_t                  f_pos;
        unsigned short          f_count, f_flags;
        unsigned long           f_reada, f_ramax, f_raend, f_ralen, f_rawin;
-
-       /* pid or -pgrp where SIGIO should be sent */
-       int                     f_owner;
+       struct fown_struct      f_owner;
 
        unsigned long           f_version;
 
index 8c75cc3c5feac1beffac2d6c634b83442a6e9e1c..a725bbe367e8a774ebabafae76e2270c86a7e110 100644 (file)
@@ -121,7 +121,7 @@ extern void minix_read_inode(struct inode *);
 extern void minix_write_inode(struct inode *);
 extern int minix_statfs(struct super_block *, struct statfs *, int);
 extern int minix_sync_inode(struct inode *);
-extern int minix_sync_file(struct inode *, struct file *);
+extern int minix_sync_file(struct file *, struct dentry *);
 
 extern struct inode_operations minix_file_inode_operations;
 extern struct inode_operations minix_dir_inode_operations;
index bcaba246f93d1fee4f23c5ab78c0f5f8426dab16..e3e9ea98ab9df7bb55b3a5caa224df852345c372 100644 (file)
@@ -77,7 +77,7 @@ void smb_free_all_inodes(struct smb_sb_info *server);
 void smb_init_root(struct smb_sb_info *server);
 int  smb_stat_root(struct smb_sb_info *server);
 void smb_init_dir_cache(void);
-void smb_invalid_dir_cache(unsigned long ino);
+void smb_invalid_dir_cache(struct inode *);
 void smb_free_dir_cache(void);
 
 /* linux/fs/smbfs/ioctl.c */
@@ -104,7 +104,7 @@ __u8 *smb_setup_header(struct smb_sb_info *server, __u8 command,
                       __u16 wct, __u16 bcc);
 int smb_offerconn(struct smb_sb_info *server);
 int smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt);
-int smb_close(struct dentry *);
+int smb_close(struct inode *);
 int smb_open(struct dentry *, int);
 static inline int
 smb_is_open(struct inode *i)
index 743e3954a62c68a41b28f58d4b68ed4e849735e2..73ea69a89986a5f009774f2268380cc90451f600 100644 (file)
@@ -22,6 +22,7 @@ struct smb_inode_info {
         * (open == generation).
         */
         unsigned int open;
+       void * dentry;          /* The dentry we were opened with */
        __u16 fileid;           /* What id to handle a file with? */
        __u16 attr;             /* Attribute fields, DOS value */
 
index 176e88c862b06c58507f3e325d2015a5285e1a61..a1443646b8b471a8fb483d7ae9282df764196a7e 100644 (file)
@@ -39,6 +39,7 @@
 #define ERRbadshare 32          /* Share mode on file conflict with open mode */
 #define ERRlock 33              /* Lock request conflicts with existing lock */
 #define ERRfilexists 80         /* File in operation already exists */
+#define ERRundocumented1 123    /* Invalid name?? e.g. .tmp* */
 #define ERRbadpipe 230          /* Named pipe invalid */
 #define ERRpipebusy 231         /* All instances of pipe are busy */
 #define ERRpipeclosing 232      /* named pipe close in progress */
index 53ead0c99c2ee391c4f9c9425cdec8fa155767b6..93e4400ce3cc888e6bf099347d1390a09d0bb85c 100644 (file)
@@ -398,8 +398,8 @@ extern void sysv_write_inode(struct inode *);
 extern void sysv_put_inode(struct inode *);
 extern int sysv_statfs(struct super_block *, struct statfs *, int);
 extern int sysv_sync_inode(struct inode *);
-extern int sysv_sync_file(struct inode *, struct file *);
-extern int sysv_mmap(struct inode *, struct file *, struct vm_area_struct *);
+extern int sysv_sync_file(struct file *, struct dentry *);
+extern int sysv_mmap(struct file *, struct vm_area_struct *);
 
 extern struct inode_operations sysv_file_inode_operations;
 extern struct inode_operations sysv_file_inode_operations_with_bmap;
index d5c90133decd67b035c81dfba23f58839173afde..76c38483422394d04d5a97aa9f7fe28e68889296 100644 (file)
@@ -132,8 +132,9 @@ static void release(struct task_struct * p)
        if (p != current) {
 #ifdef __SMP__
                /* FIXME! Cheesy, but kills the window... -DaveM */
-               while (p->has_cpu)
+               do {
                        barrier();
+               } while (p->has_cpu);
                spin_unlock_wait(&scheduler_lock);
 #endif
                charge_uid(p, -1);
index 0e75643437b9aae07b9466e461adc11f2cd6bf8a..24a8943ad78f6910e02a24b8c3a2d27fe5f8663a 100644 (file)
@@ -1213,11 +1213,16 @@ static int msync_interval(struct vm_area_struct * vma,
        if (vma->vm_ops->sync) {
                int error;
                error = vma->vm_ops->sync(vma, start, end-start, flags);
-               if (error)
-                       return error;
-               if (flags & MS_SYNC)
-                       return file_fsync(NULL,vma->vm_dentry);
-               return 0;
+               if (!error && (flags & MS_SYNC)) {
+                       struct dentry * dentry = vma->vm_dentry;
+                       if (dentry) {
+                               struct inode * inode = dentry->d_inode;
+                               down(&inode->i_sem);
+                               error = file_fsync(NULL,dentry);
+                               up(&inode->i_sem);
+                       }
+               }
+               return error;
        }
        return 0;
 }
index 307537e0c21ec620c80fc41176c7c7ea572e7455..472f648117dd6ec5fd67ca721d71f61fde85f550 100644 (file)
@@ -797,10 +797,11 @@ static struct arp_table * arp_alloc(int how)
 
        entry = (struct arp_table *)neigh_alloc(sizeof(struct arp_table),
                                                &arp_neigh_ops);
-       atomic_set(&entry->u.neigh.refcnt, 1);
 
        if (entry != NULL)
        {
+               atomic_set(&entry->u.neigh.refcnt, 1);
+
                if (how)
                        atomic_inc(&arp_size);
 
index dc1b90ff79e2eebf3f2d0a1623d0074435a544aa..8e60f1a509c974dc2d567f816566118d9321b6a8 100644 (file)
@@ -605,11 +605,14 @@ static int tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb)
        memcpy(skb_put(skb, size2), ((char *) th2) + (th2->doff << 2), size2);
        
        /* Update sizes on original skb, both TCP and IP. */
-       skb->end_seq += size2;
+       skb->end_seq += buff->end_seq - buff->seq;
        if (th2->urg) {
                th1->urg = 1;
                th1->urg_ptr = th2->urg_ptr + size1;
        }
+       if (th2->fin) {
+               th1->fin = 1;
+       }
 
        /* ... and off you go. */
        kfree_skb(buff, FREE_WRITE);
index bcdb13610cf607c0393e1e012d9c2bb2e8495058..971163963792db65a95074756cc648b0c597889c 100644 (file)
@@ -352,7 +352,7 @@ call_allocate(struct rpc_task *task)
        if ((task->tk_buffer = rpc_malloc(task, bufsiz)) != NULL)
                return;
 
-       if (!signalled()) {
+       if (1 || !signalled()) {
                xprt_release(task);
                task->tk_action = call_reserve;
                rpc_delay(task, HZ);
index 960093cadee4bd53f7ee12bfa47238239c565d32..fb02640f9990e400c28576bb824eb1b974b3d192 100644 (file)
@@ -390,7 +390,7 @@ __rpc_execute(struct rpc_task *task)
                        dprintk("RPC: %4d sync task going to sleep\n",
                                                        task->tk_pid);
                        current->timeout = 0;
-                       interruptible_sleep_on(&task->tk_wait);
+                       sleep_on(&task->tk_wait);
 
                        /* When the task received a signal, remove from
                         * any queues etc, and make runnable again. */
@@ -408,7 +408,7 @@ __rpc_execute(struct rpc_task *task)
                 * clean up after sleeping on some queue, we don't
                 * break the loop here, but go around once more.
                 */
-               if (!RPC_IS_ASYNC(task) && signalled()) {
+               if (0 && !RPC_IS_ASYNC(task) && signalled()) {
                        dprintk("RPC: %4d got signal (map %08lx)\n",
                                task->tk_pid,
                                current->signal & ~current->blocked);
index 62d2d7b40a60c3a282e9233af63279f6cc5c2008..87a5ed82efcb6449d56c093fb7817d26e066996d 100644 (file)
@@ -750,7 +750,7 @@ again:
                rqstp->rq_wait = NULL;
                svc_serv_enqueue(serv, rqstp);
 
-               current->state = TASK_INTERRUPTIBLE;
+               current->state = TASK_UNINTERRUPTIBLE;
                add_wait_queue(&rqstp->rq_wait, &wait);
                enable_bh(NET_BH);
                schedule();
index dc4fd0515073f0da7c02cf7597bc800d83b79dbf..0372500ee9eae52dd5a1e7c1aace9643c35acce5 100644 (file)
@@ -1073,6 +1073,7 @@ xprt_release(struct rpc_task *task)
 
        if (!(req = task->tk_rqstp))
                return;
+       task->tk_rqstp = NULL;
        memset(req, 0, sizeof(*req));   /* mark unused */
 
        dprintk("RPC: %4d release request %p\n", task->tk_pid, req);