diff options
135 files changed, 4295 insertions, 2543 deletions
@@ -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, MD 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, NM 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 diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index 86a2391ea..c1c171f2b 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX @@ -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 diff --git a/Documentation/Changes b/Documentation/Changes index 8cabe2d38..b00bd197d 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -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 diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 458f9b0ed..78525c4e0 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -1434,13 +1434,9 @@ CONFIG_ATALK machine on the Internet that has a program like lynx or netscape). EtherTalk is the name used for appletalk over ethernet and the cheaper and slower LocalTalk is appletalk over a proprietary - apple network using serial links. Ethertalk is fully supported by - Linux, however the localtalk drivers are not yet ready to ship. The - kernel however supports localtalk and when such drivers become - available all you will need to do is download and install the - localtalk driver in order to join a Localtalk network. The - NET-2-HOWTO, available via ftp (user: anonymous) in - sunsite.unc.edu:/pub/Linux/docs/HOWTO contains valuable information + apple network using serial links. Ethertalk and Localtalk is fully + supported by Linux. The NET-2-HOWTO, available via ftp (user: anonymous) + in sunsite.unc.edu:/pub/Linux/docs/HOWTO contains valuable information as well. This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called appletalk.o. If you want to compile @@ -1461,8 +1457,6 @@ CONFIG_LTPC If you are in doubt, this card is the one with the 65C02 chip on it. You also need version 1.3.3 or later of the netatalk package. This driver is experimental, which means that it may not work. - In particular the module support is not yet working for the 2.1.xx - kernels, so choose Y or N, but not M for now. See README.ltpc in the drivers/net directory, and the web site http://www.math.unm.edu/~bradford/ltpc.html @@ -1471,10 +1465,8 @@ CONFIG_COPS This allows you to use COPS AppleTalk cards to connect to LocalTalk networks. You also need version 1.3.3 or later of the netatalk package. This driver is experimental, which means that it may not - work. In particular the module support is not yet working for the - 2.1.xx kernels, so choose Y or N, but not M for now. This driver - will only work if you choose "Appletalk DDP" networking support, - above. + work. This driver will only work if you choose "Appletalk DDP" + networking support, above. Please read the file Documentation/networking/README.cops. See the web site http://www.math.unm.edu/~bradford/ltpc.html for localtalk IP tools. @@ -1483,7 +1475,7 @@ Dayna firmware support CONFIG_COPS_DAYNA Support COPS compatible cards with Dayna style firmware (Dayna DL2000/ Daynatalk/PC (half length), COPS LT-95, Farallon PhoneNET PC - III). + III, Farallon PhoneNET PC II). Tangent firmware support CONFIG_COPS_TANGENT diff --git a/Documentation/devices.tex b/Documentation/devices.tex index f9aa0294d..37bdfae0b 100644 --- a/Documentation/devices.tex +++ b/Documentation/devices.tex @@ -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} diff --git a/Documentation/devices.txt b/Documentation/devices.txt index c9697e262..4c390293b 100644 --- a/Documentation/devices.txt +++ b/Documentation/devices.txt @@ -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 diff --git a/Documentation/parport.txt b/Documentation/parport.txt index 17a659e55..aa9f3ca45 100644 --- a/Documentation/parport.txt +++ b/Documentation/parport.txt @@ -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 diff --git a/Documentation/stallion.txt b/Documentation/stallion.txt index e838de545..73d31f7bd 100644 --- a/Documentation/stallion.txt +++ b/Documentation/stallion.txt @@ -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 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 55 +SUBLEVEL = 56 ARCH = mips diff --git a/arch/alpha/defconfig b/arch/alpha/defconfig index 22adc7f62..9f8cde775 100644 --- a/arch/alpha/defconfig +++ b/arch/alpha/defconfig @@ -42,6 +42,7 @@ CONFIG_SYSVIPC=y CONFIG_SYSCTL=y CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set CONFIG_BINFMT_EM86=y # CONFIG_PARPORT is not set @@ -141,7 +142,6 @@ CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_NCR53C8XX is not set -# CONFIG_SCSI_PPA is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_QLOGIC_FAS is not set CONFIG_SCSI_QLOGIC_ISP=y @@ -150,8 +150,6 @@ CONFIG_SCSI_QLOGIC_ISP=y # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_ULTRASTOR is not set -# CONFIG_SCSI_MESH is not set -# CONFIG_SCSI_MAC53C94 is not set # # Network device support @@ -164,6 +162,7 @@ CONFIG_NET_ETHERNET=y # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set # CONFIG_NET_ISA is not set CONFIG_NET_EISA=y # CONFIG_PCNET32 is not set @@ -176,7 +175,6 @@ CONFIG_DE4X5=y # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set # CONFIG_DLCI is not set -# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_NET_RADIO is not set # CONFIG_SLIP is not set diff --git a/arch/alpha/kernel/bios32.c b/arch/alpha/kernel/bios32.c index 385fc9494..851d33be7 100644 --- a/arch/alpha/kernel/bios32.c +++ b/arch/alpha/kernel/bios32.c @@ -1182,32 +1182,6 @@ unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end) } -const char *pcibios_strerror (int error) -{ - static char buf[80]; - - switch (error) { - case PCIBIOS_SUCCESSFUL: - return "SUCCESSFUL"; - - case PCIBIOS_FUNC_NOT_SUPPORTED: - return "FUNC_NOT_SUPPORTED"; - - case PCIBIOS_BAD_VENDOR_ID: - return "SUCCESSFUL"; - - case PCIBIOS_DEVICE_NOT_FOUND: - return "DEVICE_NOT_FOUND"; - - case PCIBIOS_BAD_REGISTER_NUMBER: - return "BAD_REGISTER_NUMBER"; - - default: - sprintf (buf, "UNKNOWN RETURN 0x%x", error); - return buf; - } -} - asmlinkage int sys_pciconfig_read( unsigned long bus, unsigned long dfn, diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index f725e2aba..a736704a0 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -135,8 +135,6 @@ asmlinkage int osf_getdirentries(unsigned int fd, struct osf_dirent *dirent, { int error; struct file *file; - struct dentry *dentry; - struct inode *inode; struct osf_dirent_callback buf; error = -EBADF; @@ -147,14 +145,6 @@ asmlinkage int osf_getdirentries(unsigned int fd, struct osf_dirent *dirent, if (!file) goto out; - dentry = file->f_dentry; - if (!dentry) - goto out; - - inode = dentry->d_inode; - if (!inode) - goto out; - buf.dirent = dirent; buf.basep = basep; buf.count = count; @@ -164,7 +154,7 @@ asmlinkage int osf_getdirentries(unsigned int fd, struct osf_dirent *dirent, if (!file->f_op || !file->f_op->readdir) goto out; - error = file->f_op->readdir(inode, file, &buf, osf_filldir); + error = file->f_op->readdir(file, &buf, osf_filldir); if (error < 0) goto out; diff --git a/arch/i386/defconfig b/arch/i386/defconfig index 93f300de7..d4118f63f 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -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 diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index d4800f987..590b69c38 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -257,7 +257,8 @@ static const char * k5model(unsigned int nr) { static const char *model[] = { "SSA5 (PR-75, PR-90, PR-100)", "5k86 (PR-120, PR-133)", - "5k86 (PR-166)", "5k86 (PR-200)", "", "", "K6" + "5k86 (PR-166)", "5k86 (PR-200)", "", "", + "K6(PR-133..PR-166)","K6(PR-133..PR-200)" }; if (nr < sizeof(model)/sizeof(char *)) return model[nr]; diff --git a/drivers/block/README.fd b/drivers/block/README.fd index 3ceb16c0b..d05120c59 100644 --- a/drivers/block/README.fd +++ b/drivers/block/README.fd @@ -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: ================================================== diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index 7a08808f2..77add0b3a 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -1981,7 +1981,7 @@ static int floppy_release( struct inode * inode, struct file * filp ) if (!filp || (filp->f_mode & (2 | OPEN_WRITE_BIT))) /* if the file is mounted OR (writable now AND writable at open time) Linus: Does this cover all cases? */ - block_fsync (inode, filp); + block_fsync (filp, filp->f_dentry); if (fd_ref[drive] < 0) fd_ref[drive] = 0; diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 04ea60ff8..7af5aeee1 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3502,7 +3502,7 @@ static int floppy_release(struct inode * inode, struct file * filp) if (!filp || (filp->f_mode & (2 | OPEN_WRITE_BIT))) /* if the file is mounted OR (writable now AND writable at * open time) Linus: Does this cover all cases? */ - block_fsync(inode,filp); + block_fsync(filp, filp->f_dentry); if (UDRS->fd_ref < 0) UDRS->fd_ref=0; @@ -3865,6 +3865,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 }, diff --git a/drivers/block/ide-probe.c b/drivers/block/ide-probe.c index 25b3d54fa..ddaf1b0c6 100644 --- a/drivers/block/ide-probe.c +++ b/drivers/block/ide-probe.c @@ -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 */ diff --git a/drivers/block/ide.h b/drivers/block/ide.h index ecfdc12ea..eb3f54a55 100644 --- a/drivers/block/ide.h +++ b/drivers/block/ide.h @@ -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 */ diff --git a/drivers/block/rd.c b/drivers/block/rd.c index b8239df9b..759dbbca8 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -360,7 +360,7 @@ identify_ramdisk_image(kdev_t device, struct file *fp, int start_block)) * Read block 0 to test for gzipped kernel */ if (fp->f_op->llseek) - fp->f_op->llseek(fp->f_dentry->d_inode, fp, start_block * BLOCK_SIZE, 0); + fp->f_op->llseek(fp, start_block * BLOCK_SIZE, 0); fp->f_pos = start_block * BLOCK_SIZE; fp->f_op->read(fp->f_dentry->d_inode, fp, buf, size); @@ -390,8 +390,7 @@ identify_ramdisk_image(kdev_t device, struct file *fp, int start_block)) * Read block 1 to test for minix and ext2 superblock */ if (fp->f_op->llseek) - fp->f_op->llseek(fp->f_dentry->d_inode, fp, - (start_block+1) * BLOCK_SIZE, 0); + fp->f_op->llseek(fp, (start_block+1) * BLOCK_SIZE, 0); fp->f_pos = (start_block+1) * BLOCK_SIZE; fp->f_op->read(fp->f_dentry->d_inode, fp, buf, size); @@ -421,7 +420,7 @@ identify_ramdisk_image(kdev_t device, struct file *fp, int start_block)) done: if (fp->f_op->llseek) - fp->f_op->llseek(fp->f_dentry->d_inode, fp, start_block * BLOCK_SIZE, 0); + fp->f_op->llseek(fp, start_block * BLOCK_SIZE, 0); fp->f_pos = start_block * BLOCK_SIZE; if ((nblocks > 0) && blk_size[MAJOR(device)]) { diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index 4dc442673..12be2e362 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -842,7 +842,7 @@ static int floppy_release(struct inode *inode, struct file *filp) return -ENXIO; fs = &floppy_states[0]; if (filp == 0 || (filp->f_mode & (2 | OPEN_WRITE_BIT))) - block_fsync(inode, filp); + block_fsync(filp, filp->f_dentry); sw = fs->swim3; if (fs->ref_count > 0 && --fs->ref_count == 0) { swim3_action(fs, MOTOR_OFF); diff --git a/drivers/char/amigamouse.c b/drivers/char/amigamouse.c index 602695c39..6977d2398 100644 --- a/drivers/char/amigamouse.c +++ b/drivers/char/amigamouse.c @@ -159,11 +159,10 @@ static void mouse_interrupt(int irq, void *dummy, struct pt_regs *fp) MSE_INT_ON(); } -static int fasync_mouse(struct inode *inode, struct file *filp, int on) +static int fasync_mouse(struct file *filp, int on) { int retval; - - retval = fasync_helper(inode, filp, on, &mouse.fasyncptr); + retval = fasync_helper(filp, on, &mouse.fasyncptr); if (retval < 0) return retval; return 0; @@ -175,7 +174,7 @@ static int fasync_mouse(struct inode *inode, struct file *filp, int on) static int release_mouse(struct inode * inode, struct file * file) { - fasync_mouse(inode, file, 0); + fasync_mouse(file, 0); if (--mouse.active) return 0; free_irq(IRQ_AMIGA_VERTB, mouse_interrupt); diff --git a/drivers/char/apm_bios.c b/drivers/char/apm_bios.c index 67ec582e4..565600738 100644 --- a/drivers/char/apm_bios.c +++ b/drivers/char/apm_bios.c @@ -13,7 +13,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * $Id: apm_bios.c,v 1.1.1.1 1997/06/01 03:17:29 ralf Exp $ + * $Id: apm_bios.c,v 1.2 1997/09/12 01:31:41 ralf Exp $ * * October 1995, Rik Faith (faith@cs.unc.edu): * Minor enhancements and updates (to the patch set) for 1.3.x @@ -958,7 +958,7 @@ static int do_open(struct inode * inode, struct file * filp) as = (struct apm_bios_struct *)kmalloc(sizeof(*as), GFP_KERNEL); if (as == NULL) { - printk(KERN_ERR "apm_bios: cannot allocate struct of size %d bytes", + printk(KERN_ER "apm_bios: cannot allocate struct of size %d bytes", sizeof(*as)); return -ENOMEM; } diff --git a/drivers/char/atarimouse.c b/drivers/char/atarimouse.c index 950cb1546..2641c9834 100644 --- a/drivers/char/atarimouse.c +++ b/drivers/char/atarimouse.c @@ -54,11 +54,10 @@ static void atari_mouse_interrupt(char *buf) /* ikbd_mouse_rel_pos(); */ } -static int fasync_mouse(struct inode *inode, struct file *filp, int on) +static int fasync_mouse(struct file *filp, int on) { int retval; - - retval = fasync_helper(inode, filp, on, &mouse.fasyncptr); + retval = fasync_helper(filp, on, &mouse.fasyncptr); if (retval < 0) return retval; return 0; @@ -66,7 +65,7 @@ static int fasync_mouse(struct inode *inode, struct file *filp, int on) static int release_mouse(struct inode *inode, struct file *file) { - fasync_mouse(inode, file, 0); + fasync_mouse(file, 0); if (--mouse.active) return 0; ikbd_mouse_disable(); diff --git a/drivers/char/atixlmouse.c b/drivers/char/atixlmouse.c index c8a730a35..7ffee43bc 100644 --- a/drivers/char/atixlmouse.c +++ b/drivers/char/atixlmouse.c @@ -95,11 +95,10 @@ void mouse_interrupt(int irq, void *dev_id, struct pt_regs * regs) ATIXL_MSE_ENABLE_UPDATE(); } -static int fasync_mouse(struct inode *inode, struct file *filp, int on) +static int fasync_mouse(struct file *filp, int on) { int retval; - - retval = fasync_helper(inode, filp, on, &mouse.fasync); + retval = fasync_helper(filp, on, &mouse.fasync); if (retval < 0) return retval; return 0; @@ -107,7 +106,7 @@ static int fasync_mouse(struct inode *inode, struct file *filp, int on) static int release_mouse(struct inode * inode, struct file * file) { - fasync_mouse(inode, file, 0); + fasync_mouse(file, 0); if (--mouse.active) return 0; ATIXL_MSE_INT_OFF(); /* Interrupts are really shut down here */ diff --git a/drivers/char/busmouse.c b/drivers/char/busmouse.c index 3e2ee97bd..9e160cb93 100644 --- a/drivers/char/busmouse.c +++ b/drivers/char/busmouse.c @@ -106,11 +106,12 @@ static void mouse_interrupt(int irq, void *dev_id, struct pt_regs *regs) MSE_INT_ON(); } -static int fasync_mouse(struct inode *inode, struct file *filp, int on) +static int fasync_mouse(struct file *filp, int on) { int retval; + struct inode *inode = filp->f_dentry->d_inode; - retval = fasync_helper(inode, filp, on, &mouse.fasyncptr); + retval = fasync_helper(filp, on, &mouse.fasyncptr); if (retval < 0) return retval; return 0; @@ -122,7 +123,7 @@ static int fasync_mouse(struct inode *inode, struct file *filp, int on) static int close_mouse(struct inode * inode, struct file * file) { - fasync_mouse(inode, file, 0); + fasync_mouse(file, 0); if (--mouse.active) return 0; MSE_INT_OFF(); diff --git a/drivers/char/fbmem.c b/drivers/char/fbmem.c index 4a5bea195..d475413b3 100644 --- a/drivers/char/fbmem.c +++ b/drivers/char/fbmem.c @@ -199,10 +199,9 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, } } -static int -fb_mmap(struct inode *inode, struct file *file, struct vm_area_struct * vma) +static int fb_mmap(struct file *file, struct vm_area_struct * vma) { - struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)]; + struct fb_ops *fb = registered_fb[GET_FB_IDX(file->f_dentry->d_inode->i_rdev)]; struct fb_fix_screeninfo fix; if (! fb) diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 270159480..f18d25d9a 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -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++; } diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 770607df4..49a6c65db 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -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,17 +285,13 @@ 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; } -static long long lp_lseek(struct inode * inode, struct file * file, - long long offset, int origin) +static long long lp_lseek(struct file * file, long long offset, int origin) { return -ESPIPE; } @@ -432,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 @@ -451,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 @@ -467,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) { @@ -517,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; @@ -531,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; diff --git a/drivers/char/lp_m68k.c b/drivers/char/lp_m68k.c index 117dc3fe7..bdb3405ca 100644 --- a/drivers/char/lp_m68k.c +++ b/drivers/char/lp_m68k.c @@ -353,8 +353,7 @@ static long lp_write(struct inode *inode, struct file *file, } #endif -static long long lp_lseek(struct inode * inode, struct file * file, - long long offset, int origin) +static long long lp_lseek(struct file * file, long long offset, int origin) { return -ESPIPE; } diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 78df2e3be..94c207e10 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -117,7 +117,7 @@ static long write_mem(struct inode * inode, struct file * file, return do_write_mem(file,__va(p),p,buf,count); } -static int mmap_mem(struct inode * inode, struct file * file, struct vm_area_struct * vma) +static int mmap_mem(struct file * file, struct vm_area_struct * vma) { unsigned long offset = vma->vm_offset; @@ -330,7 +330,7 @@ out: return written ? written : -EFAULT; } -static int mmap_zero(struct inode * inode, struct file * file, struct vm_area_struct * vma) +static int mmap_zero(struct file * file, struct vm_area_struct * vma) { if (vma->vm_flags & VM_SHARED) return -EINVAL; @@ -350,8 +350,7 @@ static long write_full(struct inode * inode, struct file * file, * both devices with "a" now. This was previously impossible. SRB. */ -static long long null_lseek(struct inode * inode, struct file * file, - long long offset, int orig) +static long long null_lseek(struct file * file, long long offset, int orig) { return file->f_pos=0; } @@ -363,8 +362,7 @@ static long long null_lseek(struct inode * inode, struct file * file, * also note that seeking relative to the "end of file" isn't supported: * it has no meaning, so it returns -EINVAL. */ -static long long memory_lseek(struct inode * inode, struct file * file, - long long offset, int orig) +static long long memory_lseek(struct file * file, long long offset, int orig) { switch (orig) { case 0: diff --git a/drivers/char/msbusmouse.c b/drivers/char/msbusmouse.c index 8f98231b8..a8c32ce6d 100644 --- a/drivers/char/msbusmouse.c +++ b/drivers/char/msbusmouse.c @@ -89,11 +89,11 @@ static void ms_mouse_interrupt(int irq, void *dev_id, struct pt_regs * regs) } } -static int fasync_mouse(struct inode *inode, struct file *filp, int on) +static int fasync_mouse(struct file *filp, int on) { int retval; - retval = fasync_helper(inode, filp, on, &mouse.fasyncptr); + retval = fasync_helper(filp, on, &mouse.fasyncptr); if (retval < 0) return retval; return 0; @@ -101,7 +101,7 @@ static int fasync_mouse(struct inode *inode, struct file *filp, int on) static int release_mouse(struct inode * inode, struct file * file) { - fasync_mouse(inode, file, 0); + fasync_mouse(file, 0); if (--mouse.active) return 0; MS_MSE_INT_OFF(); diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c new file mode 100644 index 000000000..402981749 --- /dev/null +++ b/drivers/char/nvram.c @@ -0,0 +1,695 @@ +/* + * CMOS/NV-RAM driver for Linux + * + * Copyright (C) 1997 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> + * idea by and with help from Richard Jelinek <rj@suse.de> + * + * This driver allows you to access the contents of the non-volatile memory in + * the mc146818rtc.h real-time clock. This chip is built into all PCs and into + * many Atari machines. In the former it's called "CMOS-RAM", in the latter + * "NVRAM" (NV stands for non-volatile). + * + * The data are supplied as a (seekable) character device, /dev/nvram. The + * size of this file is 50, the number of freely available bytes in the memory + * (i.e., not used by the RTC itself). + * + * Checksums over the NVRAM contents are managed by this driver. In case of a + * bad checksum, reads and writes return -EIO. The checksum can be initialized + * to a sane state either by ioctl(NVRAM_INIT) (clear whole NVRAM) or + * ioctl(NVRAM_SETCKS) (doesn't change contents, just makes checksum valid + * again; use with care!) + * + * This file also provides some functions for other parts of the kernel that + * want to access the NVRAM: nvram_{read,write,check_checksum,set_checksum}. + * Obviously this can be used only if this driver is always configured into + * the kernel and is not a module. Since the functions are used by some Atari + * drivers, this is the case on the Atari. + * + */ + +#define NVRAM_VERSION "1.0" + +#include <linux/module.h> +#include <linux/config.h> + +#define PC 1 +#define ATARI 2 + +/* select machine configuration */ +#if defined(CONFIG_ATARI) +#define MACH ATARI +#elif defined(__i386__) /* and others?? */ +#define MACH PC +#else +#error Cannot build nvram driver for this machine configuration. +#endif + +#if MACH == PC + +/* RTC in a PC */ +#define CHECK_DRIVER_INIT() 1 + +/* On PCs, the checksum is built only over bytes 2..31 */ +#define PC_CKS_RANGE_START 2 +#define PC_CKS_RANGE_END 31 +#define PC_CKS_LOC 32 + +#define mach_check_checksum pc_check_checksum +#define mach_set_checksum pc_set_checksum +#define mach_proc_infos pc_proc_infos + +#endif + +#if MACH == ATARI + +/* Special parameters for RTC in Atari machines */ +#include <asm/atarihw.h> +#include <asm/atariints.h> +#define RTC_PORT(x) (TT_RTC_BAS + 2*(x)) +#define CHECK_DRIVER_INIT() (MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK)) + +/* On Ataris, the checksum is over all bytes except the checksum bytes + * themselves; these are at the very end */ +#define ATARI_CKS_RANGE_START 0 +#define ATARI_CKS_RANGE_END 47 +#define ATARI_CKS_LOC 48 + +#define mach_check_checksum atari_check_checksum +#define mach_set_checksum atari_set_checksum +#define mach_proc_infos atari_proc_infos + +#endif + +/* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with + * interrupts disabled. Due to the index-port/data-port design of the RTC, we + * don't want two different things trying to get to it at once. (e.g. the + * periodic 11 min sync from time.c vs. this driver.) + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/miscdevice.h> +#include <linux/malloc.h> +#include <linux/ioport.h> +#include <linux/fcntl.h> +#include <linux/mc146818rtc.h> +#include <linux/nvram.h> +#include <linux/init.h> +#ifdef CONFIG_PROC_FS +#include <linux/proc_fs.h> +#endif + +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/system.h> + + +static int nvram_open_cnt = 0; /* #times opened */ +static int nvram_open_mode; /* special open modes */ +#define NVRAM_WRITE 1 /* opened for writing (exclusive) */ +#define NVRAM_EXCL 2 /* opened with O_EXCL */ + +#define RTC_FIRST_BYTE 14 /* RTC register number of first NVRAM byte */ +#define NVRAM_BYTES 50 /* number of NVRAM bytes */ + + +static int mach_check_checksum( void ); +static void mach_set_checksum( void ); +#ifdef CONFIG_PROC_FS +static int mach_proc_infos( unsigned char *contents, char *buffer, int *len, + off_t *begin, off_t offset, int size ); +#endif + + +/* + * These are the internal NVRAM access functions, which do NOT disable + * interrupts and do not check the checksum. Both tasks are left to higher + * level function, so they need to be done only once per syscall. + */ + +static __inline__ unsigned char nvram_read_int( int i ) +{ + return( CMOS_READ( RTC_FIRST_BYTE+i ) ); +} + +static __inline__ void nvram_write_int( unsigned char c, int i ) +{ + CMOS_WRITE( c, RTC_FIRST_BYTE+i ); +} + +static __inline__ int nvram_check_checksum_int( void ) +{ + return( mach_check_checksum() ); +} + +static __inline__ void nvram_set_checksum_int( void ) +{ + mach_set_checksum(); +} + +#if MACH == ATARI + +/* + * These non-internal functions are provided to be called by other parts of + * the kernel. It's up to the caller to ensure correct checksum before reading + * or after writing (needs to be done only once). + * + * They're only built if CONFIG_ATARI is defined, because Atari drivers use + * them. For other configurations (PC), the rest of the kernel can't rely on + * them being present (this driver couldn't be configured at all, or as a + * module), so they access config information themselves. + */ + +unsigned char nvram_read_byte( int i ) +{ + unsigned long flags; + unsigned char c; + + save_flags(flags); + cli(); + c = nvram_read_int( i ); + restore_flags(flags); + return( c ); +} + +void nvram_write_byte( unsigned char c, int i ) +{ + unsigned long flags; + + save_flags(flags); + cli(); + nvram_write_int( c, i ); + restore_flags(flags); +} + +int nvram_check_checksum( void ) +{ + unsigned long flags; + int rv; + + save_flags(flags); + cli(); + rv = nvram_check_checksum_int(); + restore_flags(flags); + return( rv ); +} + +void nvram_set_checksum( void ) +{ + unsigned long flags; + + save_flags(flags); + cli(); + nvram_set_checksum_int(); + restore_flags(flags); +} + +#endif /* MACH == ATARI */ + + +/* + * The are the file operation function for user access to /dev/nvram + */ + +static long long nvram_llseek(struct file *file,loff_t offset, int origin ) +{ + switch( origin ) { + case 0: + /* nothing to do */ + break; + case 1: + offset += file->f_pos; + break; + case 2: + offset += NVRAM_BYTES; + break; + } + return( (offset >= 0) ? (file->f_pos = offset) : -EINVAL ); +} + +static long nvram_read( struct inode * inode, struct file * file, + char * buf, unsigned long count ) +{ + unsigned long flags; + unsigned i = file->f_pos; + char *tmp = buf; + + save_flags(flags); + cli(); + + if (!nvram_check_checksum_int()) { + restore_flags(flags); + return( -EIO ); + } + + for( ; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp ) + put_user( nvram_read_int(i), tmp ); + file->f_pos = i; + + restore_flags(flags); + return( tmp - buf ); +} + +static long nvram_write( struct inode * inode, struct file * file, + const char * buf, unsigned long count ) +{ + unsigned long flags; + unsigned i = file->f_pos; + const char *tmp = buf; + char c; + + save_flags(flags); + cli(); + + if (!nvram_check_checksum_int()) { + restore_flags(flags); + return( -EIO ); + } + + for( ; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp ) { + get_user( c, tmp ); + nvram_write_int( c, i ); + } + nvram_set_checksum_int(); + file->f_pos = i; + + restore_flags(flags); + return( tmp - buf ); +} + +static int nvram_ioctl( struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg ) +{ + unsigned long flags; + int i; + + switch( cmd ) { + + case NVRAM_INIT: /* initialize NVRAM contents and checksum */ + if (!suser()) + return( -EACCES ); + + save_flags(flags); + cli(); + + for( i = 0; i < NVRAM_BYTES; ++i ) + nvram_write_int( 0, i ); + nvram_set_checksum_int(); + + restore_flags(flags); + return( 0 ); + + case NVRAM_SETCKS: /* just set checksum, contents unchanged + * (maybe useful after checksum garbaged + * somehow...) */ + if (!suser()) + return( -EACCES ); + + save_flags(flags); + cli(); + nvram_set_checksum_int(); + restore_flags(flags); + return( 0 ); + + default: + return( -EINVAL ); + } +} + +static int nvram_open( struct inode *inode, struct file *file ) +{ + if ((nvram_open_cnt && (file->f_flags & O_EXCL)) || + (nvram_open_mode & NVRAM_EXCL) || + ((file->f_mode & 2) && (nvram_open_mode & NVRAM_WRITE))) + return( -EBUSY ); + + if (file->f_flags & O_EXCL) + nvram_open_mode |= NVRAM_EXCL; + if (file->f_mode & 2) + nvram_open_mode |= NVRAM_WRITE; + nvram_open_cnt++; + MOD_INC_USE_COUNT; + return( 0 ); +} + +static int nvram_release( struct inode *inode, struct file *file ) +{ + nvram_open_cnt--; + if (file->f_flags & O_EXCL) + nvram_open_mode &= ~NVRAM_EXCL; + if (file->f_mode & 2) + nvram_open_mode &= ~NVRAM_WRITE; + + MOD_DEC_USE_COUNT; + return( 0 ); +} + + +#ifdef CONFIG_PROC_FS + +struct proc_dir_entry *proc_nvram; + +static int nvram_read_proc( char *buffer, char **start, off_t offset, + int size, int *eof, void *data ) +{ + unsigned long flags; + unsigned char contents[NVRAM_BYTES]; + int i, len = 0; + off_t begin = 0; + + save_flags(flags); + cli(); + for( i = 0; i < NVRAM_BYTES; ++i ) + contents[i] = nvram_read_int( i ); + restore_flags(flags); + + *eof = mach_proc_infos( contents, buffer, &len, &begin, offset, size ); + + if (offset >= begin + len) + return( 0 ); + *start = buffer + (begin - offset); + return( size < begin + len - offset ? size : begin + len - offset ); + +} + +/* This macro frees the machine specific function from bounds checking and + * this like that... */ +#define PRINT_PROC(fmt,args...) \ + do { \ + *len += sprintf( buffer+*len, fmt, ##args ); \ + if (*begin + *len > offset + size) \ + return( 0 ); \ + if (*begin + *len < offset) { \ + *begin += *len; \ + *len = 0; \ + } \ + } while(0) + +#endif + +static struct file_operations nvram_fops = { + nvram_llseek, + nvram_read, + nvram_write, + NULL, /* No readdir */ + NULL, /* No poll */ + nvram_ioctl, + NULL, /* No mmap */ + nvram_open, + nvram_release +}; + +static struct miscdevice nvram_dev = { + NVRAM_MINOR, + "nvram", + &nvram_fops +}; + + +__initfunc(int nvram_init(void)) +{ + /* First test whether the driver should init at all */ + if (!CHECK_DRIVER_INIT()) + return( -ENXIO ); + + printk( "Non-volatile memory driver v%s\n", NVRAM_VERSION ); + misc_register( &nvram_dev ); +#ifdef CONFIG_PROC_FS + if ((proc_nvram = create_proc_entry( "nvram", 0, 0 ))) + proc_nvram->read_proc = nvram_read_proc; +#endif + + return( 0 ); +} + +#ifdef MODULE +int init_module (void) +{ + return( nvram_init() ); +} + +void cleanup_module (void) +{ +#ifdef CONFIG_PROC_FS + if (proc_nvram) + remove_proc_entry( "nvram", 0 ); +#endif + misc_deregister( &nvram_dev ); +} +#endif + + +/* + * Machine specific functions + */ + + +#if MACH == PC + +static int pc_check_checksum( void ) +{ + int i; + unsigned short sum = 0; + + for( i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i ) + sum += nvram_read_int( i ); + return( (sum & 0xffff) == + ((nvram_read_int(PC_CKS_LOC) << 8) | + nvram_read_int(PC_CKS_LOC+1)) ); +} + +static void pc_set_checksum( void ) +{ + int i; + unsigned short sum = 0; + + for( i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i ) + sum += nvram_read_int( i ); + nvram_write_int( sum >> 8, PC_CKS_LOC ); + nvram_write_int( sum & 0xff, PC_CKS_LOC+1 ); +} + +#ifdef CONFIG_PROC_FS + +static char *floppy_types[] = { + "none", "5.25'' 360k", "5.25'' 1.2M", "3.5'' 720k", "3.5'' 1.44M" +}; + +static char *gfx_types[] = { + "EGA, VGA, ... (with BIOS)", + "CGA (40 cols)", + "CGA (80 cols)", + "monochrome", +}; + +static int pc_proc_infos( unsigned char *nvram, char *buffer, int *len, + off_t *begin, off_t offset, int size ) +{ + unsigned long flags; + int checksum; + int type; + + save_flags(flags); + cli(); + checksum = nvram_check_checksum_int(); + restore_flags(flags); + + PRINT_PROC( "Checksum status: %svalid\n", checksum ? "" : "not " ); + + PRINT_PROC( "# floppies : %d\n", + (nvram[6] & 1) ? (nvram[6] >> 6) + 1 : 0 ); + PRINT_PROC( "Floppy 0 type : " ); + type = nvram[2] >> 4; + if (type < sizeof(floppy_types)/sizeof(*floppy_types)) + PRINT_PROC( "%s\n", floppy_types[type] ); + else + PRINT_PROC( "%d (unknown)\n", type ); + PRINT_PROC( "Floppy 1 type : " ); + type = nvram[2] & 0x0f; + if (type < sizeof(floppy_types)/sizeof(*floppy_types)) + PRINT_PROC( "%s\n", floppy_types[type] ); + else + PRINT_PROC( "%d (unknown)\n", type ); + + PRINT_PROC( "HD 0 type : " ); + type = nvram[4] >> 4; + if (type) + PRINT_PROC( " %02x\n", type == 0x0f ? nvram[11] : type ); + else + PRINT_PROC( "none\n" ); + + PRINT_PROC( "HD 1 type : " ); + type = nvram[4] & 0x0f; + if (type) + PRINT_PROC( " %02x\n", type == 0x0f ? nvram[12] : type ); + else + PRINT_PROC( "none\n" ); + + PRINT_PROC( "HD type 48 data: %d/%d/%d C/H/S, precomp %d, lz %d\n", + nvram[18] | (nvram[19] << 8), + nvram[20], nvram[25], + nvram[21] | (nvram[22] << 8), + nvram[23] | (nvram[24] << 8) ); + PRINT_PROC( "HD type 49 data: %d/%d/%d C/H/S, precomp %d, lz %d\n", + nvram[39] | (nvram[40] << 8), + nvram[41], nvram[46], + nvram[42] | (nvram[43] << 8), + nvram[44] | (nvram[45] << 8) ); + + PRINT_PROC( "DOS base memory: %d kB\n", nvram[7] | (nvram[8] << 8) ); + PRINT_PROC( "Extended memory: %d kB (configured), %d kB (tested)\n", + nvram[9] | (nvram[10] << 8), + nvram[34] | (nvram[35] << 8) ); + + PRINT_PROC( "Gfx adapter : %s\n", gfx_types[ (nvram[6] >> 4)&3 ] ); + + PRINT_PROC( "FPU : %sinstalled\n", + (nvram[6] & 2) ? "" : "not " ); + + return( 1 ); +} +#endif + +#endif /* MACH == PC */ + +#if MACH == ATARI + +static int atari_check_checksum( void ) +{ + int i; + unsigned char sum = 0; + + for( i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i ) + sum += nvram_read_int( i ); + return( nvram_read_int( ATARI_CKS_LOC ) == (~sum & 0xff) && + nvram_read_int( ATARI_CKS_LOC+1 ) == (sum & 0xff) ); +} + +static void atari_set_checksum( void ) +{ + int i; + unsigned char sum = 0; + + for( i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i ) + sum += nvram_read_int( i ); + nvram_write_int( ~sum, ATARI_CKS_LOC ); + nvram_write_int( sum, ATARI_CKS_LOC+1 ); +} + +#ifdef CONFIG_PROC_FS + +static struct { + unsigned char val; + char *name; +} boot_prefs[] = { + { 0x80, "TOS" }, + { 0x40, "ASV" }, + { 0x20, "NetBSD (?)" }, + { 0x10, "Linux" }, + { 0x00, "unspecified" } +}; + +static char *languages[] = { + "English (US)", + "German", + "French", + "English (UK)", + "Spanish", + "Italian", + "6 (undefined)", + "Swiss (French)", + "Swiss (German)" +}; + +static char *dateformat[] = { + "MM%cDD%cYY", + "DD%cMM%cYY", + "YY%cMM%cDD", + "YY%cDD%cMM", + "4 (undefined)", + "5 (undefined)", + "6 (undefined)", + "7 (undefined)" +}; + +static char *colors[] = { + "2", "4", "16", "256", "65536", "??", "??", "??" +}; + +#define fieldsize(a) (sizeof(a)/sizeof(*a)) + +static int atari_proc_infos( unsigned char *nvram, char *buffer, int *len, + off_t *begin, off_t offset, int size ) +{ + int checksum = nvram_check_checksum(); + int i; + unsigned vmode; + + PRINT_PROC( "Checksum status : %svalid\n", checksum ? "" : "not " ); + + PRINT_PROC( "Boot preference : " ); + for( i = fieldsize(boot_prefs)-1; i >= 0; --i ) { + if (nvram[1] == boot_prefs[i].val) { + PRINT_PROC( "%s\n", boot_prefs[i].name ); + break; + } + } + if (i < 0) + PRINT_PROC( "0x%02x (undefined)\n", nvram[1] ); + + PRINT_PROC( "SCSI arbitration : %s\n", (nvram[16] & 0x80) ? "on" : "off" ); + PRINT_PROC( "SCSI host ID : " ); + if (nvram[16] & 0x80) + PRINT_PROC( "%d\n", nvram[16] & 7 ); + else + PRINT_PROC( "n/a\n" ); + + /* the following entries are defined only for the Falcon */ + if ((atari_mch_cookie >> 16) != ATARI_MCH_FALCON) + return; + + PRINT_PROC( "OS language : " ); + if (nvram[6] < fieldsize(languages)) + PRINT_PROC( "%s\n", languages[nvram[6]] ); + else + PRINT_PROC( "%u (undefined)\n", nvram[6] ); + PRINT_PROC( "Keyboard language: " ); + if (nvram[7] < fieldsize(languages)) + PRINT_PROC( "%s\n", languages[nvram[7]] ); + else + PRINT_PROC( "%u (undefined)\n", nvram[7] ); + PRINT_PROC( "Date format : " ); + PRINT_PROC( dateformat[nvram[8]&7], + nvram[9] ? nvram[9] : '/', nvram[9] ? nvram[9] : '/' ); + PRINT_PROC( ", %dh clock\n", nvram[8] & 16 ? 24 : 12 ); + PRINT_PROC( "Boot delay : " ); + if (nvram[10] == 0) + PRINT_PROC( "default" ); + else + PRINT_PROC( "%ds%s\n", nvram[10], + nvram[10] < 8 ? ", no memory test" : "" ); + + vmode = (nvram[14] << 8) || nvram[15]; + PRINT_PROC( "Video mode : %s colors, %d columns, %s %s monitor\n", + colors[vmode & 7], + vmode & 8 ? 80 : 40, + vmode & 16 ? "VGA" : "TV", + vmode & 32 ? "PAL" : "NTSC" ); + PRINT_PROC( " %soverscan, compat. mode %s%s\n", + vmode & 64 ? "" : "no ", + vmode & 128 ? "on" : "off", + vmode & 256 ? + (vmode & 16 ? ", line doubling" : ", half screen") : "" ); + + return( 1 ); +} +#endif + +#endif /* MACH == ATARI */ + +/* + * Local variables: + * c-indent-level: 4 + * tab-width: 4 + * End: + */ diff --git a/drivers/char/pc110pad.c b/drivers/char/pc110pad.c index d9c5ac453..71b75deb2 100644 --- a/drivers/char/pc110pad.c +++ b/drivers/char/pc110pad.c @@ -474,11 +474,11 @@ static void sample_ps2(int d[3]) -static int fasync_pad(struct inode *inode, struct file *filp, int on) +static int fasync_pad(struct file *filp, int on) { int retval; - retval = fasync_helper(inode, filp, on, &asyncptr); + retval = fasync_helper(filp, on, &asyncptr); if (retval < 0) return retval; return 0; @@ -490,7 +490,7 @@ static int fasync_pad(struct inode *inode, struct file *filp, int on) */ static int close_pad(struct inode * inode, struct file * file) { - fasync_pad(inode, file, 0); + fasync_pad(file, 0); if (--active) return 0; outb(0x30, current_params.io+2); /* switch off digitiser */ diff --git a/drivers/char/pcwd.c b/drivers/char/pcwd.c index 9a77783b3..2f8a5a75b 100644 --- a/drivers/char/pcwd.c +++ b/drivers/char/pcwd.c @@ -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); diff --git a/drivers/char/psaux.c b/drivers/char/psaux.c index e07c8648d..972f38ad3 100644 --- a/drivers/char/psaux.c +++ b/drivers/char/psaux.c @@ -104,11 +104,11 @@ static inline int queue_empty(void) return queue->head == queue->tail; } -static int fasync_aux(struct inode *inode, struct file *filp, int on) +static int fasync_aux(struct file *filp, int on) { int retval; - retval = fasync_helper(inode, filp, on, &queue->fasync); + retval = fasync_helper(filp, on, &queue->fasync); if (retval < 0) return retval; return 0; @@ -270,7 +270,7 @@ static void aux_interrupt(int cpl, void *dev_id, struct pt_regs * regs) static int release_aux(struct inode * inode, struct file * file) { - fasync_aux(inode, file, 0); + fasync_aux(file, 0); if (--aux_count) return 0; aux_start_atomic(); @@ -408,7 +408,7 @@ static int release_qp(struct inode * inode, struct file * file) { unsigned char status; - fasync_aux(inode, file, 0); + fasync_aux(file, 0); if (!--qp_count) { if (!poll_qp_status()) printk("Warning: Mouse device busy in release_qp()\n"); diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 5f03f8887..b150dd7e1 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -76,8 +76,7 @@ static struct wait_queue *rtc_wait; static struct timer_list rtc_irq_timer; -static long long rtc_llseek(struct inode *inode, struct file *file, - loff_t offset, int origin); +static long long rtc_llseek(struct file *file, loff_t offset, int origin); static long rtc_read(struct inode *inode, struct file *file, char *buf, unsigned long count); @@ -142,8 +141,7 @@ static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) * Now all the various file operations that we export. */ -static long long rtc_llseek(struct inode *inode, struct file *file, - loff_t offset, int origin) +static long long rtc_llseek(struct file *file, loff_t offset, int origin) { return -ESPIPE; } diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 184a21040..1ec03230b 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -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) @@ -3217,15 +3215,45 @@ static void stl_cd1400flush(stlport_t *portp) /*****************************************************************************/ /* + * 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); } diff --git a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c index 9d4ee2449..3a8d02b22 100644 --- a/drivers/char/tpqic02.c +++ b/drivers/char/tpqic02.c @@ -1,4 +1,4 @@ -/* $Id: tpqic02.c,v 1.10 1997/01/26 07:13:20 davem Exp $ +/* $Id: tpqic02.c,v 1.1.1.1 1997/06/01 03:17:28 ralf Exp $ * * Driver for tape drive support for Linux-i386 * @@ -134,8 +134,8 @@ static volatile struct mtget ioctl_status; /* current generic status */ static volatile struct tpstatus tperror; /* last drive status */ -static char rcs_revision[] = "$Revision: 1.10 $"; -static char rcs_date[] = "$Date: 1997/01/26 07:13:20 $"; +static char rcs_revision[] = "$Revision: 1.1.1.1 $"; +static char rcs_date[] = "$Date: 1997/06/01 03:17:28 $"; /* Flag bits for status and outstanding requests. * (Could all be put in one bit-field-struct.) @@ -1712,8 +1712,7 @@ static void qic02_tape_interrupt(int irq, void *dev_id, struct pt_regs *regs) } /* qic02_tape_interrupt */ -static long long qic02_tape_lseek(struct inode * inode, struct file * file, - long long offset, int origin) +static long long qic02_tape_lseek(struct file * file, long long offset, int origin) { return -EINVAL; /* not supported */ } /* qic02_tape_lseek */ diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 4c6ecae22..2148a06a6 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -115,7 +115,7 @@ static int tty_open(struct inode *, struct file *); static int tty_release(struct inode *, struct file *); static int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); -static int tty_fasync(struct inode * inode, struct file * filp, int on); +static int tty_fasync(struct file * filp, int on); #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -327,8 +327,7 @@ static int hung_up_tty_ioctl(struct inode * inode, struct file * file, return cmd == TIOCSPGRP ? -ENOTTY : -EIO; } -static long long tty_lseek(struct inode * inode, struct file * file, - long long offset, int orig) +static long long tty_lseek(struct file * file, long long offset, int orig) { return -ESPIPE; } @@ -381,7 +380,7 @@ void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops) continue; if (filp->f_op != &tty_fops) continue; - tty_fasync(filp->f_dentry->d_inode, filp, 0); + tty_fasync(filp, 0); filp->f_op = fops; } @@ -926,7 +925,7 @@ static void release_dev(struct file * filp) check_tty_count(tty, "release_dev"); - tty_fasync(filp->f_dentry->d_inode, filp, 0); + tty_fasync(filp, 0); idx = MINOR(tty->device) - tty->driver.minor_start; pty_master = (tty->driver.type == TTY_DRIVER_TYPE_PTY && @@ -1263,7 +1262,7 @@ static unsigned int tty_poll(struct file * filp, poll_table * wait) * to set up the fasync queue. It returns negative on error, 0 if it did * no changes and positive if it added/deleted the entry. */ -int fasync_helper(struct inode * inode, struct file * filp, int on, struct fasync_struct **fapp) +int fasync_helper(struct file * filp, int on, struct fasync_struct **fapp) { struct fasync_struct *fa, **fp; unsigned long flags; @@ -1298,27 +1297,26 @@ int fasync_helper(struct inode * inode, struct file * filp, int on, struct fasyn return 1; } -static int tty_fasync(struct inode * inode, struct file * filp, int on) +static int tty_fasync(struct file * filp, int on) { struct tty_struct * tty; int retval; tty = (struct tty_struct *)filp->private_data; - if (tty_paranoia_check(tty, inode->i_rdev, "tty_fasync")) + if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "tty_fasync")) return 0; - retval = fasync_helper(inode, filp, on, &tty->fasync); + retval = fasync_helper(filp, on, &tty->fasync); if (retval <= 0) return retval; 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)) diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c index c0d7440c3..9d2ecda3a 100644 --- a/drivers/char/vc_screen.c +++ b/drivers/char/vc_screen.c @@ -79,11 +79,10 @@ vcs_size(struct inode *inode) return size; } -static long long -vcs_lseek(struct inode *inode, struct file *file, long long offset, int orig) +static long long vcs_lseek(struct file *file, long long offset, int orig) { int size; - size = vcs_size(inode); + size = vcs_size(file->f_dentry->d_inode); switch (orig) { case 0: diff --git a/drivers/char/wdt.c b/drivers/char/wdt.c index 31837eee2..cbe763975 100644 --- a/drivers/char/wdt.c +++ b/drivers/char/wdt.c @@ -155,8 +155,7 @@ void wdt_interrupt(int irq, void *dev_id, struct pt_regs *regs) } -static long long wdt_llseek(struct inode *inode, struct file *file, long long offset, - int origin) +static long long wdt_llseek(struct file *file, long long offset, int origin) { return -ESPIPE; } diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c index 86d8a3432..f096101d5 100644 --- a/drivers/isdn/isdn_common.c +++ b/drivers/isdn/isdn_common.c @@ -1,4 +1,4 @@ -/* $Id: isdn_common.c,v 1.2 1997/06/03 09:24:18 ralf Exp $ +/* $Id: isdn_common.c,v 1.3 1997/09/12 01:31:49 ralf Exp $ * Linux ISDN subsystem, common used functions (linklevel). * @@ -21,6 +21,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_common.c,v $ + * Revision 1.3 1997/09/12 01:31:49 ralf + * Merge with Linux 2.1.55. More bugfixes and goodies from my private + * CVS archive. + * * Revision 1.2 1997/06/03 09:24:18 ralf * Sync with Linux 2.1.42. * @@ -221,7 +225,7 @@ isdn_dev *dev = (isdn_dev *) 0; -static char *isdn_revision = "$Revision: 1.2 $"; +static char *isdn_revision = "$Revision: 1.3 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -925,8 +929,7 @@ isdn_read(struct inode *inode, struct file *file, char *buf, RWARG count) return -ENODEV; } -static LSTYPE -isdn_lseek(struct inode *inode, struct file *file, LSARG offset, int orig) +static LSTYPE isdn_lseek(struct file *file, LSARG offset, int orig) { return -ESPIPE; } diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index 30a7100c0..6e1f5fadf 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -86,8 +86,7 @@ static int adb_release(struct inode *inode, struct file *file) return 0; } -static long long adb_lseek(struct inode *inode, struct file *file, - long long offset, int origin) +static long long adb_lseek(struct file *file, long long offset, int origin) { return -ESPIPE; } diff --git a/drivers/macintosh/nvram.c b/drivers/macintosh/nvram.c index 9bb6166e4..0f2ab2f82 100644 --- a/drivers/macintosh/nvram.c +++ b/drivers/macintosh/nvram.c @@ -12,8 +12,7 @@ #define NVRAM_SIZE 8192 -static long long nvram_llseek(struct inode *inode, struct file *file, - loff_t offset, int origin) +static long long nvram_llseek(struct file *file, loff_t offset, int origin) { switch (origin) { case 1: diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 9d568b2fd..795df5697 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -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 diff --git a/drivers/misc/parport_pc.c b/drivers/misc/parport_pc.c index ae32bc91c..477b350e3 100644 --- a/drivers/misc/parport_pc.c +++ b/drivers/misc/parport_pc.c @@ -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; } diff --git a/drivers/misc/parport_share.c b/drivers/misc/parport_share.c index e4c58370f..6d518d284 100644 --- a/drivers/misc/parport_share.c +++ b/drivers/misc/parport_share.c @@ -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; } diff --git a/drivers/net/Config.in b/drivers/net/Config.in index 2e721ba8d..b90affadc 100644 --- a/drivers/net/Config.in +++ b/drivers/net/Config.in @@ -126,7 +126,7 @@ if [ "$CONFIG_DLCI" = "y" -o "$CONFIG_DLCI" = "m" ]; then fi # -# LocalTalk +# AppleTalk # if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_ATALK" != "n" ]; then @@ -136,6 +136,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'Dayna firmware support' CONFIG_COPS_DAYNA bool 'Tangent firmware support' CONFIG_COPS_TANGENT fi + dep_tristate 'IP-over-DDP driver support' CONFIG_IPDDP $CONFIG_ATALK fi fi @@ -202,10 +203,10 @@ fi # # WAN drivers support # -if [ "$CONFIG_WAN_ROUTER" = "y" ]; then +if [ "$CONFIG_WAN_ROUTER" != "n" ]; then bool 'WAN drivers' CONFIG_WAN_DRIVERS if [ "$CONFIG_WAN_DRIVERS" = "y" ]; then - bool 'Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA + dep_tristate 'Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_DRIVERS if [ "$CONFIG_VENDOR_SANGOMA" = "y" ]; then int ' Maximum number of cards' CONFIG_WANPIPE_CARDS 1 bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25 diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 920c17dc2..a79d7b4ea 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -727,6 +727,14 @@ else endif endif +ifeq ($(CONFIG_IPDDP),y) +L_OBJS += ipddp.o +else + ifeq ($(CONFIG_IPDDP),m) + M_OBJS += ipddp.o + endif +endif + ifeq ($(CONFIG_BAYCOM),y) L_OBJS += baycom.o CONFIG_HDLCDRV_BUILTIN = y diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 4fdfbb6b1..b568c12bf 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -326,6 +326,17 @@ static struct device atp_dev = { # define NEXT_DEV (&dev_cops) #endif /* COPS */ +#if defined(CONFIG_IPDDP) + extern int ipddp_init(struct device *dev); + static struct device dev_ipddp = { + "ipddp0\0 ", + 0, 0, 0, 0, + 0x0, 0, + 0, 0, 0, NEXT_DEV, ipddp_init }; +# undef NEXT_DEV +# define NEXT_DEV (&dev_ipddp) +#endif /* CONFIG_IPDDP */ + /* The first device defaults to I/O base '0', which means autoprobe. */ #ifndef ETH0_ADDR # define ETH0_ADDR 0 diff --git a/drivers/net/ipddp.c b/drivers/net/ipddp.c new file mode 100644 index 000000000..8106ffc2d --- /dev/null +++ b/drivers/net/ipddp.c @@ -0,0 +1,309 @@ +/* + * ipddp.c: IP-over-DDP driver for Linux + * + * Authors: + * - Original code by: Bradford W. Johnson <johns393@maroon.tc.umn.edu> + * - Moved to driver by: Jay Schulist <Jay.Schulist@spacs.k12.wi.us> + * + * Derived from: + * - Almost all code already existed in net/appletalk/ddp.c I just + * moved/reorginized it into a driver file. Original IP-over-DDP code + * was done by Bradford W. Johnson <johns393@maroon.tc.umn.edu> + * - skeleton.c: A network driver outline for linux. + * Written 1993-94 by Donald Becker. + * - dummy.c: A dummy net driver. By Nick Holloway. + * + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + */ + +static const char *version = +"ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n"; + +#include <linux/config.h> +#ifdef MODULE +#include <linux/module.h> +#include <linux/version.h> +#endif + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/fcntl.h> +#include <linux/interrupt.h> +#include <linux/ptrace.h> +#include <linux/ioport.h> +#include <linux/in.h> +#include <linux/malloc.h> +#include <linux/string.h> +#include <asm/uaccess.h> +#include <asm/system.h> +#include <asm/bitops.h> +#include <asm/io.h> +#include <asm/dma.h> +#include <linux/errno.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/if_arp.h> +#include <linux/atalk.h> +#include <linux/ip.h> +#include <net/route.h> + +#include "ipddp.h" /* Our stuff */ + +/* + * The name of the card. Is used for messages and in the requests for + * io regions, irqs and dma channels + */ + +static const char *cardname = "ipddp"; + +/* Use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */ +#ifndef IPDDP_DEBUG +#define IPDDP_DEBUG 1 +#endif +static unsigned int ipddp_debug = IPDDP_DEBUG; + +/* Index to functions, as function prototypes. */ +static int ipddp_xmit(struct sk_buff *skb, struct device *dev); +static struct net_device_stats *ipddp_get_stats(struct device *dev); +static int ipddp_rebuild_header(struct sk_buff *skb); +static int ipddp_header(struct sk_buff *skb, struct device *dev, + unsigned short type, void *daddr, void *saddr, unsigned len); +static int ipddp_ioctl(struct device *dev, struct ifreq *ifr, int cmd); + + +static int ipddp_open(struct device *dev) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + + return 0; +} + +static int ipddp_close(struct device *dev) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + + return 0; +} + +int ipddp_init(struct device *dev) +{ + static unsigned version_printed = 0; + + if (ipddp_debug && version_printed++ == 0) + printk("%s", version); + + /* Initalize the device structure. */ + dev->hard_start_xmit = ipddp_xmit; + + dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL); + if(!dev->priv) + return -ENOMEM; + memset(dev->priv,0,sizeof(struct enet_statistics)); + + dev->open = ipddp_open; + dev->stop = ipddp_close; + dev->get_stats = ipddp_get_stats; + dev->do_ioctl = ipddp_ioctl; + dev->hard_header = ipddp_header; /* see ip_output.c */ + dev->rebuild_header = ipddp_rebuild_header; + + dev->type = ARPHRD_IPDDP; /* IP over DDP tunnel */ + dev->family = AF_INET; + dev->mtu = 585; + dev->flags |= IFF_NOARP; + + /* + * The worst case header we will need is currently a + * ethernet header (14 bytes) and a ddp header (sizeof ddpehdr+1) + * We send over SNAP so that takes another 8 bytes. + */ + dev->hard_header_len = 14+8+sizeof(struct ddpehdr)+1; + + /* Fill in the device structure with ethernet-generic values. */ + ether_setup(dev); + + return 0; +} + +/* + * Transmit LLAP/ELAP frame using aarp_send_ddp. + */ +static int ipddp_xmit(struct sk_buff *skb, struct device *dev) +{ + /* Retrieve the saved address hint */ + struct at_addr *a=(struct at_addr *)skb->data; + skb_pull(skb,4); + + ((struct net_device_stats *) dev->priv)->tx_packets++; + ((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len; + + if(ipddp_debug>1) + printk("ipddp_xmit: Headroom %d\n",skb_headroom(skb)); + + if(aarp_send_ddp(skb->dev,skb,a,NULL) < 0) + dev_kfree_skb(skb,FREE_WRITE); + + return 0; +} + +/* + * Get the current statistics. This may be called with the card open or closed. + */ +static struct net_device_stats *ipddp_get_stats(struct device *dev) +{ + return (struct net_device_stats *)dev->priv; +} + +/* + * Now the packet really wants to go out. + */ +static int ipddp_rebuild_header(struct sk_buff *skb) +{ + u32 paddr = ((struct rtable*)skb->dst)->rt_gateway; + struct ddpehdr *ddp; + struct at_addr at; + struct ipddp_route *rt; + struct at_addr *our_addr; + + /* + * On entry skb->data points to the ddpehdr we reserved earlier. + * skb->h.raw will be the higher level header. + */ + + /* + * We created this earlier. + */ + + ddp = (struct ddpehdr *) (skb->data+4); + + /* find appropriate route */ + + for(rt=ipddp_route_head;rt;rt=rt->next) + { + if(rt->ip == paddr) + break; + } + + if(!rt) { + printk("ipddp unreachable dst %08lx\n",ntohl(paddr)); + return -ENETUNREACH; + } + + our_addr = atalk_find_dev_addr(rt->dev); + + /* fill in ddpehdr */ + ddp->deh_len = skb->len; + ddp->deh_hops = 1; + ddp->deh_pad = 0; + ddp->deh_sum = 0; + ddp->deh_dnet = rt->at.s_net; /* FIXME more hops?? */ + ddp->deh_snet = our_addr->s_net; + ddp->deh_dnode = rt->at.s_node; + ddp->deh_snode = our_addr->s_node; + ddp->deh_dport = 72; + ddp->deh_sport = 72; + + *((__u8 *)(ddp+1)) = 22; /* ddp type = IP */ + + /* fix up length field */ + *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); + + /* set skb->dev to appropriate device */ + skb->dev = rt->dev; + + /* skb->raddr = (unsigned long) at */ + at = rt->at; + /* Hide it at the start of the buffer */ + memcpy(skb->data,(void *)&at,sizeof(at)); + skb->arp = 1; /* so the actual device doesn't try to arp it... */ + skb->protocol = htons(ETH_P_ATALK); /* Protocol has changed */ + + return 0; +} + +static int ipddp_header(struct sk_buff *skb, struct device *dev, + unsigned short type, void *daddr, void *saddr, unsigned len) +{ + if(ipddp_debug>=2) + printk("%s: ipddp_header\n", cardname); + + /* Push down the header space and the type byte */ + skb_push(skb, sizeof(struct ddpehdr)+1+4); + + return 0; +} + +static int ipddp_ioctl(struct device *dev, struct ifreq *ifr, int cmd) +{ + struct ipddp_route *urt = (struct ipddp_route *)ifr->ifr_data; + + if(!suser()) + return -EPERM; + + /* for now we only have one route at a time */ + + switch(cmd) + { + case SIOCADDIPDDPRT: + if(copy_from_user(&ipddp_route_test,urt,sizeof(struct ipddp_route))) + return -EFAULT; + ipddp_route_test.dev = atrtr_get_dev(&ipddp_route_test.at); + if (dev==NULL) + return -ENETUNREACH; + ipddp_route_test.next = NULL; + printk("%s: Added route through %s\n", + ipddp_route_test.dev->name, cardname); + ipddp_route_head = &ipddp_route_test; + return 0; + + case SIOCFINDIPDDPRT: + if(copy_to_user(urt,&ipddp_route_test,sizeof(struct ipddp_route))) + return -EFAULT; + return 0; + + case SIOCDELIPDDPRT: + ipddp_route_test.dev = NULL; + ipddp_route_head = NULL; + return 0; + + default: + return -EINVAL; + } +} + +#ifdef MODULE /* Module specific functions for ipddp.c */ + +static struct device dev_ipddp= +{ + "ipddp0\0 ", + 0, 0, 0, 0, + 0x0, 0, + 0, 0, 0, NULL, ipddp_init +}; + +int init_module(void) +{ + if (register_netdev(&dev_ipddp) != 0) + return -EIO; + + return 0; +} + +void cleanup_module(void) +{ + unregister_netdev(&dev_ipddp); + kfree(dev_ipddp.priv); + dev_ipddp.priv = NULL; +} + +#endif /* MODULE */ diff --git a/drivers/net/ipddp.h b/drivers/net/ipddp.h new file mode 100644 index 000000000..6093adfec --- /dev/null +++ b/drivers/net/ipddp.h @@ -0,0 +1,27 @@ +/* + * ipddp.h: Header for IP-over-DDP driver for Linux. + */ + +#ifndef __LINUX_IPDDP_H +#define __LINUX_IPDDP_H + +#ifdef __KERNEL__ + +#define SIOCADDIPDDPRT SIOCDEVPRIVATE +#define SIOCDELIPDDPRT SIOCDEVPRIVATE+1 +#define SIOCFINDIPDDPRT SIOCDEVPRIVATE+2 + +struct ipddp_route +{ + struct device *dev; /* Carrier device */ + __u32 ip; /* IP address */ + struct at_addr at; /* Gateway appletalk address */ + int flags; + struct ipddp_route *next; +}; + +static struct ipddp_route *ipddp_route_head; +static struct ipddp_route ipddp_route_test; + +#endif /* __KERNEL__ */ +#endif /* __LINUX_IPDDP_H */ diff --git a/drivers/net/x25_asy.c b/drivers/net/x25_asy.c index f6f953201..ce4aeb609 100644 --- a/drivers/net/x25_asy.c +++ b/drivers/net/x25_asy.c @@ -4,6 +4,11 @@ * o tbusy handling * o allow users to set the parameters * o sync/async switching ? + * + * Note: This does _not_ implement CCITT X.25 asynchronous framing + * recommendations. Its primarily for testing purposes. If you wanted + * to do CCITT then in theory all you need is to nick the HDLC async + * checksum routines from ppp.c */ #include <linux/config.h> diff --git a/drivers/pnp/parport_probe.c b/drivers/pnp/parport_probe.c index 85f89e4c7..fc2f82702 100644 --- a/drivers/pnp/parport_probe.c +++ b/drivers/pnp/parport_probe.c @@ -1,4 +1,4 @@ -/* $Id: parport_probe.c,v 1.3 1997/08/06 19:15:53 miguel Exp $ +/* $Id: parport_probe.c,v 1.4 1997/09/12 01:32:20 ralf Exp $ * Parallel port device probing code * * Authors: Carsten Gross, carsten@sol.wohnheim.uni-ulm.de @@ -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: diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in index a137680cb..de7a65d6c 100644 --- a/drivers/scsi/Config.in +++ b/drivers/scsi/Config.in @@ -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 diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index cfff8bfa3..aeda681c1 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -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]); diff --git a/drivers/scsi/eata.h b/drivers/scsi/eata.h new file mode 100644 index 000000000..8292ef514 --- /dev/null +++ b/drivers/scsi/eata.h @@ -0,0 +1,41 @@ +/* + * eata.h - used by the low-level driver for EATA/DMA SCSI host adapters. + */ +#ifndef _EATA_H +#define _EATA_H + +#include <scsi/scsicam.h> + +int eata2x_detect(Scsi_Host_Template *); +int eata2x_release(struct Scsi_Host *); +int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int eata2x_abort(Scsi_Cmnd *); +int eata2x_reset(Scsi_Cmnd *, unsigned int); + +#define EATA_VERSION "3.11.00" + + +#define EATA { \ + NULL, /* Ptr for modules */ \ + NULL, /* usage count for modules */ \ + NULL, \ + NULL, \ + "EATA/DMA 2.0x rev. " EATA_VERSION " ", \ + eata2x_detect, \ + eata2x_release, \ + NULL, \ + NULL, \ + eata2x_queuecommand, \ + eata2x_abort, \ + eata2x_reset, \ + NULL, \ + scsicam_bios_param, \ + 0, /* can_queue, reset by detect */ \ + 7, /* this_id, reset by detect */ \ + 0, /* sg_tablesize, reset by detect */ \ + 0, /* cmd_per_lun, reset by detect */ \ + 0, /* number of boards present */ \ + 1, /* unchecked isa dma, reset by detect */ \ + ENABLE_CLUSTERING \ + } +#endif diff --git a/drivers/scsi/sr_vendor.c b/drivers/scsi/sr_vendor.c index a81e77d7a..e8f73f1b2 100644 --- a/drivers/scsi/sr_vendor.c +++ b/drivers/scsi/sr_vendor.c @@ -18,12 +18,14 @@ * 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> @@ -44,7 +46,10 @@ #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; diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c index 6a0076dde..fa980051a 100644 --- a/drivers/scsi/u14-34f.c +++ b/drivers/scsi/u14-34f.c @@ -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]); diff --git a/drivers/scsi/u14-34f.h b/drivers/scsi/u14-34f.h index 9381f7729..004936393 100644 --- a/drivers/scsi/u14-34f.h +++ b/drivers/scsi/u14-34f.h @@ -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 */ \ diff --git a/drivers/sound/dmasound.c b/drivers/sound/dmasound.c index b7da7932a..1c37f9f5a 100644 --- a/drivers/sound/dmasound.c +++ b/drivers/sound/dmasound.c @@ -668,10 +668,9 @@ static long state_read(char *dest, unsigned long count); static int sound_open(struct inode *inode, struct file *file); -static int sound_fsync(struct inode *inode, struct file *filp); +static int sound_fsync(struct file *filp, struct dentry *dentry); static void sound_release(struct inode *inode, struct file *file); -static long long sound_lseek(struct inode *inode, struct file *file, - long long offset, int orig); +static long long sound_lseek(struct file *file, long long offset, int orig); static long sound_read(struct inode *inode, struct file *file, char *buf, unsigned long count); static long sound_write(struct inode *inode, struct file *file, @@ -3071,9 +3070,9 @@ static int sound_open(struct inode *inode, struct file *file) } -static int sound_fsync(struct inode *inode, struct file *filp) +static int sound_fsync(struct file *filp, struct dentry *dentry) { - int dev = MINOR(inode->i_rdev) & 0x0f; + int dev = MINOR(dentry->d_inode->i_rdev) & 0x0f; switch (dev) { case SND_DEV_STATUS: @@ -3116,8 +3115,7 @@ static void sound_release(struct inode *inode, struct file *file) } -static long long sound_lseek(struct inode *inode, struct file *file, - long long offset, int orig) +static long long sound_lseek(struct file *file, long long offset, int orig) { return -ESPIPE; } @@ -3186,25 +3184,25 @@ static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd, return(0); case SNDCTL_DSP_POST: case SNDCTL_DSP_SYNC: - return(sound_fsync(inode, file)); + return(sound_fsync(file, file->f_dentry)); /* ++TeSche: before changing any of these it's probably wise to * wait until sound playing has settled down */ case SNDCTL_DSP_SPEED: - sound_fsync(inode, file); + sound_fsync(file, file->f_dentry); IOCTL_IN(arg, data); return(IOCTL_OUT(arg, sound_set_speed(data))); case SNDCTL_DSP_STEREO: - sound_fsync(inode, file); + sound_fsync(file, file->f_dentry); IOCTL_IN(arg, data); return(IOCTL_OUT(arg, sound_set_stereo(data))); case SOUND_PCM_WRITE_CHANNELS: - sound_fsync(inode, file); + sound_fsync(file, file->f_dentry); IOCTL_IN(arg, data); return(IOCTL_OUT(arg, sound_set_stereo(data-1)+1)); case SNDCTL_DSP_SETFMT: - sound_fsync(inode, file); + sound_fsync(file, file->f_dentry); IOCTL_IN(arg, data); return(IOCTL_OUT(arg, sound_set_format(data))); case SNDCTL_DSP_GETFMTS: diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c index a9af5956b..450197a34 100644 --- a/drivers/sound/soundcard.c +++ b/drivers/sound/soundcard.c @@ -80,8 +80,7 @@ sound_write (struct inode *inode, struct file *file, const char *buf, unsigned l return sound_write_sw (dev, &files[dev], buf, count); } -static long long -sound_lseek (struct inode *inode, struct file *file, long long offset, int orig) +static long long sound_lseek (struct file *file, long long offset, int orig) { return -EPERM; } @@ -139,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 @@ -256,13 +255,13 @@ sound_poll (struct file *file, poll_table * wait) } static int -sound_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma) +sound_mmap (struct file *file, struct vm_area_struct *vma) { int dev, dev_class; unsigned long size; struct dma_buffparms *dmap = NULL; - dev = MINOR (inode->i_rdev); + dev = MINOR (file->f_dentry->d_inode->i_rdev); files[dev].flags = file->f_flags; diff --git a/fs/Makefile b/fs/Makefile index 6061adad6..871524350 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -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 \ diff --git a/fs/affs/dir.c b/fs/affs/dir.c index e936e5bb5..cfd05640b 100644 --- a/fs/affs/dir.c +++ b/fs/affs/dir.c @@ -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 index 000000000..562a5d8b7 --- /dev/null +++ b/fs/bad_inode.c @@ -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; +} + diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index 0ff5b7ff6..2e9733706 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c @@ -62,7 +62,7 @@ while (file.f_op->write(inode,&file,(char *)(addr),(nr)) != (nr)) goto close_cor #define DUMP_SEEK(offset) \ if (file.f_op->llseek) { \ - if (file.f_op->llseek(inode,&file,(offset),0) != (offset)) \ + if (file.f_op->llseek(&file,(offset),0) != (offset)) \ goto close_coredump; \ } else file.f_pos = (offset) @@ -492,7 +492,7 @@ do_load_aout_library(int fd) /* Seek into the file */ if (file->f_op->llseek) { - if ((error = file->f_op->llseek(inode, file, 0, 0)) != 0) + if ((error = file->f_op->llseek(file, 0, 0)) != 0) return -ENOEXEC; } else file->f_pos = 0; diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 837ce563b..5187ae1cb 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -852,7 +852,7 @@ do_load_elf_library(int fd){ /* seek to the beginning of the file */ if (file->f_op->llseek) { - if ((error = file->f_op->llseek(inode, file, 0, 0)) != 0) + if ((error = file->f_op->llseek(file, 0, 0)) != 0) return -ENOEXEC; } else file->f_pos = 0; @@ -961,7 +961,7 @@ static int dump_write(struct file *file, const void *addr, int nr) static int dump_seek(struct file *file, off_t off) { if (file->f_op->llseek) { - if (file->f_op->llseek(file->f_dentry->d_inode, file, off, 0) != off) + if (file->f_op->llseek(file, off, 0) != off) return 0; } else file->f_pos = off; diff --git a/fs/block_dev.c b/fs/block_dev.c index f42026ac2..dbb9d14dc 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -287,7 +287,12 @@ long block_read(struct inode * inode, struct file * filp, return read; } -int block_fsync(struct inode *inode, struct file *filp) +/* + * Filp may be NULL when we are called by an msync of a vma + * since the vma has no handle. + */ + +int block_fsync(struct file *filp, struct dentry *dentry) { - return fsync_dev (inode->i_rdev); + return fsync_dev(dentry->d_inode->i_rdev); } diff --git a/fs/buffer.c b/fs/buffer.c index 62c4aa318..6025dcd31 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -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}; @@ -282,9 +282,13 @@ asmlinkage int sys_sync(void) return 0; } -int file_fsync (struct inode *inode, struct file *filp) +/* + * filp may be NULL if called via the msync of a vma. + */ + +int file_fsync(struct file *filp, struct dentry *dentry) { - return fsync_dev(inode->i_dev); + return fsync_dev(dentry->d_inode->i_dev); } asmlinkage int sys_fsync(unsigned int fd) @@ -316,7 +320,10 @@ asmlinkage int sys_fsync(unsigned int fd) if (!file->f_op || !file->f_op->fsync) goto out; - err = file->f_op->fsync(inode,file); + /* 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(); @@ -353,7 +360,7 @@ asmlinkage int sys_fdatasync(unsigned int fd) goto out; /* this needs further work, at the moment it is identical to fsync() */ - err = file->f_op->fsync(inode,file); + err = file->f_op->fsync(file, file->f_dentry); out: unlock_kernel(); diff --git a/fs/dcache.c b/fs/dcache.c index afc24db1e..600e5b0e3 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -119,7 +119,7 @@ int d_invalidate(struct dentry * dentry) * something (at which point we need to unuse * all dentries). */ -void shrink_dcache(void) +void prune_dcache(int count) { for (;;) { struct dentry *dentry; @@ -143,6 +143,8 @@ void shrink_dcache(void) parent = dentry->d_parent; d_free(dentry); dput(parent); + if (!--count) + break; } } } @@ -177,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); @@ -211,8 +218,11 @@ 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 }); - res->d_parent = res; - d_instantiate(res, root_inode); + if (res) { + res->d_sb = root_inode->i_sb; + res->d_parent = res; + d_instantiate(res, root_inode); + } } return res; } @@ -344,7 +354,7 @@ void d_add(struct dentry * entry, struct inode * inode) x = y; y = __tmp; } while (0) /* - * We cannibalize "newdentry" when moving dentry on top of it, + * We cannibalize "target" when moving dentry on top of it, * because it's going to be thrown away anyway. We could be more * polite about it, though. * @@ -369,7 +369,7 @@ int read_exec(struct dentry *dentry, unsigned long offset, if (!file.f_op->read) goto close_readexec; if (file.f_op->llseek) { - if (file.f_op->llseek(inode,&file,offset,0) != offset) + if (file.f_op->llseek(&file,offset,0) != offset) goto close_readexec; } else file.f_pos = offset; diff --git a/fs/ext2/file.c b/fs/ext2/file.c index d632133f1..b5f55efd6 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -36,7 +36,7 @@ #include <linux/fs.h> #include <linux/ext2_fs.h> -static long long ext2_file_lseek(struct inode *, struct file *, long long, int); +static long long ext2_file_lseek(struct file *, long long, int); static long ext2_file_write (struct inode *, struct file *, const char *, unsigned long); static int ext2_release_file (struct inode *, struct file *); @@ -84,12 +84,13 @@ struct inode_operations ext2_file_inode_operations = { /* * Make sure the offset never goes beyond the 32-bit mark.. */ -static long long ext2_file_lseek(struct inode *inode, +static long long ext2_file_lseek( struct file *file, long long offset, int origin) { long long retval; + struct inode *inode = file->f_dentry->d_inode; switch (origin) { case 2: diff --git a/fs/ext2/fsync.c b/fs/ext2/fsync.c index 9993af1a6..8a9bdf902 100644 --- a/fs/ext2/fsync.c +++ b/fs/ext2/fsync.c @@ -38,18 +38,12 @@ 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; } @@ -284,9 +250,15 @@ static int sync_tindirect (struct inode * inode, u32 * tiblock, int wait) return err; } -int ext2_sync_file (struct inode * inode, struct file * file) +/* + * File may be NULL when we are called. Perhaps we shouldn't + * even pass file to fsync ? + */ + +int ext2_sync_file(struct file * file, struct dentry *dentry) { int wait, err = 0; + struct inode *inode = dentry->d_inode; if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) @@ -312,5 +284,5 @@ int ext2_sync_file (struct inode * inode, struct file * file) } skip: err |= ext2_sync_inode (inode); - return (err < 0) ? -EIO : 0; + return err ? -EIO : 0; } diff --git a/fs/fat/mmap.c b/fs/fat/mmap.c index a858cd2cc..fd66e51d1 100644 --- a/fs/fat/mmap.c +++ b/fs/fat/mmap.c @@ -91,8 +91,10 @@ struct vm_operations_struct fat_file_mmap = { * This is used for a general mmap of an msdos file * Returns 0 if ok, or a negative error code if not. */ -int fat_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma) +int fat_mmap(struct file * file, struct vm_area_struct * vma) { + struct inode *inode = file->f_dentry->d_inode; + if (vma->vm_flags & VM_SHARED) /* only PAGE_COW or read-only supported now */ return -EINVAL; if (vma->vm_offset & (inode->i_sb->s_blocksize - 1)) diff --git a/fs/fcntl.c b/fs/fcntl.c index 57eef2530..ce00e439f 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -83,7 +83,7 @@ static int setfl(struct file * filp, unsigned long arg) /* Did FASYNC state change? */ if ((arg ^ filp->f_flags) & FASYNC) { if (filp->f_op->fasync) - filp->f_op->fasync(inode, filp, (arg & FASYNC) != 0); + filp->f_op->fasync(filp, (arg & FASYNC) != 0); } /* required for strict SunOS emulation */ @@ -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; } } diff --git a/fs/inode.c b/fs/inode.c index 7c9881222..6a8423c39 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -125,33 +125,6 @@ static inline void init_once(struct inode * inode) sema_init(&inode->i_sem, 1); } - -/* - * Look out! This returns with the inode lock held if - * it got an inode.. - */ -static struct inode * grow_inodes(void) -{ - struct inode * inode = (struct inode *)__get_free_page(GFP_KERNEL); - - if (inode) { - int size; - struct inode * tmp; - - spin_lock(&inode_lock); - size = PAGE_SIZE - 2*sizeof(struct inode); - tmp = inode; - do { - tmp++; - init_once(tmp); - list_add(&tmp->i_list, &inode_unused); - size -= sizeof(struct inode); - } while (size >= 0); - init_once(inode); - } - return inode; -} - static inline void write_inode(struct inode *inode) { if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->write_inode) @@ -238,7 +211,8 @@ void write_inode_now(struct inode *inode) */ void clear_inode(struct inode *inode) { - truncate_inode_pages(inode, 0); + if (inode->i_nrpages) + truncate_inode_pages(inode, 0); wait_on_inode(inode); if (IS_WRITABLE(inode) && inode->i_sb && inode->i_sb->dq_op) inode->i_sb->dq_op->drop(inode); @@ -253,6 +227,7 @@ void clear_inode(struct inode *inode) static void dispose_list(struct list_head * head) { struct list_head *next; + int count = 0; next = head->next; for (;;) { @@ -263,12 +238,14 @@ static void dispose_list(struct list_head * head) if (tmp == head) break; inode = list_entry(tmp, struct inode, i_list); - truncate_inode_pages(inode, 0); + clear_inode(inode); + count++; } /* Add them all to the unused list in one fell swoop */ spin_lock(&inode_lock); list_splice(head, &inode_unused); + inodes_stat.nr_free_inodes += count; spin_unlock(&inode_lock); } @@ -326,25 +303,25 @@ int invalidate_inodes(struct super_block * sb) } /* - * This is called with the inode lock held. It just looks at the last - * inode on the in-use list, and if the inode is trivially freeable - * we just move it to the unused list. - * - * Otherwise we just move the inode to be the first inode and expect to - * get back to the problem later.. + * This is called with the inode lock held. It searches + * the in-use for the specified number of freeable inodes. + * Freeable inodes are moved to a temporary list and then + * placed on the unused list by dispose_list. + * + * N.B. The spinlock is released to call dispose_list. */ #define CAN_UNUSE(inode) \ (((inode)->i_count == 0) && \ - ((inode)->i_nrpages == 0) && \ (!(inode)->i_state)) -static void try_to_free_inodes(void) +static void try_to_free_inodes(int goal) { struct list_head * tmp; struct list_head *head = &inode_in_use; + LIST_HEAD(freeable); + int found = 0, search = goal << 1; - tmp = head->prev; - if (tmp != head) { + while ((tmp = head->prev) != head && search--) { struct inode * inode; list_del(tmp); @@ -352,13 +329,81 @@ static void try_to_free_inodes(void) if (CAN_UNUSE(inode)) { list_del(&inode->i_hash); INIT_LIST_HEAD(&inode->i_hash); - head = &inode_unused; + list_add(tmp, &freeable); + if (++found < goal) + continue; + break; } list_add(tmp, head); } + /* + * If we didn't free any inodes, do a limited + * pruning of the dcache to help the next time. + */ + spin_unlock(&inode_lock); + if (found) + dispose_list(&freeable); + else + prune_dcache(goal); + spin_lock(&inode_lock); +} + +/* + * This is called with the spinlock held, but releases + * the lock when freeing or allocating inodes. + * Look out! This returns with the inode lock held if + * it got an inode.. + */ +static struct inode * grow_inodes(void) +{ + struct inode * inode; + + /* + * Check whether to shrink the dcache ... if we've + * allocated more than half of the nominal maximum, + * try shrinking before allocating more. + */ + if (inodes_stat.nr_inodes >= (max_inodes >> 1)) { + struct list_head * tmp; + + spin_unlock(&inode_lock); + prune_dcache(128); + spin_lock(&inode_lock); + try_to_free_inodes(128); + tmp = inode_unused.next; + if (tmp != &inode_unused) { + inodes_stat.nr_free_inodes--; + list_del(tmp); + inode = list_entry(tmp, struct inode, i_list); + return inode; + } + } + + spin_unlock(&inode_lock); + inode = (struct inode *)__get_free_page(GFP_KERNEL); + if (inode) { + int size; + struct inode * tmp; + + spin_lock(&inode_lock); + size = PAGE_SIZE - 2*sizeof(struct inode); + tmp = inode; + do { + tmp++; + init_once(tmp); + list_add(&tmp->i_list, &inode_unused); + inodes_stat.nr_free_inodes++; + size -= sizeof(struct inode); + } while (size >= 0); + init_once(inode); + inodes_stat.nr_inodes += PAGE_SIZE / sizeof(struct inode); + } + return inode; } - +/* + * Called with the inode lock held. + */ static struct inode * find_inode(struct super_block * sb, unsigned long ino, struct list_head *head) { struct list_head *tmp; @@ -416,17 +461,22 @@ struct inode * get_empty_inode(void) struct list_head * tmp; spin_lock(&inode_lock); - try_to_free_inodes(); + /* + * Check whether to restock the unused list. + */ + if (inodes_stat.nr_free_inodes < 16) + try_to_free_inodes(8); tmp = inode_unused.next; if (tmp != &inode_unused) { list_del(tmp); + inodes_stat.nr_free_inodes--; inode = list_entry(tmp, struct inode, i_list); add_new_inode: + list_add(&inode->i_list, &inode_in_use); inode->i_sb = NULL; inode->i_dev = 0; inode->i_ino = ++last_ino; inode->i_count = 1; - list_add(&inode->i_list, &inode_in_use); inode->i_state = 0; spin_unlock(&inode_lock); clean_inode(inode); @@ -437,7 +487,6 @@ add_new_inode: * Warning: if this succeeded, we will now * return with the inode lock. */ - spin_unlock(&inode_lock); inode = grow_inodes(); if (inode) goto add_new_inode; @@ -455,6 +504,7 @@ static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, s if (tmp != &inode_unused) { list_del(tmp); + inodes_stat.nr_free_inodes--; inode = list_entry(tmp, struct inode, i_list); add_new_inode: list_add(&inode->i_list, &inode_in_use); @@ -477,20 +527,18 @@ add_new_inode: * state of the inode when it is locked, as we * just created it (so there can be no old holders * that haven't tested I_LOCK). - * - * Verify this some day! */ inode->i_state &= ~I_LOCK; + wake_up(&inode->i_wait); return inode; } /* - * Uhhuh.. We need to expand. Unlock for the allocation, - * but note that "grow_inodes()" will return with the - * lock held again if the allocation succeeded. + * Uhhuh.. We need to expand. Note that "grow_inodes()" will + * release the spinlock, but will return with the lock held + * again if the allocation succeeded. */ - spin_unlock(&inode_lock); inode = grow_inodes(); if (inode) { /* We released the lock, so.. */ @@ -498,6 +546,7 @@ add_new_inode: if (!old) goto add_new_inode; list_add(&inode->i_list, &inode_unused); + inodes_stat.nr_free_inodes++; spin_unlock(&inode_lock); wait_on_inode(old); return old; @@ -518,14 +567,25 @@ struct inode *iget(struct super_block *sb, unsigned long ino) struct inode * inode; spin_lock(&inode_lock); + if (!inodes_stat.nr_free_inodes) + goto restock; +search: inode = find_inode(sb, ino, head); if (!inode) { - try_to_free_inodes(); return get_new_inode(sb, ino, head); } spin_unlock(&inode_lock); wait_on_inode(inode); return inode; + + /* + * We restock the freelist before calling find, + * in order to avoid repeating the search. + * (The unused list usually won't be empty.) + */ +restock: + try_to_free_inodes(8); + goto search; } void insert_inode_hash(struct inode *inode) @@ -560,9 +620,18 @@ void iput(struct inode *inode) } if (list_empty(&inode->i_hash)) { list_del(&inode->i_list); + INIT_LIST_HEAD(&inode->i_list); + spin_unlock(&inode_lock); + clear_inode(inode); + spin_lock(&inode_lock); list_add(&inode->i_list, &inode_unused); + inodes_stat.nr_free_inodes++; } } + if (inode->i_count > (1<<15)) { + printk("iput: device %s inode %ld count wrapped\n", + kdevname(inode->i_dev), inode->i_ino); + } spin_unlock(&inode_lock); } } diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index 98814d220..ad70f7b55 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c @@ -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) { diff --git a/fs/locks.c b/fs/locks.c index 909c2eacb..738fa0bca 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -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); @@ -322,7 +334,7 @@ int fcntl_getlk(unsigned int fd, struct flock *l) return -EINVAL; if (filp->f_op->lock) { - error = filp->f_op->lock(inode, filp, F_GETLK, &file_lock); + error = filp->f_op->lock(filp, F_GETLK, &file_lock); if (error < 0) return error; fl = &file_lock; @@ -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); @@ -420,7 +433,7 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l) } if (filp->f_op->lock != NULL) { - error = filp->f_op->lock(inode, filp, cmd, &file_lock); + error = filp->f_op->lock(filp, cmd, &file_lock); if (error < 0) return (error); } @@ -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) && @@ -451,13 +464,13 @@ void locks_remove_locks(struct task_struct *task, struct file *filp) locks_delete_lock(before, 0); if (filp->f_op->lock) { file_lock.fl_type = F_UNLCK; - filp->f_op->lock(inode, filp, F_SETLK, &file_lock); + 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 diff --git a/fs/minix/fsync.c b/fs/minix/fsync.c index 9510d6364..44606d260 100644 --- a/fs/minix/fsync.c +++ b/fs/minix/fsync.c @@ -328,10 +328,14 @@ int V2_minix_sync_file(struct inode * inode, struct file * file) } /* - * The function which is called for file synchronization. + * The function which is called for file synchronization. File may be + * NULL */ -int minix_sync_file(struct inode * inode, struct file * file) + +int minix_sync_file(struct file * file, struct dentry *dentry) { + struct inode *inode = dentry->d_inode; + if (INODE_VERSION(inode) == MINIX_V1) return V1_minix_sync_file(inode, file); else diff --git a/fs/namei.c b/fs/namei.c index 5aa6a5422..54714754d 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -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); diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c index 9a302a213..9a2067848 100644 --- a/fs/ncpfs/file.c +++ b/fs/ncpfs/file.c @@ -24,7 +24,7 @@ static inline int min(int a, int b) return a < b ? a : b; } -static int ncp_fsync(struct inode *inode, struct file *file) +static int ncp_fsync(struct file *file, struct dentry *dentry) { return 0; } diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c index 269d3ef07..5dfdeb27f 100644 --- a/fs/ncpfs/mmap.c +++ b/fs/ncpfs/mmap.c @@ -116,8 +116,10 @@ struct vm_operations_struct ncp_file_mmap = /* This is used for a general mmap of a ncp file */ -int ncp_mmap(struct inode *inode, struct file *file, struct vm_area_struct *vma) +int ncp_mmap(struct file *file, struct vm_area_struct *vma) { + struct inode *inode = file->f_dentry->d_inode; + DPRINTK("ncp_mmap: called\n"); if (!ncp_conn_valid(NCP_SERVER(inode))) { diff --git a/fs/nfs/file.c b/fs/nfs/file.c index eb4735a6d..4587950ef 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -32,13 +32,12 @@ #define NFSDBG_FACILITY NFSDBG_FILE -static int nfs_file_mmap(struct inode *, struct file *, - struct vm_area_struct *); +static int nfs_file_mmap(struct file *, struct vm_area_struct *); static long nfs_file_read(struct inode *, struct file *, char *, unsigned long); static long nfs_file_write(struct inode *, struct file *, const char *, unsigned long); static int nfs_file_close(struct inode *, struct file *); -static int nfs_fsync(struct inode *, struct file *); +static int nfs_fsync(struct file *, struct dentry *dentry); static struct file_operations nfs_file_operations = { NULL, /* lseek - default */ @@ -114,20 +113,21 @@ nfs_file_read(struct inode * inode, struct file * file, } static int -nfs_file_mmap(struct inode * inode, struct file * file, - struct vm_area_struct * vma) +nfs_file_mmap(struct file * file, struct vm_area_struct * vma) { int status; + struct inode *inode = file->f_dentry->d_inode; dfprintk(VFS, "nfs: mmap(%x/%ld)\n", inode->i_dev, inode->i_ino); if ((status = nfs_revalidate_inode(NFS_SERVER(inode), inode)) < 0) return status; - return generic_file_mmap(inode, file, vma); + return generic_file_mmap(file, vma); } -static int nfs_fsync(struct inode *inode, struct file *file) +static int nfs_fsync(struct file *file, struct dentry *dentry) { + struct inode *inode = dentry->d_inode; dfprintk(VFS, "nfs: fsync(%x/%ld)\n", inode->i_dev, inode->i_ino); return nfs_flush_dirty_pages(inode, 0, 0); @@ -175,9 +175,10 @@ nfs_file_write(struct inode *inode, struct file *file, * Lock a (portion of) a file */ int -nfs_lock(struct inode *inode, struct file *filp, int cmd, struct file_lock *fl) +nfs_lock(struct file *filp, int cmd, struct file_lock *fl) { int status; + struct inode * inode; dprintk("NFS: nfs_lock(f=%4x/%ld, t=%x, fl=%x, r=%ld:%ld)\n", filp->f_dentry->d_inode->i_dev, filp->f_dentry->d_inode->i_ino, diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 449fc0d4e..ec5a1f7be 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -56,6 +56,16 @@ #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; } /* diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index dbbfbc78f..df6eb0e2c 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -294,7 +294,7 @@ nfsd_close(struct file *filp) void nfsd_sync(struct inode *inode, struct file *filp) { - filp->f_op->fsync(inode, filp); + filp->f_op->fsync(filp, filp->f_dentry); } /* @@ -928,7 +928,8 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, file.f_inode->i_dev, file.f_inode->i_ino, (int) file.f_pos, (int) oldlen, (int) cd.buflen); */ - err = file.f_op->readdir(&file, &cd, (filldir_t) func); + err = file.f_op->readdir(&file, + &cd, (filldir_t) func); if (err < 0) { nfsd_close(&file); @@ -717,7 +717,7 @@ int __fput(struct file *filp) struct inode * inode = dentry->d_inode; if (filp->f_op && filp->f_op->release) - error = filp->f_op->release(inode,filp); + error = filp->f_op->release(inode, filp); filp->f_dentry = NULL; if (filp->f_mode & FMODE_WRITE) put_write_access(inode); @@ -133,8 +133,7 @@ static long pipe_write(struct inode * inode, struct file * filp, return written; } -static long long pipe_lseek(struct inode * inode, struct file * file, - long long offset, int orig) +static long long pipe_lseek(struct file * file, long long offset, int orig) { return -ESPIPE; } diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 358060020..83139f492 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -20,8 +20,7 @@ static long proc_file_read(struct inode * inode, struct file * file, char * buf, unsigned long nbytes); static long proc_file_write(struct inode * inode, struct file * file, const char * buffer, unsigned long count); -static long long proc_file_lseek(struct inode * inode, struct file * file, - long long offset, int orig); +static long long proc_file_lseek(struct file * file, long long offset, int orig); int proc_match(int len, const char *name,struct proc_dir_entry * de) { @@ -190,8 +189,7 @@ proc_file_write(struct inode * inode, struct file * file, } -static long long proc_file_lseek(struct inode * inode, struct file * file, - long long offset, int orig) +static long long proc_file_lseek(struct file * file, long long offset, int orig) { switch (orig) { case 0: diff --git a/fs/proc/mem.c b/fs/proc/mem.c index 97acb5ee8..126683ea4 100644 --- a/fs/proc/mem.c +++ b/fs/proc/mem.c @@ -187,8 +187,7 @@ static long mem_write(struct inode * inode, struct file * file, #endif -static long long mem_lseek(struct inode * inode, struct file * file, - long long offset, int orig) +static long long mem_lseek(struct file * file, long long offset, int orig) { switch (orig) { case 0: @@ -205,8 +204,7 @@ static long long mem_lseek(struct inode * inode, struct file * file, /* * This isn't really reliable by any means.. */ -int mem_mmap(struct inode * inode, struct file * file, - struct vm_area_struct * vma) +int mem_mmap(struct file * file, struct vm_area_struct * vma) { struct task_struct *tsk; pgd_t *src_dir, *dest_dir; @@ -214,7 +212,8 @@ int mem_mmap(struct inode * inode, struct file * file, pte_t *src_table, *dest_table; unsigned long stmp, dtmp; struct vm_area_struct *src_vma = NULL; - + struct inode *inode = file->f_dentry->d_inode; + /* Get the source's task information */ tsk = get_task(inode->i_ino >> 16); diff --git a/fs/proc/scsi.c b/fs/proc/scsi.c index b1e77398c..831a2623d 100644 --- a/fs/proc/scsi.c +++ b/fs/proc/scsi.c @@ -33,7 +33,7 @@ static long proc_readscsi(struct inode * inode, struct file * file, char * buf, unsigned long count); static long proc_writescsi(struct inode * inode, struct file * file, const char * buf, unsigned long count); -static long long proc_scsilseek(struct inode *, struct file *, long long, int); +static long long proc_scsilseek(struct file *, long long, int); extern void build_proc_dir_hba_entries(uint); @@ -177,8 +177,7 @@ static long proc_writescsi(struct inode * inode, struct file * file, } -static long long proc_scsilseek(struct inode * inode, struct file * file, - long long offset, int orig) +static long long proc_scsilseek(struct file * file, long long offset, int orig) { switch (orig) { case 0: diff --git a/fs/read_write.c b/fs/read_write.c index 6d31c7af0..df3d34d3e 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -19,16 +19,13 @@ #include <asm/uaccess.h> -static long long default_llseek(struct inode *inode, - struct file *file, - long long offset, - int origin) +static long long default_llseek(struct file *file, long long offset, int origin) { long long retval; switch (origin) { case 2: - offset += inode->i_size; + offset += file->f_dentry->d_inode->i_size; break; case 1: offset += file->f_pos; @@ -45,15 +42,14 @@ static long long default_llseek(struct inode *inode, return retval; } -static inline long long llseek(struct inode * inode, struct file *file, - long long offset, unsigned int origin) +static inline long long llseek(struct file *file, long long offset, unsigned int origin) { - long long (*fn)(struct inode *, struct file *, long long, int); + long long (*fn)(struct file *, long long, int); fn = default_llseek; if (file->f_op && file->f_op->llseek) fn = file->f_op->llseek; - return fn(inode, file, offset, origin); + return fn(file, offset, origin); } asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int origin) @@ -73,7 +69,7 @@ asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int origin) retval = -EINVAL; if (origin > 2) goto bad; - retval = llseek(inode, file, offset, origin); + retval = llseek(file, offset, origin); bad: unlock_kernel(); return retval; @@ -100,8 +96,7 @@ asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high, if (origin > 2) goto bad; - offset = llseek(inode, file, - (((unsigned long long) offset_high << 32) | offset_low), + offset = llseek(file, (((unsigned long long) offset_high << 32) | offset_low), origin); retval = offset; diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c index 2b0c4d1e2..3196e9009 100644 --- a/fs/smbfs/dir.c +++ b/fs/smbfs/dir.c @@ -19,6 +19,12 @@ #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; } diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c index 33fe1778f..9653a7be6 100644 --- a/fs/smbfs/file.c +++ b/fs/smbfs/file.c @@ -19,6 +19,10 @@ #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) { @@ -26,8 +30,10 @@ min(int a, int b) } static int -smb_fsync(struct inode *inode, struct file *file) +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; } @@ -39,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; @@ -46,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; @@ -81,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; } @@ -123,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; @@ -135,6 +161,7 @@ io_error: smb_refresh_inode(inode); clear_bit(PG_locked, &page->flags); + wake_up(&page->wait); return written ? written : result; } @@ -145,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 @@ -153,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 @@ -175,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 inode * inode, struct file * file, - struct vm_area_struct * vma) +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; status = smb_revalidate_inode(inode); - if (status < 0) - return status; - - return generic_file_mmap(inode, file, vma); + if (status >= 0) + { + status = generic_file_mmap(file, vma); + } + return status; } /* @@ -207,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 = diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index edea04905..9203650e2 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -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 *); @@ -82,6 +85,23 @@ smb_iget(struct super_block *sb, struct smb_fattr *fattr) } 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) { pr_debug("smb_iget: %p\n", read_fattr); @@ -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; diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c index 311457a74..57b4be6fb 100644 --- a/fs/smbfs/proc.c +++ b/fs/smbfs/proc.c @@ -29,7 +29,12 @@ #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) @@ -79,6 +84,15 @@ smb_encode_smb_length(__u8 * p, __u32 len) return p + 4; } +/* + * 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) +{ + return &dentry->d_sb->u.smbfs_sb; +} + static int smb_d_path(struct dentry * entry, char * buf) { if (IS_ROOT(entry)) { @@ -283,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) @@ -301,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) @@ -322,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; } @@ -349,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; @@ -371,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 @@ -503,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; @@ -532,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 */ @@ -545,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) @@ -586,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; } @@ -600,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; } @@ -633,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 @@ -697,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); @@ -719,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: @@ -761,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: @@ -787,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: @@ -813,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: @@ -882,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; } @@ -982,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); @@ -1098,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)); @@ -1105,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); } @@ -1135,6 +1235,7 @@ smb_decode_long_dirent(struct smb_sb_info *server, char *p, } smb_finish_dirent(server, &(entry->attr)); + return result; } @@ -1148,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; @@ -1168,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]); @@ -1197,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) @@ -1243,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) { @@ -1278,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; } } @@ -1320,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", @@ -1342,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); @@ -1353,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); @@ -1373,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; @@ -1412,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), @@ -1440,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); @@ -1546,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; @@ -1560,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); @@ -1573,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 diff --git a/fs/smbfs/sock.c b/fs/smbfs/sock.c index 1687be10b..aceca122b 100644 --- a/fs/smbfs/sock.c +++ b/fs/smbfs/sock.c @@ -24,10 +24,13 @@ #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; } diff --git a/fs/sysv/fsync.c b/fs/sysv/fsync.c index df3b948df..96b0649a4 100644 --- a/fs/sysv/fsync.c +++ b/fs/sysv/fsync.c @@ -178,9 +178,10 @@ static int sync_tindirect(struct inode *inode, unsigned long *tiblockp, int conv return err; } -int sysv_sync_file(struct inode * inode, struct file * file) +int sysv_sync_file(struct file * file, struct dentry *dentry) { int wait, err = 0; + struct inode *inode = dentry->d_inode; if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) diff --git a/include/linux/atalk.h b/include/linux/atalk.h index 70e691251..051e03484 100644 --- a/include/linux/atalk.h +++ b/include/linux/atalk.h @@ -16,6 +16,7 @@ #define ATADDR_ANYPORT (__u8)0 #define ATADDR_BCAST (__u8)255 #define DDP_MAXSZ 587 +#define DDP_MAXHOPS 15 /* 4 bits of hop counter */ #define SIOCATALKDIFADDR (SIOCPROTOPRIVATE + 0) @@ -70,8 +71,6 @@ struct atalk_sock unsigned char src_port; }; -#define DDP_MAXHOPS 15 /* 4 bits of hop counter */ - #ifdef __KERNEL__ #include <asm/byteorder.h> @@ -154,11 +153,14 @@ extern __inline__ struct atalk_iface *atalk_find_dev(struct device *dev) } extern struct at_addr *atalk_find_dev_addr(struct device *dev); +extern struct device *atrtr_get_dev(struct at_addr *sa); extern int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, void *hwaddr); extern void aarp_send_probe(struct device *dev, struct at_addr *addr); + #ifdef MODULE +extern void aarp_device_down(struct device *dev); extern void aarp_cleanup_module(void); -#endif +#endif /* MODULE */ -#endif -#endif +#endif /* __KERNEL__ */ +#endif /* __LINUX_ATALK_H__ */ diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 2735f37ea..ebdf22bfc 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -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 { @@ -102,9 +103,11 @@ extern void d_delete(struct dentry *); /* allocate/de-allocate */ extern struct dentry * d_alloc(struct dentry * parent, const struct qstr *name); -extern void shrink_dcache(void); +extern void prune_dcache(int); extern int d_invalidate(struct dentry *); +#define shrink_dcache() prune_dcache(0) + /* only used at mount-time */ extern struct dentry * d_alloc_root(struct inode * root_inode, struct dentry * old_root); diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h index 2831b1850..604548798 100644 --- a/include/linux/ext2_fs.h +++ b/include/linux/ext2_fs.h @@ -465,7 +465,7 @@ extern int ext2_read (struct inode *, struct file *, char *, int); extern int ext2_write (struct inode *, struct file *, char *, int); /* fsync.c */ -extern int ext2_sync_file (struct inode *, struct file *); +extern int ext2_sync_file (struct file *, struct dentry *); /* ialloc.c */ extern struct inode * ext2_new_inode (const struct inode *, int, int *); diff --git a/include/linux/fs.h b/include/linux/fs.h index 8380d0a67..fb47b00da 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -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. @@ -369,6 +369,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; @@ -377,9 +382,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; @@ -471,7 +474,7 @@ struct fasync_struct { #define FASYNC_MAGIC 0x4601 -extern int fasync_helper(struct inode *, struct file *, int, struct fasync_struct **); +extern int fasync_helper(struct file *, int, struct fasync_struct **); #include <linux/minix_fs_sb.h> #include <linux/ext2_fs_sb.h> @@ -533,20 +536,20 @@ struct super_block { typedef int (*filldir_t)(void *, const char *, int, off_t, ino_t); struct file_operations { - long long (*llseek) (struct inode *, struct file *, long long, int); + long long (*llseek) (struct file *, long long, int); long (*read) (struct inode *, struct file *, char *, unsigned long); long (*write) (struct inode *, struct file *, const char *, unsigned long); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, poll_table *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); - int (*mmap) (struct inode *, struct file *, struct vm_area_struct *); + int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*release) (struct inode *, struct file *); - int (*fsync) (struct inode *, struct file *); - int (*fasync) (struct inode *, struct file *, int); + int (*fsync) (struct file *, struct dentry *); + int (*fasync) (struct file *, int); int (*check_media_change) (kdev_t dev); int (*revalidate) (kdev_t dev); - int (*lock) (struct inode *, struct file *, int, struct file_lock *); + int (*lock) (struct file *, int, struct file_lock *); }; struct inode_operations { @@ -787,7 +790,7 @@ extern struct buffer_head * breada(kdev_t dev,int block, int size, extern int brw_page(int, struct page *, kdev_t, int [], int, int); extern int generic_readpage(struct inode *, struct page *); -extern int generic_file_mmap(struct inode *, struct file *, struct vm_area_struct *); +extern int generic_file_mmap(struct file *, struct vm_area_struct *); extern long generic_file_read(struct inode *, struct file *, char *, unsigned long); extern long generic_file_write(struct inode *, struct file *, const char *, unsigned long); @@ -812,8 +815,8 @@ extern int read_ahead[]; extern long char_write(struct inode *, struct file *, const char *, unsigned long); extern long block_write(struct inode *, struct file *, const char *, unsigned long); -extern int block_fsync(struct inode *, struct file *); -extern int file_fsync(struct inode *, struct file *); +extern int block_fsync(struct file *, struct dentry *dir); +extern int file_fsync(struct file *, struct dentry *dir); extern void dcache_add(struct inode *, const char *, int, unsigned long); extern int dcache_lookup(struct inode *, const char *, int, unsigned long *); diff --git a/include/linux/minix_fs.h b/include/linux/minix_fs.h index 8c75cc3c5..a725bbe36 100644 --- a/include/linux/minix_fs.h +++ b/include/linux/minix_fs.h @@ -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; diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h index 2c7843ea7..08ab3506a 100644 --- a/include/linux/msdos_fs.h +++ b/include/linux/msdos_fs.h @@ -232,7 +232,7 @@ extern long fat_file_write(struct inode *, struct file *, const char *, unsigned extern void fat_truncate(struct inode *inode); /* mmap.c */ -extern int fat_mmap(struct inode *, struct file *, struct vm_area_struct *); +extern int fat_mmap(struct file *, struct vm_area_struct *); /* vfat.c */ diff --git a/include/linux/ncp_fs.h b/include/linux/ncp_fs.h index 846f9dcea..7fb97f9d5 100644 --- a/include/linux/ncp_fs.h +++ b/include/linux/ncp_fs.h @@ -150,7 +150,7 @@ void ncp_lock_server(struct ncp_server *server); void ncp_unlock_server(struct ncp_server *server); /* linux/fs/ncpfs/mmap.c */ -int ncp_mmap(struct inode *inode, struct file *file, struct vm_area_struct *vma); +int ncp_mmap(struct file *file, struct vm_area_struct *vma); #endif /* __KERNEL__ */ diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 94acfc5d6..9591046ca 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -169,8 +169,7 @@ extern int nfs_mmap(struct inode *inode, struct file *file, /* * linux/fs/nfs/locks.c */ -extern int nfs_lock(struct inode *inode, struct file *file, - int cmd, struct file_lock *fl); +extern int nfs_lock(struct file *file, int cmd, struct file_lock *fl); /* * linux/fs/nfs/write.c diff --git a/include/linux/smb_fs.h b/include/linux/smb_fs.h index be01f3048..e3e9ea98a 100644 --- a/include/linux/smb_fs.h +++ b/include/linux/smb_fs.h @@ -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) @@ -149,7 +149,7 @@ int smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command, int *lrparam, unsigned char **rparam); /* linux/fs/smbfs/mmap.c */ -int smb_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma); +int smb_mmap(struct file * file, struct vm_area_struct * vma); #endif /* __KERNEL__ */ diff --git a/include/linux/smb_fs_i.h b/include/linux/smb_fs_i.h index 743e3954a..73ea69a89 100644 --- a/include/linux/smb_fs_i.h +++ b/include/linux/smb_fs_i.h @@ -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 */ diff --git a/include/linux/smbno.h b/include/linux/smbno.h index 176e88c86..a1443646b 100644 --- a/include/linux/smbno.h +++ b/include/linux/smbno.h @@ -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 */ diff --git a/include/linux/sysv_fs.h b/include/linux/sysv_fs.h index 53ead0c99..93e4400ce 100644 --- a/include/linux/sysv_fs.h +++ b/include/linux/sysv_fs.h @@ -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; diff --git a/include/linux/tty_flip.h b/include/linux/tty_flip.h index 97316607b..948e54550 100644 --- a/include/linux/tty_flip.h +++ b/include/linux/tty_flip.h @@ -10,10 +10,11 @@ _INLINE_ void tty_insert_flip_char(struct tty_struct *tty, unsigned char ch, char flag) { - if (tty->flip.count++ >= TTY_FLIPBUF_SIZE) - return; - *tty->flip.flag_buf_ptr++ = flag; - *tty->flip.char_buf_ptr++ = ch; + if (tty->flip.count < TTY_FLIPBUF_SIZE) { + tty->flip.count++; + *tty->flip.flag_buf_ptr++ = flag; + *tty->flip.char_buf_ptr++ = ch; + } } _INLINE_ void tty_schedule_flip(struct tty_struct *tty) diff --git a/kernel/exit.c b/kernel/exit.c index 922449fc6..c99dc8b45 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -132,8 +132,9 @@ 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); diff --git a/mm/filemap.c b/mm/filemap.c index e6e4cd424..c02a31696 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1175,9 +1175,11 @@ static struct vm_operations_struct file_private_mmap = { }; /* This is used for a general mmap of a disk file */ -int generic_file_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma) + +int generic_file_mmap(struct file * file, struct vm_area_struct * vma) { struct vm_operations_struct * ops; + struct inode *inode = file->f_dentry->d_inode; if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) { ops = &file_shared_mmap; @@ -1213,11 +1215,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(vma->vm_dentry->d_inode, NULL); - 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; } @@ -296,7 +296,7 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len, } } if (!error) - error = file->f_op->mmap(file->f_dentry->d_inode, file, vma); + error = file->f_op->mmap(file, vma); if (error) { if (correct_wcount) diff --git a/net/Config.in b/net/Config.in index d9ec19354..f5a06935a 100644 --- a/net/Config.in +++ b/net/Config.in @@ -31,9 +31,6 @@ if [ "$CONFIG_IPX" != "n" ]; then fi fi tristate 'Appletalk DDP' CONFIG_ATALK -if [ "$CONFIG_ATALK" != "n" ]; then - bool 'IP-over-DDP support (EXPERIMENTAL)' CONFIG_IPDDP -fi tristate 'Amateur Radio AX.25 Level 2' CONFIG_AX25 if [ "$CONFIG_AX25" != "n" ]; then bool 'AX.25 DAMA Slave support' CONFIG_AX25_DAMA_SLAVE @@ -53,6 +50,6 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then # if [ "$CONFIG_LLC" = "y" ]; then # bool 'Netbeui (EXPERIMENTAL)' CONFIG_NETBEUI # fi - bool 'WAN router' CONFIG_WAN_ROUTER + tristate 'WAN router' CONFIG_WAN_ROUTER fi endmenu diff --git a/net/appletalk/Makefile b/net/appletalk/Makefile index 19379a44a..4adbc858c 100644 --- a/net/appletalk/Makefile +++ b/net/appletalk/Makefile @@ -1,5 +1,5 @@ # -# Makefile for the Linux TCP/IP (INET) layer. +# Makefile for the Linux AppleTalk layer. # # Note! Dependencies are done automagically by 'make dep', which also # removes any old dependencies. DON'T put your own dependencies here @@ -8,9 +8,11 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := appletalk.o -O_OBJS := aarp.o ddp.o +O_OBJS := aarp.o M_OBJS := $(O_TARGET) +OX_OBJS += ddp.o + ifeq ($(CONFIG_SYSCTL),y) O_OBJS += sysctl_net_atalk.o endif diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c index f8a510e62..2cb6f3888 100644 --- a/net/appletalk/aarp.c +++ b/net/appletalk/aarp.c @@ -22,7 +22,9 @@ * References: * Inside Appletalk (2nd Ed). */ - + +#include <linux/config.h> +#if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) #include <asm/uaccess.h> #include <asm/system.h> #include <asm/bitops.h> @@ -89,7 +91,6 @@ static struct timer_list aarp_timer; /* * Delete an aarp queue */ - static void aarp_expire(struct aarp_entry *a) { struct sk_buff *skb; @@ -403,10 +404,9 @@ static struct aarp_entry *aarp_alloc(void) } /* - * Find an entry. We might return an expired but not yet purged entry. We - * don't care as it will do no harm. + * Find an entry. We might return an expired but not yet purged entry. We + * don't care as it will do no harm. */ - static struct aarp_entry *aarp_find_entry(struct aarp_entry *list, struct device *dev, struct at_addr *sat) { unsigned long flags; @@ -426,7 +426,6 @@ static struct aarp_entry *aarp_find_entry(struct aarp_entry *list, struct device /* * Send a DDP frame */ - int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, void *hwaddr) { static char ddp_eth_multicast[ETH_ALEN]={ 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF }; @@ -620,7 +619,6 @@ int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, vo * An entry in the aarp unresolved queue has become resolved. Send * all the frames queued under it. */ - static void aarp_resolved(struct aarp_entry **list, struct aarp_entry *a, int hash) { struct sk_buff *skb; @@ -662,7 +660,6 @@ static void aarp_resolved(struct aarp_entry **list, struct aarp_entry *a, int ha * This is called by the SNAP driver whenever we see an AARP SNAP * frame. We currently only support ethernet. */ - static int aarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) { struct elapaarp *ea=(struct elapaarp *)skb->h.raw; @@ -833,39 +830,32 @@ __initfunc(void aarp_proto_init(void)) #ifdef MODULE -/* Free all the entries in an aarp list. Caller should turn off interrupts. */ -static void free_entry_list(struct aarp_entry *list) +/* + * Remove the AARP entries associated with a device. + * Called from cleanup_module() in ddp.c. + */ +void aarp_device_down(struct device *dev) { - struct aarp_entry *tmp; + int ct = 0; - while (list != NULL) + for(ct = 0; ct < AARP_HASH_SIZE; ct++) { - tmp = list->next; - aarp_expire(list); - list = tmp; + aarp_expire_device(&resolved[ct], dev); + aarp_expire_device(&unresolved[ct], dev); } + + return; } -/* General module cleanup. Called from cleanup_module() in ddp.c. */ +/* + * General module cleanup. Called from cleanup_module() in ddp.c. + */ void aarp_cleanup_module(void) { - unsigned long flags; - int i; - - save_flags(flags); - cli(); - del_timer(&aarp_timer); unregister_netdevice_notifier(&aarp_notifier); unregister_snap_client(aarp_snap_id); - - for (i = 0; i < AARP_HASH_SIZE; i++) - { - free_entry_list(resolved[i]); - free_entry_list(unresolved[i]); - } - - restore_flags(flags); } #endif /* MODULE */ +#endif /* CONFIG_ATALK || CONFIG_ATALK_MODULE */ diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index dc659d18f..5f070e903 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -25,6 +25,10 @@ * Alan Cox : Posix bits * Alan Cox/Mike Freeman : Possible fix to NBP problems * Bradford Johnson : IP-over-DDP (experimental) + * Jay Schulist : Moved IP-over-DDP to its own + * driver file. (ipddp.c & ipddp.h) + * Jay Schulist : Made work as module with + * Appletalk drivers, cleaned it. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -34,6 +38,7 @@ */ #include <linux/config.h> +#if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) #include <linux/module.h> #include <asm/uaccess.h> #include <asm/system.h> @@ -72,35 +77,34 @@ #undef APPLETALK_DEBUG - #ifdef APPLETALK_DEBUG #define DPRINT(x) print(x) #else #define DPRINT(x) -#endif +#endif /* APPLETALK_DEBUG */ #ifdef CONFIG_SYSCTL extern inline void atalk_register_sysctl(void); extern inline void atalk_unregister_sysctl(void); -#endif +#endif /* CONFIG_SYSCTL */ struct datalink_proto *ddp_dl, *aarp_dl; static struct proto_ops atalk_dgram_ops; #define min(a,b) (((a)<(b))?(a):(b)) -/***********************************************************************************************************************\ -* * -* Handlers for the socket list. * -* * -\***********************************************************************************************************************/ +/**************************************************************************\ +* * +* Handlers for the socket list. * +* * +\**************************************************************************/ -static struct sock *atalk_socket_list=NULL; +static struct sock *atalk_socket_list = NULL; /* - * Note: Sockets may not be removed _during_ an interrupt or inet_bh - * handler using this technique. They can be added although we do not - * use this facility. + * Note: Sockets may not be removed _during_ an interrupt or inet_bh + * handler using this technique. They can be added although we do not + * use this facility. */ extern inline void atalk_remove_socket(struct sock *sk) @@ -117,70 +121,73 @@ static struct sock *atalk_search_socket(struct sockaddr_at *to, struct atalk_ifa { struct sock *s; - for( s = atalk_socket_list; s != NULL; s = s->next ) + for(s = atalk_socket_list; s != NULL; s = s->next) { - if ( to->sat_port != s->protinfo.af_at.src_port ) + if(to->sat_port != s->protinfo.af_at.src_port) { continue; } - if ( to->sat_addr.s_net == 0 && - to->sat_addr.s_node == ATADDR_BCAST && - s->protinfo.af_at.src_net == atif->address.s_net ) + if(to->sat_addr.s_net == 0 + && to->sat_addr.s_node == ATADDR_BCAST + && s->protinfo.af_at.src_net == atif->address.s_net) { break; } - if ( to->sat_addr.s_net == s->protinfo.af_at.src_net && - (to->sat_addr.s_node == s->protinfo.af_at.src_node - ||to->sat_addr.s_node == ATADDR_BCAST - ||to->sat_addr.s_node == ATADDR_ANYNODE )) + if(to->sat_addr.s_net == s->protinfo.af_at.src_net + && (to->sat_addr.s_node == s->protinfo.af_at.src_node + || to->sat_addr.s_node == ATADDR_BCAST + || to->sat_addr.s_node == ATADDR_ANYNODE)) { break; } /* XXXX.0 */ } - return( s ); + + return (s); } /* - * Find a socket in the list. + * Find a socket in the list. */ - static struct sock *atalk_find_socket(struct sockaddr_at *sat) { struct sock *s; - for ( s = atalk_socket_list; s != NULL; s = s->next ) + for(s = atalk_socket_list; s != NULL; s = s->next) { - if ( s->protinfo.af_at.src_net != sat->sat_addr.s_net ) + if(s->protinfo.af_at.src_net != sat->sat_addr.s_net) { continue; } - if ( s->protinfo.af_at.src_node != sat->sat_addr.s_node ) + + if(s->protinfo.af_at.src_node != sat->sat_addr.s_node) { continue; } - if ( s->protinfo.af_at.src_port != sat->sat_port ) + + if(s->protinfo.af_at.src_port != sat->sat_port) { continue; } + break; } - return( s ); + + return (s); } extern inline void atalk_destroy_socket(struct sock *sk) { - sklist_destroy_socket(&atalk_socket_list,sk); + sklist_destroy_socket(&atalk_socket_list, sk); MOD_DEC_USE_COUNT; } /* - * Called from proc fs + * Called from proc fs */ - int atalk_get_info(char *buffer, char **start, off_t offset, int length, int dummy) { struct sock *s; @@ -189,76 +196,74 @@ int atalk_get_info(char *buffer, char **start, off_t offset, int length, int dum off_t begin=0; /* - * Output the appletalk data for the /proc virtual fs. + * Output the appletalk data for the /proc virtual fs. */ - len += sprintf (buffer,"Type local_addr remote_addr tx_queue rx_queue st uid\n"); - for (s = atalk_socket_list; s != NULL; s = s->next) + len += sprintf(buffer,"Type local_addr remote_addr tx_queue rx_queue st uid\n"); + for(s = atalk_socket_list; s != NULL; s = s->next) { - len += sprintf (buffer+len,"%02X ", s->type); - len += sprintf (buffer+len,"%04X:%02X:%02X ", + len += sprintf(buffer+len,"%02X ", s->type); + len += sprintf(buffer+len,"%04X:%02X:%02X ", ntohs(s->protinfo.af_at.src_net), s->protinfo.af_at.src_node, s->protinfo.af_at.src_port); - len += sprintf (buffer+len,"%04X:%02X:%02X ", + len += sprintf(buffer+len,"%04X:%02X:%02X ", ntohs(s->protinfo.af_at.dest_net), s->protinfo.af_at.dest_node, s->protinfo.af_at.dest_port); - len += sprintf (buffer+len,"%08X:%08X ", - atomic_read(&s->wmem_alloc), - atomic_read(&s->rmem_alloc)); - len += sprintf (buffer+len,"%02X %d\n", s->state, SOCK_INODE(s->socket)->i_uid); + len += sprintf(buffer+len,"%08X:%08X ", + atomic_read(&s->wmem_alloc), + atomic_read(&s->rmem_alloc)); + len += sprintf(buffer+len,"%02X %d\n", s->state, + SOCK_INODE(s->socket)->i_uid); /* Are we still dumping unwanted data then discard the record */ - pos=begin+len; + pos = begin + len; - if(pos<offset) + if(pos < offset) { - len=0; /* Keep dumping into the buffer start */ - begin=pos; + len = 0; /* Keep dumping into the buffer start */ + begin = pos; } - if(pos>offset+length) /* We have dumped enough */ + if(pos > offset + length) /* We have dumped enough */ break; } /* The data in question runs from begin to begin+len */ - *start=buffer+(offset-begin); /* Start of wanted data */ - len-=(offset-begin); /* Remove unwanted header data from length */ - if(len>length) - len=length; /* Remove unwanted tail data from length */ + *start = buffer + (offset - begin); /* Start of wanted data */ + len -= (offset - begin); /* Remove unwanted header data from length */ + if(len > length) + len = length; /* Remove unwanted tail data from length */ - return len; + return (len); } -/*******************************************************************************************************************\ -* * -* Routing tables for the Appletalk socket layer * -* * -\*******************************************************************************************************************/ - +/**************************************************************************\ +* * +* Routing tables for the Appletalk socket layer. * +* * +\**************************************************************************/ -static struct atalk_route *atalk_router_list=NULL; -static struct atalk_route atrtr_default; /* For probing devices or in a routerless network */ -static struct atalk_iface *atalk_iface_list=NULL; +static struct atalk_route *atalk_router_list = NULL; +static struct atalk_iface *atalk_iface_list = NULL; +static struct atalk_route atrtr_default; /* For probing devices or in a routerless network */ /* - * Appletalk interface control + * Appletalk interface control */ /* - * Drop a device. Doesn't drop any of its routes - that is the - * the callers problem. Called when we down the interface or - * delete the address. + * Drop a device. Doesn't drop any of its routes - that is the the callers + * problem. Called when we down the interface or delete the address. */ - static void atif_drop_device(struct device *dev) { struct atalk_iface **iface = &atalk_iface_list; struct atalk_iface *tmp; - while ((tmp = *iface) != NULL) + while((tmp = *iface) != NULL) { - if (tmp->dev == dev) + if(tmp->dev == dev) { *iface = tmp->next; kfree_s(tmp, sizeof(struct atalk_iface)); @@ -267,15 +272,19 @@ static void atif_drop_device(struct device *dev) else iface = &tmp->next; } + + MOD_DEC_USE_COUNT; } static struct atalk_iface *atif_add_device(struct device *dev, struct at_addr *sa) { - struct atalk_iface *iface=(struct atalk_iface *) - kmalloc(sizeof(*iface), GFP_KERNEL); + struct atalk_iface *iface = (struct atalk_iface *) + kmalloc(sizeof(*iface), GFP_KERNEL); unsigned long flags; + if(iface==NULL) - return NULL; + return (NULL); + iface->dev=dev; dev->atalk_ptr=iface; iface->address= *sa; @@ -285,13 +294,15 @@ static struct atalk_iface *atif_add_device(struct device *dev, struct at_addr *s iface->next=atalk_iface_list; atalk_iface_list=iface; restore_flags(flags); - return iface; + + MOD_INC_USE_COUNT; + + return (iface); } /* - * Perform phase 2 AARP probing on our tentative address. + * Perform phase 2 AARP probing on our tentative address. */ - static int atif_probe_device(struct atalk_iface *atif) { int ct; @@ -310,19 +321,20 @@ static int atif_probe_device(struct atalk_iface *atif) * addresses. This needs tidying up when someone does localtalk * drivers */ + if((atif->dev->type == ARPHRD_LOCALTLK || atif->dev->type == ARPHRD_PPP) && atif->dev->do_ioctl) { /* fake up the request and pass it down */ sa = (struct sockaddr_at*)&atreq.ifr_addr; sa->sat_addr.s_node = probe_node; - sa->sat_addr.s_net = probe_net; - if (!(err=atif->dev->do_ioctl(atif->dev,&atreq,SIOCSIFADDR))) + sa->sat_addr.s_net = probe_net; + if(!(err=atif->dev->do_ioctl(atif->dev,&atreq,SIOCSIFADDR))) { (void)atif->dev->do_ioctl(atif->dev,&atreq,SIOCGIFADDR); atif->address.s_net=htons(sa->sat_addr.s_net); atif->address.s_node=sa->sat_addr.s_node; - return 0; + return (0); } /* * If it didn't like our faked request then fail: @@ -330,190 +342,197 @@ static int atif_probe_device(struct atalk_iface *atif) * through. That needs us to fix all the devices up * properly. We can then also dump the localtalk test. */ - return err; + return (err); } /* - * Offset the network we start probing with. + * Offset the network we start probing with. */ - if(probe_net==ATADDR_ANYNET) + if(probe_net == ATADDR_ANYNET) { if(!netrange) - probe_net=ntohs(atif->nets.nr_firstnet); + probe_net = ntohs(atif->nets.nr_firstnet); else - probe_net=ntohs(atif->nets.nr_firstnet) + (jiffies%netrange); + probe_net = ntohs(atif->nets.nr_firstnet) + (jiffies%netrange); } if(probe_node == ATADDR_ANYNODE) probe_node = jiffies&0xFF; - /* - * Scan the networks. + * Scan the networks. */ - for(netct=0;netct<=netrange;netct++) + for(netct = 0; netct <= netrange; netct++) { /* - * Sweep the available nodes from a given start. + * Sweep the available nodes from a given start. */ - atif->address.s_net=htons(probe_net); - for(nodect=0;nodect<256;nodect++) + atif->address.s_net = htons(probe_net); + for(nodect = 0; nodect < 256; nodect++) { - atif->address.s_node=((nodect+probe_node)&0xFF); - if(atif->address.s_node>0&&atif->address.s_node<254) + atif->address.s_node = ((nodect+probe_node) & 0xFF); + if(atif->address.s_node > 0 && atif->address.s_node<254) { /* - * Probe a proposed address. + * Probe a proposed address. */ - for(ct=0;ct<AARP_RETRANSMIT_LIMIT;ct++) + for(ct = 0; ct < AARP_RETRANSMIT_LIMIT; ct++) { aarp_send_probe(atif->dev, &atif->address); /* - * Defer 1/10th + * Defer 1/10th */ current->timeout = jiffies + (HZ/10); current->state = TASK_INTERRUPTIBLE; schedule(); - if(atif->status&ATIF_PROBE_FAIL) + if(atif->status & ATIF_PROBE_FAIL) break; } - if(!(atif->status&ATIF_PROBE_FAIL)) - return 0; + if(!(atif->status & ATIF_PROBE_FAIL)) + return (0); } - atif->status&=~ATIF_PROBE_FAIL; + atif->status &= ~ATIF_PROBE_FAIL; } probe_net++; - if(probe_net>ntohs(atif->nets.nr_lastnet)) - probe_net=ntohs(atif->nets.nr_firstnet); + if(probe_net > ntohs(atif->nets.nr_lastnet)) + probe_net = ntohs(atif->nets.nr_firstnet); } - return -EADDRINUSE; /* Network is full... */ + + return (-EADDRINUSE); /* Network is full... */ } struct at_addr *atalk_find_dev_addr(struct device *dev) { struct atalk_iface *iface=dev->atalk_ptr; + if(iface) - return &iface->address; - return NULL; + return (&iface->address); + + return (NULL); } static struct at_addr *atalk_find_primary(void) { struct atalk_iface *iface; - struct atalk_iface *fiface; + struct atalk_iface *fiface = NULL; + /* - * Return a point-to-point interface only if - * there is no non-ptp interface available. + * Return a point-to-point interface only if + * there is no non-ptp interface available. */ - fiface=NULL; - for(iface=atalk_iface_list;iface!=NULL;iface=iface->next) + for(iface=atalk_iface_list; iface != NULL; iface=iface->next) { - if(!fiface && !(iface->dev->flags&IFF_LOOPBACK)) + if(!fiface && !(iface->dev->flags & IFF_LOOPBACK)) fiface=iface; - if(!(iface->dev->flags&(IFF_LOOPBACK|IFF_POINTOPOINT))) - return &iface->address; + if(!(iface->dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) + return (&iface->address); } - if (fiface) - return &fiface->address; - if ( atalk_iface_list != NULL ) - return &atalk_iface_list->address; + + if(fiface) + return (&fiface->address); + if(atalk_iface_list != NULL) + return (&atalk_iface_list->address); else - return NULL; + return (NULL); } /* - * Find a match for 'any network' - ie any of our interfaces with that - * node number will do just nicely. + * Find a match for 'any network' - ie any of our interfaces with that + * node number will do just nicely. */ - static struct atalk_iface *atalk_find_anynet(int node, struct device *dev) { struct atalk_iface *iface=dev->atalk_ptr; - if (iface==NULL || ( iface->status & ATIF_PROBE )) - return NULL; - if ( node == ATADDR_BCAST || iface->address.s_node == node || node == ATADDR_ANYNODE) - return iface; - return NULL; + + if(iface==NULL || (iface->status & ATIF_PROBE)) + return (NULL); + if(node == ATADDR_BCAST || iface->address.s_node == node + || node == ATADDR_ANYNODE) + return (iface); + + return (NULL); } /* - * Find a match for a specific network:node pair + * Find a match for a specific network:node pair */ - static struct atalk_iface *atalk_find_interface(int net, int node) { struct atalk_iface *iface; - for(iface=atalk_iface_list;iface!=NULL;iface=iface->next) + + for(iface=atalk_iface_list; iface != NULL; iface=iface->next) { if((node==ATADDR_BCAST || node==ATADDR_ANYNODE || iface->address.s_node==node) && iface->address.s_net==net - && !(iface->status&ATIF_PROBE)) - return iface; + && !(iface->status & ATIF_PROBE)) + return (iface); } - return NULL; + + return (NULL); } /* - * Find a route for an appletalk packet. This ought to get cached in - * the socket (later on...). We know about host routes and the fact - * that a route must be direct to broadcast. + * Find a route for an appletalk packet. This ought to get cached in + * the socket (later on...). We know about host routes and the fact + * that a route must be direct to broadcast. */ - static struct atalk_route *atrtr_find(struct at_addr *target) { struct atalk_route *r; - for(r=atalk_router_list;r!=NULL;r=r->next) + + for(r=atalk_router_list; r != NULL; r=r->next) { - if(!(r->flags&RTF_UP)) + if(!(r->flags & RTF_UP)) continue; - if(r->target.s_net==target->s_net) + if(r->target.s_net == target->s_net) { - if(!(r->flags&RTF_HOST) || r->target.s_node==target->s_node) - return r; + if(!(r->flags&RTF_HOST) + || r->target.s_node == target->s_node) + return (r); } } + if(atrtr_default.dev) - return &atrtr_default; - return NULL; + return (&atrtr_default); + + return (NULL); } /* - * Given an appletalk network find the device to use. This can be - * a simple lookup. + * Given an appletalk network find the device to use. This can be + * a simple lookup. */ - -static struct device *atrtr_get_dev(struct at_addr *sa) +struct device *atrtr_get_dev(struct at_addr *sa) { struct atalk_route *atr=atrtr_find(sa); - if(atr==NULL) - return NULL; + + if(atr == NULL) + return (NULL); else - return atr->dev; + return (atr->dev); } /* - * Set up a default router. + * Set up a default router. */ - static void atrtr_set_default(struct device *dev) { - atrtr_default.dev=dev; - atrtr_default.flags= RTF_UP; - atrtr_default.gateway.s_net=htons(0); - atrtr_default.gateway.s_node=0; + atrtr_default.dev = dev; + atrtr_default.flags = RTF_UP; + atrtr_default.gateway.s_net = htons(0); + atrtr_default.gateway.s_node = 0; } /* - * Add a router. Basically make sure it looks valid and stuff the - * entry in the list. While it uses netranges we always set them to one - * entry to work like netatalk. + * Add a router. Basically make sure it looks valid and stuff the + * entry in the list. While it uses netranges we always set them to one + * entry to work like netatalk. */ - static int atrtr_create(struct rtentry *r, struct device *devhint) { struct sockaddr_at *ta=(struct sockaddr_at *)&r->rt_dst; @@ -525,113 +544,113 @@ static int atrtr_create(struct rtentry *r, struct device *devhint) save_flags(flags); /* - * Fixme: Raise/Lower a routing change semaphore for these - * operations. + * Fixme: Raise/Lower a routing change semaphore for these + * operations. */ /* - * Validate the request + * Validate the request */ - if(ta->sat_family!=AF_APPLETALK) - return -EINVAL; + if(ta->sat_family != AF_APPLETALK) + return (-EINVAL); if(devhint == NULL && ga->sat_family != AF_APPLETALK) - return -EINVAL; + return (-EINVAL); /* - * Now walk the routing table and make our decisions + * Now walk the routing table and make our decisions. */ - - for(rt=atalk_router_list;rt!=NULL;rt=rt->next) + for(rt=atalk_router_list; rt!=NULL; rt=rt->next) { if(r->rt_flags != rt->flags) continue; if(ta->sat_addr.s_net == rt->target.s_net) { - if(!(rt->flags&RTF_HOST)) + if(!(rt->flags & RTF_HOST)) break; if(ta->sat_addr.s_node == rt->target.s_node) break; } } - if ( devhint == NULL ) + if(devhint == NULL) { - for ( riface = NULL, iface = atalk_iface_list; iface; iface = iface->next ) + for(riface = NULL, iface = atalk_iface_list; iface; iface = iface->next) { - if ( riface == NULL && ntohs( ga->sat_addr.s_net ) >= ntohs( iface->nets.nr_firstnet ) && - ntohs( ga->sat_addr.s_net ) <= ntohs( iface->nets.nr_lastnet )) + if(riface == NULL && ntohs(ga->sat_addr.s_net) >= ntohs(iface->nets.nr_firstnet) && + ntohs(ga->sat_addr.s_net) <= ntohs(iface->nets.nr_lastnet)) { riface = iface; } - if ( ga->sat_addr.s_net == iface->address.s_net && ga->sat_addr.s_node == iface->address.s_node ) + if(ga->sat_addr.s_net == iface->address.s_net + && ga->sat_addr.s_node == iface->address.s_node) riface = iface; } - if ( riface == NULL ) - return -ENETUNREACH; + + if(riface == NULL) + return (-ENETUNREACH); devhint = riface->dev; } - if(rt==NULL) + if(rt == NULL) { - rt=(struct atalk_route *)kmalloc(sizeof(struct atalk_route), GFP_KERNEL); - if(rt==NULL) - return -ENOBUFS; + rt = (struct atalk_route *)kmalloc(sizeof(struct atalk_route), GFP_KERNEL); + if(rt == NULL) + return (-ENOBUFS); cli(); - rt->next=atalk_router_list; - atalk_router_list=rt; + rt->next = atalk_router_list; + atalk_router_list = rt; } /* - * Fill in the entry. + * Fill in the routing entry. */ - rt->target=ta->sat_addr; - rt->dev=devhint; - rt->flags=r->rt_flags; - rt->gateway=ga->sat_addr; + rt->target = ta->sat_addr; + rt->dev = devhint; + rt->flags = r->rt_flags; + rt->gateway = ga->sat_addr; restore_flags(flags); - return 0; -} + return (0); +} /* - * Delete a route. Find it and discard it. + * Delete a route. Find it and discard it. */ - static int atrtr_delete( struct at_addr *addr ) { struct atalk_route **r = &atalk_router_list; struct atalk_route *tmp; - while ((tmp = *r) != NULL) + while((tmp = *r) != NULL) { - if (tmp->target.s_net == addr->s_net && - (!(tmp->flags&RTF_GATEWAY) || - tmp->target.s_node == addr->s_node )) + if(tmp->target.s_net == addr->s_net + && (!(tmp->flags&RTF_GATEWAY) + || tmp->target.s_node == addr->s_node)) { *r = tmp->next; kfree_s(tmp, sizeof(struct atalk_route)); - return 0; + return (0); } r = &tmp->next; } - return -ENOENT; + + return (-ENOENT); } /* - * Called when a device is downed. Just throw away any routes - * via it. + * Called when a device is downed. Just throw away any routes + * via it. */ - void atrtr_device_down(struct device *dev) { struct atalk_route **r = &atalk_router_list; struct atalk_route *tmp; - while ((tmp = *r) != NULL) + while((tmp = *r) != NULL) { - if (tmp->dev == dev) + if(tmp->dev == dev) { *r = tmp->next; kfree_s(tmp, sizeof(struct atalk_route)); @@ -639,53 +658,51 @@ void atrtr_device_down(struct device *dev) else r = &tmp->next; } - if(atrtr_default.dev==dev) + + if(atrtr_default.dev == dev) atrtr_set_default(NULL); } /* - * A device event has occurred. Watch for devices going down and - * delete our use of them (iface and route). + * A device event has occurred. Watch for devices going down and + * delete our use of them (iface and route). */ - static int ddp_device_event(struct notifier_block *this, unsigned long event, void *ptr) { - if(event==NETDEV_DOWN) + if(event == NETDEV_DOWN) { /* Discard any use of this */ atrtr_device_down((struct device *)ptr); atif_drop_device((struct device *)ptr); } - return NOTIFY_DONE; + + return (NOTIFY_DONE); } /* - * ioctl calls. Shouldn't even need touching. + * ioctl calls. Shouldn't even need touching. */ /* - * Device configuration ioctl calls. + * Device configuration ioctl calls. */ - int atif_ioctl(int cmd, void *arg) { struct ifreq atreq; - static char aarp_mcast[6]={0x09,0x00,0x00,0xFF,0xFF,0xFF}; + static char aarp_mcast[6] = {0x09, 0x00, 0x00, 0xFF, 0xFF, 0xFF}; struct netrange *nr; struct sockaddr_at *sa; struct device *dev; struct atalk_iface *atif; - int err; int ct; int limit; struct rtentry rtdef; - err = copy_from_user(&atreq,arg,sizeof(atreq)); - if (err) - return -EFAULT; + if(copy_from_user(&atreq,arg,sizeof(atreq))) + return (-EFAULT); - if((dev=dev_get(atreq.ifr_name))==NULL) - return -ENODEV; + if((dev = dev_get(atreq.ifr_name)) == NULL) + return (-ENODEV); sa=(struct sockaddr_at*)&atreq.ifr_addr; atif=atalk_find_dev(dev); @@ -694,149 +711,154 @@ int atif_ioctl(int cmd, void *arg) { case SIOCSIFADDR: if(!suser()) - return -EPERM; - if(sa->sat_family!=AF_APPLETALK) - return -EINVAL; - if(dev->type!=ARPHRD_ETHER&&dev->type!=ARPHRD_LOOPBACK - &&dev->type!=ARPHRD_LOCALTLK && dev->type!=ARPHRD_PPP) - return -EPROTONOSUPPORT; + return (-EPERM); + if(sa->sat_family != AF_APPLETALK) + return (-EINVAL); + if(dev->type != ARPHRD_ETHER + && dev->type != ARPHRD_LOOPBACK + && dev->type != ARPHRD_LOCALTLK + && dev->type != ARPHRD_PPP) + return (-EPROTONOSUPPORT); + nr=(struct netrange *)&sa->sat_zero[0]; + /* - * Phase 1 is fine on localtalk but we don't - * do Ethertalk phase 1. Anyone wanting to add - * it go ahead. + * Phase 1 is fine on Localtalk but we don't do + * Ethertalk phase 1. Anyone wanting to add it go ahead. */ - if(dev->type==ARPHRD_ETHER && nr->nr_phase!=2) - return -EPROTONOSUPPORT; - if(sa->sat_addr.s_node==ATADDR_BCAST || sa->sat_addr.s_node == 254) - return -EINVAL; + if(dev->type == ARPHRD_ETHER && nr->nr_phase != 2) + return (-EPROTONOSUPPORT); + if(sa->sat_addr.s_node == ATADDR_BCAST + || sa->sat_addr.s_node == 254) + return (-EINVAL); if(atif) { /* - * Already setting address. + * Already setting address. */ if(atif->status&ATIF_PROBE) - return -EBUSY; + return (-EBUSY); - atif->address.s_net=sa->sat_addr.s_net; - atif->address.s_node=sa->sat_addr.s_node; + atif->address.s_net = sa->sat_addr.s_net; + atif->address.s_node = sa->sat_addr.s_node; atrtr_device_down(dev); /* Flush old routes */ } else { atif=atif_add_device(dev, &sa->sat_addr); if (atif == NULL) - return -ENOMEM; + return (-ENOMEM); } atif->nets= *nr; /* - * Check if the chosen address is used. If so we - * error and atalkd will try another. + * Check if the chosen address is used. If so we + * error and atalkd will try another. */ - if(!(dev->flags&IFF_LOOPBACK) && atif_probe_device(atif)<0) + if(!(dev->flags & IFF_LOOPBACK) && atif_probe_device(atif) < 0) { atif_drop_device(dev); - return -EADDRINUSE; + return (-EADDRINUSE); } /* - * Hey it worked - add the direct - * routes. + * Hey it worked - add the direct routes. */ - sa=(struct sockaddr_at *)&rtdef.rt_gateway; - sa->sat_family=AF_APPLETALK; - sa->sat_addr.s_net=atif->address.s_net; - sa->sat_addr.s_node=atif->address.s_node; - sa=(struct sockaddr_at *)&rtdef.rt_dst; - rtdef.rt_flags=RTF_UP; - sa->sat_family=AF_APPLETALK; - sa->sat_addr.s_node=ATADDR_ANYNODE; - if(dev->flags&IFF_LOOPBACK) - rtdef.rt_flags|=RTF_HOST; + sa = (struct sockaddr_at *)&rtdef.rt_gateway; + sa->sat_family = AF_APPLETALK; + sa->sat_addr.s_net = atif->address.s_net; + sa->sat_addr.s_node = atif->address.s_node; + sa = (struct sockaddr_at *)&rtdef.rt_dst; + rtdef.rt_flags = RTF_UP; + sa->sat_family = AF_APPLETALK; + sa->sat_addr.s_node = ATADDR_ANYNODE; + if(dev->flags & IFF_LOOPBACK) + rtdef.rt_flags |= RTF_HOST; + /* - * Routerless initial state. + * Routerless initial state. */ - if(nr->nr_firstnet==htons(0) && nr->nr_lastnet==htons(0xFFFE)) + if(nr->nr_firstnet == htons(0) + && nr->nr_lastnet == htons(0xFFFE)) { - sa->sat_addr.s_net=atif->address.s_net; + sa->sat_addr.s_net = atif->address.s_net; atrtr_create(&rtdef, dev); atrtr_set_default(dev); } else { - limit=ntohs(nr->nr_lastnet); - if(limit-ntohs(nr->nr_firstnet) > 256) + limit = ntohs(nr->nr_lastnet); + if(limit - ntohs(nr->nr_firstnet) > 256) { printk(KERN_WARNING "Too many routes/iface.\n"); - return -EINVAL; + return (-EINVAL); } for(ct=ntohs(nr->nr_firstnet);ct<=limit;ct++) { - sa->sat_addr.s_net=htons(ct); + sa->sat_addr.s_net = htons(ct); atrtr_create(&rtdef, dev); } } dev_mc_add(dev, aarp_mcast, 6, 1); - return 0; + return (0); + case SIOCGIFADDR: - if(atif==NULL) - return -EADDRNOTAVAIL; + if(atif == NULL) + return (-EADDRNOTAVAIL); ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_family=AF_APPLETALK; ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr=atif->address; break; + case SIOCGIFBRDADDR: - if(atif==NULL) - return -EADDRNOTAVAIL; + if(atif == NULL) + return (-EADDRNOTAVAIL); ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_family=AF_APPLETALK; ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr.s_net=atif->address.s_net; ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr.s_node=ATADDR_BCAST; break; + case SIOCATALKDIFADDR: if(!suser()) - return -EPERM; - if(sa->sat_family!=AF_APPLETALK) - return -EINVAL; - if(atif==NULL) - return -EADDRNOTAVAIL; + return (-EPERM); + if(sa->sat_family != AF_APPLETALK) + return (-EINVAL); + if(atif == NULL) + return (-EADDRNOTAVAIL); atrtr_device_down(atif->dev); atif_drop_device(atif->dev); break; } - err = copy_to_user(arg,&atreq,sizeof(atreq)); - if (err) - { - err = -EFAULT; - } - return err; + if(copy_to_user(arg, &atreq, sizeof(atreq))) + return (-EFAULT); + + return (0); } /* - * Routing ioctl() calls + * Routing ioctl() calls */ - static int atrtr_ioctl(unsigned int cmd, void *arg) { - int err; struct rtentry rt; - err = copy_from_user(&rt,arg,sizeof(rt)); - if (err) - return -EFAULT; + if(copy_from_user(&rt, arg, sizeof(rt))) + return (-EFAULT); switch(cmd) { case SIOCDELRT: - if(rt.rt_dst.sa_family!=AF_APPLETALK) - return -EINVAL; - return atrtr_delete(&((struct sockaddr_at *)&rt.rt_dst)->sat_addr); + if(rt.rt_dst.sa_family != AF_APPLETALK) + return (-EINVAL); + return (atrtr_delete(&((struct sockaddr_at *)&rt.rt_dst)->sat_addr)); + case SIOCADDRT: - return atrtr_create(&rt, NULL); + return (atrtr_create(&rt, NULL)); + default: - return -EINVAL; + return (-EINVAL); } } @@ -849,28 +871,28 @@ int atalk_if_get_info(char *buffer, char **start, off_t offset, int length, int off_t pos=0; off_t begin=0; - len += sprintf (buffer,"Interface Address Networks Status\n"); - for (iface = atalk_iface_list; iface != NULL; iface = iface->next) + len += sprintf(buffer,"Interface Address Networks Status\n"); + for(iface = atalk_iface_list; iface != NULL; iface = iface->next) { - len += sprintf (buffer+len,"%-16s %04X:%02X %04X-%04X %d\n", - iface->dev->name, - ntohs(iface->address.s_net),iface->address.s_node, - ntohs(iface->nets.nr_firstnet),ntohs(iface->nets.nr_lastnet), - iface->status); - pos=begin+len; - if(pos<offset) + len += sprintf(buffer+len,"%-16s %04X:%02X %04X-%04X %d\n", + iface->dev->name, ntohs(iface->address.s_net), + iface->address.s_node, ntohs(iface->nets.nr_firstnet), + ntohs(iface->nets.nr_lastnet), iface->status); + pos = begin + len; + if(pos < offset) { - len=0; - begin=pos; + len = 0; + begin = pos; } - if(pos>offset+length) + if(pos > offset + length) break; } - *start=buffer+(offset-begin); - len-=(offset-begin); - if(len>length) - len=length; - return len; + *start = buffer + (offset - begin); + len -= (offset - begin); + if(len > length) + len = length; + + return (len); } /* Called from proc fs - just make it print the routes neatly */ @@ -882,138 +904,151 @@ int atalk_rt_get_info(char *buffer, char **start, off_t offset, int length, int off_t pos=0; off_t begin=0; - len += sprintf (buffer,"Target Router Flags Dev\n"); + len += sprintf(buffer,"Target Router Flags Dev\n"); if(atrtr_default.dev) { - rt=&atrtr_default; - len += sprintf (buffer+len,"Default %04X:%02X %-4d %s\n", + rt = &atrtr_default; + len += sprintf(buffer+len,"Default %04X:%02X %-4d %s\n", ntohs(rt->gateway.s_net), rt->gateway.s_node, rt->flags, rt->dev->name); } - for (rt = atalk_router_list; rt != NULL; rt = rt->next) + + for(rt = atalk_router_list; rt != NULL; rt = rt->next) { - len += sprintf (buffer+len,"%04X:%02X %04X:%02X %-4d %s\n", + len += sprintf(buffer+len,"%04X:%02X %04X:%02X %-4d %s\n", ntohs(rt->target.s_net),rt->target.s_node, ntohs(rt->gateway.s_net), rt->gateway.s_node, rt->flags, rt->dev->name); - pos=begin+len; - if(pos<offset) + pos = begin + len; + if(pos < offset) { - len=0; - begin=pos; + len = 0; + begin = pos; } - if(pos>offset+length) + if(pos > offset + length) break; } - *start=buffer+(offset-begin); - len-=(offset-begin); - if(len>length) - len=length; - return len; + + *start = buffer + (offset - begin); + len -= (offset - begin); + if(len > length) + len = length; + + return (len); } -/*******************************************************************************************************************\ -* * -* Handling for system calls applied via the various interfaces to an Appletalk socket object * -* * -\*******************************************************************************************************************/ +/**************************************************************************\ +* * +* Handling for system calls applied via the various interfaces to an * +* Appletalk socket object. * +* * +\**************************************************************************/ /* - * Checksum: This is 'optional'. It's quite likely also a good - * candidate for assembler hackery 8) + * Checksum: This is 'optional'. It's quite likely also a good + * candidate for assembler hackery 8) */ - unsigned short atalk_checksum(struct ddpehdr *ddp, int len) { unsigned long sum=0; /* Assume unsigned long is >16 bits */ unsigned char *data=(unsigned char *)ddp; - len-=4; /* skip header 4 bytes */ - data+=4; + len -= 4; /* skip header 4 bytes */ + data += 4; /* This ought to be unwrapped neatly. I'll trust gcc for now */ while(len--) { - sum+=*data; - sum<<=1; - if(sum&0x10000) + sum += *data; + sum <<= 1; + if(sum & 0x10000) { sum++; - sum&=0xFFFF; + sum &= 0xFFFF; } data++; } + if(sum) return htons((unsigned short)sum); + return 0xFFFF; /* Use 0xFFFF for 0. 0 itself means none */ } /* - * Create a socket. Initialise the socket, blank the addresses - * set the state. + * Create a socket. Initialise the socket, blank the addresses + * set the state. */ - static int atalk_create(struct socket *sock, int protocol) { struct sock *sk; - sk=sk_alloc(AF_APPLETALK, GFP_KERNEL); - if(sk==NULL) - return(-ENOMEM); + + sk = sk_alloc(AF_APPLETALK, GFP_KERNEL); + if(sk == NULL) + return (-ENOMEM); + switch(sock->type) { - /* This RAW is an extension. It is trivial to do and gives you - the full ELAP frame. Should be handy for CAP 8) */ + /* + * We permit SOCK_DGRAM and RAW is an extension. It is + * trivial to do and gives you the full ELAP frame. + * Should be handy for CAP 8) + */ case SOCK_RAW: - /* We permit DDP datagram sockets */ case SOCK_DGRAM: sock->ops = &atalk_dgram_ops; break; + default: sk_free((void *)sk); - return(-ESOCKTNOSUPPORT); + return (-ESOCKTNOSUPPORT); } MOD_INC_USE_COUNT; sock_init_data(sock,sk); - sk->destruct=NULL; + sk->destruct = NULL; /* Checksums on by default */ - sk->mtu=DDP_MAXSZ; - sk->zapped=1; - return(0); + sk->mtu = DDP_MAXSZ; + sk->zapped = 1; + + return (0); } /* - * Free a socket. No work needed + * Free a socket. No work needed */ - static int atalk_release(struct socket *sock, struct socket *peer) { struct sock *sk=sock->sk; - if(sk==NULL) - return(0); + + if(sk == NULL) + return (0); + if(!sk->dead) sk->state_change(sk); - sk->dead=1; - sock->sk=NULL; + + sk->dead = 1; + sock->sk = NULL; atalk_destroy_socket(sk); - return(0); + + return (0); } /* - * Pick a source address if one is not given. Just return - * an error if not supportable. + * Pick a source address if one is not given. Just return + * an error if not supportable. */ - static int atalk_pick_port(struct sockaddr_at *sat) { - for ( sat->sat_port = ATPORT_RESERVED; sat->sat_port < ATPORT_LAST; sat->sat_port++ ) + for(sat->sat_port = ATPORT_RESERVED; sat->sat_port < ATPORT_LAST; sat->sat_port++) { - if ( atalk_find_socket( sat ) == NULL ) + if(atalk_find_socket(sat) == NULL) return sat->sat_port; } - return -EBUSY; + + return (-EBUSY); } static int atalk_autobind(struct sock *sk) @@ -1022,381 +1057,189 @@ static int atalk_autobind(struct sock *sk) struct sockaddr_at sat; int n; - if ( ap == NULL || ap->s_net == htons( ATADDR_ANYNET )) - return -EADDRNOTAVAIL; - sk->protinfo.af_at.src_net = sat.sat_addr.s_net = ap->s_net; + if(ap == NULL || ap->s_net == htons(ATADDR_ANYNET)) + return (-EADDRNOTAVAIL); + + sk->protinfo.af_at.src_net = sat.sat_addr.s_net = ap->s_net; sk->protinfo.af_at.src_node = sat.sat_addr.s_node = ap->s_node; - if (( n = atalk_pick_port( &sat )) < 0 ) - return( n ); - sk->protinfo.af_at.src_port=n; + if((n = atalk_pick_port(&sat)) < 0) + return (n); + + sk->protinfo.af_at.src_port = n; atalk_insert_socket(sk); - sk->zapped=0; - return 0; + sk->zapped = 0; + + return (0); } /* - * Set the address 'our end' of the connection. + * Set the address 'our end' of the connection. */ - static int atalk_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { struct sock *sk; struct sockaddr_at *addr=(struct sockaddr_at *)uaddr; - sk=sock->sk; + sk = sock->sk; - if(sk->zapped==0) - return(-EINVAL); + if(sk->zapped == 0) + return (-EINVAL); - if(addr_len!=sizeof(struct sockaddr_at)) - return -EINVAL; + if(addr_len != sizeof(struct sockaddr_at)) + return (-EINVAL); - if(addr->sat_family!=AF_APPLETALK) - return -EAFNOSUPPORT; + if(addr->sat_family != AF_APPLETALK) + return (-EAFNOSUPPORT); - if(addr->sat_addr.s_net==htons(ATADDR_ANYNET)) + if(addr->sat_addr.s_net == htons(ATADDR_ANYNET)) { struct at_addr *ap=atalk_find_primary(); - if(ap==NULL) - return -EADDRNOTAVAIL; - sk->protinfo.af_at.src_net=addr->sat_addr.s_net=ap->s_net; - sk->protinfo.af_at.src_node=addr->sat_addr.s_node=ap->s_node; + + if(ap == NULL) + return (-EADDRNOTAVAIL); + + sk->protinfo.af_at.src_net = addr->sat_addr.s_net = ap->s_net; + sk->protinfo.af_at.src_node = addr->sat_addr.s_node= ap->s_node; } else { - if ( atalk_find_interface( addr->sat_addr.s_net, addr->sat_addr.s_node ) == NULL ) - return -EADDRNOTAVAIL; - sk->protinfo.af_at.src_net=addr->sat_addr.s_net; - sk->protinfo.af_at.src_node=addr->sat_addr.s_node; + if(atalk_find_interface(addr->sat_addr.s_net, addr->sat_addr.s_node) == NULL) + return (-EADDRNOTAVAIL); + + sk->protinfo.af_at.src_net = addr->sat_addr.s_net; + sk->protinfo.af_at.src_node = addr->sat_addr.s_node; } if(addr->sat_port == ATADDR_ANYPORT) { int n = atalk_pick_port(addr); if(n < 0) - return n; - sk->protinfo.af_at.src_port=addr->sat_port=n; + return (n); + + sk->protinfo.af_at.src_port = addr->sat_port = n; } else - sk->protinfo.af_at.src_port=addr->sat_port; + sk->protinfo.af_at.src_port = addr->sat_port; - if(atalk_find_socket(addr)!=NULL) - return -EADDRINUSE; + if(atalk_find_socket(addr) != NULL) + return (-EADDRINUSE); atalk_insert_socket(sk); - sk->zapped=0; - return(0); + sk->zapped = 0; + + return (0); } /* - * Set the address we talk to. + * Set the address we talk to. */ - static int atalk_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags) { struct sock *sk=sock->sk; struct sockaddr_at *addr; - sk->state = TCP_CLOSE; + sk->state = TCP_CLOSE; sock->state = SS_UNCONNECTED; - if(addr_len!=sizeof(*addr)) - return(-EINVAL); - addr=(struct sockaddr_at *)uaddr; + if(addr_len != sizeof(*addr)) + return (-EINVAL); + addr = (struct sockaddr_at *)uaddr; - if(addr->sat_family!=AF_APPLETALK) - return -EAFNOSUPPORT; - if(addr->sat_addr.s_node==ATADDR_BCAST && !sk->broadcast) + if(addr->sat_family != AF_APPLETALK) + return (-EAFNOSUPPORT); + + if(addr->sat_addr.s_node == ATADDR_BCAST && !sk->broadcast) { #if 1 printk(KERN_WARNING "%s is broken and did not set SO_BROADCAST. It will break when 2.2 is released.\n", current->comm); #else - return -EACCES; + return (-EACCES); #endif } + if(sk->zapped) { - if(atalk_autobind(sk)<0) - return -EBUSY; + if(atalk_autobind(sk) < 0) + return (-EBUSY); } - if(atrtr_get_dev(&addr->sat_addr)==NULL) - return -ENETUNREACH; + if(atrtr_get_dev(&addr->sat_addr) == NULL) + return (-ENETUNREACH); + + sk->protinfo.af_at.dest_port = addr->sat_port; + sk->protinfo.af_at.dest_net = addr->sat_addr.s_net; + sk->protinfo.af_at.dest_node = addr->sat_addr.s_node; - sk->protinfo.af_at.dest_port=addr->sat_port; - sk->protinfo.af_at.dest_net=addr->sat_addr.s_net; - sk->protinfo.af_at.dest_node=addr->sat_addr.s_node; sock->state = SS_CONNECTED; - sk->state=TCP_ESTABLISHED; - return(0); + sk->state = TCP_ESTABLISHED; + + return (0); } /* - * Not relevant + * Not relevant */ - static int atalk_accept(struct socket *sock, struct socket *newsock, int flags) { - if(newsock->sk) { + if(newsock->sk) + { sk_free(newsock->sk); MOD_DEC_USE_COUNT; } - return -EOPNOTSUPP; + + return (-EOPNOTSUPP); } /* - * Find the name of an appletalk socket. Just copy the right - * fields into the sockaddr. + * Find the name of an appletalk socket. Just copy the right + * fields into the sockaddr. */ - static int atalk_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { struct sockaddr_at sat; struct sock *sk; - sk=sock->sk; + sk = sock->sk; if(sk->zapped) { - if(atalk_autobind(sk)<0) - return -ENOBUFS; + if(atalk_autobind(sk) < 0) + return (-ENOBUFS); } *uaddr_len = sizeof(struct sockaddr_at); if(peer) { - if(sk->state!=TCP_ESTABLISHED) - return -ENOTCONN; - sat.sat_addr.s_net=sk->protinfo.af_at.dest_net; - sat.sat_addr.s_node=sk->protinfo.af_at.dest_node; - sat.sat_port=sk->protinfo.af_at.dest_port; + if(sk->state != TCP_ESTABLISHED) + return (-ENOTCONN); + sat.sat_addr.s_net = sk->protinfo.af_at.dest_net; + sat.sat_addr.s_node = sk->protinfo.af_at.dest_node; + sat.sat_port = sk->protinfo.af_at.dest_port; } else { - sat.sat_addr.s_net=sk->protinfo.af_at.src_net; - sat.sat_addr.s_node=sk->protinfo.af_at.src_node; - sat.sat_port=sk->protinfo.af_at.src_port; + sat.sat_addr.s_net = sk->protinfo.af_at.src_net; + sat.sat_addr.s_node = sk->protinfo.af_at.src_node; + sat.sat_port = sk->protinfo.af_at.src_port; } - sat.sat_family = AF_APPLETALK; - memcpy(uaddr,&sat,sizeof(sat)); - return(0); -} - -/* - * IP-over-DDP support. Under construction. - */ - -#ifdef CONFIG_IPDDP - -#define SIOCADDIPDDPRT SIOCDEVPRIVATE -#define SIOCDELIPDDPRT SIOCDEVPRIVATE+1 -#define SIOCFINDIPDDPRT SIOCDEVPRIVATE+2 - -struct ipddp_route -{ - struct device *dev; /* Carrier device */ - __u32 ip; /* IP address */ - struct at_addr at; /* Gateway appletalk address */ - int flags; - struct ipddp_route *next; -}; - -static struct ipddp_route *ipddp_route_head; - -static struct ipddp_route ipddp_route_test; - -int ipddp_open(struct device *dev) -{ - MOD_INC_USE_COUNT; - return 0; -} -int ipddp_close(struct device *dev) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -int ipddp_xmit(struct sk_buff *skb, struct device *dev) -{ - /* Retrieve the saved address hint */ - struct at_addr *a=(struct at_addr *)skb->data; - skb_pull(skb,4); - - ((struct net_device_stats *) dev->priv)->tx_packets++; - ((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len; - - /* printk("ipddp_xmit called with headroom %d\n",skb_headroom(skb)); */ - - if( aarp_send_ddp(skb->dev,skb,a,NULL) < 0 ) - dev_kfree_skb(skb,FREE_WRITE); - - return 0; -} - -struct net_device_stats *ipddp_get_stats(struct device *dev) -{ - return (struct net_device_stats *) dev->priv; -} - -int ipddp_ioctl(struct device *dev, struct ifreq *ifr, int cmd) -{ - struct ipddp_route *urt = (struct ipddp_route *)ifr->ifr_data; - - if(!suser()) - return -EPERM; - - /* for now we only have one route at a time */ - - switch(cmd) - { - case SIOCADDIPDDPRT: - if(copy_from_user(&ipddp_route_test,urt,sizeof(struct ipddp_route))) - return -EFAULT; - ipddp_route_test.dev = atrtr_get_dev(&ipddp_route_test.at); - if (dev==NULL) - return -ENETUNREACH; - ipddp_route_test.next = NULL; - printk("added ipddp route through %s\n",ipddp_route_test.dev->name); - ipddp_route_head = &ipddp_route_test; - return 0; - case SIOCFINDIPDDPRT: - if(copy_to_user(urt,&ipddp_route_test,sizeof(struct ipddp_route))) - return -EFAULT; - return 0; - case SIOCDELIPDDPRT: - ipddp_route_test.dev = NULL; - ipddp_route_head = NULL; - return 0; - default: - return -EINVAL; - } -} - -int ipddp_header (struct sk_buff *skb, struct device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) -{ - /* printk("ipddp_header\n"); */ - /* Push down the header space and the type byte */ - skb_push(skb, sizeof(struct ddpehdr)+1+4); - return 0; -} - -/* - * Now the packet really wants to go out. - */ - -int ipddp_rebuild_header (struct sk_buff *skb) -{ - struct ddpehdr *ddp; - struct at_addr at; - struct ipddp_route *rt; - struct at_addr *our_addr; - u32 paddr = ((struct rtable *)skb->dst)->rt_gateway; - - /* - * On entry skb->data points to the ddpehdr we reserved earlier. - * skb->h.raw will be the higher level header. - */ - - /* - * We created this earlier - */ - - ddp = (struct ddpehdr *) (skb->data+4); - - /* find appropriate route */ - - for(rt=ipddp_route_head;rt;rt=rt->next) - { - if(rt->ip == paddr) - break; - } - - if(!rt) { - printk("ipddp unreachable dst %08lx\n",ntohl(paddr)); - return -ENETUNREACH; - } - - our_addr = atalk_find_dev_addr(rt->dev); - - /* fill in ddpehdr */ - ddp->deh_len = skb->len; - ddp->deh_hops = 1; - ddp->deh_pad = 0; - ddp->deh_sum = 0; - ddp->deh_dnet = rt->at.s_net; /* FIXME more hops?? */ - ddp->deh_snet = our_addr->s_net; - ddp->deh_dnode = rt->at.s_node; - ddp->deh_snode = our_addr->s_node; - ddp->deh_dport = 72; - ddp->deh_sport = 72; - - *((__u8 *)(ddp+1)) = 22; /* ddp type = IP */ - - /* fix up length field */ - *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); - - /* set skb->dev to appropriate device */ - skb->dev = rt->dev; - - /* skb->raddr = (unsigned long) at */ - at = rt->at; - /* Hide it at the start of the buffer */ - memcpy(skb->data,(void *)&at,sizeof(at)); - skb->arp = 1; /* so the actual device doesn't try to arp it... */ - skb->protocol = htons(ETH_P_ATALK); /* Protocol has changed */ - - return 0; -} - -int ipddp_init (struct device *dev) -{ - ether_setup(dev); - dev->hard_start_xmit = ipddp_xmit; - dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL); - if(!dev->priv) - return -ENOMEM; - memset(dev->priv,0,sizeof(struct enet_statistics)); - dev->get_stats = ipddp_get_stats; - dev->do_ioctl = ipddp_ioctl; - dev->type = ARPHRD_IPDDP; /* IP over DDP tunnel */ - dev->family = AF_INET; - dev->mtu = 585; - dev->flags |= IFF_NOARP; - dev->hard_header = ipddp_header; /* see ip_output.c */ - dev->rebuild_header = ipddp_rebuild_header; - /* - * The worst case header we will need is currently a - * ethernet header (14 bytes) and a ddp header (sizeof ddpehdr+1) - * We send over SNAP so that takes another 8 bytes. - */ - dev->hard_header_len = 14+8+sizeof(struct ddpehdr)+1; - dev->open = ipddp_open; - dev->stop = ipddp_close; + sat.sat_family = AF_APPLETALK; + memcpy(uaddr, &sat, sizeof(sat)); - return 0; + return (0); } -static struct device dev_ipddp = { - "ipddp0\0 ", - 0, 0, 0, 0, - 0x0, 0, - 0, 0, 0, NULL, ipddp_init }; - -#endif /* CONFIG_IPDDP */ - /* - * Receive a packet (in skb) from device dev. This has come from the SNAP decoder, and on entry - * skb->h.raw is the DDP header, skb->len is the DDP length. The physical headers have been - * extracted. PPP should probably pass frames marked as for this layer - * [ie ARPHRD_ETHERTALK] + * Receive a packet (in skb) from device dev. This has come from the SNAP + * decoder, and on entry skb->h.raw is the DDP header, skb->len is the DDP + * header, skb->len is the DDP length. The physical headers have been + * extracted. PPP should probably pass frames marked as for this layer. + * [ie ARPHRD_ETHERTALK] */ - static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) { struct sock *sock; @@ -1406,13 +1249,12 @@ static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type int origlen; /* Size check */ - if(skb->len<sizeof(*ddp)) + if(skb->len < sizeof(*ddp)) { kfree_skb(skb,FREE_READ); - return(0); + return (0); } - /* * Fix up the length field [Ok this is horrible but otherwise * I end up with unions of bit fields and messy bit field order @@ -1423,254 +1265,264 @@ static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type * run until we put it back) */ - *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); + *((__u16 *)ddp) = ntohs(*((__u16 *)ddp)); /* - * Trim buffer in case of stray trailing data + * Trim buffer in case of stray trailing data */ origlen = skb->len; - skb_trim(skb,min(skb->len,ddp->deh_len)); + skb_trim(skb, min(skb->len, ddp->deh_len)); /* - * Size check to see if ddp->deh_len was crap - * (Otherwise we'll detonate most spectacularly - * in the middle of recvmsg()). + * Size check to see if ddp->deh_len was crap + * (Otherwise we'll detonate most spectacularly + * in the middle of recvmsg()). */ - - if(skb->len<sizeof(*ddp)) + if(skb->len < sizeof(*ddp)) { kfree_skb(skb,FREE_READ); - return(0); + return (0); } /* - * Any checksums. Note we don't do htons() on this == is assumed to be - * valid for net byte orders all over the networking code... + * Any checksums. Note we don't do htons() on this == is assumed to be + * valid for net byte orders all over the networking code... */ - - if(ddp->deh_sum && atalk_checksum(ddp, ddp->deh_len)!= ddp->deh_sum) + if(ddp->deh_sum && atalk_checksum(ddp, ddp->deh_len) != ddp->deh_sum) { /* Not a valid appletalk frame - dustbin time */ - kfree_skb(skb,FREE_READ); - return(0); + kfree_skb(skb, FREE_READ); + return (0); } if(call_in_firewall(AF_APPLETALK, skb->dev, ddp, NULL,&skb)!=FW_ACCEPT) { kfree_skb(skb, FREE_READ); - return 0; + return (0); } /* Check the packet is aimed at us */ if(ddp->deh_dnet == 0) /* Net 0 is 'this network' */ - atif=atalk_find_anynet(ddp->deh_dnode, dev); + atif = atalk_find_anynet(ddp->deh_dnode, dev); else - atif=atalk_find_interface(ddp->deh_dnet,ddp->deh_dnode); + atif = atalk_find_interface(ddp->deh_dnet, ddp->deh_dnode); - /* Not ours */ - if(atif==NULL) + /* + * Not ours, so we route the packet via the correct Appletalk interface. + */ + if(atif == NULL) { struct atalk_route *rt; struct at_addr ta; - /* Don't route multicast, etc., packets, or packets - sent to "this network" */ + /* + * Don't route multicast, etc., packets, or packets + * sent to "this network" + */ if (skb->pkt_type != PACKET_HOST || ddp->deh_dnet == 0) { kfree_skb(skb, FREE_READ); - return(0); + return (0); } /* - * Check firewall allows this routing + * Check firewall allows this routing */ - - if(call_fw_firewall(AF_APPLETALK, skb->dev, ddp, NULL, &skb)!=FW_ACCEPT) + if(call_fw_firewall(AF_APPLETALK, skb->dev, ddp, NULL, &skb) != FW_ACCEPT) { kfree_skb(skb, FREE_READ); - return(0); + return (0); } - ta.s_net=ddp->deh_dnet; - ta.s_node=ddp->deh_dnode; + ta.s_net = ddp->deh_dnet; + ta.s_node = ddp->deh_dnode; /* Route the packet */ - rt=atrtr_find(&ta); - if(rt==NULL || ddp->deh_hops==15) + rt = atrtr_find(&ta); + if(rt == NULL || ddp->deh_hops == DDP_MAXHOPS) { kfree_skb(skb, FREE_READ); - return(0); + return (0); } ddp->deh_hops++; /* - * Route goes through another gateway, so - * set the target to the gateway instead. + * Route goes through another gateway, so + * set the target to the gateway instead. */ - - if(rt->flags&RTF_GATEWAY) + if(rt->flags & RTF_GATEWAY) { - ta.s_net = rt->gateway.s_net; + ta.s_net = rt->gateway.s_net; ta.s_node = rt->gateway.s_node; } /* Fix up skb->len field */ - skb_trim(skb,min(origlen, rt->dev->hard_header_len + + skb_trim(skb, min(origlen, rt->dev->hard_header_len + ddp_dl->header_length + ddp->deh_len)); - *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); /* Mend the byte order */ + /* Mend the byte order */ + *((__u16 *)ddp) = ntohs(*((__u16 *)ddp)); /* - * Send the buffer onwards - */ - - /* - * Now we must always be careful. If it's come from - * localtalk to ethertalk it might not fit + * Send the buffer onwards + * + * Now we must always be careful. If it's come from + * localtalk to ethertalk it might not fit * - * Order matters here: If a packet has to be copied - * to make a new headroom (rare hopefully) then it - * won't need unsharing. + * Order matters here: If a packet has to be copied + * to make a new headroom (rare hopefully) then it + * won't need unsharing. * - * Note. ddp-> becomes invalid at the realloc. + * Note. ddp-> becomes invalid at the realloc. */ - - if(skb_headroom(skb)<22) + if(skb_headroom(skb) < 22) /* 22 bytes - 12 ether, 2 len, 3 802.2 5 snap */ - skb=skb_realloc_headroom(skb, 32); + skb = skb_realloc_headroom(skb, 32); else - skb=skb_unshare(skb, GFP_ATOMIC, FREE_READ); + skb = skb_unshare(skb, GFP_ATOMIC, FREE_READ); /* - * If the buffer didnt vanish into the lack of - * space bitbucket we can send it. + * If the buffer didn't vanish into the lack of + * space bitbucket we can send it. */ - if(skb) { skb->arp = 1; /* Resolved */ - if(aarp_send_ddp(rt->dev, skb, &ta, NULL)==-1) + if(aarp_send_ddp(rt->dev, skb, &ta, NULL) == -1) kfree_skb(skb, FREE_READ); } - return 0; + + return (0); } - /* Which socket - atalk_search_socket() looks for a *full match* - of the <net,node,port> tuple */ - tosat.sat_addr.s_net = ddp->deh_dnet; + /* + * Which socket - atalk_search_socket() looks for a *full match* + * of the <net,node,port> tuple. + */ + tosat.sat_addr.s_net = ddp->deh_dnet; tosat.sat_addr.s_node = ddp->deh_dnode; tosat.sat_port = ddp->deh_dport; - sock=atalk_search_socket( &tosat, atif ); + sock = atalk_search_socket(&tosat, atif); - if(sock==NULL) /* But not one of our sockets */ + if(sock == NULL) /* But not one of our sockets */ { - kfree_skb(skb,FREE_READ); - return(0); + kfree_skb(skb, FREE_READ); + return (0); } #ifdef CONFIG_IPDDP /* * Check if IP-over-DDP */ - - if(skb->data[12]==22) + if(skb->data[12] == 22) { - struct net_device_stats *estats = - (struct net_device_stats *) dev_ipddp.priv; - skb->protocol=htons(ETH_P_IP); - skb_pull(skb,13); - skb->dev=&dev_ipddp; + struct device *dev; + struct net_device_stats *estats; + + if((dev = dev_get("ipddp0")) == NULL) + return (-ENODEV); + + estats = (struct net_device_stats *) dev->priv; + skb->protocol = htons(ETH_P_IP); + skb_pull(skb, 13); + skb->dev = dev; skb->h.raw = skb->data; + /* printk("passing up ipddp, 0x%02x better be 45\n",skb->data[0]); * printk("tot_len %d, skb->len %d\n", * ntohs(skb->h.iph->tot_len),skb->len); */ + estats->rx_packets++; - estats->rx_bytes+=skb->len+13; - netif_rx(skb); - return 0; + estats->rx_bytes += skb->len + 13; + netif_rx(skb); /* Send the SKB up to a higher place. */ + + return (0); } -#endif /* CONFIG_IPDDP */ +#endif /* CONFIG_IPDDP */ + /* * Queue packet (standard) */ skb->sk = sock; - if(sock_queue_rcv_skb(sock,skb)<0) + if(sock_queue_rcv_skb(sock, skb) < 0) { - skb->sk=NULL; + skb->sk = NULL; kfree_skb(skb, FREE_WRITE); } - return(0); + + return (0); } /* - * Receive a localtalk frame. We make some demands on the caller here. - * Caller must provide enough headroom on the packet to pull the short - * header and append a long one. + * Receive a localtalk frame. We make some demands on the caller here. + * Caller must provide enough headroom on the packet to pull the short + * header and append a long one. */ - - static int ltalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) { struct ddpehdr *ddp; struct at_addr *ap; + /* - * Expand any short form frames. + * Expand any short form frames. */ - - if(skb->mac.raw[2]==1) + if(skb->mac.raw[2] == 1) { /* - * Find our address. + * Find our address. */ - ap=atalk_find_dev_addr(dev); - if(ap==NULL || skb->len<sizeof(struct ddpshdr)) + ap = atalk_find_dev_addr(dev); + if(ap == NULL || skb->len < sizeof(struct ddpshdr)) { kfree_skb(skb, FREE_READ); - return 0; + return (0); } /* - * The push leaves us with a ddephdr not an shdr, and - * handily the port bytes in the right place preset. + * The push leaves us with a ddephdr not an shdr, and + * handily the port bytes in the right place preset. */ - skb_push(skb, sizeof(*ddp)-4); - ddp=(struct ddpehdr *)skb->data; + skb_push(skb, sizeof(*ddp) - 4); + ddp = (struct ddpehdr *)skb->data; /* - * Now fill in the long header. + * Now fill in the long header. */ /* - * These two first. The mac overlays the new source/dest - * network information so we MUST copy these before - * we write the network numbers ! + * These two first. The mac overlays the new source/dest + * network information so we MUST copy these before + * we write the network numbers ! */ - ddp->deh_dnode=skb->mac.raw[0]; /* From physical header */ - ddp->deh_snode=skb->mac.raw[1]; /* From physical header */ + ddp->deh_dnode = skb->mac.raw[0]; /* From physical header */ + ddp->deh_snode = skb->mac.raw[1]; /* From physical header */ - ddp->deh_dnet=ap->s_net; /* Network number */ - ddp->deh_snet=ap->s_net; - ddp->deh_sum=0; /* No checksum */ + ddp->deh_dnet = ap->s_net; /* Network number */ + ddp->deh_snet = ap->s_net; + ddp->deh_sum = 0; /* No checksum */ /* - * Not sure about this bit... + * Not sure about this bit... */ - ddp->deh_len=skb->len; - ddp->deh_hops=15; /* Non routable, so force a drop + ddp->deh_len = skb->len; + ddp->deh_hops = DDP_MAXHOPS; /* Non routable, so force a drop if we slip up later */ - *((__u16 *)ddp)=htons(*((__u16 *)ddp)); /* Mend the byte order */ + + /* Mend the byte order */ + *((__u16 *)ddp) = htons(*((__u16 *)ddp)); } skb->h.raw = skb->data; - return atalk_rcv(skb,dev,pt); + + return (atalk_rcv(skb, dev, pt)); } static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len, @@ -1688,66 +1540,68 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len, int err; int flags = msg->msg_flags; - if(flags&~MSG_DONTWAIT) - return -EINVAL; + if(flags & ~MSG_DONTWAIT) + return (-EINVAL); - if(len>587) - return -EMSGSIZE; + if(len > DDP_MAXSZ) + return (-EMSGSIZE); if(usat) { if(sk->zapped) { - if(atalk_autobind(sk)<0) - return -EBUSY; + if(atalk_autobind(sk) < 0) + return (-EBUSY); } - if(msg->msg_namelen <sizeof(*usat)) - return(-EINVAL); + if(msg->msg_namelen < sizeof(*usat)) + return (-EINVAL); if(usat->sat_family != AF_APPLETALK) - return -EINVAL; + return (-EINVAL); + /* netatalk doesn't implement this check */ - if(usat->sat_addr.s_node==ATADDR_BCAST && !sk->broadcast) + if(usat->sat_addr.s_node == ATADDR_BCAST && !sk->broadcast) { printk(KERN_INFO "SO_BROADCAST: Fix your netatalk as it will break before 2.2\n"); #if 0 - return -EPERM; + return (-EPERM); #endif } } else { - if(sk->state!=TCP_ESTABLISHED) - return -ENOTCONN; - usat=&local_satalk; - usat->sat_family=AF_APPLETALK; - usat->sat_port=sk->protinfo.af_at.dest_port; - usat->sat_addr.s_node=sk->protinfo.af_at.dest_node; - usat->sat_addr.s_net=sk->protinfo.af_at.dest_net; + if(sk->state != TCP_ESTABLISHED) + return (-ENOTCONN); + usat =& local_satalk; + usat->sat_family = AF_APPLETALK; + usat->sat_port = sk->protinfo.af_at.dest_port; + usat->sat_addr.s_node = sk->protinfo.af_at.dest_node; + usat->sat_addr.s_net = sk->protinfo.af_at.dest_net; } /* Build a packet */ SOCK_DEBUG(sk, "SK %p: Got address.\n",sk); - size=sizeof(struct ddpehdr)+len+ddp_dl->header_length; /* For headers */ + /* For headers */ + size = sizeof(struct ddpehdr) + len + ddp_dl->header_length; - if(usat->sat_addr.s_net!=0 || usat->sat_addr.s_node == ATADDR_ANYNODE) + if(usat->sat_addr.s_net != 0 || usat->sat_addr.s_node == ATADDR_ANYNODE) { - rt=atrtr_find(&usat->sat_addr); - if(rt==NULL) - return -ENETUNREACH; - dev=rt->dev; + rt = atrtr_find(&usat->sat_addr); + if(rt == NULL) + return (-ENETUNREACH); + dev = rt->dev; } else { struct at_addr at_hint; - at_hint.s_node=0; - at_hint.s_net=sk->protinfo.af_at.src_net; - rt=atrtr_find(&at_hint); - if(rt==NULL) - return -ENETUNREACH; - dev=rt->dev; + at_hint.s_node = 0; + at_hint.s_net = sk->protinfo.af_at.src_net; + rt = atrtr_find(&at_hint); + if(rt == NULL) + return (-ENETUNREACH); + dev = rt->dev; } SOCK_DEBUG(sk, "SK %p: Size needed %d, device %s\n", sk, size, dev->name); @@ -1755,105 +1609,105 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len, size += dev->hard_header_len; skb = sock_alloc_send_skb(sk, size, 0, flags&MSG_DONTWAIT, &err); - if(skb==NULL) - return err; + if(skb == NULL) + return (err); - skb->sk=sk; - skb->arp=1; - skb_reserve(skb,ddp_dl->header_length); - skb_reserve(skb,dev->hard_header_len); + skb->sk = sk; + skb->arp = 1; + skb_reserve(skb, ddp_dl->header_length); + skb_reserve(skb, dev->hard_header_len); - skb->dev=dev; + skb->dev = dev; SOCK_DEBUG(sk, "SK %p: Begin build.\n", sk); - ddp=(struct ddpehdr *)skb_put(skb,sizeof(struct ddpehdr)); - ddp->deh_pad=0; - ddp->deh_hops=0; - ddp->deh_len=len+sizeof(*ddp); + ddp = (struct ddpehdr *)skb_put(skb,sizeof(struct ddpehdr)); + ddp->deh_pad = 0; + ddp->deh_hops = 0; + ddp->deh_len = len + sizeof(*ddp); /* - * Fix up the length field [Ok this is horrible but otherwise - * I end up with unions of bit fields and messy bit field order - * compiler/endian dependencies.. + * Fix up the length field [Ok this is horrible but otherwise + * I end up with unions of bit fields and messy bit field order + * compiler/endian dependencies.. */ - *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); + *((__u16 *)ddp) = ntohs(*((__u16 *)ddp)); - ddp->deh_dnet=usat->sat_addr.s_net; - ddp->deh_snet=sk->protinfo.af_at.src_net; - ddp->deh_dnode=usat->sat_addr.s_node; - ddp->deh_snode=sk->protinfo.af_at.src_node; - ddp->deh_dport=usat->sat_port; - ddp->deh_sport=sk->protinfo.af_at.src_port; + ddp->deh_dnet = usat->sat_addr.s_net; + ddp->deh_snet = sk->protinfo.af_at.src_net; + ddp->deh_dnode = usat->sat_addr.s_node; + ddp->deh_snode = sk->protinfo.af_at.src_node; + ddp->deh_dport = usat->sat_port; + ddp->deh_sport = sk->protinfo.af_at.src_port; SOCK_DEBUG(sk, "SK %p: Copy user data (%d bytes).\n", sk, len); - err = memcpy_fromiovec(skb_put(skb,len),msg->msg_iov,len); - if (err) + err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len); + if(err) { kfree_skb(skb, FREE_WRITE); - return -EFAULT; + return (-EFAULT); } - if(sk->no_check==1) - ddp->deh_sum=0; + if(sk->no_check == 1) + ddp->deh_sum = 0; else - ddp->deh_sum=atalk_checksum(ddp, len+sizeof(*ddp)); + ddp->deh_sum = atalk_checksum(ddp, len + sizeof(*ddp)); - if(call_out_firewall(AF_APPLETALK, skb->dev, ddp, NULL, &skb)!=FW_ACCEPT) + if(call_out_firewall(AF_APPLETALK, skb->dev, ddp, NULL, &skb) != FW_ACCEPT) { kfree_skb(skb, FREE_WRITE); - return -EPERM; + return (-EPERM); } /* - * Loopback broadcast packets to non gateway targets (ie routes - * to group we are in) + * Loopback broadcast packets to non gateway targets (ie routes + * to group we are in) */ - - if(ddp->deh_dnode==ATADDR_BCAST) + if(ddp->deh_dnode == ATADDR_BCAST) { - if((!(rt->flags&RTF_GATEWAY))&&(!(dev->flags&IFF_LOOPBACK))) + if((!(rt->flags&RTF_GATEWAY)) && (!(dev->flags&IFF_LOOPBACK))) { - struct sk_buff *skb2=skb_copy(skb, GFP_KERNEL); + struct sk_buff *skb2 = skb_copy(skb, GFP_KERNEL); if(skb2) { - loopback=1; + loopback = 1; SOCK_DEBUG(sk, "SK %p: send out(copy).\n", sk); - if(aarp_send_ddp(dev,skb2,&usat->sat_addr, NULL)==-1) + if(aarp_send_ddp(dev, skb2, &usat->sat_addr, NULL) == -1) kfree_skb(skb2, FREE_WRITE); /* else queued/sent above in the aarp queue */ } } } - if((dev->flags&IFF_LOOPBACK) || loopback) + if((dev->flags & IFF_LOOPBACK) || loopback) { SOCK_DEBUG(sk, "SK %p: Loop back.\n", sk); /* loop back */ skb_orphan(skb); ddp_dl->datalink_header(ddp_dl, skb, dev->dev_addr); - skb->mac.raw=skb->data; - skb->h.raw = skb->data + ddp_dl->header_length + dev->hard_header_len; + skb->mac.raw = skb->data; + skb->h.raw = skb->data + ddp_dl->header_length + dev->hard_header_len; skb_pull(skb,dev->hard_header_len); skb_pull(skb,ddp_dl->header_length); - atalk_rcv(skb,dev,NULL); + atalk_rcv(skb, dev, NULL); } else { SOCK_DEBUG(sk, "SK %p: send out.\n", sk); - if ( rt->flags & RTF_GATEWAY ) { + if (rt->flags & RTF_GATEWAY) + { gsat.sat_addr = rt->gateway; usat = &gsat; } - if(aarp_send_ddp(dev,skb,&usat->sat_addr, NULL)==-1) + if(aarp_send_ddp(dev, skb, &usat->sat_addr, NULL) == -1) kfree_skb(skb, FREE_WRITE); /* else queued/sent above in the aarp queue */ } SOCK_DEBUG(sk, "SK %p: Done write (%d).\n", sk, len); - return len; -} + return (len); +} static int atalk_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm) @@ -1863,60 +1717,60 @@ static int atalk_recvmsg(struct socket *sock, struct msghdr *msg, int size, struct ddpehdr *ddp = NULL; int copied = 0; struct sk_buff *skb; - int er = 0; + int err = 0; - skb=skb_recv_datagram(sk,flags&~MSG_DONTWAIT,flags&MSG_DONTWAIT,&er); - if(skb==NULL) - return er; + skb = skb_recv_datagram(sk,flags&~MSG_DONTWAIT,flags&MSG_DONTWAIT,&err); + if(skb == NULL) + return (err); ddp = (struct ddpehdr *)(skb->h.raw); - if(sk->type==SOCK_RAW) + if(sk->type == SOCK_RAW) { - copied=ddp->deh_len; + copied = ddp->deh_len; if(copied > size) { - copied=size; - msg->msg_flags|=MSG_TRUNC; + copied = size; + msg->msg_flags |= MSG_TRUNC; } - er = skb_copy_datagram_iovec(skb,0,msg->msg_iov,copied); - if (er) - goto out; + + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); } else { - copied=ddp->deh_len - sizeof(*ddp); - if (copied > size) + copied = ddp->deh_len - sizeof(*ddp); + if(copied > size) { copied = size; - msg->msg_flags|=MSG_TRUNC; + msg->msg_flags |= MSG_TRUNC; } - er = skb_copy_datagram_iovec(skb,sizeof(*ddp),msg->msg_iov,copied); - if (er) - goto out; + err = skb_copy_datagram_iovec(skb,sizeof(*ddp),msg->msg_iov,copied); } - if(sat) + + if(!err) { - sat->sat_family=AF_APPLETALK; - sat->sat_port=ddp->deh_sport; - sat->sat_addr.s_node=ddp->deh_snode; - sat->sat_addr.s_net=ddp->deh_snet; + if(sat) + { + sat->sat_family = AF_APPLETALK; + sat->sat_port = ddp->deh_sport; + sat->sat_addr.s_node = ddp->deh_snode; + sat->sat_addr.s_net = ddp->deh_snet; + } + msg->msg_namelen = sizeof(*sat); } - msg->msg_namelen=sizeof(*sat); -out: - skb_free_datagram(sk, skb); - return er ? er : (copied); -} + skb_free_datagram(sk, skb); /* Free the datagram. */ + + return (err ? err : (copied)); +} static int atalk_shutdown(struct socket *sk,int how) { - return -EOPNOTSUPP; + return (-EOPNOTSUPP); } /* - * Appletalk ioctl calls. + * Appletalk ioctl calls. */ - static int atalk_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg) { long amount=0; @@ -1929,43 +1783,48 @@ static int atalk_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg) */ case TIOCOUTQ: amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); - if(amount<0) - amount=0; + if(amount < 0) + amount = 0; break; + case TIOCINQ: { struct sk_buff *skb; /* These two are safe on a single CPU system as only user tasks fiddle here */ - if((skb=skb_peek(&sk->receive_queue))!=NULL) - amount=skb->len-sizeof(struct ddpehdr); + if((skb = skb_peek(&sk->receive_queue)) != NULL) + amount = skb->len-sizeof(struct ddpehdr); break; } + case SIOCGSTAMP: - if (sk) + if(sk) { - if(sk->stamp.tv_sec==0) + if(sk->stamp.tv_sec == 0) return -ENOENT; - return copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval)) ? -EFAULT : 0; + return (copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval)) ? -EFAULT : 0); } - return -EINVAL; + return (-EINVAL); + /* - * Routing + * Routing */ case SIOCADDRT: case SIOCDELRT: if(!suser()) return -EPERM; - return(atrtr_ioctl(cmd,(void *)arg)); + return (atrtr_ioctl(cmd,(void *)arg)); + /* - * Interface + * Interface */ case SIOCGIFADDR: case SIOCSIFADDR: case SIOCGIFBRDADDR: case SIOCATALKDIFADDR: - return atif_ioctl(cmd,(void *)arg); + return (atif_ioctl(cmd,(void *)arg)); + /* - * Physical layer ioctl calls + * Physical layer ioctl calls */ case SIOCSIFLINK: case SIOCGIFHWADDR: @@ -1979,7 +1838,7 @@ static int atalk_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg) case SIOCGIFCOUNT: case SIOGIFINDEX: case SIOGIFNAME: - return(dev_ioctl(cmd,(void *) arg)); + return ((dev_ioctl(cmd,(void *) arg))); case SIOCSIFMETRIC: case SIOCSIFBRDADDR: @@ -1989,20 +1848,23 @@ static int atalk_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg) case SIOCSIFMEM: case SIOCGIFDSTADDR: case SIOCSIFDSTADDR: - return -EINVAL; + return (-EINVAL); default: - return -EINVAL; + return (-EINVAL); } - return put_user(amount, (int *)arg); + + return (put_user(amount, (int *)arg)); } -static struct net_proto_family atalk_family_ops = { +static struct net_proto_family atalk_family_ops= +{ AF_APPLETALK, atalk_create }; -static struct proto_ops atalk_dgram_ops = { +static struct proto_ops atalk_dgram_ops= +{ AF_APPLETALK, sock_no_dup, @@ -2023,7 +1885,8 @@ static struct proto_ops atalk_dgram_ops = { atalk_recvmsg }; -static struct notifier_block ddp_notifier={ +static struct notifier_block ddp_notifier= +{ ddp_device_event, NULL, 0 @@ -2047,41 +1910,53 @@ struct packet_type ppptalk_packet_type= NULL }; -static char ddp_snap_id[]={0x08,0x00,0x07,0x80,0x9B}; +static char ddp_snap_id[] = {0x08, 0x00, 0x07, 0x80, 0x9B}; + +/* + * Export symbols for use by drivers when Appletalk is a module. + */ +EXPORT_SYMBOL(aarp_send_ddp); +EXPORT_SYMBOL(atrtr_get_dev); +EXPORT_SYMBOL(atalk_find_dev_addr); #ifdef CONFIG_PROC_FS -static struct proc_dir_entry proc_appletalk = { +static struct proc_dir_entry proc_appletalk= +{ PROC_NET_ATALK, 9, "appletalk", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_net_inode_operations, atalk_get_info }; -static struct proc_dir_entry proc_atalk_route = { + +static struct proc_dir_entry proc_atalk_route= +{ PROC_NET_AT_ROUTE, 11,"atalk_route", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_net_inode_operations, atalk_rt_get_info }; -static struct proc_dir_entry proc_atalk_iface = { + +static struct proc_dir_entry proc_atalk_iface= +{ PROC_NET_ATIF, 11,"atalk_iface", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_net_inode_operations, atalk_if_get_info }; -#endif +#endif /* CONFIG_PROC_FS */ /* Called by proto.c on kernel start up */ __initfunc(void atalk_proto_init(struct net_proto *pro)) { (void) sock_register(&atalk_family_ops); - if ((ddp_dl = register_snap_client(ddp_snap_id, atalk_rcv)) == NULL) + if((ddp_dl = register_snap_client(ddp_snap_id, atalk_rcv)) == NULL) printk(KERN_CRIT "Unable to register DDP with SNAP.\n"); - ltalk_packet_type.type=htons(ETH_P_LOCALTALK); + ltalk_packet_type.type = htons(ETH_P_LOCALTALK); dev_add_pack(<alk_packet_type); - ppptalk_packet_type.type=htons(ETH_P_PPPTALK); + ppptalk_packet_type.type = htons(ETH_P_PPPTALK); dev_add_pack(&ppptalk_packet_type); register_netdevice_notifier(&ddp_notifier); @@ -2091,88 +1966,80 @@ __initfunc(void atalk_proto_init(struct net_proto *pro)) proc_net_register(&proc_appletalk); proc_net_register(&proc_atalk_route); proc_net_register(&proc_atalk_iface); -#endif +#endif /* CONFIG_PROC_FS */ #ifdef CONFIG_SYSCTL atalk_register_sysctl(); -#endif - -#ifdef CONFIG_IPDDP - register_netdev(&dev_ipddp); -#endif /* CONFIG_IPDDP */ +#endif /* CONFIG_SYSCTL */ printk(KERN_INFO "Appletalk 0.18 for Linux NET3.037\n"); } #ifdef MODULE -EXPORT_NO_SYMBOLS; int init_module(void) { atalk_proto_init(NULL); - return 0; + return (0); } /* - * FIX THIS: If there are any routes/devices configured - * for appletalk we must not be unloaded. + * Actually down the interface. */ - -/* Remove all route entries. Interrupts must be off. */ -extern inline void free_route_list(void) +static void atalk_iface_down(struct atalk_iface *iface) { - struct atalk_route *list = atalk_router_list, *tmp; + atrtr_device_down(iface->dev); /* Remove all routes for the device */ + aarp_device_down(iface->dev); /* Remove AARP entries for the device */ + atif_drop_device(iface->dev); /* Remove the device */ - while (list != NULL) - { - tmp = list->next; - kfree_s(list, sizeof(struct atalk_route)); - list = tmp; - } + return; } -/* Remove all interface entries. Interrupts must be off. */ -extern inline void free_interface_list(void) -{ - struct atalk_iface *list = atalk_iface_list, *tmp; - - while (list != NULL) - { - tmp = list->next; - list->dev->atalk_ptr = NULL; - kfree_s(list, sizeof(struct atalk_iface)); - list = tmp; - } -} +/* + * Note on MOD_{INC,DEC}_USE_COUNT: + * + * Use counts are incremented/decremented when + * sockets are created/deleted. + * + * Appletalk interfaces are not incremented untill atalkd is run + * and are only decremented when they are downed. + * + * Ergo, before the appletalk module can be removed, all Appletalk + * sockets be closed from user space. + */ void cleanup_module(void) { - unsigned long flags; + struct atalk_iface *ifaces = atalk_iface_list, *tmp; - save_flags(flags); - cli(); - - aarp_cleanup_module(); + while(ifaces != NULL) + { + tmp = ifaces->next; + ifaces->dev->atalk_ptr = NULL; + atalk_iface_down(ifaces); + ifaces = tmp; + } #ifdef CONFIG_SYSCTL atalk_unregister_sysctl(); -#endif +#endif /* CONFIG_SYSCTL */ #ifdef CONFIG_PROC_FS proc_net_unregister(PROC_NET_ATALK); proc_net_unregister(PROC_NET_AT_ROUTE); proc_net_unregister(PROC_NET_ATIF); -#endif +#endif /* CONFIG_PROC_FS */ + + aarp_cleanup_module(); /* General aarp clean-up. */ + unregister_netdevice_notifier(&ddp_notifier); dev_remove_pack(<alk_packet_type); dev_remove_pack(&ppptalk_packet_type); unregister_snap_client(ddp_snap_id); sock_unregister(atalk_family_ops.family); - free_route_list(); - free_interface_list(); - - restore_flags(flags); + return; } #endif /* MODULE */ +#endif /* CONFIG_ATALK || CONFIG_ATALK_MODULE */ diff --git a/net/appletalk/sysctl_net_atalk.c b/net/appletalk/sysctl_net_atalk.c index c2c1a8c64..776902889 100644 --- a/net/appletalk/sysctl_net_atalk.c +++ b/net/appletalk/sysctl_net_atalk.c @@ -59,9 +59,3 @@ void atalk_unregister_sysctl(void) { } #endif - - - - - - diff --git a/net/core/dev.c b/net/core/dev.c index c2b29617a..5970c5bab 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1006,7 +1006,7 @@ static int dev_ifname(struct ifreq *arg) strcpy(ifr.ifr_name, dev->name); - err = copy_to_user(&ifr, arg, sizeof(struct ifreq)); + err = copy_to_user(arg, &ifr, sizeof(struct ifreq)); return (err)?-EFAULT:0; } diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index ebf2c6c6b..472f64811 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -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); @@ -1265,7 +1266,7 @@ void arp_send(int type, int ptype, u32 dest_ip, arp = (struct arphdr *) skb_put(skb,sizeof(struct arphdr) + 2*(dev->addr_len+4)); skb->arp = 1; skb->dev = dev; - skb->protocol = htons (ETH_P_IP); + skb->protocol = htons (ETH_P_ARP); /* * Fill the device header for the ARP frame diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index ddb398938..74dbd2266 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_output.c,v 1.1.1.1 1997/06/01 03:16:26 ralf Exp $ + * Version: $Id: tcp_output.c,v 1.2 1997/09/12 01:34:42 ralf Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -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); diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index a5a884646..57b528c0d 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: icmp.c,v 1.1.1.1 1997/06/01 03:16:27 ralf Exp $ + * $Id: icmp.c,v 1.2 1997/07/20 15:01:57 ralf Exp $ * * Based on net/ipv4/icmp.c * @@ -92,7 +92,6 @@ struct icmpv6_msg { /* * getfrag callback - * not static because it's needed in ndisc.c */ static int icmpv6_getfrag(const void *data, struct in6_addr *saddr, @@ -131,11 +130,12 @@ static int icmpv6_getfrag(const void *data, struct in6_addr *saddr, } /* - * an inline helper for the "simple" if statement bellow + * an inline helper for the "simple" if statement below * checks if parameter problem report is caused by an * unrecognized IPv6 option that has the Option Type * highest-order two bits set to 10 */ + static __inline__ int opt_unrec(struct sk_buff *skb, __u32 offset) { char *buff = skb->nh.raw; diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 25b34465c..a54582816 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: ip6_fib.c,v 1.7 1997/04/12 04:32:46 davem Exp $ + * $Id: ip6_fib.c,v 1.1.1.1 1997/06/01 03:16:27 ralf Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -235,7 +235,15 @@ static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr, key = (struct rt6key *)((u8 *)fn->leaf + offset); + /* + * Prefix match + */ if (addr_match(&key->addr, addr, fn->fn_bit)) { + + /* + * Exact match ? + */ + if (plen == fn->fn_bit) { /* clean up an intermediate node */ if ((fn->fn_flags & RTN_RTINFO) == 0) { @@ -248,6 +256,10 @@ static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr, return fn; } + /* + * We have more bits to go + */ + if (plen > fn->fn_bit) { /* Walk down on tree. */ fn->fn_sernum = sernum; @@ -255,6 +267,11 @@ static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr, pn = fn; fn = dir ? fn->right: fn->left; + /* + * Round we go. Note if fn has become + * NULL then dir is set and fn is handled + * top of loop. + */ continue; } } @@ -611,7 +628,8 @@ static struct rt6_info * fib6_find_prefix(struct fib6_node *fn) } /* - * called to trim the tree of intermediate nodes when possible + * Called to trim the tree of intermediate nodes when possible. "fn" + * is the node we want to try and remove. */ static void fib6_del_2(struct fib6_node *fn) @@ -621,6 +639,10 @@ static void fib6_del_2(struct fib6_node *fn) fn->fn_flags &= ~RTN_RTINFO; rt6_stats.fib_route_nodes--; + /* + * Can't delete a root node + */ + if (fn->fn_flags & RTN_TL_ROOT) return; @@ -630,43 +652,89 @@ static void fib6_del_2(struct fib6_node *fn) child = NULL; + /* + * We have a child to left + */ + if (fn->left) { children++; child = fn->left; } + /* + * To right + */ + if (fn->right) { children++; child = fn->right; } + /* + * We can't tidy a case of two children. + */ + if (children > 1 || (fn->fn_flags & RTN_RTINFO)) break; + /* + * The node we plan to tidy has an stree. Talk about + * making life hard. + */ + if (fn->subtree) goto stree_node; + /* + * Up we go + */ + pn = fn->parent; + /* + * Not a ROOT - we can tidy + */ + if ((fn->fn_flags & RTN_ROOT) == 0) { + /* + * Make our child our parents child + */ if (pn->left == fn) pn->left = child; else pn->right = child; + /* + * Reparent the child + */ if (child) child->parent = pn; + /* + * Discard leaf entries + */ if (fn->leaf) rt6_release(fn->leaf); } else { if (children) break; + /* + * No children so no subtree + */ pn->subtree = NULL; } + /* + * We are discarding + */ node_free(fn); + + /* + * Our merge of entries might propogate further + * up the tree, so move up a level and retry. + */ + fn = pn; } while (!(fn->fn_flags & RTN_TL_ROOT)); @@ -685,18 +753,29 @@ stree_node: fn->leaf = rt; } +/* + * Remove our entry in the tree. This throws away the route entry + * from the list of entries attached to this fib node. It doesn't + * expunge from the tree. + */ + static struct fib6_node * fib6_del_1(struct rt6_info *rt) { struct fib6_node *fn; fn = rt->rt6i_node; + /* We need a fib node! */ if (fn) { struct rt6_info **back; struct rt6_info *lf; back = &fn->leaf; + /* + * Walk the leaf entries looking for ourself + */ + for(lf = fn->leaf; lf; lf=lf->u.next) { if (rt == lf) { /* diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index cf107efcd..ad33e86a2 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -6,7 +6,7 @@ * Pedro Roque <roque@di.fc.ul.pt> * Ian P. Morris <I.P.Morris@soton.ac.uk> * - * $Id: ip6_input.c,v 1.6 1997/05/11 16:06:52 davem Exp $ + * $Id: ip6_input.c,v 1.1.1.1 1997/06/01 03:16:27 ralf Exp $ * * Based in linux/net/ipv4/ip_input.c * @@ -374,6 +374,9 @@ int ip6_mc_input(struct sk_buff *skb) if (ipv6_chk_mcast_addr(skb->dev, &hdr->daddr)) deliver = 1; + /* + * IPv6 multicast router mode isnt currently supported. + */ #if 0 if (ipv6_config.multicast_route) { int addr_type; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 6c14747eb..cafa5eafb 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: ip6_output.c,v 1.3 1997/03/18 18:24:37 davem Exp $ + * $Id: ip6_output.c,v 1.1.1.1 1997/06/01 03:16:27 ralf Exp $ * * Based on linux/net/ipv4/ip_output.c * @@ -47,7 +47,9 @@ static void ipv6_build_mac_hdr(struct sk_buff *skb, struct dst_entry *dst, if (dev->hard_header) { int mac; - + + /* Maybe when Alexey has done his new magic I'll hack this + it seems to be worth 1-2% on IPv4 */ #if 0 if (dst->hh) hh_copy_header(dst->hh, skb); @@ -143,7 +145,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, /* * To avoid extra problems ND packets are send through this - * routine. It's code duplication but i really want to avoid + * routine. It's code duplication but I really want to avoid * extra checks since ipv6_build_header is used by TCP (which * is for us performace critical) */ diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 1b4235dbd..612534930 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: route.c,v 1.1.1.1 1997/06/01 03:16:27 ralf Exp $ + * $Id: route.c,v 1.2 1997/08/06 19:16:57 miguel Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -733,6 +733,25 @@ int ip6_del_rt(struct rt6_info *rt) int ip6_route_del(struct in6_rtmsg *rtmsg) { + struct rt6_info *rt; + struct device *dev=NULL; + + /* + * Find device + */ + if(rtmsg->rtmsg_ifindex) + dev=dev_get_by_index(rtmsg->rtmsg_ifindex); + /* + * Find route + */ + rt=rt6_lookup(&rtmsg->rtmsg_dst, &rtmsg->rtmsg_src, dev, rtmsg->rtmsg_flags); + + /* + * Blow it away + */ + if(rt) + ip6_del_rt(rt); + return 0; } diff --git a/net/netlink.c b/net/netlink.c index f33c04040..9bf31a126 100644 --- a/net/netlink.c +++ b/net/netlink.c @@ -126,8 +126,7 @@ static long netlink_read(struct inode * inode, struct file * file, char * buf, return err ? -EFAULT : count; } -static loff_t netlink_lseek(struct inode * inode, struct file * file, - loff_t offset, int origin) +static long long netlink_lseek(struct file * file, long long offset, int origin) { return -ESPIPE; } diff --git a/net/socket.c b/net/socket.c index ce8bb95c5..3405677cd 100644 --- a/net/socket.c +++ b/net/socket.c @@ -96,8 +96,7 @@ #include <net/scm.h> -static long long sock_lseek(struct inode *inode, struct file *file, - long long offset, int whence); +static long long sock_lseek(struct file *file, long long offset, int whence); static long sock_read(struct inode *inode, struct file *file, char *buf, unsigned long size); static long sock_write(struct inode *inode, struct file *file, @@ -107,7 +106,7 @@ static int sock_close(struct inode *inode, struct file *file); static unsigned int sock_poll(struct file *file, poll_table *wait); static int sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); -static int sock_fasync(struct inode *inode, struct file *filp, int on); +static int sock_fasync(struct file *filp, int on); /* @@ -353,8 +352,7 @@ int sock_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags) * Sockets are not seekable. */ -static long long sock_lseek(struct inode *inode, struct file *file, - long long offset, int whence) +static long long sock_lseek(struct file *file,long long offset, int whence) { return -ESPIPE; } @@ -482,7 +480,7 @@ int sock_close(struct inode *inode, struct file *filp) printk(KERN_DEBUG "sock_close: NULL inode\n"); return 0; } - sock_fasync(inode, filp, 0); + sock_fasync(filp, 0); sock_release(socki_lookup(inode)); return 0; } @@ -491,7 +489,7 @@ int sock_close(struct inode *inode, struct file *filp) * Update the socket async list */ -static int sock_fasync(struct inode *inode, struct file *filp, int on) +static int sock_fasync(struct file *filp, int on) { struct fasync_struct *fa, *fna=NULL, **prev; struct socket *sock; @@ -504,7 +502,7 @@ static int sock_fasync(struct inode *inode, struct file *filp, int on) return -ENOMEM; } - sock = socki_lookup(inode); + sock = socki_lookup(filp->f_dentry->d_inode); prev=&(sock->fasync_list); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index bcdb13610..971163963 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -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); diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 960093cad..fb02640f9 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -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); diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 3e1d57873..b5495df93 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -74,7 +74,9 @@ EXPORT_SYMBOL(svc_wake_up); /* RPC statistics */ #ifdef CONFIG_PROC_FS EXPORT_SYMBOL(rpc_proc_register); +EXPORT_SYMBOL(rpc_register_sysctl); EXPORT_SYMBOL(rpc_proc_unregister); +EXPORT_SYMBOL(rpc_proc_init); EXPORT_SYMBOL(rpc_proc_read); EXPORT_SYMBOL(svc_proc_register); EXPORT_SYMBOL(svc_proc_unregister); diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 62d2d7b40..87a5ed82e 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -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(); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index dc4fd0515..0372500ee 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -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); diff --git a/net/unix/garbage.c b/net/unix/garbage.c index 02fafc7f6..d68f018fd 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c @@ -35,31 +35,20 @@ */ #include <linux/kernel.h> -#include <linux/major.h> -#include <linux/signal.h> #include <linux/sched.h> -#include <linux/errno.h> #include <linux/string.h> -#include <linux/stat.h> #include <linux/socket.h> #include <linux/un.h> -#include <linux/fcntl.h> -#include <linux/termios.h> -#include <linux/socket.h> -#include <linux/sockios.h> #include <linux/net.h> -#include <linux/in.h> #include <linux/fs.h> #include <linux/malloc.h> -#include <linux/vmalloc.h> - -#include <asm/uaccess.h> #include <linux/skbuff.h> #include <linux/netdevice.h> #include <net/sock.h> #include <net/tcp.h> #include <net/af_unix.h> #include <linux/proc_fs.h> +#include <linux/vmalloc.h> #include <net/scm.h> /* Internal data structures and random procedures: */ |