diff -u --recursive --new-file v2.1.9/linux/CREDITS linux/CREDITS --- v2.1.9/linux/CREDITS Tue Nov 12 15:56:01 1996 +++ linux/CREDITS Wed Nov 13 08:11:16 1996 @@ -713,6 +713,10 @@ S: L-4505 Differdange S: Luxembourg +N: Gerd Knorr +E: kraxel@cs.tu-berlin.de +D: SCSI CD-ROM driver hacking, minor bug fixes + N: Harald Koenig E: koenig@tat.physik.uni-tuebingen.de D: XFree86 (S3), DCF77, some kernel hacks and fixes diff -u --recursive --new-file v2.1.9/linux/Documentation/Changes linux/Documentation/Changes --- v2.1.9/linux/Documentation/Changes Tue Nov 12 15:56:01 1996 +++ linux/Documentation/Changes Wed Nov 13 08:22:15 1996 @@ -1,58 +1,39 @@ Intro ===== -This document contains a list of the latest stable releases of the most -important packages for Linux as well as instructions for newcomers to -the 2.0.x series of kernels. By glancing through it, you should be -able to find out what you need to upgrade in order to successfully run -the latest kernels. - - It was originally based on material from the linux-kernel mailing -list, Jared Mauch's web page "Software Victims of the 1.3 Kernel -Development" (http://www2.nether.net/~jared/victim.html), and Axel -Boldt's (boldt@math.ucsb.edu) Configure.help file, among other sources, -and was originally written and maintained by Alessandro Sigala -(ssigala@globalnet.it). - - There is now a web page based on this material, thanks to John -Taylor. Check out http://www.cviog.uga.edu/LinuxBleed.html if you -prefer a HTML-ized shopping list. - - Para aquellos que prefieran una version en castellano de este -documento, consultad la traduccion de Alfredo Sanjuan en -http://slug.ctv.es/~alfredo/Cambios.html (Spanish translation). - - Akik magyarul szeretnenek olvasni az uj kernellel kapcsolatos -valtozasokrol, az alabbi cimen megtalaljak Nyitrai Tamas forditasat: -http://www.datanet.hu/generations/linux/newkernel.html (Hungarian -translation). - - Tamas also maintains a version of this file at -http://www.datanet.hu/generations/linux/Changes.html (English version). - - For people who prefer Japanese (thanks to Mitsuhiro Kojima): Kono -bunshou no nihongo ban wa -http://jf.gee.kyoto-u.ac.jp/JF/v2.0/Changes-2.0.html ni arimasu. +This document is designed to provide a list of the minimum levels of +software necessary to run the 2.1.x kernels, as well as provide brief +instructions regarding any other "Gotchas" users may encounter when +trying life on the Bleeding Edge. If upgrading from a pre-2.0.x +kernel, please consult the Changes file included with 2.0.x kernels for +additional information; most of that information will not be repeated +here. Basically, this document assumes that your system is already +functional and running at least 2.0.x. + + It is originally based on my "Changes" file for 2.0.x kernels and +therefore owes credit to the same people as that file (Jared Mauch, +Axel Boldt, Alessandro Sigala, and countless other users all over the +'net). Please feel free to submit changes, corrections, gripes, +flames, money, etc. to me (gt1355b@prism.gatech.edu). If you do so, +you don't need to bother doing so in the form of a diff, as this is +generated by texinfo so a diff is useless anyway (though I can +incorporate one by hand if you insist upon sending it that way ;-). - Voyez le site http://www.linux-kheops.com/traduc/kernels/ pour la -traduction francais (merci, David Bourgin). (French translation) - -Last updated: November 5, 1996. +Last updated: November 13, 1996. Current Author: Chris Ricker (gt1355b@prism.gatech.edu). -Current Releases -**************** +Current Minimal Requirements +**************************** + + Upgrade to at *least* these software revisions before thinking you've +encountered a bug! - Kernel modules 2.0.0 -- PPP daemon 2.2.0f -- Dynamic linker (ld.so) 1.7.14 -- GNU CC 2.7.2.1 +- Gnu C 2.7.2.1 - Binutils 2.7.0.3 -- Linux C Library Stable: 5.2.18, Beta: 5.4.10 +- Linux C Library 5.4.12 - Linux C++ Library 2.7.2.1 -- Termcap 2.0.8 - Procps 1.01 -- Gpm 1.10 - SysVinit 2.64 - Util-linux 2.5 - Mount 2.5p @@ -62,525 +43,27 @@ Upgrade notes ************* -Network errors with recent kernels -================================== - - Many default network scripts are set up to add a route to the -localhost at 127.0.0.1 at startup. However, they do this incorrectly. -To fix the error, which is now spotted by the kernel (causing many -daemons to quit working), look for a line like `route add -net -127.0.0.1' in your network configuration files and change it to `route -add -net 127.0.0.0'. - - This error is present in all Red Hat distributions through Red Hat -3.03 (and derivative distributions like Caldera). If you're running -one of these, edit /etc/sysconfig/network-scripts/ifup-lo, changing the -line `route add -net $(IPADDR)' to `route add -net 127.0.0.0' and you -should be fine. - - People have also reported problems due to the naming of the dummy -network interface driver. If the dummy driver is compiled into the -kernel, its name is "dummy." If the dummy driver is compiled as a -module, its name is "dummy0." Furthermore, more than one dummy driver -can be loaded if compiled as a module. Each subsequent loading of the -driver adds a new dummy interface whose name is incremented by one -("dummy1," "dummy2," etc.). - -Booting Changes -=============== - - The boot support in 2.0.x (for arch/i386) has been enhanced so that -it now can load bigger kernels (bzImage) and that the loaders now can -load an initial ramdisk (initrd). For initrd see -Documentation/initrd.txt. For building bigger kernels use one of the -following make targets: bzImage, bzlilo, bzdisk (equivalent to make -targets zImage, zlilo, and zdisk respectively). If you want or need to -use the new features you'll need to upgrade your bootloaders. Lilo can -be found at ftp://lrcftp.epfl.ch/pub/linux/local/lilo/lilo.19.tar.gz. -LOADLIN is at -ftp://sunsite.unc.edu/pub/Linux/system/Linux-boot/lodlin16.tgz. If -you're using more unusual loaders like SysLinux or etherboot, the -latest versions are 1.3 and 2.0, respectively. - - Ramdisk support does not work with the latest kernels if ramdisk=0 -option is present. Many older distributions (mainly Slackware) have -this option in their lilo.config file. Comment it out and re-run lilo -if you need ramdisks. - - The definition of SIOCSARP in /usr/include/linux/sockios.h was -changed. This means bootpd has to be re-compiled in order to work. - - The kernel reboot method is now, by default, a cold reboot so that -the kernel will work on systems that don't support other methods. If -you want to be able to do a warm reboot, add a reboot=warm option to -lilo.conf. - -The Linux C Library -=================== - - The latest stable Linux C Library release is 5.2.18. If you upgrade -to this from 5.0.9 or earlier, be sure to read the -`release.libc-5.2.18' file, since GNU make and a few other fairly -important utils can be broken by the upgrade. - - The current (beta) Linux C Library release is 5.3.12. In this -release there are some important changes that may cause troubles to -buggy programs (programs that call free() on a pointer not returned by -malloc() work with previous libc, but not with this release) so read the -`release.libc-5.3.12' file carefully! In the latest libc releases a -dirent bug, which erroneously defined d->reclen to d->namlen if USE_GNU -was defined, has been fixed. Unfortunately, some GNU packages depend -on this bug. GNU make 3.xx is one of them. To fix that you need to -patch and recompile those programs (a patch for make is included in the -file `release.libc-.5.3.9', and the address to obtain a precompiled -binary is at the end of this file). - - Also, the libc-5.3.x line has a known security hole relating to -rlogin. Libc-5.3.12 fixes this, so if you're going to run an -experimental libc, be sure to upgrade to 5.3.12. Libc-5.4.10 is -currently available as well, but it may have problems, so caveat emptor. - - If you're getting an error message that is something to the effect of - - `fcntl_setlk() called by process 123 with broken flock() emulation' - - then you need to upgrade to at least libc-5.2.18 as well. A proper -(in other words, BSD-style ;-) flock system call was added to 2.0.x, -and older libc's will now give this error. It doesn't *really* matter, -so you can just ignore it. If it really annoys you, upgrade libc (and -recompile any static binaries you might have that are linked against -the old libc). If you're feeling lazy, just comment out - - ` printk(KERN_WARNING -"fcntl_setlk() called by process %d with broken flock() - emulation\n", current->pid);' - - in linux/fs/locks.c and recompile. If you're still running a.out, -there's an unofficial libc-4.7.6 release out to which you can upgrade -to fix this problem. Libc is available from -ftp://sunsite.unc.edu/pub/Linux/GCC/. - -GCC Signal 11 error -=================== - - Many people have been reporting messages like the following, -especially when compiling a new kernel: - - `gcc: Internal compiler error: program cc1 got fatal signal 11'. - - This is NOT a kernel bug. Rather, these messages are generally -caused by hardware problems. See http://www.bitwizard.nl/sig11/ for -the sig11 FAQ. - - On the other hand, if you're using a gcc patched for Pentium -optimization and are getting these errors, downgrade to a standard GNU -gcc before assuming your hardware (or the kernel) is to blame. - - On a related note, if you get random OOPses that don't seem to be -related to anything and you have a motherboard with APM support, try -disabling the APM support and/or compiling the kernel with APM support. - -Procps utilities -================ - - Due to changes in the structure of the /proc filesystem, you need to -upgrade procps to the latest release, currently 1.01. Otherwise, -you'll get floating point errors with some ps commands or other similar -surprises. Grab -ftp://sunsite.unc.edu/pub/Linux/system/Status/ps/procps-1.01.tgz. - -Kernel Modules -============== - - Almost all drivers in 2.0.x can be modules, and kerneld is now -incorporated into the kernel. To take advantage of this, you'll need -the latest version of the module support apps. These are available at -http://www.pi.se/blox/modules/modules-2.0.0.tar.gz. Note: If you try to -load a module and get a message like - - `gcc2_compiled, undefined Failed to load module! The symbols from -kernel 1.3.foo don't match 1.3.foo' - - where `foo' is a number for a recent kernel, then it's definitely -time to upgrade module utilities. - - Another little tip: you can't have both a.out *and* ELF support -compiled as modules. Otherwise, you get a nice Catch-22 when you try -to run insmod to install a.out/ELF support so you can run insmod ;-). -If you have an all-ELF system, but need a.out for the occasional legacy -app, then you can do a.out support as a module. Otherwise, you should -probably leave it in the kernel, and if you haven't gone ELF yet, you -can probably say no to ELF support. Similarly, any partitions that you -have to mount at startup have to have their necessary file system and -device drivers compiled into the kernel, so don't get grandiose ideas -about going completely modular and then forget to compile ext2fs -support and ide/SCSI drive support into your kernel ;-). - -Kernel messages -=============== - - Kernel messages without a specific log level use the kernel's -default log level. In 1.2 kernels, the default log level was 6 -(information), while in 2.0.x kernels it is 4 (warning). Adjust your -configuration of syslogd appropriately (or edit printk.c in the kernel -source ;-). - -PPP driver -========== - - You need to be running a pppd from ppp-2.2.0.tar.gz or greater. The -latest stable release is 2.2.0f and is available at -ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/ppp/ppp-2.2.0f.tar.gz. - -Named pipes (SysVinit) -====================== - - Linux's handling of named pipes changed (it now does it The Right Way -instead of the SunOS way ;-). This broke some programs that depended -on the SunOS behavior, most notably SysVinit. If you're running 2.59 -or earlier, you will probably get a weird error on shutdown in which -your computer shuts down fine but "INIT: error reading initrequest" or -words to that effect scroll across your screen hundreds of times. To -fix, upgrade to -ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.64.tar.gz. - - If you're trying to run NCSA httpd, you might have problems with -pre-spawning daemons. Upgrade to the latest release (1.5.2), available -from http://hoohoo.ncsa.uiuc.edu/ or check out Apache -(http://www.apache.org/). - - The new named pipe behavior also causes problems with Hylafax. If -you're running the hylafax daemon, it will just keep eating up CPU time -until you have no idle time free. To fix this, edit port.h included -with the Hylafax distribution and change the line - - CONFIG_OPENFIFO="O_RDONLY" - - to - - CONFIG_OPENFIFO="O_RDWR" - - A similar method (finding all named pipes opened read-only and -changing them to read-write) will fix any program that is broken -because of this change. - -File Locking (Sendmail) -======================= - - As of pre2.0.6 (aka 1.99.6), mixed-style file locking is no longer -allowed. For example, a file cannot be simultaneously locked with -`flock' and `fcntl'. See Documentation/locks.txt for all the gory -details. Among the programs this has impacted are older sendmails. If -you get a message that sendmail cannot lock aliases.dir (or other -files), you'll need to upgrade to at least 8.7.x. The latest sendmail -is at ftp://ftp.cs.berkeley.edu/ucb/src/sendmail/sendmail.8.8.2.tar.gz. - -Uugetty -======= - - Older uugettys will not allow use of a bidirectional serial line. To -fix this problem, upgrade to -ftp://sunsite.unc.edu/pub/Linux/system/Serial/getty_ps-2.0.7i.tar.gz. - -Kbd -=== - - For those of you needing non-ASCII character/font support, you should -upgrade to ftp.funet.fi:/pub/OS/Linux/PEOPLE/Linus/kbd-0.91.tar.gz. - -Mount -===== - - The mount util is distributed as part of util-linux, which is -currently at release 2.5. Some may find, especially when using the -loop or xiafs file system, NFS, or automounting, that they need to -upgrade to the latest release of mount, available from -ftp://ftp.win.tue.nl/pub/linux/util/mount-2.5p.tar.gz. - -Console -======= - - The Linux console type has changed. If your setup is old enough -that you have problems, you'll need to update your termcap. To fix, -add linux to one of the types in /etc/termcap or snoop around -http://www.ccil.org/~esr/ncurses.html (reputedly the latest universal -termcap maintainer). You may also need to update terminfo by running -the following as root: - - ln -s /usr/lib/terminfo/l/linux /usr/lib/terminfo/c/console - - Better yet, just get the latest official Linux termcap from -ftp://sunsite.unc.edu/pub/Linux/GCC/termcap-2.0.8.tar.gz. If you -upgrade to this release read the `README' file contained into the -package to get some important information about the `tgetent' function -changes! Note that there is now a fixed version at -ftp://sunsite.unc.edu/pub/Linux/GCC/termcap-2.0.8.fix. If some of your -apps complain that termcap entries are too long and you don't need some -of the more esoteric terms in the standard 2.0.8 termcap, just download -termcap-2.0.8.fix and move it to /etc/termcap. - - Also, the console driver is now responsible for keeping track of -correspondence between character codes and glyph bitmaps. If you -encounter problems, try `loadunimap def' to get back the default -correspondence. - -Hdparm -====== - - Hdparm has been upgraded to take advantage of the latest features of -the kernel drivers. The latest non-beta version can be found at -ftp://sunsite.unc.edu/pub/Linux/kernel/patches/diskdrives/hdparm-3.1.tar.gz. - -IP Accounting -============= - - All IP packets coming in or going out via one of the network -interfaces are now passing the accounting chain. So, packets being -forwarded are passing this chain twice. Since pre2.0.7 (aka 1.99.7), -accounting rules can be defined so that they will only match in one -direction (either incoming or outgoing). - - There also exists a possibility to match on device names and/or -device addresses, so that only packets coming in/going out via that -device (network interface) match with a rule. You'll need to get -ipfwadm from ftp://ftp.xos.nl/pub/linux/ipfwadm/ipfwadm-2.3.0.tar.gz to -use this. - -IP Firewalls -============ - - The IP firewall code has been changed drastically for 2.0.x. There -are now 3 categories of firewall rules: one for incoming packets, one -for outgoing packets, and one for packets being forwarded. There also -exists a possibility to match on device names and/or device addresses, -so that only packets coming in/going out via that device (network -interface) match with a rule. This is especially useful to prevent -spoofing. You'll need to get -ftp://ftp.xos.nl/pub/linux/ipfwadm/ipfwadm-2.3.0.tar.gz to use this. - -IP Masquerading -=============== - - IP masquerading is now part of the standard kernel. However, you -always need to load separate modules (ip_masq_ftp.o and/or -ip_masq_irc.o) if you are going to use FTP or IRC in combination with -masquerading. You'll need to get -ftp://ftp.xos.nl/pub/linux/ipfwadm/ipfwadm-2.3.0.tar.gz to use this. - -ISDN support -============ - - The new kernels support ISDN. You'll need ISDN utils available from -ftp://ftp.franken.de/pub/isdn4linux/v2.0/isdn4k-utils-2.0.tar.gz to try -this. - -Frame Relay -=========== - - Frame relay support for Linux is now available as well. Currently, -only Sangoma cards are supported, but the interface is such that others -will be as drivers become available. To use this, grab -ftp://linux.invlogic.com/pub/fr/frad-0.15.tgz (soon to be -frad-0.20.tgz). Another package of interest is -ftp://linux.invlogic.com/pub/routing/routing.tgz (which allows Linux to -make routing decisions based on packet source). - -Networking -========== - - Some of the /proc/net entries have changed. You'll need to upgrade -to the latest net-tools in -ftp://ftp.inka.de/pub/comp/Linux/networking/NetTools/, where the latest -is currently net-tools-1.32-alpha.tar.gz. See -http://www.inka.de/sites/lina/linux/NetTools/index_en.html for more -information. Note that there is currently no ipfw (which is part of -net-tools) which works with 2.0.x kernels. If you need its functions, -learn how to use ipfwadm or patch ipfw to get it to work (ipfw's current -maintainer does not currently have time to fix it). - -Xntpd -===== - - Older versions of xntpd will not work with the latest kernels. -Upgrade to xntp3.5f.tar.Z, available from -ftp://louie.udel.edu/pub/ntp/xntp3.5f.tar.Z. - -Sound driver -============ - - The sound driver was upgraded in the 2.0.x kernels, breaking vplay. -To fix this problem, get a new version of the sndkit from -ftp://ftp.best.com/pub/front/tasd/snd-util-3.5.tar.gz. Some users -report that various other sound utils (cdd2wav-sbpcd, for example) need -to be recompiled before they will work with the new kernels. - -Tcsh -==== - - If tcsh acts funny, get the source from -ftp://anise.ee.cornell.edu/pub/tcsh and add #define SYSMALLOC in -config_f.h before recompiling tcsh. Binaries can be found in -ftp://sunsite.unc.edu/pub/Linux/system/Shells/ and a corrected one will -probably wind up there eventually. - -Make -==== - - If make no longer works, you need to read the release notes for the -libc you upgraded to. The latest libc and release notes can be found at -ftp://tsx-11.mit.edu/pub/linux/packages/GCC. This is NOT an error due -to the kernel, though many people have mistakenly thought it is. When -you upgrade to libc-5.3.9, you have to patch make to get it to work. -All of this is documented in the release notes with libc. Upgrading -libc can also break xterm support. If it does, you need to recompile -xterm. - -Loop device -=========== - - 2.0.x kernels include loop device support which lets you mount a -file as a file system, which can allow for all sorts of cool things -like encrypted file systems and such. To use it, you'll need a -modified version of mount from -ftp://ftp.win.tue.nl/pub/linux/util/mount-2.5k.tar.gz; preliminary work -on encrypted file system support can be found in -ftp.funet.fi:/pub/Linux/BETA/loop/des.1.tar.gz. - -Multiple device -=============== - - Multiple device support (allowing you to group several partitions -into one logical device) has also been added. Check out -ftp://sweet-smoke.ufr-info-p7.ibp.fr/pub/Linux/md035.tar.gz to try this -out. - -Arp -=== - - Arp daemon support has been added. Check out -http://www.loran.com/~layes/arpd/index.html for more info and -http://www.loran.com/~layes/arpd/arpd-1.0.2.tar.gz for a copy of arpd. - -Quota -===== - - Quota support has also been added. You need to get quotas-1.55 from -ftp://ftp.funet.fi/pub/Linux/kernel/src/subsystems/quota/all.tar.gz. You -may need to copy its mntent.h over to /usr/include/mntent.h to get it to -compile. - -Process Accounting -================== - - Process accounting support has also been integrated into the new -kernels. To use this feature, you'll need to get -ftp://iguana.hut.fi/pub/linux/Kernel/process_accounting/acct_1.3.73.tar.gz. - -Bdflush and Updated +General Information =================== - Bdflush has also been integrated into the new kernels, so those of -you using it on older systems no longer need to hunt for the patches to -implement it once you upgrade to 2.0.x. You do still need to run the -update daemon, however. You should probably upgrade to the latest -updated, currently -ftp://sunsite.unc.edu/pub/Linux/system/Daemons/updated-1.2.tar.gz. This -(and later) versions will not spawn a bdflush daemon, since that is now -done by the kernel (kflushd). If you upgrade, be sure to leave update -in your init scripts and remove bdflush. - -APM support -=========== - - Advanced Power Management (APM) support has been added to the kernel -as well. APM, which is primarily of use in laptops, provides access to -battery status information and may help to conserve battery power. The -support files can be found in -ftp://tsx-11.mit.edu/pub/linux/packages/laptops/apm/apmd-2.4.tar.gz - -iBCS and Dosemu -=============== - - For a version of iBCS that works with 2.0.x kernels, grab -ftp://tsx-11.mit.edu/pub/linux/BETA/ibcs2/ibcs-2.0-960610.tar.gz + now performs a cold reboot instead of a warm reboot +for increased hardware compatibility. If you want a warm reboot and +know it works on your hardware, add a "reboot=warm" command line option +in Lilo. - For a version of Dosemu that works (well, at least as well as DOS -ever works ;-), get -ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/Development/dosemu-0.64.0.3.tgz -or check out http://www.ednet.ns.ca/auto/rddc. Be sure to follow the -instructions in README.newkernels about patching your include files, or -it will not compile. - -Mtools and Fdutils -================== - - The floppy ioctl numbering scheme has changed for 2.0.x. For -backwards compatibility, the old system was supported through 1.3.x and -will generate a warning in 2.0. In 2.1.x, the old scheme will -disappear entirely. - - To avoid trouble (or at least annoying messages), you'll need to -recompile any programs which emit floppy ioctls, including mtools and -fdutils. For mtools, get -ftp://sunsite.unc.edu/pub/Linux/utils/disk-management/mtools-3.0.src.tar.gz -and for fdutils, get -ftp://sunsite.unc.edu/pub/Linux/system/Misc/fdutils-4.3.src.tar.gz. - - In the future, fdformat might disappear entirely, so get used to -using superformat instead. - -Cyclades Serial Driver -====================== - - The Cyclades driver has been changed so that the minor numbers start -at 0 instead of 32 (for example, ttyC0 should be major 19, minor 0 for -2.0.x kernels; in older kernels, it would have been major 19, minor -32). Use mknod or a sufficiently new version of MAKEDEV to fix this. - -NCR 53c810 SCSI Driver -====================== - - Drivers for this card are now included in the standard linux source. -However, they require Perl to be installed before they will compile. -As far as I know, this is the only code in the kernel source that -requires Perl to compile. If your kernel compile fails and you happen -to have included this driver in your configuration, make sure you have -Perl installed. - -Perl +Libc ==== - While we're on the subject, changes made for the 2.0.x series cause -the connect() Perl (both 4 and 5) call to time out while connecting to -remote systems. The problem is not actually in the connect() call; -rather, the optional bind() call usually used with connect() causes the -problem. Remove the bind() call and your Perl scripts should connect. - - Also, Perl scripts using the readdir call now misbehave if you're -using an old version of Perl, due to changes in libc. Upgrade to a -more current Perl to avoid any unpleasantness. - -Groff -===== - - Those of you running Slackware may experience weirdness with man -pages due to changes in groff. If your man pages display for - -when present at the end of a line, try setting an appropriate value -(many have reported success with "latin1", for example) for the -environmental variable LESSCHARSET. Another, and probably better, -solution is to edit the file /usr/lib/man.config and change all -`-Tlatin1' options to `-Tascii'. An alternate solution, for those of -you who can't reformat your man files in .../cat* directories is to -edit /usr/lib/man.config, setting the PAGER to `PAGER -(LESSCHARSET=latin1;export LESSCHARSET;/usr/bin/less -is)'. - -E2fsprogs -========= - - e2fsprogs 1.02 will work with the latest kernels, but it cannot be -compiled on them. If you need (or want) to compile your own copy, -you'll need to get the latest version, currently available at -ftp://tsx-11.mit.edu/pub/linux/packages/ext2fs/e2fsprogs-1.06.tar.gz. + Linux-2.1.x is ELF-only. You can still compile a.out apps if you +really want, but your kernel must be compiled ELF. If you can't +currently compile ELF, consult the ELF howto at +http://sunsite.unc.edu/mdw/HOWTO/ELF-HOWTO.html and upgrade your system +accordingly. + + For modules to work, you need to be running libc-5.4.7 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, that is libc-5.4.12. How to know the version of the installed programs ************************************************* @@ -589,13 +72,10 @@ installed programs and libraries. The SysVinit version display requires that you be logged in as root. -GNU CC: gcc -v and gcc --version -PPP: pppd -h (wrong but it show the version) -Libc: ls -l /lib/libc.so.5 -Libc++: ls -l /usr/lib/libg++.so +Gnu C: gcc -v or gcc --version +Libc: ls -l /lib/libc.so.* +Libc++: ls -l /usr/lib/libg++.so.* Binutils: ld -v -ldd: ldd -v and ldd -V -termcap: ls -l /lib/libtermcap.so.* modules: insmod -V procps: ps --version SysVinit: cat /proc/`cat /var/run/syslog.pid`/environ|strings|awk '$1 ~ @@ -611,8 +91,8 @@ Installation notes: ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/release.binutils-2.7.0.3 -GNU CC -====== +Gnu C +===== ftp://sunsite.unc.edu/pub/Linux/GCC/gcc-2.7.2.1.bin.tar.gz Installation notes: @@ -626,15 +106,10 @@ Installation notes for 5.2.18: ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.2.18 -The latest 5.4.10 release: -ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.4.10.bin.tar.gz -Installation notes for 5.4.10: -ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.4.10 - -Patched make sources: -ftp://sunsite.unc.edu/pub/Linux/devel/make/make-3.74.patched.tar.gz -Patched make binary: -ftp://sunsite.unc.edu/pub/Linux/devel/make/make-3.74-direntfix-elf.tgz +The latest 5.4.12 release (when it gets there): +ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.4.12.bin.tar.gz +Installation notes for 5.4.12: +ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.4.12 Linux C++ Library ================= @@ -648,34 +123,16 @@ ftp://sunsite.unc.edu/pub/Linux/GCC/ld.so-1.7.14.tar.gz -Termcap Library -=============== - -ftp://sunsite.unc.edu/pub/Linux/GCC/termcap-2.0.8.tar.gz - Modules utilities ================= -The latest public release: ftp://sunsite.unc.edu/pub/Linux/kernel/modules-2.0.0.tar.gz -PPP Daemon and utilities -======================== - -The latest public release: -ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/ppp/ppp-2.2.0f.tar.gz - Procps utilities ================ ftp://sunsite.unc.edu/pub/Linux/system/Status/ps/procps-1.01.tgz -Gpm mouse utilities -=================== - -ftp://iride.unipv.it/pub/gpm/gpm-1.10.tar.gz -ftp://sunsite.unc.edu/pub/Linux/system/Daemons/gpm-1.10.tar.gz - SysVinit utilities ================== @@ -686,16 +143,6 @@ ftp://sunsite.unc.edu/pub/Linux/system/Misc/util-linux-2.5.tar.gz -Mtools -====== - -ftp://sunsite.unc.edu/pub/Linux/utils/disk-management/mtools-3.0.src.tar.gz - -Fdutils -======= - -ftp://sunsite.unc.edu/pub/Linux/system/Misc/fdutils-4.3.src.tar.gz - Other Info ========== @@ -708,20 +155,14 @@ your favorite Red Hat mirror site before installing the non-RPM version. Remember, you might need to use the -force option to get the upgrade to install. Almost everything you need is available in -ftp://ftp.redhat.com/pub/current/i386/updates/2.0-kernel/ and its -mirrors. +ftp://ftp.redhat.com/pub/contrib/ For others, David Bourgin has put together a package of everything -necessary to quickly and easily upgrade to 2.0.x. See -ftp://ftp.wsc.com/pub/freeware/linux/update.linux/ for more information -and the files. This package also includes many bug-fixes, such as the -latest sendmail. There's also an alternate lightweight termcap in the -same directory that works well for many people. - -Please send info about any other packages that 2.0.x "broke" or about -any new features of 2.0.x that require extra or new packages for use to -Chris Ricker (gt1355b@prism.gatech.edu). I generate this from a -modified texinfo setup, so you don't need to bother generating a diff -against the current version before you send the additional information -to me. +necessary to quickly and easily upgrade to 2.1.x. See +ftp://ftp.wsc.com/pub/freeware/linux/update.linux/kernel-v2.1.x/ for +more information and the files. + +Please send info about any other packages that 2.1.x "broke" or about +any new features of 2.1.x that require extra or new packages for use to +Chris Ricker (gt1355b@prism.gatech.edu). diff -u --recursive --new-file v2.1.9/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.9/linux/Documentation/Configure.help Tue Nov 12 15:56:01 1996 +++ linux/Documentation/Configure.help Wed Nov 13 08:11:17 1996 @@ -1243,6 +1243,13 @@ say M here and read Documentation/modules.txt and Documentation/scsi.txt . +Enable vendor-specific extentions (for SCSI CDROM) +CONFIG_BLK_DEV_SR_VENDOR + This enables the usage of vendor specific SCSI commands. This is + required for some stuff which is newer than the SCSI-II standard, + most important is the multisession CD support. You'll probably want + to say y here, unless you have a _real old_ CD-ROM drive. + SCSI generic support CONFIG_CHR_DEV_SG If you want to use SCSI scanners, synthesizers or CD-writers or just diff -u --recursive --new-file v2.1.9/linux/Documentation/devices.tex linux/Documentation/devices.tex --- v2.1.9/linux/Documentation/devices.tex Mon Sep 2 08:41:25 1996 +++ linux/Documentation/devices.tex Fri Nov 15 13:01:14 1996 @@ -42,7 +42,7 @@ % \title{{\bf Linux Allocated Devices}} \author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$} -\date{Last revised: July 9, 1996} +\date{Last revised: November 13, 1996} \maketitle % \noindent @@ -179,7 +179,11 @@ \major{52}{}{char }{Spellcaster DataComm/BRI ISDN card} \major{53}{}{char }{BDM interface for remote debugging MC683xx microcontrollers} \major{54}{}{char }{Electrocardiognosis Holter serial card} -\major{55}{--59}{}{Unallocated} +\major{55}{}{char }{DSP56001 digital signal processor} +\major{56}{}{char }{Apple Desktop Bus} +\major{57}{}{char }{Hayes ESP serial card} +\major{58}{}{char }{Hayes ESP serial card -- alternate devices} +\major{59}{}{}{Unallocated} \major{60}{--63}{}{Local/experimental use} \major{64}{--119}{}{Unallocated} \major{120}{--127}{}{Local/experimental use} @@ -453,6 +457,7 @@ \minor{5}{/dev/atarimouse}{Atari mouse} \minor{6}{/dev/sunmouse}{Sun mouse} \minor{7}{/dev/amigamouse1}{Second Amiga mouse} + \minor{8}{/dev/smouse}{Simple serial mouse driver} \minor{128}{/dev/beep}{Fancy beep device} \minor{129}{/dev/modreq}{Kernel module load request} \minor{130}{/dev/watchdog}{Watchdog timer port} @@ -1116,7 +1121,35 @@ heart monitoring equipment. \begin{devicelist} -\major{55}{--59}{}{Unallocated} +\major{55}{}{char }{DSP56001 digital signal processor} + \minor{0}{/dev/dsp56k}{First DSP56001} +\end{devicelist} + +\begin{devicelist} +\major{56}{}{char }{Apple Desktop Bus} + \minor{0}{/dev/adb}{ADB bus control} +\end{devicelist} + +\noindent +Additional devices will be added to this number, all starting with +{\file /dev/adb}. + +\begin{devicelist} +\major{57}{}{char }{Hayes ESP serial card} + \minor{0}{/dev/ttyP0}{First ESP port} + \minor{1}{/dev/ttyP1}{Second ESP port} + \minordots +\end{devicelist} + +\begin{devicelist} +\major{58}{}{char }{Hayes ESP serial card -- alternate devices} + \minor{0}{/dev/cup0}{Callout device corresponding to {\file ttyP0}} + \minor{1}{/dev/cup1}{Callout device corresponding to {\file ttyP1}} + \minordots +\end{devicelist} + +\begin{devicelist} +\major{59}{}{}{Unallocated} \end{devicelist} \begin{devicelist} @@ -1182,9 +1215,9 @@ \link{/dev/ramdisk}{ram0}{symbolic}{Backward compatibility} \link{/dev/ftape}{rft0}{symbolic}{Backward compatibility} \link{/dev/scd?}{sr?}{hard}{Alternate name for CD-ROMs} -%\link{/dev/fd?H*}{fd?D*}{hard}{Compatible floppy formats} -%\link{/dev/fd?E*}{fd?D*}{hard}{Compatible floppy formats} -%\link{/dev/fd?E*}{fd?H*}{hard}{Compatible floppy formats} +\link{/dev/fd?D*}{fd?u*}{hard}{Backward compatibility} +\link{/dev/fd?H*}{fd?u*}{hard}{Backward compatibility} +\link{/dev/fd?E*}{fd?u*}{hard}{Backward compatibility} \end{nodelist} \subsection{Locally defined links} diff -u --recursive --new-file v2.1.9/linux/Documentation/devices.txt linux/Documentation/devices.txt --- v2.1.9/linux/Documentation/devices.txt Wed Jul 10 13:11:44 1996 +++ linux/Documentation/devices.txt Fri Nov 15 13:01:14 1996 @@ -2,7 +2,7 @@ Maintained by H. Peter Anvin - Last revised: July 9, 1996 + Last revised: November 13, 1996 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 @@ -269,6 +269,7 @@ 5 = /dev/atarimouse Atari mouse 6 = /dev/sunmouse Sun mouse 7 = /dev/amigamouse1 Second Amiga mouse + 8 = /dev/smouse Simple serial mouse driver 128 = /dev/beep Fancy beep device 129 = /dev/modreq Kernel module load request 130 = /dev/watchdog Watchdog timer port @@ -785,7 +786,26 @@ to transfer data from Holter 24-hour heart monitoring equipment. - 55-59 UNALLOCATED + 55 char DSP56001 digital signal processor + 0 = /dev/dsp56k First DSP56001 + + 56 char Apple Desktop Bus + 0 = /dev/adb ADB bus control + + Additional devices will be added to this number, all + starting with /dev/adb. + + 57 char Hayes ESP serial card + 0 = /dev/ttyP0 First ESP port + 1 = /dev/ttyP1 Second ESP port + ... + + 58 char Hayes ESP serial card - alternate devices + 0 = /dev/cup0 Callout device corresponding to ttyP0 + 1 = /dev/cup1 Callout device corresponding to ttyP1 + ... + + 59 UNALLOCATED 60-63 LOCAL/EXPERIMENTAL USE Allocated for local/experimental use. For devices not diff -u --recursive --new-file v2.1.9/linux/Makefile linux/Makefile --- v2.1.9/linux/Makefile Tue Nov 12 15:56:02 1996 +++ linux/Makefile Wed Nov 13 11:07:40 1996 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 9 +SUBLEVEL = 10 ARCH = i386 @@ -285,6 +285,7 @@ if [ -f BLOCK_MODULES ]; then inst_mod BLOCK_MODULES block; fi; \ if [ -f NET_MODULES ]; then inst_mod NET_MODULES net; fi; \ if [ -f IPV4_MODULES ]; then inst_mod IPV4_MODULES ipv4; fi; \ + if [ -f IPV6_MODULES ]; then inst_mod IPV6_MODULES ipv6; fi; \ if [ -f SCSI_MODULES ]; then inst_mod SCSI_MODULES scsi; fi; \ if [ -f FS_MODULES ]; then inst_mod FS_MODULES fs; fi; \ if [ -f CDROM_MODULES ]; then inst_mod CDROM_MODULES cdrom; fi; \ diff -u --recursive --new-file v2.1.9/linux/arch/alpha/defconfig linux/arch/alpha/defconfig --- v2.1.9/linux/arch/alpha/defconfig Wed Oct 16 10:48:06 1996 +++ linux/arch/alpha/defconfig Thu Nov 14 18:40:20 1996 @@ -102,6 +102,7 @@ CONFIG_BLK_DEV_SD=y # CONFIG_CHR_DEV_ST is not set CONFIG_BLK_DEV_SR=y +# CONFIG_BLK_DEV_SR_VENDOR is not set # CONFIG_CHR_DEV_SG is not set # @@ -123,9 +124,9 @@ # CONFIG_SCSI_AM53C974 is not set # CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_DMA is not set # CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_EATA is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GENERIC_NCR5380 is not set # CONFIG_SCSI_NCR53C406A is not set @@ -193,6 +194,7 @@ CONFIG_ISO9660_FS=y # CONFIG_HPFS_FS is not set # CONFIG_SYSV_FS is not set +# CONFIG_AFFS_FS is not set # CONFIG_UFS_FS is not set # diff -u --recursive --new-file v2.1.9/linux/arch/alpha/lib/strlen_user.S linux/arch/alpha/lib/strlen_user.S --- v2.1.9/linux/arch/alpha/lib/strlen_user.S Sun Nov 10 20:12:08 1996 +++ linux/arch/alpha/lib/strlen_user.S Fri Nov 15 15:43:56 1996 @@ -1,5 +1,5 @@ /* - * arch/alpha/lib/strlen_user.S + * arch/alpha/lib/__strlen_user.S * * Just like strlen except returns -EFAULT if an exception occurs * before the terminator is found. @@ -13,7 +13,7 @@ 99: x,##y; \ .section __ex_table,"a"; \ .gprel32 99b; \ - lda zero, $exception-99b(v0); \ + lda zero, $exception-99b(zero); \ .text @@ -21,12 +21,12 @@ .set noat .text - .globl strlen_user - .ent strlen_user + .globl __strlen_user + .ent __strlen_user .frame sp, 0, ra .align 3 -strlen_user: +__strlen_user: .prologue 0 EX( ldq_u t0, 0(a0) ) # load first quadword (a0 may be misaligned) @@ -34,7 +34,7 @@ insqh t1, a0, t1 andnot a0, 7, v0 or t1, t0, t0 - nop # dual issue the next two on ev5 + subq a0, 1, a0 # return "1+strlen" (0 for exception) cmpbge zero, t0, t1 # t1 <- bitmask: bit i == 1 <==> i-th byte == 0 bne t1, $found @@ -58,8 +58,10 @@ nop # dual issue next two on ev4 and ev5 subq v0, a0, v0 + ret $exception: + mov zero, v0 ret - .end strlen_user + .end __strlen_user diff -u --recursive --new-file v2.1.9/linux/arch/i386/boot/Makefile linux/arch/i386/boot/Makefile --- v2.1.9/linux/arch/i386/boot/Makefile Fri Sep 20 18:43:03 1996 +++ linux/arch/i386/boot/Makefile Wed Nov 13 07:54:31 1996 @@ -25,7 +25,7 @@ bzImage: $(CONFIGURE) bbootsect setup compressed/bvmlinux tools/bbuild if hash $(ENCAPS) 2> /dev/null; then \ - $(OBJDUMP) $(OBJDUMP_FLAGS) -o $(IMAGE_OFFSET) compressed/bvmlinux > compressed/bvmlinux.out; \ + $(OBJDUMP) $(OBJDUMP_FLAGS) -o $(BZIMAGE_OFFSET) compressed/bvmlinux > compressed/bvmlinux.out; \ else \ $(OBJCOPY) compressed/bvmlinux compressed/bvmlinux.out; \ fi diff -u --recursive --new-file v2.1.9/linux/arch/i386/kernel/ksyms.c linux/arch/i386/kernel/ksyms.c --- v2.1.9/linux/arch/i386/kernel/ksyms.c Tue Oct 29 19:58:02 1996 +++ linux/arch/i386/kernel/ksyms.c Thu Nov 14 18:20:31 1996 @@ -20,6 +20,7 @@ X(dump_thread), X(dump_fpu), X(ioremap), + X(iounmap), XNOVERS(__down_failed), XNOVERS(__up_wakeup), #ifdef __SMP__ diff -u --recursive --new-file v2.1.9/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v2.1.9/linux/drivers/block/floppy.c Sun Nov 10 20:12:08 1996 +++ linux/drivers/block/floppy.c Thu Nov 14 09:14:46 1996 @@ -1013,7 +1013,7 @@ FDCS->reset = 1; return; } - if ((long) raw_cmd->kernel_data % 512){ + if (((unsigned long) raw_cmd->kernel_data) % 512){ printk("non aligned address: %p\n", raw_cmd->kernel_data); cont->done(0); FDCS->reset=1; @@ -2541,7 +2541,8 @@ } /* 64 kb boundaries */ if (CROSS_64KB(CURRENT->buffer, max_size << 9)) - max_size = (K_64 - ((long) CURRENT->buffer) % K_64)>>9; + max_size = (K_64 - + ((unsigned long)CURRENT->buffer) % K_64)>>9; direct = transfer_size(ssize,max_sector,max_size) - sector_t; /* * We try to read tracks, but if we get too many errors, we diff -u --recursive --new-file v2.1.9/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c --- v2.1.9/linux/drivers/block/ide-cd.c Tue Nov 12 15:56:05 1996 +++ linux/drivers/block/ide-cd.c Wed Nov 13 08:46:17 1996 @@ -2647,8 +2647,8 @@ return nslots; } - -void ide_cdrom_setup (ide_drive_t *drive) +static +int ide_cdrom_setup (ide_drive_t *drive) { struct cdrom_info *info = drive->driver_data; int nslots; @@ -2750,8 +2750,12 @@ nslots = ide_cdrom_probe_capabilities (drive); - if (ide_cdrom_register (drive, nslots)) - printk ("%s: Can't register\n", drive->name); + if (ide_cdrom_register (drive, nslots)) { + printk ("%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name); + info->devinfo.handle = NULL; + return 1; + } + return 0; } /* Forwarding functions to generic routines. */ @@ -2765,13 +2769,22 @@ int ide_cdrom_open (struct inode *ip, struct file *fp, ide_drive_t *drive) { - return cdrom_fops.open (ip, fp); + int rc; + + MOD_INC_USE_COUNT; + rc = cdrom_fops.open (ip, fp); + if (rc) { + drive->usage--; + MOD_DEC_USE_COUNT; + } + return rc; } void ide_cdrom_release (struct inode *inode, struct file *file, ide_drive_t *drive) { cdrom_fops.release (inode, file); + MOD_DEC_USE_COUNT; } int ide_cdrom_check_media_change (ide_drive_t *drive) @@ -2785,6 +2798,7 @@ int ide_cdrom_cleanup(ide_drive_t *drive) { struct cdrom_info *info = drive->driver_data; + struct cdrom_device_info *devinfo = &info->devinfo; if (ide_unregister_subdriver (drive)) return 1; @@ -2792,6 +2806,8 @@ kfree (info->sector_buffer); if (info->toc != NULL) kfree (info->toc); + if (devinfo->handle == drive && unregister_cdrom (devinfo)) + printk ("%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name); kfree (info); drive->driver_data = NULL; return 0; @@ -2860,10 +2876,17 @@ kfree (info); continue; } - failed--; memset (info, 0, sizeof (struct cdrom_info)); drive->driver_data = info; - ide_cdrom_setup (drive); + DRIVER(drive)->busy++; + if (ide_cdrom_setup (drive)) { + DRIVER(drive)->busy--; + if (ide_cdrom_cleanup (drive)) + printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name); + continue; + } + DRIVER(drive)->busy--; + failed--; } ide_register_module(&ide_cdrom_module); MOD_DEC_USE_COUNT; diff -u --recursive --new-file v2.1.9/linux/drivers/cdrom/Makefile linux/drivers/cdrom/Makefile --- v2.1.9/linux/drivers/cdrom/Makefile Tue Nov 12 15:56:05 1996 +++ linux/drivers/cdrom/Makefile Wed Nov 13 11:04:35 1996 @@ -90,11 +90,11 @@ ifeq ($(CONFIG_CM206),y) L_OBJS += cm206.o -C = 1 +USE_GENERIC_CD=1 else ifeq ($(CONFIG_CM206),m) M_OBJS += cm206.o - CM = 1 + USE_MODULAR_GENERIC_CD=1 endif endif #CONFIG_CM206 @@ -127,6 +127,14 @@ M_OBJS += isp16.o endif endif #CONFIG_ISP16_CDI + +ifeq ($(CONFIG_BLK_DEV_SR),y) +USE_GENERIC_CD=1 +else + ifeq ($(CONFIG_BLK_DEV_SR),m) + USE_MODULAR_GENERIC_CD=1 + endif +endif #SCSI CDROM DRIVER ifeq ($(CONFIG_BLK_DEV_IDECD),y) USE_GENERIC_CD=1 diff -u --recursive --new-file v2.1.9/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- v2.1.9/linux/drivers/cdrom/cdrom.c Tue Nov 12 15:56:06 1996 +++ linux/drivers/cdrom/cdrom.c Wed Nov 13 08:16:13 1996 @@ -268,13 +268,11 @@ meaningful format indicated above. */ -#undef current /* set in sched.h */ - static void sanitize_format(union cdrom_addr *addr, - u_char * current, u_char requested) + u_char * curr, u_char requested) { - if (*current == requested) + if (*curr == requested) return; /* nothing to be done! */ if (requested == CDROM_LBA) { addr->lba = (int) addr->msf.frame + @@ -287,7 +285,7 @@ addr->msf.second = lba % 60; addr->msf.minute = lba / 60; } - *current = requested; + *curr = requested; } /* All checking and format change makes this code really hard to read! diff -u --recursive --new-file v2.1.9/linux/drivers/cdrom/mcd.c linux/drivers/cdrom/mcd.c --- v2.1.9/linux/drivers/cdrom/mcd.c Tue Oct 29 19:58:04 1996 +++ linux/drivers/cdrom/mcd.c Thu Nov 14 09:31:08 1996 @@ -61,6 +61,10 @@ 07 July 1995 Modifications by Andrew J. Kroll Bjorn Ekwall added unregister_blkdev to mcd_init() + + Michael K. Johnson added retries on open + for slow drives which take a while to recognize that they contain + a CD. */ #include @@ -1095,6 +1099,7 @@ mcd_open(struct inode *ip, struct file *fp) { int st; + int count = 0; if (mcdPresent == 0) return -ENXIO; /* no hardware */ @@ -1106,9 +1111,16 @@ mcd_invalidate_buffers(); - st = statusCmd(); /* check drive status */ - if (st == -1) - return -EIO; /* drive doesn't respond */ + do { + st = statusCmd(); /* check drive status */ + if (st == -1) + return -EIO; /* drive doesn't respond */ + if ((st & MST_READY) == 0) { /* no disk? wait a sec... */ + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + HZ; + schedule(); + } + } while (((st & MST_READY) == 0) && count++ < MCD_RETRY_ATTEMPTS); if ((st & MST_READY) == 0) /* no disk in drive */ { diff -u --recursive --new-file v2.1.9/linux/drivers/char/ChangeLog linux/drivers/char/ChangeLog --- v2.1.9/linux/drivers/char/ChangeLog Sun Nov 10 20:12:10 1996 +++ linux/drivers/char/ChangeLog Thu Nov 14 09:28:45 1996 @@ -1,3 +1,9 @@ +Thu Nov 14 00:06:09 1996 Theodore Ts'o + + * serial.c (autoconfig): Fix autoconfiguration problems; + info->flags wasn't getting initialized from the state + structure. Put in more paranoid test for the 16750. + Fri Nov 8 20:19:50 1996 Theodore Ts'o * n_tty.c (n_tty_flush_buffer): Only call driver->unthrottle() if diff -u --recursive --new-file v2.1.9/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v2.1.9/linux/drivers/char/serial.c Sun Nov 10 20:12:11 1996 +++ linux/drivers/char/serial.c Thu Nov 14 09:28:45 1996 @@ -50,7 +50,7 @@ #include static char *serial_name = "Serial driver"; -static char *serial_version = "4.20"; +static char *serial_version = "4.21"; DECLARE_TASK_QUEUE(tq_serial); @@ -2687,7 +2687,7 @@ (void)serial_inp(info, UART_IIR); (void)serial_inp(info, UART_MSR); - timeout = jiffies+2*HZ/100; + timeout = jiffies+ ((2*HZ)/100); while (timeout >= jiffies) { if (rs_irq_triggered) break; @@ -2758,7 +2758,9 @@ if (!state->port) return; info = &scr_info; /* This is just for serial_{in,out} */ - info->port = state->port; + info->magic = SERIAL_MAGIC; + info->port = state->port; + info->flags = state->flags; save_flags(flags); cli(); @@ -2848,8 +2850,13 @@ serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); scratch = serial_in(info, UART_IIR) >> 5; - if (scratch == 7) - state->type = PORT_16750; + if (scratch == 7) { + serial_outp(info, UART_LCR, 0); + serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); + scratch = serial_in(info, UART_IIR) >> 5; + if (scratch == 7) + state->type = PORT_16750; + } serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); } serial_outp(info, UART_LCR, scratch2); diff -u --recursive --new-file v2.1.9/linux/drivers/isdn/teles/proto.h linux/drivers/isdn/teles/proto.h --- v2.1.9/linux/drivers/isdn/teles/proto.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/isdn/teles/proto.h Fri Nov 15 12:51:02 1996 @@ -0,0 +1,18 @@ +/* $Id: proto.h,v 1.1 1996/09/23 01:53:52 fritz Exp $ + * + * not much now - just the l3 proto discriminator + * + * $Log: proto.h,v $ + * Revision 1.1 1996/09/23 01:53:52 fritz + * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6). + * + */ + +#ifndef PROTO_H +#define PROTO_H + +#define PROTO_EURO 0x08 +#define PROTO_DIS_N0 0x40 +#define PROTO_DIS_N1 0x41 + +#endif diff -u --recursive --new-file v2.1.9/linux/drivers/net/tulip.c linux/drivers/net/tulip.c --- v2.1.9/linux/drivers/net/tulip.c Fri Nov 1 17:13:18 1996 +++ linux/drivers/net/tulip.c Wed Nov 13 11:22:23 1996 @@ -17,7 +17,8 @@ static char *version = "tulip.c:v0.10 8/11/95 becker@cesdis.gsfc.nasa.gov\n" " +0.72 4/17/96 " -"http://www.dsl.tutics.tut.ac.jp/~linux/tulip\n"; +"http://www.dsl.tutics.tut.ac.jp/~linux/tulip\n" +" +0.01 10/24/96 mjacob@feral.com (2.1.7)\n"; /* A few user-configurable values. */ @@ -334,6 +335,7 @@ int setup_frame[48]; /* Pseudo-Tx frame to init address table. */ void (*port_select)(struct device *dev); int (*port_fail)(struct device *dev); + struct device *next_module; char *signature; unsigned int cur_rx, cur_tx; /* The next free ring entry */ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ @@ -367,7 +369,6 @@ static void tulip_interrupt(int irq, void *dev_id, struct pt_regs *regs); static int tulip_close(struct device *dev); static struct enet_statistics *tulip_get_stats(struct device *dev); -static struct device *tulip_alloc(struct device *dev); static void set_multicast_list(struct device *dev); #define generic21140_fail NULL @@ -379,6 +380,11 @@ static int generic21040_fail(struct device *dev); static int generic21041_fail(struct device *dev); +#ifdef MODULE +/* A list of all installed Tulip devices, for removing the driver module. */ +static struct device *root_tulip_dev = NULL; +#endif + static struct { void (*port_select)(struct device *dev); int (*port_fail)(struct device *dev); @@ -436,7 +442,6 @@ #ifdef MODULE static int if_port=TULIP_AUTO_PORT; -static size_t alloc_size; #ifdef TULIP_FULL_DUPLEX static int full_duplex=1; #else @@ -1132,6 +1137,7 @@ *setup_frm++ = eaddrs[2]; } while (++i < 15); +#ifndef __alpha__ /* Now add this frame to the Tx list. */ { unsigned long flags; @@ -1152,46 +1158,8 @@ /* Trigger an immediate transmit demand. */ tio_write(TPOLL_TRIGGER, CSR1); } - } -} - -static struct device *tulip_alloc(struct device *dev) -{ - struct tulip_private *tp; - char *buff; -#ifndef MODULE - size_t alloc_size; #endif - if (!dev || dev->priv) { - struct device *olddev = dev; - - alloc_size = sizeof(struct device) - + sizeof(struct tulip_private) - + ETHNAMSIZ; - alloc_size = ROUND_UP(alloc_size, 8); - - buff = (char *)kmalloc(alloc_size, GFP_KERNEL); - dev = (struct device *)buff; - if (dev == NULL) { - printk("tulip_alloc: kmalloc failed.\n"); - return(NULL); - } - tp = (struct tulip_private *)(buff + sizeof(struct device)); - memset(buff, 0, alloc_size); - dev->priv = (void *)tp; - dev->name = (char *)(buff + sizeof(struct device) - + sizeof(struct tulip_private)); - if (olddev) { - dev->next = olddev->next; - olddev->next = dev; - } - } else { - alloc_size = ROUND_UP(sizeof(struct tulip_private), 8); - tp = (struct tulip_private *)kmalloc(alloc_size, GFP_KERNEL); - memset((void *)tp, 0, alloc_size); - dev->priv = (void *)tp; } - return(dev); } int @@ -1200,6 +1168,7 @@ { /* See note below on the Znyx 315 etherarray. */ static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'}; + static int last_irq; char detect_mesg[80], *mesgp=detect_mesg; struct tulip_private *tp = (struct tulip_private *)dev->priv; int i; @@ -1269,11 +1238,13 @@ for (i = 0; i < ETH_ALEN - 1; i++) dev->dev_addr[i] = last_phys_addr[i]; dev->dev_addr[i] = last_phys_addr[i] + 1; + irq = last_irq; } for (i = 0; i < ETH_ALEN - 1; i++) mesgp += sprintf(mesgp, "%2.2x:", dev->dev_addr[i]); mesgp += sprintf(mesgp, "%2.2x, IRQ %d\n", last_phys_addr[i] = dev->dev_addr[i], irq); + last_irq = irq; /* copy ethernet address */ if (card_type(tp, device_id, @@ -1295,21 +1266,20 @@ dev->set_multicast_list = &set_multicast_list; #ifdef MODULE - ether_setup(dev); if (if_port == TULIP_AUTO_PORT) if_port = TULIP_PORT; else tp->port_fix = 1; dev->if_port = if_port; tp->full_duplex = full_duplex; + tp->next_module = root_tulip_dev; + root_tulip_dev = dev; #else #ifdef TULIP_FULL_DUPLEX tp->full_duplex = 1; #endif - init_etherdev(dev, 0); dev->if_port = TULIP_PORT; #endif - #ifdef TULIP_FIX_PORT tp->port_fix = 1; #endif @@ -1340,14 +1310,13 @@ if (!pcibios_present()) return(-ENODEV); - for (pci_index = 0; pci_index < 8; pci_index++) { + for (pci_index = 0; pci_index < 0xff; pci_index++) { /* Search for the PCI_DEVICE_ID_DEV_TULIP* chips */ - for (cno = 0; pci_chips[cno] != PCI_DEVICE_ID_NONE; cno ++) + for (cno = 0; pci_chips[cno] != PCI_DEVICE_ID_NONE; cno++) { if (pcibios_find_device(PCI_VENDOR_ID_DEC, pci_chips[cno], pci_index, &pci_bus, &pci_device_fn) == 0) { - struct device *dp; /* get IO address */ pcibios_read_config_dword(pci_bus, pci_device_fn, @@ -1355,19 +1324,14 @@ &pci_ioaddr); /* Remove I/O space marker in bit 0. */ pci_ioaddr &= ~3; - for (dp = tulip_head; dp != NULL; dp = dp->next) - if (dp->base_addr == pci_ioaddr) break; - if (dp) continue; /* get IRQ */ - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq); -#ifdef MODULE - /* compare requested IRQ/IO address */ - if (dev && dev->base_addr && - dev->base_addr != pci_ioaddr) continue; -#else - if ((dev = tulip_alloc(dev)) == NULL) break; -#endif + pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pci_irq); + dev = init_etherdev(NULL, + ROUND_UP(sizeof(struct device) + + sizeof (struct tulip_private) + + ETHNAMSIZ, 8)); + + if (dev == NULL) break; if (!tulip_head) { printk(version); tulip_head = dev; @@ -1394,56 +1358,48 @@ PCI_LATENCY_TIMER, 100); } if (tulip_hwinit(dev, pci_ioaddr, pci_irq, - pci_chips[cno]) < 0) continue; - num ++; -#ifdef MODULE - return(0); -#endif + pci_chips[cno]) < 0) { + continue; + } + num++; #ifdef TULIP_MAX_CARDS if (num >= TULIP_MAX_CARDS) return(0); #endif } } + } return(num > 0 ? 0: -ENODEV); } #ifdef MODULE -#ifdef __alpha__ -#if 1 -static int io = 0xb000; -#else -static int io = 0x10400; -#endif -#else -static int io = 0xfc80; -#endif -static struct device *mod_dev; +/* The parameters that may be passed in... */ +/* This driver does nothing with options yet. It will later be used to + pass the full-duplex flag, etc. */ +int debug = -1; -int init_module(void) +int +init_module(void) { - if ((mod_dev = tulip_alloc(0)) == NULL) return(-EIO); - - mod_dev->base_addr = io; - mod_dev->irq = 0; - mod_dev->init = &tulip_probe; - - if (register_netdev(mod_dev)) { - printk("tulip: register_netdev() returned non-zero.\n"); - kfree_s(mod_dev, alloc_size); - return -EIO; - } - return(0); + root_tulip_dev = NULL; + return tulip_probe(NULL); } void cleanup_module(void) { - release_region(mod_dev->base_addr, TULIP_TOTAL_SIZE); - unregister_netdev(mod_dev); - kfree_s(mod_dev, alloc_size); -} + struct device *next_dev; + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + while (root_tulip_dev) { + next_dev = + ((struct tulip_private *) root_tulip_dev->priv)->next_module; + unregister_netdev(root_tulip_dev); + release_region(root_tulip_dev->base_addr, TULIP_TOTAL_SIZE); + kfree(root_tulip_dev); + root_tulip_dev = next_dev; + } +} #endif /* MODULE */ diff -u --recursive --new-file v2.1.9/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.1.9/linux/drivers/scsi/Config.in Sun Nov 10 20:12:12 1996 +++ linux/drivers/scsi/Config.in Wed Nov 13 08:11:17 1996 @@ -3,6 +3,9 @@ dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI dep_tristate 'SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI +if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then + bool ' Enable vendor-specific extentions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR +fi dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' diff -u --recursive --new-file v2.1.9/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v2.1.9/linux/drivers/scsi/Makefile Sat Oct 5 16:58:34 1996 +++ linux/drivers/scsi/Makefile Wed Nov 13 08:11:17 1996 @@ -58,8 +58,12 @@ endif endif +ifeq ($(CONFIG_BLK_DEV_SR_VENDOR),y) +SR_VENDOR = sr_vendor.o +endif + ifeq ($(CONFIG_BLK_DEV_SR),y) -L_OBJS += sr.o sr_ioctl.o +L_OBJS += sr.o sr_ioctl.o $(SR_VENDOR) else ifeq ($(CONFIG_BLK_DEV_SR),m) M_OBJS += sr_mod.o @@ -376,8 +380,8 @@ scsicam.o scsi_proc.o $(LD) $(LD_RFLAG) -r -o $@ $(MX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o -sr_mod.o: sr.o sr_ioctl.o - $(LD) $(LD_RFLAG) -r -o $@ sr.o sr_ioctl.o +sr_mod.o: sr.o sr_ioctl.o $(SR_VENDOR) + $(LD) $(LD_RFLAG) -r -o $@ sr.o sr_ioctl.o $(SR_VENDOR) sd_mod.o: sd.o sd_ioctl.o $(LD) $(LD_RFLAG) -r -o $@ sd.o sd_ioctl.o diff -u --recursive --new-file v2.1.9/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c --- v2.1.9/linux/drivers/scsi/advansys.c Wed Oct 9 08:55:21 1996 +++ linux/drivers/scsi/advansys.c Fri Nov 15 02:45:57 1996 @@ -1,4 +1,4 @@ -/* $Id: advansys.c,v 1.24 1996/10/05 00:58:14 bobf Exp bobf $ */ +/* $Id: advansys.c,v 1.29 1996/11/15 00:45:07 bobf Exp bobf $ */ /* * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters * @@ -19,9 +19,9 @@ /* * The driver has been used in the following kernels: - * v1.2.13, v1.3.57, v2.0.21, v2.1.0 + * v1.2.13, v1.3.57, v2.0.25, v2.1.9 */ -#define ASC_VERSION "1.8" /* AdvanSys Driver Version */ +#define ASC_VERSION "2.0" /* AdvanSys Driver Version */ /* @@ -54,10 +54,10 @@ Connectivity Products: ABP510/5150 - Bus-Master ISA (240 CDB) (Footnote 1) - ABP5140 - Bus-Master ISA PnP (16 CDB) (Footnote 1) - ABP5142 - Bus-Master ISA PnP with floppy (16 CDB) + ABP5140 - Bus-Master ISA PnP (16 CDB) (Footnote 1, 3) + ABP5142 - Bus-Master ISA PnP with floppy (16 CDB) (Footnote 4) ABP920 - Bus-Master PCI (16 CDB) - ABP930 - Bus-Master PCI (16 CDB) + ABP930 - Bus-Master PCI (16 CDB) (Footnote 5) ABP930U - Bus-Master PCI Ultra (16 CDB) ABP960 - Bus-Master PCI MAC/PC (16 CDB) (Footnote 2) ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB) @@ -80,9 +80,11 @@ 1. This board has been shipped by HP with the 4020i CD-R drive. The board has no BIOS so it cannot control a boot device, but it can control any secondary SCSI device. - 2. This board has been sold by Iomega as a Jaz Jet PCI adapter. - + 3. This board has been sold by SIIG as the i540 SpeedMaster. + 4. This board has been sold by SIIG as the i542 SpeedMaster. + 5. This board has been sold by SIIG as the Fast SCSI Pro PCI. + B. Linux v1.2.X - Directions for Adding the AdvanSys Driver These directions apply to v1.2.13. For versions that follow v1.2.13. @@ -454,26 +456,34 @@ 5. Add request response time statistics and other information to the adapter /proc file: /proc/scsi/advansys[0...]. + 1.9 (10/21/96): + 1. Add conditionally compiled code (ASC_QUEUE_FLOW_CONTROL) to + make use of mid-level SCSI driver device queue depth flow + control mechanism. This will eliminate aborts caused by a + device being unable to keep up with requests and eliminate + repeat busy or QUEUE FULL status returned by a device. + 2. Incorporate miscellaneous Asc Library bug fixes. + 3. To allow the driver to work in kernels with broken module + support set 'cmd_per_lun' if the driver is compile as a + module. This change affects kernels v1.3.89 to present. + 4. Remove PCI BIOS address from the driver banner. The PCI BIOS + is relocated by the motherboard BIOS and its new address can + not be determined by the driver. + 5. Add mid-level SCSI queue depth information to the adapter + /proc file: /proc/scsi/advansys[0...]. + + 2.0 (11/14/96): + 1. Change allocation of global structures used for device + initialization to guarantee they are in DMA-able memory. + Previously when the driver was loaded as a module these + structures might not have been in DMA-able memory, causing + device initialization to fail. + I. Known Problems or Issues - 1. If a large "Device Queue Size" is set in the adapter - BIOS and a device supports the queue depth and the device - is heavily loaded, requests may be sent to the device - faster than they can be executed causing the requests to - queue up in the low-level driver on a wait queue. This may - lead to time-out abort requests by the mid-level driver. - - The short term solution is to set a smaller "Device Queue - Size" in the adapter BIOS. Response times can be monitored - per device by reading the /proc/scsi/advansys/[0...] file. - - The long term solution is to modify the mid-level driver to - institute a flow control mechanism between the two levels. - The low-level driver would notify the mid-level driver when - a device is falling behind on executing requests. This would - prevent the mid-level driver from sending more requests until - the low-level driver has notified it that the device has caught - up on request execution. + 1. Remove conditional constants (ASC_QUEUE_FLOW_CONTROL) around + the queue depth flow control code when mid-level SCSI changes + are included in Linux. J. Credits @@ -570,7 +580,7 @@ #define ASC_LIB_VERSION_MAJOR 1 #define ASC_LIB_VERSION_MINOR 22 -#define ASC_LIB_SERIAL_NUMBER 89 +#define ASC_LIB_SERIAL_NUMBER 91 typedef unsigned char uchar; @@ -645,7 +655,6 @@ #define ASC_PCI_ID2FUNC( id ) (((id) >> 8) & 0x7) #define ASC_PCI_MKID( bus, dev, func ) ((((dev) & 0x1F) << 11) | (((func) & 0x7) << 8) | ((bus) & 0xFF)) -#define Asc_DvcLib_Status int #define ASC_DVCLIB_CALL_DONE (1) #define ASC_DVCLIB_CALL_FAILED (0) #define ASC_DVCLIB_CALL_ERROR (-1) @@ -853,7 +862,7 @@ #define SCSI_SENKEY_MEDIUM_ERR 0x03 #define SCSI_SENKEY_HW_ERR 0x04 #define SCSI_SENKEY_ILLEGAL 0x05 -#define SCSI_SENKEY_ATTENSION 0x06 +#define SCSI_SENKEY_ATTENTION 0x06 #define SCSI_SENKEY_PROTECTED 0x07 #define SCSI_SENKEY_BLANK 0x08 #define SCSI_SENKEY_V_UNIQUE 0x09 @@ -1379,7 +1388,6 @@ #define ASC_IERR_SCAM 0x0800 #define ASC_IERR_SET_SDTR 0x1000 #define ASC_IERR_RW_LRAM 0x8000 -#define ASC_DVCLIB_STATUS 0x00 #define ASC_DEF_IRQ_NO 10 #define ASC_MAX_IRQ_NO 15 #define ASC_MIN_IRQ_NO 10 @@ -2138,7 +2146,7 @@ #define ASC_INFO_SIZE 128 /* advansys_info() line size */ /* /proc/scsi/advansys/[0...] related definitions */ -#define ASC_PRTBUF_SIZE 1024 +#define ASC_PRTBUF_SIZE 2048 #define ASC_PRTLINE_SIZE 160 #define ASC_PRT_NEXT() \ @@ -2310,7 +2318,11 @@ #endif /* ADVANSYS_STATS */ #define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit)) -#define ASC_TENTHS(num, den) ((((num) * 10)/(den)) - (10 * ((num)/(den)))) + +/* If the result wraps when calculating tenths, return 0. */ +#define ASC_TENTHS(num, den) \ + (((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \ + 0 : ((((num) * 10)/(den)) - (10 * ((num)/(den))))) /* * Display a message to the console. @@ -2490,9 +2502,6 @@ ulong sg_cnt; /* # scatter-gather I/O requests received */ ulong sg_elem; /* # scatter-gather elements */ ulong sg_xfer; /* # scatter-gather transfer 512-bytes */ - /* Device SCSI Command Queuing Statistics */ - ASC_SCSI_BIT_ID_TYPE queue_full; - ushort queue_full_cnt[ASC_MAX_TID+1]; }; #endif /* ADVANSYS_STATS */ @@ -2529,9 +2538,19 @@ asc_queue_t waiting; /* Waiting command queue */ asc_queue_t done; /* Done command queue */ ASC_SCSI_BIT_ID_TYPE init_tidmask; /* Target initialized mask */ + /* The following three structures must be in DMA-able memory. */ + ASC_SCSI_REQ_Q scsireqq; + ASC_CAP_INFO cap_info; + ASC_SCSI_INQUIRY inquiry; + Scsi_Device *device[ASC_MAX_TID+1]; /* Mid-Level Scsi Device */ + ushort reqcnt[ASC_MAX_TID+1]; /* Starvation request count */ +#if ASC_QUEUE_FLOW_CONTROL + ushort nerrcnt[ASC_MAX_TID+1]; /* No error request count */ +#endif /* ASC_QUEUE_FLOW_CONTROL */ + ASC_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */ + ushort queue_full_cnt[ASC_MAX_TID+1]; /* Queue full count */ ASCEEP_CONFIG eep_config; /* EEPROM configuration */ ulong last_reset; /* Saved time of last reset */ - ushort rcnt[ASC_MAX_TID+1]; /* Starvation Request Count */ #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) /* /proc/scsi/advansys/[0...] */ char *prtbuf; /* Statistics Print Buffer */ @@ -2616,13 +2635,6 @@ STATIC uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 }; /* - * Global structures used for device initialization. - */ -STATIC ASC_SCSI_REQ_Q asc_scsireqq = { { 0 } }; -STATIC ASC_CAP_INFO asc_cap_info = { 0 }; -STATIC ASC_SCSI_INQUIRY asc_inquiry = { { 0 } }; - -/* * Global structures required to issue a command. */ STATIC ASC_SCSI_Q asc_scsi_q = { { 0 } }; @@ -3124,6 +3136,7 @@ memset(boardp, 0, sizeof(asc_board_t)); boardp->id = asc_board_count - 1; asc_dvc_varp = &boardp->asc_dvc_var; + asc_dvc_varp->drv_ptr = (ulong) boardp; asc_dvc_varp->cfg = &boardp->asc_dvc_cfg; asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0]; asc_dvc_varp->iop_base = iop; @@ -3179,9 +3192,9 @@ /* * Get the board configuration. * - * AscInitGetConfig() may change the board's bus_type value. - * The asc_bus[bus] value should no longer be used. If the - * bus_type field must be referenced only use the bit-wise + * NOTE: AscInitGetConfig() may change the board's bus_type + * value. The asc_bus[bus] value should no longer be used. If + * the bus_type field must be referenced only use the bit-wise * AND operator "&". */ ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n"); @@ -3312,7 +3325,7 @@ */ /* AscInitSetConfig() will set the IRQ for non-PCI boards. */ - if (asc_dvc_varp->bus_type != ASC_IS_PCI) { + if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) { shp->irq = asc_dvc_varp->irq_no; } @@ -3351,16 +3364,33 @@ */ shp->select_queue_depths = advansys_select_queue_depths; - shp->cmd_per_lun = 0; /* 'cmd_per_lun' is no longer used. */ +#ifdef MODULE + /* + * Following v1.3.89, 'cmd_per_lun' is no longer needed + * and should be set to zero. But because of a bug introduced + * in v1.3.89 if the driver is compiled as a module and + * 'cmd_per_lun' is zero, the Mid-Level SCSI function + * 'allocate_device' will panic. To allow the driver to + * work as a module in these kernels set 'cmd_per_lun' to 1. + */ + shp->cmd_per_lun = 1; +#else /* MODULE */ + shp->cmd_per_lun = 0; +#endif /* MODULE */ #endif /* version >= v1.3.89 */ /* - * Maximum number of scatter-gather elements adapter can handle. - * - * Set a conservative 'sg_tablesize' value to prevent memory - * allocation failures. + * Set the maximum number of scatter-gather elements adapter + * can handle. */ + #ifdef MODULE + /* + * If the driver is compiled as a module, set a conservative + * 'sg_tablesize' value to prevent memory allocation failures. + * Memory allocation errors are more likely to occur at module + * load time, then at driver initialization time. + */ shp->sg_tablesize = 8; #else /* MODULE */ /* @@ -3539,25 +3569,28 @@ ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng, (unsigned) shp->base, shp->io_port, shp->io_port + (shp->n_io_port - 1), shp->irq, shp->dma_channel); + } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) { + if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA) + == ASC_IS_PCI_ULTRA) { + busname = "PCI Ultra"; + } else { + busname = "PCI"; + } + sprintf(info, + "AdvanSys SCSI %s: %s %u CDB: IO %X-%X, IRQ %u", + ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng, + shp->io_port, shp->io_port + (shp->n_io_port - 1), shp->irq); } else { if (asc_dvc_varp->bus_type & ASC_IS_VL) { busname = "VL"; } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) { busname = "EISA"; - } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) { - if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA) - == ASC_IS_PCI_ULTRA) { - busname = "PCI Ultra"; - } else { - busname = "PCI"; - } } else { busname = "?"; ASC_PRINT2( "advansys_info: board %d: unknown bus type %d\n", boardp->id, asc_dvc_varp->bus_type); } - /* No DMA channel for non-ISA busses. */ sprintf(info, "AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X-%X, IRQ %u", ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng, @@ -4429,6 +4462,11 @@ if (device->host != shp) { continue; } + /* + * Save a pointer to the device and set its initial/maximum + * queue depth. + */ + boardp->device[device->id] = device; device->queue_depth = boardp->asc_dvc_var.max_dvc_qng[device->id]; ASC_DBG3(1, "advansys_select_queue_depths: shp %x, id %d, depth %d\n", (unsigned) shp, device->id, device->queue_depth); @@ -4516,6 +4554,7 @@ { asc_board_t *boardp; ASC_DVC_VAR *asc_dvc_varp; + Scsi_Device *device; int ret; ASC_ASSERT(interrupts_enabled() == ASC_FALSE); @@ -4524,6 +4563,7 @@ boardp = ASC_BOARDP(scp->host); asc_dvc_varp = &boardp->asc_dvc_var; + device = boardp->device[scp->target]; /* * If this is the first command, then initialize the device. If @@ -4557,25 +4597,26 @@ asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->target); asc_scsi_q.q1.target_lun = scp->lun; asc_scsi_q.q2.target_ix = ASC_TIDLUN_TO_IX(scp->target, scp->lun); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) asc_scsi_q.q1.sense_addr = (ulong) &scp->sense_buffer[0]; -#else /* version >= v2.1.0 */ +#else /* version >= v2.0.0 */ asc_scsi_q.q1.sense_addr = virt_to_bus(&scp->sense_buffer[0]); -#endif /* version >= v2.1.0 */ +#endif /* version >= v2.0.0 */ asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer); /* - * If there are more than five outstanding commands for the - * current target, then every tenth command send an ORDERED - * request. This heuristic tries to retain the benefit of - * request sorting while preventing request starvation. + * If there are any outstanding requests for the current target, + * then every 255th request send an ORDERED request. This heuristic + * tries to retain the benefit of request sorting while preventing + * request starvation. 255 is the max number of tags or pending commands + * a device may have outstanding. * * The request count is incremented below for every successfully * started request. * */ - if ((asc_dvc_varp->cur_dvc_qng[scp->target] > 5) && - (boardp->rcnt[scp->target] % 10) == 0) { + if ((asc_dvc_varp->cur_dvc_qng[scp->target] > 0) && + (boardp->reqcnt[scp->target] % 255) == 0) { asc_scsi_q.q2.tag_code = M2_QTAG_MSG_ORDERED; } else { asc_scsi_q.q2.tag_code = M2_QTAG_MSG_SIMPLE; @@ -4590,11 +4631,11 @@ * CDB request of single contiguous buffer. */ ASC_STATS(scp->host, cont_cnt); -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) asc_scsi_q.q1.data_addr = (ulong) scp->request_buffer; -#else /* version >= v2.1.0 */ +#else /* version >= v2.0.0 */ asc_scsi_q.q1.data_addr = virt_to_bus(scp->request_buffer); -#endif /* version >= v2.1.0 */ +#endif /* version >= v2.0.0 */ asc_scsi_q.q1.data_cnt = scp->request_bufflen; ASC_STATS_ADD(scp->host, cont_xfer, ASC_CEILING(scp->request_bufflen, 512)); @@ -4636,11 +4677,11 @@ */ slp = (struct scatterlist *) scp->request_buffer; for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) { -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) asc_sg_head.sg_list[sgcnt].addr = (ulong) slp->address; -#else /* version >= v2.1.0 */ +#else /* version >= v2.0.0 */ asc_sg_head.sg_list[sgcnt].addr = virt_to_bus(slp->address); -#endif /* version >= v2.1.0 */ +#endif /* version >= v2.0.0 */ asc_sg_head.sg_list[sgcnt].bytes = slp->length; ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512)); } @@ -4658,21 +4699,55 @@ ASC_STATS(scp->host, asc_noerror); /* * Increment monotonically increasing per device successful - * request count. Wrapping of 'rcnt' doesn't matter. + * request counter. Wrapping doesn't matter. */ - boardp->rcnt[scp->target]++; + boardp->reqcnt[scp->target]++; + +#if ASC_QUEUE_FLOW_CONTROL + /* + * Conditionally increment the device queue depth. + * + * If no error occurred and there have been 100 consecutive + * successfull requests and the current queue depth is less + * than the maximum queue depth, then increment the current + * queue depth. + */ + if (boardp->nerrcnt[scp->target]++ > 100) { + boardp->nerrcnt[scp->target] = 0; + if ((device->queue_curr_depth < device->queue_depth) && + (!(boardp->queue_full & ASC_TIX_TO_TARGET_ID(scp->target)) || + (boardp->queue_full_cnt[scp->target] > + device->queue_curr_depth))) { + device->queue_curr_depth++; + } + } +#endif /* ASC_QUEUE_FLOW_CONTROL */ asc_enqueue(&boardp->active, scp, ASC_BACK); ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n"); break; case ASC_BUSY: /* Caller must enqueue request and retry later. */ ASC_STATS(scp->host, asc_busy); +#if ASC_QUEUE_FLOW_CONTROL + /* + * Clear consecutive no error counter and if possbile decrement + * queue depth. + */ + boardp->nerrcnt[scp->target] = 0; + if (device->queue_curr_depth > 1) { + device->queue_curr_depth--; + } +#endif /* ASC_QUEUE_FLOW_CONTROL */ break; case ASC_ERROR: ASC_PRINT2( "asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code %x\n", boardp->id, asc_dvc_varp->err_code); ASC_STATS(scp->host, asc_error); +#if ASC_QUEUE_FLOW_CONTROL + /* Clear consecutive no error counter. */ + boardp->nerrcnt[scp->target] = 0; +#endif /* ASC_QUEUE_FLOW_CONTROL */ scp->result = HOST_BYTE(DID_ERROR); asc_enqueue(&boardp->done, scp, ASC_BACK); break; @@ -4681,6 +4756,10 @@ "asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code %x\n", boardp->id, asc_dvc_varp->err_code); ASC_STATS(scp->host, asc_unknown); +#if ASC_QUEUE_FLOW_CONTROL + /* Clear consecutive no error counter. */ + boardp->nerrcnt[scp->target] = 0; +#endif /* ASC_QUEUE_FLOW_CONTROL */ scp->result = HOST_BYTE(DID_ERROR); asc_enqueue(&boardp->done, scp, ASC_BACK); break; @@ -4836,6 +4915,9 @@ asc_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp) { asc_board_t *boardp; + ASC_SCSI_REQ_Q *scsireqq; + ASC_CAP_INFO *cap_info; + ASC_SCSI_INQUIRY *inquiry; int found; ASC_SCSI_BIT_ID_TYPE save_use_tagged_qng; ASC_SCSI_BIT_ID_TYPE save_can_tagged_qng; @@ -4852,9 +4934,11 @@ boardp = ASC_BOARDP(scp->host); /* Set-up AscInitPollTarget() arguments. */ - memset(&asc_scsireqq, 0, sizeof(ASC_SCSI_REQ_Q)); - memset(&asc_cap_info, 0, sizeof(ASC_CAP_INFO)); - memset(&asc_inquiry, 0, sizeof(ASC_SCSI_INQUIRY)); + scsireqq = &boardp->scsireqq; + memset(scsireqq, 0, sizeof(ASC_SCSI_REQ_Q)); + cap_info = &boardp->cap_info; + memset(cap_info, 0, sizeof(ASC_CAP_INFO)); + inquiry = &boardp->inquiry; /* * XXX - AscInitPollBegin() re-initializes these fields to @@ -4872,24 +4956,24 @@ return ASC_FALSE; } - asc_scsireqq.sense_ptr = &asc_scsireqq.sense[0]; - asc_scsireqq.r1.sense_len = ASC_MIN_SENSE_LEN; - asc_scsireqq.r1.target_id = ASC_TID_TO_TARGET_ID(scp->target); - asc_scsireqq.r1.target_lun = 0; - asc_scsireqq.r2.target_ix = ASC_TIDLUN_TO_IX(scp->target, 0); + scsireqq->sense_ptr = &scsireqq->sense[0]; + scsireqq->r1.sense_len = ASC_MIN_SENSE_LEN; + scsireqq->r1.target_id = ASC_TID_TO_TARGET_ID(scp->target); + scsireqq->r1.target_lun = 0; + scsireqq->r2.target_ix = ASC_TIDLUN_TO_IX(scp->target, 0); found = ASC_FALSE; ASC_DBG(2, "asc_init_dev: AscInitPollTarget()\n"); - switch (ret = AscInitPollTarget(asc_dvc_varp, &asc_scsireqq, - &asc_inquiry, &asc_cap_info)) { + switch (ret = AscInitPollTarget(asc_dvc_varp, scsireqq, inquiry, + cap_info)) { case ASC_TRUE: found = ASC_TRUE; #ifdef ADVANSYS_DEBUG tidmask = ASC_TIX_TO_TARGET_ID(scp->target); ASC_DBG2(1, "asc_init_dev: lba %lu, blk_size %lu\n", - asc_cap_info.lba, asc_cap_info.blk_size); + cap_info->lba, cap_info->blk_size); ASC_DBG1(1, "asc_init_dev: peri_dvc_type %x\n", - asc_inquiry.byte0.peri_dvc_type); + inquiry->byte0.peri_dvc_type); if (asc_dvc_varp->use_tagged_qng & tidmask) { ASC_DBG1(1, "asc_init_dev: command queuing enabled: %d\n", asc_dvc_varp->max_dvc_qng[scp->target]); @@ -5677,7 +5761,7 @@ for (i = 0; i <= ASC_MAX_TID; i++) { if (boardp->asc_dvc_cfg.chip_scsi_id == i) { continue; - } else if (boardp->init_tidmask & (1 << i)) { + } else if (boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) { len = asc_prt_line(cp, leftlen, " %d,", i); ASC_PRT_NEXT(); } @@ -5733,7 +5817,7 @@ ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { len = asc_prt_line(cp, leftlen, " %d:%c", - i, (ep->disc_enable & (1 << i)) ? 'Y' : 'N'); + i, (ep->disc_enable & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); @@ -5744,7 +5828,7 @@ ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { len = asc_prt_line(cp, leftlen, " %d:%c", - i, (ep->use_cmd_qng & (1 << i)) ? 'Y' : 'N'); + i, (ep->use_cmd_qng & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); @@ -5755,7 +5839,7 @@ ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { len = asc_prt_line(cp, leftlen, " %d:%c", - i, (ep->start_motor & (1 << i)) ? 'Y' : 'N'); + i, (ep->start_motor & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); @@ -5766,7 +5850,7 @@ ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { len = asc_prt_line(cp, leftlen, " %d:%c", - i, (ep->init_sdtr & (1 << i)) ? 'Y' : 'N'); + i, (ep->init_sdtr & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); @@ -5794,9 +5878,15 @@ STATIC int asc_prt_driver_conf(struct Scsi_Host *shp, char *cp, int cplen) { + asc_board_t *boardp; int leftlen; int totlen; int len; +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) + int i; +#endif /* version >= v1.3.89 */ + + boardp = ASC_BOARDP(shp); leftlen = cplen; totlen = len = 0; @@ -5843,6 +5933,55 @@ ASC_BOARDP(shp)->flags, ASC_BOARDP(shp)->last_reset, jiffies); ASC_PRT_NEXT(); +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) + len = asc_prt_line(cp, leftlen, +" queue_depth: "); + ASC_PRT_NEXT(); + for (i = 0; i <= ASC_MAX_TID; i++) { + if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { + continue; + } + len = asc_prt_line(cp, leftlen, " %d:%d", + i, boardp->device[i]->queue_depth); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); +#endif /* version >= v1.3.89 */ + +#if ASC_QUEUE_FLOW_CONTROL + len = asc_prt_line(cp, leftlen, +" queue_curr_depth:"); + ASC_PRT_NEXT(); + for (i = 0; i <= ASC_MAX_TID; i++) { + if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { + continue; + } + len = asc_prt_line(cp, leftlen, " %d:%d", + i, boardp->device[i]->queue_curr_depth); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" queue_count: "); + ASC_PRT_NEXT(); + for (i = 0; i <= ASC_MAX_TID; i++) { + if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { + continue; + } + len = asc_prt_line(cp, leftlen, " %d:%d", + i, boardp->device[i]->queue_count); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); +#endif /* ASC_QUEUE_FLOW_CONTROL */ + return totlen; } @@ -5867,9 +6006,6 @@ ASC_DVC_VAR *v; ASC_DVC_CFG *c; int i; -#ifdef ADVANSYS_STATS - struct asc_stats *s; -#endif /* ADVANSYS_STATS */ boardp = ASC_BOARDP(shp); v = &boardp->asc_dvc_var; @@ -5903,11 +6039,11 @@ ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & (1 << i)) == 0)) { + ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { continue; } len = asc_prt_line(cp, leftlen, " %d:%c", - i, (v->sdtr_done & (1 << i)) ? 'Y' : 'N'); + i, (v->sdtr_done & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); @@ -5918,11 +6054,11 @@ ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & (1 << i)) == 0)) { + ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { continue; } len = asc_prt_line(cp, leftlen, " %d:%c", - i, (v->use_tagged_qng & (1 << i)) ? 'Y' : 'N'); + i, (v->use_tagged_qng & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); @@ -5934,7 +6070,7 @@ ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & (1 << i)) == 0)) { + ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { continue; } len = asc_prt_line(cp, leftlen, " %d:%u", i, v->cur_dvc_qng[i]); @@ -5949,7 +6085,7 @@ ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & (1 << i)) == 0)) { + ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { continue; } len = asc_prt_line(cp, leftlen, " %d:%u", i, v->max_dvc_qng[i]); @@ -5958,21 +6094,18 @@ len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); -#ifdef ADVANSYS_STATS - s = &boardp->asc_stats; - /* Indicate whether the device has returned queue full status. */ len = asc_prt_line(cp, leftlen, " Command Queue Full: "); ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & (1 << i)) == 0)) { + ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { continue; } - if (s->queue_full & (1 << i)) { + if (boardp->queue_full & ASC_TIX_TO_TARGET_ID(i)) { len = asc_prt_line(cp, leftlen, " %d:Y-%d", - i, s->queue_full_cnt[i]); + i, boardp->queue_full_cnt[i]); } else { len = asc_prt_line(cp, leftlen, " %d:N", i); } @@ -5980,7 +6113,6 @@ } len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); -#endif /* ADVANSYS_STATS */ return totlen; } @@ -6103,11 +6235,11 @@ { ulong bus_addr; -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) bus_addr = (ulong) buf_addr; -#else /* version >= v2.1.0 */ +#else /* version >= v2.0.0 */ bus_addr = virt_to_bus(buf_addr); -#endif /* version >= v2.1.0 */ +#endif /* version >= v2.0.0 */ return bus_addr; } @@ -6119,11 +6251,11 @@ buf_size = buf_len; asc_sg_head_ptr->entry_cnt = 1; -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) asc_sg_head_ptr->sg_list[0].addr = (ulong) buf_addr; -#else /* version >= v2.1.0 */ +#else /* version >= v2.0.0 */ asc_sg_head_ptr->sg_list[0].addr = virt_to_bus(buf_addr); -#endif /* version >= v2.1.0 */ +#endif /* version >= v2.0.0 */ asc_sg_head_ptr->sg_list[0].bytes = buf_size; return buf_size; } @@ -6280,8 +6412,6 @@ /* * Return the BIOS address of the adapter at the specified * I/O port and with the specified bus type. - * - * This function was formerly supplied by the library. */ ushort AscGetChipBiosAddress( @@ -6292,13 +6422,15 @@ ushort cfg_lsw ; ushort bios_addr ; - /* - * We can't get the BIOS address for PCI - */ - if ( bus_type & ASC_IS_PCI ) - { - return( 0 ); - } + /* + * The PCI BIOS is re-located by the motherboard BIOS. Because + * of this the driver can not determine where a PCI BIOS is + * loaded and executes. + */ + if ( bus_type & ASC_IS_PCI ) + { + return( 0 ); + } if( ( bus_type & ASC_IS_EISA ) != 0 ) { @@ -7173,6 +7305,8 @@ asc_dvc->sdtr_done |= target_id; asc_dvc->init_sdtr |= target_id; asc_dvc->pci_fix_asyn_xfer &= ~target_id; + sdtr_data = AscCalSDTRData(asc_dvc, + sdtr_xmsg.xfer_period, sdtr_xmsg.req_ack_offset); AscSetChipSDTR(iop_base, sdtr_data, tid_no); } else { q_cntl |= QC_MSG_OUT; @@ -7180,6 +7314,8 @@ sdtr_xmsg.xfer_period, sdtr_xmsg.req_ack_offset); asc_dvc->pci_fix_asyn_xfer &= ~target_id; + sdtr_data = AscCalSDTRData(asc_dvc, + sdtr_xmsg.xfer_period, sdtr_xmsg.req_ack_offset); AscSetChipSDTR(iop_base, sdtr_data, tid_no); asc_dvc->sdtr_done |= target_id; asc_dvc->init_sdtr |= target_id; @@ -7273,24 +7409,23 @@ (ushort) ((ushort) ASCV_MAX_DVC_QNG_BEG + (ushort) tid_no), cur_dvc_qng); } -#ifdef ADVANSYS_STATS { - asc_board_t *boardp; - int i; - for (i = 0; i < ASC_NUM_BOARD_SUPPORTED; i++) { - if (asc_host[i] == NULL) { - continue; - } - boardp = ASC_BOARDP(asc_host[i]); - if (&boardp->asc_dvc_var == asc_dvc) { - boardp->asc_stats.queue_full |= target_id; - boardp->asc_stats.queue_full_cnt[tid_no] = - cur_dvc_qng; - break; - } - } + asc_board_t *boardp; + boardp = (asc_board_t *) asc_dvc->drv_ptr; + + /* + * Set the device queue depth to the number of + * active requests when the QUEUE FULL condition + * was encountered. + */ + boardp->queue_full |= target_id; + boardp->queue_full_cnt[tid_no] = cur_dvc_qng; +#if ASC_QUEUE_FLOW_CONTROL + if (boardp->device[tid_no]->queue_curr_depth > cur_dvc_qng) { + boardp->device[tid_no]->queue_curr_depth = cur_dvc_qng; + } +#endif /* ASC_QUEUE_FLOW_CONTROL */ } -#endif } } AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); @@ -7608,8 +7743,10 @@ scsiq->r3.host_stat = 0; scsiq->r3.done_stat = 0; scsiq->r2.vm_id = 0; - scsiq->cdbptr = (uchar dosfar *) scsiq->cdb; scsiq->r1.data_cnt = buf_len; + scsiq->cdbptr = (uchar dosfar *) scsiq->cdb; + scsiq->sense_ptr = (uchar dosfar *) scsiq->sense ; + scsiq->r1.sense_len = ASC_MIN_SENSE_LEN ; scsiq->r2.tag_code = (uchar) M2_QTAG_MSG_SIMPLE; scsiq->r2.flag = (uchar) ASC_FLAG_SCSIQ_REQ; scsiq->r2.srb_ptr = (ulong) scsiq; @@ -7622,6 +7759,12 @@ } scsiq->r1.data_addr = phy_addr; } + if ((phy_addr = AscGetOnePhyAddr(asc_dvc, + (uchar dosfar *) scsiq->sense_ptr, + (ulong) scsiq->r1.sense_len )) == 0L) { + return (ERR); + } + scsiq->r1.sense_addr = phy_addr ; return (0); } @@ -8718,21 +8861,22 @@ { ruchar *period_table; int max_index; + int min_index; int i; period_table = asc_dvc->sdtr_period_tbl; max_index = (int) asc_dvc->max_sdtr_index; + min_index = ( int )asc_dvc->host_init_sdtr_index ; if ( - (syn_time >= period_table[0]) - && (syn_time <= period_table[max_index]) + (syn_time <= period_table[max_index]) ) { - for (i = 0; i < (max_index - 1); i++) { + for (i = min_index; i < (max_index - 1); i++) { if (syn_time <= period_table[i]) { - return (i); + return ((uchar) i); } } - return (max_index); + return ((uchar) max_index); } else { - return (max_index + 1); + return ((uchar) (max_index + 1)); } } @@ -9537,20 +9681,20 @@ asc_dvc->no_scam = 0; asc_dvc->unit_not_ready = 0; asc_dvc->queue_full_or_busy = 0; + asc_dvc->redo_scam = 0 ; + asc_dvc->res2 = 0 ; + asc_dvc->host_init_sdtr_index = 0 ; + asc_dvc->res7 = 0 ; + asc_dvc->res8 = 0 ; + asc_dvc->cfg->can_tagged_qng = 0 ; + asc_dvc->cfg->cmd_qng_enabled = 0; asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL; asc_dvc->init_sdtr = ASC_SCSI_WIDTH_BIT_SET; asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG; asc_dvc->scsi_reset_wait = 3; asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET; asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type); - asc_dvc->redo_scam = 0; - asc_dvc->res2 = 0; - asc_dvc->host_init_sdtr_index = 0; - asc_dvc->res7 = 0; - asc_dvc->res8 = 0; asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET; - asc_dvc->cfg->can_tagged_qng = 0; - asc_dvc->cfg->cmd_qng_enabled = 0; asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID; asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER; asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) | @@ -9839,6 +9983,9 @@ scsiq_req->r3.host_stat = scsi_done_q->d3.host_stat; scsiq_req->r3.scsi_stat = scsi_done_q->d3.scsi_stat; scsiq_req->r3.scsi_msg = scsi_done_q->d3.scsi_msg; + ASC_DBG4(1, "AscInitPollIsrCallBack: done_stat %x, host_stat %x, scsi_stat %x, scsi_msg %x\n", + scsi_done_q->d3.done_stat, scsi_done_q->d3.host_stat, + scsi_done_q->d3.scsi_stat, scsi_done_q->d3.scsi_msg); if ((scsi_done_q->d3.scsi_stat == SS_CHK_CONDITION) && (scsi_done_q->d3.host_stat == 0)) { cp_sen_len = (uchar) ASC_MIN_SENSE_LEN; @@ -10170,21 +10317,12 @@ int support_read_cap; int tmp_disable_init_sdtr; int sta; - ulong phy_addr; dvc_found = 0; tmp_disable_init_sdtr = FALSE; tid_bits = scsiq->r1.target_id; lun = scsiq->r1.target_lun; tid_no = ASC_TIX_TO_TID(scsiq->r2.target_ix); if ( - (phy_addr = AscGetOnePhyAddr(asc_dvc, - (uchar dosfar *) scsiq->sense_ptr, - (ulong) scsiq->r1.sense_len)) == 0L - ) { - return (ERR); - } - scsiq->r1.sense_addr = phy_addr; - if ( ((asc_dvc->init_sdtr & tid_bits) != 0) && ((asc_dvc->sdtr_done & tid_bits) == 0) ) { @@ -10301,7 +10439,7 @@ int status; int retry = 0; - ASC_DBG1(1, "PollQueueDone: timeout_sec %d", timeout_sec); + ASC_DBG1(1, "PollQueueDone: timeout_sec %d\n", timeout_sec); do { ASC_DBG(1, "PollQueueDone: before AscExeScsiQueue\n"); if ((status = AscExeScsiQueue(asc_dvc, @@ -10309,6 +10447,7 @@ ASC_DBG(1, "PollQueueDone: before AscPollQDone\n"); if ((status = AscPollQDone(asc_dvc, scsiq, timeout_sec)) != 1) { + ASC_DBG1(1, "PollQueueDone: status %x\n", status); if (status == 0x80) { if (retry++ > ASC_MAX_INIT_BUSY_RETRY) { break; @@ -10324,14 +10463,18 @@ scsiq->r3.host_stat = 0; scsiq->r3.scsi_stat = 0; scsiq->r3.scsi_msg = 0; + ASC_DBG(1, "PollQueueDone: before AscAbortSRB()\n"); AscAbortSRB(asc_dvc, (ulong) scsiq); } + ASC_DBG1(1, "PollQueueDone: status %x\n", status); ASC_DBG1(1, "PollQueueDone: done_stat %x\n", scsiq->r3.done_stat); return (scsiq->r3.done_stat); } + ASC_DBG1(1, "PollQueueDone: status %x\n", status); DvcSleepMilliSecond(5); } while (((status == 0) || (status == 0x80)) && retry++ < ASC_MAX_INIT_BUSY_RETRY); + ASC_DBG1(1, "PollQueueDone: status %x\n", status); ASC_DBG(1, "PollQueueDone: done_stat QD_WITH_ERROR\n"); return (scsiq->r3.done_stat = QD_WITH_ERROR); } @@ -10430,12 +10573,12 @@ ASC_REQ_SENSE dosfar *sen; retry = 0; tid_bits = scsiq->r1.target_id; - while (retry++ < 2) { + while (retry++ < 4) { PollScsiTestUnitReady(asc_dvc, scsiq); if (scsiq->r3.done_stat == 0x01) { return (1); } else if (scsiq->r3.done_stat == QD_WITH_ERROR) { - DvcSleepMilliSecond(100); + DvcSleepMilliSecond(200); sen = (ASC_REQ_SENSE dosfar *) scsiq->sense_ptr; if ((scsiq->r3.scsi_stat == SS_CHK_CONDITION) && ((sen->err_code & 0x70) != 0)) { @@ -10451,9 +10594,10 @@ } else { DvcSleepMilliSecond(5000); } - } else if (sen->sense_key == SCSI_SENKEY_ATTENSION) { - DvcSleepMilliSecond(500); + } else if (sen->sense_key == SCSI_SENKEY_ATTENTION) { + DvcSleepMilliSecond( ( ulong )( 500L*retry ) ) ; } else { + DvcSleepMilliSecond( 500 ) ; break; } } else { @@ -10485,6 +10629,7 @@ while (TRUE) { if (asc_dvc->err_code != 0) { scsiq->r3.done_stat = QD_WITH_ERROR; + ASC_DBG1(1, "AscPollQDone: err_code %x\n", asc_dvc->err_code); sta = ERR; break; } @@ -10497,10 +10642,12 @@ } DvcSleepMilliSecond(10); if (loop++ > loop_end) { + ASC_DBG(1, "AscPollQDone: loop finished\n"); sta = 0; break; } if (AscIsChipHalted(iop_base)) { + ASC_DBG(1, "AscPollQDone: AscIsChipHalted()\n"); #if !CC_ASCISR_CHECK_INT_PENDING AscAckInterrupt(iop_base); #endif @@ -10508,6 +10655,7 @@ loop = 0; } else { if (AscIsIntPending(iop_base)) { + ASC_DBG(1, "AscPollQDone: AscIsIntPending()\n"); #if !CC_ASCISR_CHECK_INT_PENDING AscAckInterrupt(iop_base); #endif diff -u --recursive --new-file v2.1.9/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.1.9/linux/drivers/scsi/scsi.c Fri Nov 1 17:13:18 1996 +++ linux/drivers/scsi/scsi.c Thu Nov 14 18:20:31 1996 @@ -642,26 +642,6 @@ scsi_result[1] |= 0x80; /* removable */ } - if (!strncmp (scsi_result + 8, "NEC", 3)) { - if (!strncmp (scsi_result + 16, "CD-ROM DRIVE:84 ", 16) || - !strncmp (scsi_result + 16, "CD-ROM DRIVE:25", 15)) - SDpnt->manufacturer = SCSI_MAN_NEC_OLDCDR; - else - SDpnt->manufacturer = SCSI_MAN_NEC; - } - else if (!strncmp (scsi_result + 8, "TOSHIBA", 7)) - SDpnt->manufacturer = SCSI_MAN_TOSHIBA; - else if (!strncmp (scsi_result + 8, "SONY", 4)) - SDpnt->manufacturer = SCSI_MAN_SONY; - else if (!strncmp (scsi_result + 8, "PIONEER", 7)) - SDpnt->manufacturer = SCSI_MAN_PIONEER; - else if (!strncmp (scsi_result + 8, "MATSHITA", 8)) - SDpnt->manufacturer = SCSI_MAN_MATSHITA; - else if (!strncmp (scsi_result + 8, "HP", 2)) - SDpnt->manufacturer = SCSI_MAN_HP; - else - SDpnt->manufacturer = SCSI_MAN_UNKNOWN; - memcpy (SDpnt->vendor, scsi_result + 8, 8); memcpy (SDpnt->model, scsi_result + 16, 16); memcpy (SDpnt->rev, scsi_result + 32, 4); diff -u --recursive --new-file v2.1.9/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h --- v2.1.9/linux/drivers/scsi/scsi.h Wed Oct 16 10:48:22 1996 +++ linux/drivers/scsi/scsi.h Wed Nov 13 08:11:17 1996 @@ -123,19 +123,6 @@ */ /* - * Manufacturers list - */ - -#define SCSI_MAN_UNKNOWN 0 -#define SCSI_MAN_NEC 1 -#define SCSI_MAN_TOSHIBA 2 -#define SCSI_MAN_NEC_OLDCDR 3 -#define SCSI_MAN_SONY 4 -#define SCSI_MAN_PIONEER 5 -#define SCSI_MAN_MATSHITA 6 -#define SCSI_MAN_HP 7 - -/* * As the scsi do command functions are intelligent, and may need to * redo a command, we need to keep track of the last command * executed on each one. diff -u --recursive --new-file v2.1.9/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v2.1.9/linux/drivers/scsi/sd.c Tue Oct 29 19:58:13 1996 +++ linux/drivers/scsi/sd.c Thu Nov 14 15:16:45 1996 @@ -37,6 +37,7 @@ #include #include +#include #define MAJOR_NR SCSI_DISK_MAJOR #include @@ -660,10 +661,10 @@ * a bounce buffer if we are straddling the 16Mb line */ if (contiguous && SCpnt->request.bh && - ((long) SCpnt->request.bh->b_data) + virt_to_phys(SCpnt->request.bh->b_data) + (SCpnt->request.nr_sectors << 9) - 1 > ISA_DMA_THRESHOLD && SCpnt->host->unchecked_isa_dma) { - if(((long) SCpnt->request.bh->b_data) > ISA_DMA_THRESHOLD) + if(virt_to_phys(SCpnt->request.bh->b_data) > ISA_DMA_THRESHOLD) bounce_buffer = (char *) scsi_malloc(bounce_size); if(!bounce_buffer) contiguous = 0; } @@ -720,7 +721,7 @@ if(!bhp || !CONTIGUOUS_BUFFERS(bhp,bh) || !CLUSTERABLE_DEVICE(SCpnt) || (SCpnt->host->unchecked_isa_dma && - ((unsigned long) bh->b_data-1) == ISA_DMA_THRESHOLD)) { + virt_to_phys(bh->b_data-1) == ISA_DMA_THRESHOLD)) { if (count < SCpnt->host->sg_tablesize) count++; else break; } @@ -730,7 +731,7 @@ } #if 0 if(SCpnt->host->unchecked_isa_dma && - ((unsigned int) SCpnt->request.bh->b_data-1) == ISA_DMA_THRESHOLD) count--; + virt_to_phys(SCpnt->request.bh->b_data-1) == ISA_DMA_THRESHOLD) count--; #endif SCpnt->use_sg = count; /* Number of chains */ /* scsi_malloc can only allocate in chunks of 512 bytes */ @@ -762,7 +763,7 @@ sgpnt[count].length += bh->b_size; counted += bh->b_size >> 9; - if (((long) sgpnt[count].address) + sgpnt[count].length - 1 > + if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length - 1 > ISA_DMA_THRESHOLD && (SCpnt->host->unchecked_isa_dma) && !sgpnt[count].alt_address) { sgpnt[count].alt_address = sgpnt[count].address; @@ -809,7 +810,7 @@ && CLUSTERABLE_DEVICE(SCpnt)) { char * tmp; - if (((long) sgpnt[count].address) + sgpnt[count].length + + if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length + bhp->b_size - 1 > ISA_DMA_THRESHOLD && (SCpnt->host->unchecked_isa_dma) && !sgpnt[count].alt_address) continue; @@ -871,7 +872,7 @@ /* Now handle the possibility of DMA to addresses > 16Mb */ if(SCpnt->use_sg == 0){ - if (((long) buff) + (this_count << 9) - 1 > ISA_DMA_THRESHOLD && + if (virt_to_phys(buff) + (this_count << 9) - 1 > ISA_DMA_THRESHOLD && (SCpnt->host->unchecked_isa_dma)) { if(bounce_buffer) buff = bounce_buffer; diff -u --recursive --new-file v2.1.9/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v2.1.9/linux/drivers/scsi/sr.c Wed Oct 16 10:48:22 1996 +++ linux/drivers/scsi/sr.c Wed Nov 13 08:11:17 1996 @@ -17,6 +17,9 @@ * Modified by Thomas Quinot thomas@melchior.cuivre.fdn.fr to * provide auto-eject. * + * Modified by Gerd Knorr to support the + * generic cdrom interface + * */ #include @@ -28,7 +31,9 @@ #include #include #include +#include #include +#include #include #define MAJOR_NR SCSI_CDROM_MAJOR @@ -49,53 +54,48 @@ static void sr_detach(Scsi_Device *); struct Scsi_Device_Template sr_template = {NULL, "cdrom", "sr", NULL, TYPE_ROM, - SCSI_CDROM_MAJOR, 0, 0, 0, 1, - sr_detect, sr_init, - sr_finish, sr_attach, sr_detach}; + SCSI_CDROM_MAJOR, 0, 0, 0, 1, + sr_detect, sr_init, + sr_finish, sr_attach, sr_detach}; Scsi_CD * scsi_CDs = NULL; static int * sr_sizes; static int * sr_blocksizes; -static int sr_open(struct inode *, struct file *); +static int sr_open(struct cdrom_device_info*, int); void get_sectorsize(int); -void sr_photocd(struct inode *); - -extern int sr_ioctl(struct inode *, struct file *, unsigned int, unsigned long); void requeue_sr_request (Scsi_Cmnd * SCpnt); -static int check_cdrom_media_change(kdev_t); +static int sr_media_change(struct cdrom_device_info*, int); -static void sr_release(struct inode * inode, struct file * file) +static void sr_release(struct cdrom_device_info *cdi) { - sync_dev(inode->i_rdev); - if(! --scsi_CDs[MINOR(inode->i_rdev)].device->access_count) - { - sr_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0); - if (scsi_CDs[MINOR(inode->i_rdev)].auto_eject) - sr_ioctl(inode, NULL, CDROMEJECT, 0); - } - if (scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count) - (*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)--; + sync_dev(cdi->dev); + scsi_CDs[MINOR(cdi->dev)].device->access_count--; + if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->usage_count) + (*scsi_CDs[MINOR(cdi->dev)].device->host->hostt->usage_count)--; if(sr_template.usage_count) (*sr_template.usage_count)--; } -static struct file_operations sr_fops = -{ - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* select */ - sr_ioctl, /* ioctl */ - NULL, /* mmap */ - sr_open, /* special open code */ - sr_release, /* release */ - NULL, /* fsync */ - NULL, /* fasync */ - check_cdrom_media_change, /* Disk change */ - NULL /* revalidate */ +static struct cdrom_device_ops sr_dops = { + sr_open, /* open */ + sr_release, /* release */ + sr_drive_status, /* drive status */ + sr_disk_status, /* disc status */ + sr_media_change, /* media changed */ + sr_tray_move, /* tray move */ + sr_lock_door, /* lock door */ + NULL, /* select speed */ + NULL, /* select disc */ + sr_get_last_session, /* get last session */ + sr_get_mcn, /* get universal product code */ + sr_reset, /* hard reset */ + sr_audio_ioctl, /* audio ioctl */ + sr_dev_ioctl, /* device-specific ioctl */ + CDC_CLOSE_TRAY | CDC_OPEN_TRAY| CDC_LOCK | + CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO, + 0 }; /* @@ -108,38 +108,38 @@ * an inode for that to work, and we do not always have one. */ -int check_cdrom_media_change(kdev_t full_dev){ - int retval, target; - struct inode inode; - int flag = 0; - - target = MINOR(full_dev); - - if (target >= sr_template.nr_dev) { - printk("CD-ROM request error: invalid device.\n"); - return 0; - }; - - inode.i_rdev = full_dev; /* This is all we really need here */ - retval = sr_ioctl(&inode, NULL, SCSI_IOCTL_TEST_UNIT_READY, 0); +int sr_media_change(struct cdrom_device_info *cdi, int slot){ + int retval; + + if (CDSL_CURRENT != slot) { + /* no changer support */ + return -EINVAL; + } + + retval = scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device, + SCSI_IOCTL_TEST_UNIT_READY, 0); - if(retval){ /* Unable to test, unit probably not ready. This usually + if(retval){ + /* Unable to test, unit probably not ready. This usually * means there is no disc in the drive. Mark as changed, * and we will figure it out later once the drive is * available again. */ - scsi_CDs[target].device->changed = 1; - return 1; /* This will force a flush, if called from - * check_disk_change */ + scsi_CDs[MINOR(cdi->dev)].device->changed = 1; + return 1; /* This will force a flush, if called from + * check_disk_change */ }; - retval = scsi_CDs[target].device->changed; - if(!flag) { - scsi_CDs[target].device->changed = 0; - /* If the disk changed, the capacity will now be different, - * so we force a re-read of this information */ - if (retval) scsi_CDs[target].needs_sector_size = 1; - }; + retval = scsi_CDs[MINOR(cdi->dev)].device->changed; + scsi_CDs[MINOR(cdi->dev)].device->changed = 0; + /* If the disk changed, the capacity will now be different, + * so we force a re-read of this information */ + if (retval) { +#ifdef CONFIG_BLK_DEV_SR_VENDOR + sr_cd_check(cdi); +#endif + scsi_CDs[MINOR(cdi->dev)].needs_sector_size = 1; + } return retval; } @@ -361,317 +361,26 @@ } } -/* - * Here I tried to implement support for multisession-CD's - * - * Much of this has do be done with vendor-specific SCSI-commands, because - * multisession is newer than the SCSI-II standard. - * So I have to complete it step by step. Useful information is welcome. - * - * Actually works: - * - NEC: Detection and support of multisession CD's. Special handling - * for XA-disks is not necessary. - * - * - TOSHIBA: setting density is done here now, mounting PhotoCD's should - * work now without running the program "set_density" - * Multisession CD's are supported too. - * - * Gerd Knorr - */ -/* - * 19950704 operator@melchior.cuivre.fdn.fr (Thomas Quinot) - * - * - SONY: Same as Nec. - * - * - PIONEER: works with SONY code (may be others too ?) - * - * 19961011 - * - * - HP: reportedly working. - */ - -void sr_photocd(struct inode *inode) -{ - unsigned long sector,min,sec,frame; - unsigned char buf[40]; /* the buffer for the ioctl */ - Scsi_Ioctl_Command *sic = (Scsi_Ioctl_Command *) buf; -#define CLEAR_CMD_BUFFER memset (buf, 0, sizeof buf); - unsigned char *cmd; /* the scsi-command */ - unsigned char *send; /* the data we send to the drive ... */ - unsigned char *rec; /* ... and get back */ - int rc,is_xa,no_multi; - - if (scsi_CDs[MINOR(inode->i_rdev)].xa_flags & 0x02) { -#ifdef DEBUG - printk(KERN_DEBUG "sr_photocd: CDROM and/or driver do not support multisession CD's"); -#endif - return; - } - - if (!suser()) { - /* I'm not the superuser, so SCSI_IOCTL_SEND_COMMAND isn't allowed - * for me. That's why mpcd_sector will be initialized with zero, - * because I'm not able to get the right value. Necessary only if - * access_count is 1, else no disk change happened since the last - * call of this function and we can keep the old value. - */ - if (1 == scsi_CDs[MINOR(inode->i_rdev)].device->access_count) { - scsi_CDs[MINOR(inode->i_rdev)].mpcd_sector = 0; - scsi_CDs[MINOR(inode->i_rdev)].xa_flags &= ~0x01; - } - return; - } - - sector = 0; - is_xa = 0; - no_multi = 0; - cmd = rec = sic->data; - - switch(scsi_CDs[MINOR(inode->i_rdev)].device->manufacturer) { - - case SCSI_MAN_NEC: -#ifdef DEBUG - printk(KERN_DEBUG "sr_photocd: use NEC code\n"); -#endif - CLEAR_CMD_BUFFER; - sic->inlen = 0x0; /* we send nothing... */ - sic->outlen = 0x16; /* and receive 0x16 bytes */ - cmd[0] = 0xde; - cmd[1] = 0x03; - cmd[2] = 0xb0; - rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device, - SCSI_IOCTL_SEND_COMMAND, sic); - if (rc != 0) { - if (rc != 0x28000002) /* drop "not ready" */ - printk(KERN_WARNING"sr_photocd: ioctl error (NEC): 0x%x\n",rc); - break; - } - if (rec[14] != 0 && rec[14] != 0xb0) { - printk(KERN_INFO"sr_photocd: (NEC) Hmm, seems the CDROM doesn't support multisession CD's\n"); - no_multi = 1; - break; - } - min = (unsigned long) rec[15]/16*10 + (unsigned long) rec[15]%16; - sec = (unsigned long) rec[16]/16*10 + (unsigned long) rec[16]%16; - frame = (unsigned long) rec[17]/16*10 + (unsigned long) rec[17]%16; - sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame; - is_xa = (rec[14] == 0xb0); - break; - - case SCSI_MAN_TOSHIBA: -#ifdef DEBUG - printk(KERN_DEBUG "sr_photocd: use TOSHIBA code\n"); -#endif - - /* we request some disc information (is it a XA-CD ?, - * where starts the last session ?) */ - CLEAR_CMD_BUFFER; - sic->inlen = 0; /* we send nothing... */ - sic->outlen = 4; /* and receive 4 bytes */ - cmd[0] = (unsigned char) 0x00c7; - cmd[1] = (unsigned char) 3; - rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device, - SCSI_IOCTL_SEND_COMMAND, sic); - if (rc != 0) { - if (rc == 0x28000002) { - /* Got a "not ready" - error. No chance to find out if this is - * because there is no CD in the drive or because the drive - * don't knows multisession CD's. So I need to do an extra - * check... */ - if (!kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device, - SCSI_IOCTL_TEST_UNIT_READY, NULL)) { - printk(KERN_INFO "sr_photocd: (TOSHIBA) Hmm, seems the CDROM doesn't support multisession CD's\n"); - no_multi = 1; - } - } else - printk(KERN_WARNING"sr_photocd: ioctl error (TOSHIBA #1): 0x%x\n",rc); - break; /* if the first ioctl fails, we don't call the second one */ - } - is_xa = (rec[0] == 0x20); - min = (unsigned long) rec[1]/16*10 + (unsigned long) rec[1]%16; - sec = (unsigned long) rec[2]/16*10 + (unsigned long) rec[2]%16; - frame = (unsigned long) rec[3]/16*10 + (unsigned long) rec[3]%16; - sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame; - if (sector) - sector -= CD_BLOCK_OFFSET; - - /* now we do a get_density... */ - CLEAR_CMD_BUFFER; - sic->inlen = 0; /* we send nothing... */ - sic->outlen = 12; /* and receive 12 bytes */ - cmd[0] = (unsigned char) MODE_SENSE; - cmd[2] = (unsigned char) 1; - cmd[4] = (unsigned char) 12; - rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device, - SCSI_IOCTL_SEND_COMMAND, sic); - if (rc != 0) { - printk(KERN_WARNING "sr_photocd: ioctl error (TOSHIBA #2): 0x%x\n",rc); - break; - } -#ifdef DEBUG - printk(KERN_DEBUG "sr_photocd: get_density: 0x%x\n",rec[4]); -#endif - - /* ...and only if necessary a set_density */ - if ((rec[4] != 0x81 && is_xa) || (rec[4] != 0 && !is_xa)) { -#ifdef DEBUG - printk(KERN_DEBUG "sr_photocd: doing set_density\n"); -#endif - CLEAR_CMD_BUFFER; - sic->inlen = 12; /* we send 12 bytes... */ - sic->outlen = 0; /* and receive nothing */ - cmd[0] = (unsigned char) MODE_SELECT; - cmd[1] = (unsigned char) (1 << 4); - cmd[4] = (unsigned char) 12; - send = &cmd[6]; /* this is a 6-Byte command */ - send[ 3] = (unsigned char) 0x08; /* data for cmd */ - /* density 0x81 for XA, 0 else */ - send[ 4] = (is_xa) ? - (unsigned char) 0x81 : (unsigned char) 0; - send[10] = (unsigned char) 0x08; - rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device, - SCSI_IOCTL_SEND_COMMAND, sic); - if (rc != 0) { - printk(KERN_WARNING "sr_photocd: ioctl error (TOSHIBA #3): 0x%x\n",rc); - } - /* The set_density command may have changed the - * sector size or capacity. */ - scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size = 1; - } - break; - - case SCSI_MAN_SONY: /* Thomas QUINOT */ - case SCSI_MAN_PIONEER: - case SCSI_MAN_MATSHITA: -#ifdef DEBUG - printk(KERN_DEBUG "sr_photocd: use SONY/PIONEER/MATSHITA code\n"); -#endif - get_sectorsize(MINOR(inode->i_rdev)); /* spinup (avoid timeout) */ - CLEAR_CMD_BUFFER; - sic->inlen = 0x0; /* we send nothing... */ - sic->outlen = 0x0c; /* and receive 0x0c bytes */ - - cmd[0] = READ_TOC; - cmd[8] = 0x0c; - cmd[9] = 0x40; - rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device, - SCSI_IOCTL_SEND_COMMAND, sic); - - if (rc != 0) { - if (rc != 0x28000002) /* drop "not ready" */ - printk(KERN_WARNING "sr_photocd: ioctl error (SONY/PIONEER/MATSHITA): 0x%x\n",rc); - break; - } - if ((rec[0] << 8) + rec[1] != 0x0a) { - printk(KERN_INFO "sr_photocd: (SONY/PIONEER/MATSHITA) Hmm, seems the CDROM doesn't support multisession CD's\n"); - no_multi = 1; - break; - } - sector = rec[11] + (rec[10] << 8) + (rec[9] << 16) + (rec[8] << 24); - is_xa = !!sector; - break; - case SCSI_MAN_HP: -#define DEBUG -#ifdef DEBUG - printk(KERN_DEBUG "sr_photocd: use HP code\n"); -#endif - CLEAR_CMD_BUFFER; - sic->inlen = 0x0; /* we send nothing... */ - sic->outlen = 0x4; /* and receive 4 bytes */ - cmd[0] = 0x43; /* Read TOC */ - cmd[8] = 0x04; - cmd[9] = 0x40; - rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device, - SCSI_IOCTL_SEND_COMMAND, sic); - if (rc != 0) { - if (rc != 0x28000002) /* drop "not ready" */ - printk(KERN_WARNING "sr_photocd: ioctl error (HP-1): 0x%x\n",rc); - break; - } - - if ((rc = rec[2]) == 0) { - printk (KERN_WARNING "sr_photocd: (HP) No finished session"); - break; - } - CLEAR_CMD_BUFFER; - sic->inlen = 0x0; /* we send nothing... */ - sic->outlen = 0x0c; /* and receive 0x0c bytes */ - cmd[0] = 0x43; /* Read TOC */ - cmd[6] = rc & 0x7f; /* number of last session */ - cmd[8] = 0x0c; - cmd[9] = 0x40; - rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device, - SCSI_IOCTL_SEND_COMMAND, sic); - if (rc != 0) { - if (rc != 0x28000002) /* drop "not ready" */ - printk(KERN_WARNING "sr_photocd: ioctl error (HP-2): 0x%x\n",rc); - break; - } -#undef STRICT_HP -#ifdef STRICT_HP - sector = rec[11] + (rec[10] << 8) + (rec[9] << 16); - /* HP documentation states that Logical Start Address is - returned as three (!) bytes, and that rec[8] is - reserved. This is strange, because a LBA usually is - 4 bytes long. */ -#else - sector = rec[11] + (rec[10] << 8) + (rec[9] << 16) + (rec[8] << 24); -#endif - is_xa = !!sector; - break; - case SCSI_MAN_NEC_OLDCDR: - case SCSI_MAN_UNKNOWN: - default: - sector = 0; - no_multi = 1; - break; } - -#ifdef DEBUG - if (sector) - printk (KERN_DEBUG "sr_photocd: multisession CD detected. start: %lu\n",sector); -#endif -#undef DEBUG - - scsi_CDs[MINOR(inode->i_rdev)].mpcd_sector = sector; - if (is_xa) - scsi_CDs[MINOR(inode->i_rdev)].xa_flags |= 0x01; - else - scsi_CDs[MINOR(inode->i_rdev)].xa_flags &= ~0x01; - if (no_multi) - scsi_CDs[MINOR(inode->i_rdev)].xa_flags |= 0x02; - return; -} - -static int sr_open(struct inode * inode, struct file * filp) +static int sr_open(struct cdrom_device_info *cdi, int purpose) { - if(MINOR(inode->i_rdev) >= sr_template.nr_dev || - !scsi_CDs[MINOR(inode->i_rdev)].device) return -ENXIO; /* No such device */ - - if (filp->f_mode & 2) - return -EROFS; + check_disk_change(cdi->dev); - check_disk_change(inode->i_rdev); - - if(!scsi_CDs[MINOR(inode->i_rdev)].device->access_count++) - sr_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0); - if (scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count) - (*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)++; + scsi_CDs[MINOR(cdi->dev)].device->access_count++; + if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->usage_count) + (*scsi_CDs[MINOR(cdi->dev)].device->host->hostt->usage_count)++; if(sr_template.usage_count) (*sr_template.usage_count)++; - - sr_photocd(inode); - + /* If this device did not have media in the drive at boot time, then * we would have been unable to get the sector size. Check to see if * this is the case, and try again. */ - if(scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size) - get_sectorsize(MINOR(inode->i_rdev)); + if(scsi_CDs[MINOR(cdi->dev)].needs_sector_size) + get_sectorsize(MINOR(cdi->dev)); return 0; } - /* * do_sr_request() is the request handler function for the sr driver. * Its function in life is to take block device requests, and @@ -1079,6 +788,19 @@ SDp->scsi_request_fn = do_sr_request; scsi_CDs[i].device = SDp; + + scsi_CDs[i].cdi.ops = &sr_dops; + scsi_CDs[i].cdi.handle = &scsi_CDs[i]; + scsi_CDs[i].cdi.dev = MKDEV(MAJOR_NR,i); + scsi_CDs[i].cdi.mask = 0; + scsi_CDs[i].cdi.speed = 1; + scsi_CDs[i].cdi.capacity = 1; + register_cdrom(&scsi_CDs[i].cdi, "sr"); + +#ifdef CONFIG_BLK_DEV_SR_VENDOR + sr_vendor_init(i); +#endif + sr_template.nr_dev++; if(sr_template.nr_dev > sr_template.dev_max) panic ("scsi_devices corrupt (sr)"); @@ -1184,7 +906,7 @@ if(sr_template.dev_noticed == 0) return 0; if(!sr_registered) { - if (register_blkdev(MAJOR_NR,"sr",&sr_fops)) { + if (register_blkdev(MAJOR_NR,"sr",&cdrom_fops)) { printk("Unable to get major %d for SCSI-CD\n",MAJOR_NR); return 1; } @@ -1193,7 +915,8 @@ if (scsi_CDs) return 0; - sr_template.dev_max = sr_template.dev_noticed + SR_EXTRA_DEVS; + sr_template.dev_max = + sr_template.dev_noticed + SR_EXTRA_DEVS; scsi_CDs = (Scsi_CD *) scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD), GFP_ATOMIC); memset(scsi_CDs, 0, sr_template.dev_max * sizeof(Scsi_CD)); @@ -1222,6 +945,7 @@ scsi_CDs[i].capacity = 0x1fffff; scsi_CDs[i].sector_size = 2048; /* A guess, just in case */ scsi_CDs[i].needs_sector_size = 1; + scsi_CDs[i].device->changed = 1; /* force recheck CD type */ #if 0 /* seems better to leave this for later */ get_sectorsize(i); @@ -1230,7 +954,6 @@ scsi_CDs[i].use = 1; scsi_CDs[i].ten = 1; scsi_CDs[i].remap = 1; - scsi_CDs[i].auto_eject = 0; /* Default is not to eject upon unmount. */ sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9); } @@ -1266,6 +989,7 @@ * Reset things back to a sane state so that one can re-load a new * driver (perhaps the same one). */ + unregister_cdrom(&(cpnt->cdi)); cpnt->device = NULL; cpnt->capacity = 0; SDp->attached--; @@ -1281,14 +1005,14 @@ #ifdef MODULE int init_module(void) { - sr_template.usage_count = &mod_use_count_; - return scsi_register_module(MODULE_SCSI_DEV, &sr_template); + sr_template.usage_count = &mod_use_count_; + return scsi_register_module(MODULE_SCSI_DEV, &sr_template); } void cleanup_module( void) { scsi_unregister_module(MODULE_SCSI_DEV, &sr_template); - unregister_blkdev(SCSI_CDROM_MAJOR, "sr"); + unregister_blkdev(MAJOR_NR, "sr"); sr_registered--; if(scsi_CDs != NULL) { scsi_init_free((char *) scsi_CDs, diff -u --recursive --new-file v2.1.9/linux/drivers/scsi/sr.h linux/drivers/scsi/sr.h --- v2.1.9/linux/drivers/scsi/sr.h Sat Nov 11 13:22:17 1995 +++ linux/drivers/scsi/sr.h Thu Nov 14 15:26:48 1996 @@ -17,24 +17,45 @@ #ifndef _SR_H #define _SR_H +#include + #include "scsi.h" typedef struct { unsigned capacity; /* size in blocks */ unsigned sector_size; /* size in bytes */ - Scsi_Device *device; - unsigned long mpcd_sector; /* for reading multisession-CD's */ - char xa_flags; /* some flags for handling XA-CD's */ + Scsi_Device *device; + unsigned int vendor; /* vendor code, see sr_vendor.c */ + unsigned long ms_offset; /* for reading multisession-CD's */ unsigned char sector_bit_size; /* sector size = 2^sector_bit_size */ unsigned char sector_bit_shift; /* sectors/FS block = 2^sector_bit_shift*/ unsigned needs_sector_size:1; /* needs to get sector size */ unsigned ten:1; /* support ten byte commands */ unsigned remap:1; /* support remapping */ unsigned use:1; /* is this device still supportable */ - unsigned auto_eject:1; /* auto-eject medium on last release. */ + unsigned xa_flag:1; /* CD has XA sectors */ + struct cdrom_device_info cdi; } Scsi_CD; extern Scsi_CD * scsi_CDs; + +int sr_do_ioctl(int, unsigned char*, void*, unsigned); + +int sr_lock_door(struct cdrom_device_info*, int); +int sr_tray_move(struct cdrom_device_info*, int); +int sr_drive_status(struct cdrom_device_info*, int); +int sr_disk_status(struct cdrom_device_info*); +int sr_get_last_session(struct cdrom_device_info*, struct cdrom_multisession*); +int sr_get_mcn(struct cdrom_device_info*, struct cdrom_mcn*); +int sr_reset(struct cdrom_device_info*); +int sr_audio_ioctl(struct cdrom_device_info*, unsigned int, void*); +int sr_dev_ioctl(struct cdrom_device_info*, unsigned int, unsigned long); + +/* vendor-specific */ +#ifdef CONFIG_BLK_DEV_SR_VENDOR +void sr_vendor_init(int minor); +int sr_cd_check(struct cdrom_device_info*); +#endif #endif diff -u --recursive --new-file v2.1.9/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c --- v2.1.9/linux/drivers/scsi/sr_ioctl.c Tue Oct 29 19:58:13 1996 +++ linux/drivers/scsi/sr_ioctl.c Thu Nov 14 15:27:26 1996 @@ -9,13 +9,13 @@ #include #include "scsi.h" #include "hosts.h" -#include "sr.h" #include #include +#include +#include "sr.h" extern void get_sectorsize(int); -extern void sr_photocd(struct inode *); #define IOCTL_RETRIES 3 /* The CDROM is fairly slow, so we need a little extra time */ @@ -38,7 +38,7 @@ error code is. Normally the UNIT_ATTENTION code will automatically clear after one error */ -static int do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned buflength) +int sr_do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned buflength) { Scsi_Cmnd * SCpnt; int result; @@ -88,17 +88,134 @@ return result; } -int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) +/* ---------------------------------------------------------------------- */ +/* interface to cdrom.c */ + +int sr_tray_move(struct cdrom_device_info *cdi, int pos) { - u_char sr_cmd[10]; - - kdev_t dev = inode->i_rdev; - int result, target, err; - - target = MINOR(dev); + u_char sr_cmd[10]; + + sr_cmd[0] = START_STOP; + sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device -> lun) << 5); + sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; + sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */; + + return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 255); +} + +int sr_lock_door(struct cdrom_device_info *cdi, int lock) +{ + return scsi_ioctl (scsi_CDs[MINOR(cdi->dev)].device, + lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK, + 0); +} + +int sr_drive_status(struct cdrom_device_info *cdi, int slot) +{ + if (CDSL_CURRENT != slot) { + /* we have no changer support */ + return -EINVAL; + } + + if (!scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device, + SCSI_IOCTL_TEST_UNIT_READY,0)) + return CDS_DISC_OK; + +#if 0 + /* Enable this if you want to try auto-close. Is'nt enabled by + * default because it does'nt work perfectly (no way to + * difference between "tray open" and "tray closed, no disk"), + * and for caddy drives this is useless anyway. */ + return CDS_TRAY_OPEN; +#else + return CDS_NO_DISC; +#endif +} + +int sr_disk_status(struct cdrom_device_info *cdi) +{ + struct cdrom_tochdr toc_h; + struct cdrom_tocentry toc_e; + int i; + + if (scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device,SCSI_IOCTL_TEST_UNIT_READY,0)) + return CDS_NO_DISC; + + /* if the xa-bit is on, we tell it is XA... */ + if (scsi_CDs[MINOR(cdi->dev)].xa_flag) + return CDS_XA_2_1; + + /* ...else we look for data tracks */ + if (sr_audio_ioctl(cdi, CDROMREADTOCHDR, &toc_h)) + return CDS_NO_INFO; + for (i = toc_h.cdth_trk0; i <= toc_h.cdth_trk1; i++) { + toc_e.cdte_track = i; + toc_e.cdte_format = CDROM_LBA; + if (sr_audio_ioctl(cdi, CDROMREADTOCENTRY, &toc_e)) + return CDS_NO_INFO; + if (toc_e.cdte_ctrl & CDROM_DATA_TRACK) + return CDS_DATA_1; +#if 0 + if (i == toc_h.cdth_trk0 && toc_e.cdte_addr.lba > 100) + /* guess: looks like a "hidden track" CD */ + return CDS_DATA_1; +#endif + } + return CDS_AUDIO; +} + +int sr_get_last_session(struct cdrom_device_info *cdi, + struct cdrom_multisession* ms_info) +{ + ms_info->addr.lba=scsi_CDs[MINOR(cdi->dev)].ms_offset; + ms_info->xa_flag=scsi_CDs[MINOR(cdi->dev)].xa_flag; + + return 0; +} + +int sr_get_mcn(struct cdrom_device_info *cdi,struct cdrom_mcn *mcn) +{ + u_char sr_cmd[10]; + char * buffer; + int result; + + sr_cmd[0] = SCMD_READ_SUBCHANNEL; + sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5); + sr_cmd[2] = 0x40; /* I do want the subchannel info */ + sr_cmd[3] = 0x02; /* Give me medium catalog number info */ + sr_cmd[4] = sr_cmd[5] = 0; + sr_cmd[6] = 0; + sr_cmd[7] = 0; + sr_cmd[8] = 24; + sr_cmd[9] = 0; + + buffer = (unsigned char*) scsi_malloc(512); + if(!buffer) return -ENOMEM; + + result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24); + + memcpy (mcn->medium_catalog_number, buffer + 9, 13); + mcn->medium_catalog_number[13] = 0; + + scsi_free(buffer, 512); + + return result; +} + +int sr_reset(struct cdrom_device_info *cdi) +{ + invalidate_buffers(cdi->dev); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg) +{ + u_char sr_cmd[10]; + int result, target; - if (target >= sr_template.nr_dev || - !scsi_CDs[target].device) return -ENXIO; + target = MINOR(cdi->dev); switch (cmd) { @@ -112,8 +229,8 @@ sr_cmd[8] = 0; sr_cmd[9] = 0; - result = do_ioctl(target, sr_cmd, NULL, 255); - return result; + result = sr_do_ioctl(target, sr_cmd, NULL, 255); + break; case CDROMRESUME: @@ -124,86 +241,69 @@ sr_cmd[8] = 1; sr_cmd[9] = 0; - result = do_ioctl(target, sr_cmd, NULL, 255); - - return result; + result = sr_do_ioctl(target, sr_cmd, NULL, 255); + break; case CDROMPLAYMSF: { - struct cdrom_msf msf; - - err = verify_area (VERIFY_READ, (void *) arg, sizeof (msf)); - if (err) return err; + struct cdrom_msf* msf = (struct cdrom_msf*)arg; - copy_from_user(&msf, (void *) arg, sizeof(msf)); - sr_cmd[0] = SCMD_PLAYAUDIO_MSF; sr_cmd[1] = scsi_CDs[target].device->lun << 5; sr_cmd[2] = 0; - sr_cmd[3] = msf.cdmsf_min0; - sr_cmd[4] = msf.cdmsf_sec0; - sr_cmd[5] = msf.cdmsf_frame0; - sr_cmd[6] = msf.cdmsf_min1; - sr_cmd[7] = msf.cdmsf_sec1; - sr_cmd[8] = msf.cdmsf_frame1; + sr_cmd[3] = msf->cdmsf_min0; + sr_cmd[4] = msf->cdmsf_sec0; + sr_cmd[5] = msf->cdmsf_frame0; + sr_cmd[6] = msf->cdmsf_min1; + sr_cmd[7] = msf->cdmsf_sec1; + sr_cmd[8] = msf->cdmsf_frame1; sr_cmd[9] = 0; - result = do_ioctl(target, sr_cmd, NULL, 255); - return result; + result = sr_do_ioctl(target, sr_cmd, NULL, 255); + break; } case CDROMPLAYBLK: { - struct cdrom_blk blk; - - err = verify_area (VERIFY_READ, (void *) arg, sizeof (blk)); - if (err) return err; + struct cdrom_blk* blk = (struct cdrom_blk*)arg; - copy_from_user(&blk, (void *) arg, sizeof(blk)); - sr_cmd[0] = SCMD_PLAYAUDIO10; sr_cmd[1] = scsi_CDs[target].device->lun << 5; - sr_cmd[2] = blk.from >> 24; - sr_cmd[3] = blk.from >> 16; - sr_cmd[4] = blk.from >> 8; - sr_cmd[5] = blk.from; + sr_cmd[2] = blk->from >> 24; + sr_cmd[3] = blk->from >> 16; + sr_cmd[4] = blk->from >> 8; + sr_cmd[5] = blk->from; sr_cmd[6] = 0; - sr_cmd[7] = blk.len >> 8; - sr_cmd[8] = blk.len; + sr_cmd[7] = blk->len >> 8; + sr_cmd[8] = blk->len; sr_cmd[9] = 0; - result = do_ioctl(target, sr_cmd, NULL, 255); - return result; + result = sr_do_ioctl(target, sr_cmd, NULL, 255); + break; } case CDROMPLAYTRKIND: { - struct cdrom_ti ti; + struct cdrom_ti* ti = (struct cdrom_ti*)arg; - err = verify_area (VERIFY_READ, (void *) arg, sizeof (ti)); - if (err) return err; - - copy_from_user(&ti, (void *) arg, sizeof(ti)); - sr_cmd[0] = SCMD_PLAYAUDIO_TI; sr_cmd[1] = scsi_CDs[target].device->lun << 5; sr_cmd[2] = 0; sr_cmd[3] = 0; - sr_cmd[4] = ti.cdti_trk0; - sr_cmd[5] = ti.cdti_ind0; + sr_cmd[4] = ti->cdti_trk0; + sr_cmd[5] = ti->cdti_ind0; sr_cmd[6] = 0; - sr_cmd[7] = ti.cdti_trk1; - sr_cmd[8] = ti.cdti_ind1; + sr_cmd[7] = ti->cdti_trk1; + sr_cmd[8] = ti->cdti_ind1; sr_cmd[9] = 0; - result = do_ioctl(target, sr_cmd, NULL, 255); - - return result; + result = sr_do_ioctl(target, sr_cmd, NULL, 255); + break; } case CDROMREADTOCHDR: { - struct cdrom_tochdr tochdr; + struct cdrom_tochdr* tochdr = (struct cdrom_tochdr*)arg; char * buffer; sr_cmd[0] = SCMD_READ_TOC; @@ -217,36 +317,25 @@ buffer = (unsigned char *) scsi_malloc(512); if(!buffer) return -ENOMEM; - result = do_ioctl(target, sr_cmd, buffer, 12); + result = sr_do_ioctl(target, sr_cmd, buffer, 12); - tochdr.cdth_trk0 = buffer[2]; - tochdr.cdth_trk1 = buffer[3]; + tochdr->cdth_trk0 = buffer[2]; + tochdr->cdth_trk1 = buffer[3]; scsi_free(buffer, 512); - - err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_tochdr)); - if (err) - return err; - copy_to_user ((void *) arg, &tochdr, sizeof (struct cdrom_tochdr)); - - return result; + break; } case CDROMREADTOCENTRY: { - struct cdrom_tocentry tocentry; + struct cdrom_tocentry* tocentry = (struct cdrom_tocentry*)arg; unsigned char * buffer; - err = verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_tocentry)); - if (err) return err; - - copy_from_user (&tocentry, (void *) arg, sizeof (struct cdrom_tocentry)); - sr_cmd[0] = SCMD_READ_TOC; sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | - (tocentry.cdte_format == CDROM_MSF ? 0x02 : 0); + (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0); sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; - sr_cmd[6] = tocentry.cdte_track; + sr_cmd[6] = tocentry->cdte_track; sr_cmd[7] = 0; /* MSB of length (12) */ sr_cmd[8] = 12; /* LSB of length */ sr_cmd[9] = 0; @@ -254,28 +343,21 @@ buffer = (unsigned char *) scsi_malloc(512); if(!buffer) return -ENOMEM; - result = do_ioctl (target, sr_cmd, buffer, 12); + result = sr_do_ioctl (target, sr_cmd, buffer, 12); - tocentry.cdte_ctrl = buffer[5] & 0xf; - tocentry.cdte_adr = buffer[5] >> 4; - tocentry.cdte_datamode = (tocentry.cdte_ctrl & 0x04) ? 1 : 0; - if (tocentry.cdte_format == CDROM_MSF) { - tocentry.cdte_addr.msf.minute = buffer[9]; - tocentry.cdte_addr.msf.second = buffer[10]; - tocentry.cdte_addr.msf.frame = buffer[11]; - } - else - tocentry.cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8) + tocentry->cdte_ctrl = buffer[5] & 0xf; + tocentry->cdte_adr = buffer[5] >> 4; + tocentry->cdte_datamode = (tocentry->cdte_ctrl & 0x04) ? 1 : 0; + if (tocentry->cdte_format == CDROM_MSF) { + tocentry->cdte_addr.msf.minute = buffer[9]; + tocentry->cdte_addr.msf.second = buffer[10]; + tocentry->cdte_addr.msf.frame = buffer[11]; + } else + tocentry->cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8) + buffer[10]) << 8) + buffer[11]; scsi_free(buffer, 512); - - err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_tocentry)); - if (err) - return err; - copy_to_user ((void *) arg, &tocentry, sizeof (struct cdrom_tocentry)); - - return result; + break; } case CDROMSTOP: @@ -284,8 +366,8 @@ sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; sr_cmd[4] = 0; - result = do_ioctl(target, sr_cmd, NULL, 255); - return result; + result = sr_do_ioctl(target, sr_cmd, NULL, 255); + break; case CDROMSTART: sr_cmd[0] = START_STOP; @@ -293,59 +375,13 @@ sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; sr_cmd[4] = 1; - result = do_ioctl(target, sr_cmd, NULL, 255); - return result; - - case CDROMCLOSETRAY: - sr_cmd[0] = START_STOP; - sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5); - sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; - sr_cmd[4] = 0x03; - - if ((result = do_ioctl(target, sr_cmd, NULL, 255))) - return result; - - /* Gather information about newly inserted disc */ - check_disk_change (inode->i_rdev); - sr_ioctl (inode, NULL, SCSI_IOCTL_DOORLOCK, 0); - sr_photocd (inode); - - if (scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size) - get_sectorsize (MINOR(inode->i_rdev)); - - return 0; - - case CDROMEJECT: - /* - * Allow 0 for access count for auto-eject feature. - */ - if (scsi_CDs[target].device -> access_count > 1) - return -EBUSY; + result = sr_do_ioctl(target, sr_cmd, NULL, 255); + break; - sr_ioctl (inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0); - sr_cmd[0] = START_STOP; - sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 1; - sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; - sr_cmd[4] = 0x02; - - if (!(result = do_ioctl(target, sr_cmd, NULL, 255))) - scsi_CDs[target].device -> changed = 1; - - return result; - - case CDROMEJECT_SW: - scsi_CDs[target].auto_eject = !!arg; - return 0; - case CDROMVOLCTRL: { char * buffer, * mask; - struct cdrom_volctrl volctrl; - - err = verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_volctrl)); - if (err) return err; - - copy_from_user (&volctrl, (void *) arg, sizeof (struct cdrom_volctrl)); + struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg; /* First we get the current params so we can just twiddle the volume */ @@ -359,10 +395,10 @@ buffer = (unsigned char *) scsi_malloc(512); if(!buffer) return -ENOMEM; - if ((result = do_ioctl (target, sr_cmd, buffer, 28))) { + if ((result = sr_do_ioctl (target, sr_cmd, buffer, 28))) { printk ("Hosed while obtaining audio mode page\n"); scsi_free(buffer, 512); - return result; + break; } sr_cmd[0] = MODE_SENSE; @@ -375,23 +411,24 @@ mask = (unsigned char *) scsi_malloc(512); if(!mask) { scsi_free(buffer, 512); - return -ENOMEM; + result = -ENOMEM; + break; }; - if ((result = do_ioctl (target, sr_cmd, mask, 28))) { + if ((result = sr_do_ioctl (target, sr_cmd, mask, 28))) { printk ("Hosed while obtaining mask for audio mode page\n"); scsi_free(buffer, 512); scsi_free(mask, 512); - return result; + break; } /* Now mask and substitute our own volume and reuse the rest */ buffer[0] = 0; /* Clear reserved field */ - buffer[21] = volctrl.channel0 & mask[21]; - buffer[23] = volctrl.channel1 & mask[23]; - buffer[25] = volctrl.channel2 & mask[25]; - buffer[27] = volctrl.channel3 & mask[27]; + buffer[21] = volctrl->channel0 & mask[21]; + buffer[23] = volctrl->channel1 & mask[23]; + buffer[25] = volctrl->channel2 & mask[25]; + buffer[27] = volctrl->channel3 & mask[27]; sr_cmd[0] = MODE_SELECT; sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 0x10; /* Params are SCSI-2 */ @@ -399,19 +436,16 @@ sr_cmd[4] = 28; sr_cmd[5] = 0; - result = do_ioctl (target, sr_cmd, buffer, 28); + result = sr_do_ioctl (target, sr_cmd, buffer, 28); scsi_free(buffer, 512); scsi_free(mask, 512); - return result; + break; } case CDROMVOLREAD: { char * buffer; - struct cdrom_volctrl volctrl; - - err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_volctrl)); - if (err) return err; + struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg; /* Get the current params */ @@ -425,27 +459,24 @@ buffer = (unsigned char *) scsi_malloc(512); if(!buffer) return -ENOMEM; - if ((result = do_ioctl (target, sr_cmd, buffer, 28))) { + if ((result = sr_do_ioctl (target, sr_cmd, buffer, 28))) { printk ("(CDROMVOLREAD) Hosed while obtaining audio mode page\n"); scsi_free(buffer, 512); - return result; + break; } - volctrl.channel0 = buffer[21]; - volctrl.channel1 = buffer[23]; - volctrl.channel2 = buffer[25]; - volctrl.channel3 = buffer[27]; - - copy_to_user ((void *) arg, &volctrl, sizeof (struct cdrom_volctrl)); + volctrl->channel0 = buffer[21]; + volctrl->channel1 = buffer[23]; + volctrl->channel2 = buffer[25]; + volctrl->channel3 = buffer[27]; scsi_free(buffer, 512); - - return 0; + break; } case CDROMSUBCHNL: { - struct cdrom_subchnl subchnl; + struct cdrom_subchnl* subchnl = (struct cdrom_subchnl*)arg; char * buffer; sr_cmd[0] = SCMD_READ_SUBCHANNEL; @@ -461,98 +492,46 @@ buffer = (unsigned char*) scsi_malloc(512); if(!buffer) return -ENOMEM; - result = do_ioctl(target, sr_cmd, buffer, 16); + result = sr_do_ioctl(target, sr_cmd, buffer, 16); - subchnl.cdsc_audiostatus = buffer[1]; - subchnl.cdsc_format = CDROM_MSF; - subchnl.cdsc_ctrl = buffer[5] & 0xf; - subchnl.cdsc_trk = buffer[6]; - subchnl.cdsc_ind = buffer[7]; - - subchnl.cdsc_reladdr.msf.minute = buffer[13]; - subchnl.cdsc_reladdr.msf.second = buffer[14]; - subchnl.cdsc_reladdr.msf.frame = buffer[15]; - subchnl.cdsc_absaddr.msf.minute = buffer[9]; - subchnl.cdsc_absaddr.msf.second = buffer[10]; - subchnl.cdsc_absaddr.msf.frame = buffer[11]; + subchnl->cdsc_audiostatus = buffer[1]; + subchnl->cdsc_format = CDROM_MSF; + subchnl->cdsc_ctrl = buffer[5] & 0xf; + subchnl->cdsc_trk = buffer[6]; + subchnl->cdsc_ind = buffer[7]; + + subchnl->cdsc_reladdr.msf.minute = buffer[13]; + subchnl->cdsc_reladdr.msf.second = buffer[14]; + subchnl->cdsc_reladdr.msf.frame = buffer[15]; + subchnl->cdsc_absaddr.msf.minute = buffer[9]; + subchnl->cdsc_absaddr.msf.second = buffer[10]; + subchnl->cdsc_absaddr.msf.frame = buffer[11]; scsi_free(buffer, 512); - - err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_subchnl)); - if (err) - return err; - copy_to_user ((void *) arg, &subchnl, sizeof (struct cdrom_subchnl)); - return result; + break; } - - case CDROM_GET_UPC: - { - struct cdrom_mcn mcn; - char * buffer; - - sr_cmd[0] = SCMD_READ_SUBCHANNEL; - sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5); - sr_cmd[2] = 0x40; /* I do want the subchannel info */ - sr_cmd[3] = 0x02; /* Give me medium catalog number info */ - sr_cmd[4] = sr_cmd[5] = 0; - sr_cmd[6] = 0; - sr_cmd[7] = 0; - sr_cmd[8] = 24; - sr_cmd[9] = 0; - - buffer = (unsigned char*) scsi_malloc(512); - if(!buffer) return -ENOMEM; - - result = do_ioctl(target, sr_cmd, buffer, 24); - - memcpy (mcn.medium_catalog_number, buffer + 9, 13); - mcn.medium_catalog_number[13] = 0; - - scsi_free(buffer, 512); - - err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_mcn)); - if (err) - return err; - copy_to_user ((void *) arg, &mcn, sizeof (struct cdrom_mcn)); - return result; + default: + return -EINVAL; } + + if (result) + printk("DEBUG: sr_audio: result for ioctl %x: %x\n",cmd,result); + + return result; +} +int sr_dev_ioctl(struct cdrom_device_info *cdi, + unsigned int cmd, unsigned long arg) +{ + int target, err; + + target = MINOR(cdi->dev); + + switch (cmd) { case CDROMREADMODE2: return -EINVAL; case CDROMREADMODE1: - return -EINVAL; - - /* block-copy from ../block/sbpcd.c with some adjustments... */ - case CDROMMULTISESSION: /* tell start-of-last-session to user */ - { - struct cdrom_multisession ms_info; - long lba; - - err = verify_area(VERIFY_READ, (void *) arg, - sizeof(struct cdrom_multisession)); - if (err) return (err); - - copy_from_user(&ms_info, (void *) arg, sizeof(struct cdrom_multisession)); - - if (ms_info.addr_format==CDROM_MSF) { /* MSF-bin requested */ - lba = scsi_CDs[target].mpcd_sector+CD_BLOCK_OFFSET; - ms_info.addr.msf.minute = lba / (CD_SECS*CD_FRAMES); - lba %= CD_SECS*CD_FRAMES; - ms_info.addr.msf.second = lba / CD_FRAMES; - ms_info.addr.msf.frame = lba % CD_FRAMES; - } else if (ms_info.addr_format==CDROM_LBA) /* lba requested */ - ms_info.addr.lba=scsi_CDs[target].mpcd_sector; - else return (-EINVAL); - - ms_info.xa_flag=scsi_CDs[target].xa_flags & 0x01; - - err=verify_area(VERIFY_WRITE,(void *) arg, - sizeof(struct cdrom_multisession)); - if (err) return (err); - - copy_to_user((void *) arg, &ms_info, sizeof(struct cdrom_multisession)); - return (0); - } + return -EINVAL; case BLKRAGET: if (!arg) @@ -560,24 +539,20 @@ err = verify_area(VERIFY_WRITE, (int *) arg, sizeof(int)); if (err) return err; - put_user(read_ahead[MAJOR(inode->i_rdev)], (int *) arg); + put_user(read_ahead[MAJOR(cdi->dev)], (int *) arg); return 0; case BLKRASET: if(!suser()) return -EACCES; - if(!(inode->i_rdev)) + if(!(cdi->dev)) return -EINVAL; if(arg > 0xff) return -EINVAL; - read_ahead[MAJOR(inode->i_rdev)] = arg; + read_ahead[MAJOR(cdi->dev)] = arg; return 0; - RO_IOCTLS(dev,arg); - - case CDROMRESET: - invalidate_buffers(inode->i_rdev); - return 0; + RO_IOCTLS(cdi->dev,arg); default: return scsi_ioctl(scsi_CDs[target].device,cmd,(void *) arg); diff -u --recursive --new-file v2.1.9/linux/drivers/scsi/sr_vendor.c linux/drivers/scsi/sr_vendor.c --- v2.1.9/linux/drivers/scsi/sr_vendor.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/scsi/sr_vendor.c Wed Nov 13 08:11:17 1996 @@ -0,0 +1,273 @@ +/* -*-linux-c-*- + * + * vendor-specific code for SCSI CD-ROM's goes here. + * + * This is needed becauce most of the new features (multisession and + * the like) are to new to be included into the SCSI-II standard (to + * be exact: there is'nt anything in my draft copy). + * + * Gerd Knorr + */ + +#include +#include + +#include +#include "scsi.h" +#include "hosts.h" +#include + +#include +#include +#include "sr.h" + +/* here are some constants to sort the vendors into groups */ + +#define VENDOR_CAN_NOT_HANDLE 1 /* don't know how to handle */ +#define VENDOR_NEC 2 +#define VENDOR_TOSHIBA 3 +#define VENDOR_SONY_LIKE 4 /* much drives are Sony compatible */ +#define VENDOR_HP 5 + +#define DEBUG + +void +sr_vendor_init(int minor) +{ + char *vendor = scsi_CDs[minor].device->vendor; + char *model = scsi_CDs[minor].device->model; + + if (!strncmp (vendor, "NEC", 3)) { + scsi_CDs[minor].vendor = VENDOR_NEC; + if (!strncmp (model,"CD-ROM DRIVE:25", 15) || + !strncmp (model,"CD-ROM DRIVE:36", 15) || + !strncmp (model,"CD-ROM DRIVE:83", 15) || + !strncmp (model,"CD-ROM DRIVE:84 ",16)) + /* these can't handle multisession, may hang */ + scsi_CDs[minor].cdi.mask |= CDC_MULTI_SESSION; + + } else if (!strncmp (vendor, "TOSHIBA", 7)) { + scsi_CDs[minor].vendor = VENDOR_TOSHIBA; + + } else if (!strncmp (vendor, "HP", 2)) { + scsi_CDs[minor].vendor = VENDOR_HP; + + } else { + /* most drives can handled like sony ones, so we take + * it as default */ + scsi_CDs[minor].vendor = VENDOR_SONY_LIKE; + } +} + + + +/* + * support for XA/multisession-CD's + * + * - NEC: Detection and support of multisession CD's. + * + * - TOSHIBA: Detection and support of multisession CD's. + * Some XA-Sector tweaking, required for older drives. + * + * - SONY: Detection and support of multisession CD's. + * added by Thomas Quinot + * + * - PIONEER, HITACHI, PLEXTOR, MATSHITA: known to work with SONY code. + * + * - HP: Much like SONY, but a little different... (Thomas) + * HP-Writers only ??? + */ + +#define BCD_TO_BIN(x) ((((int)x & 0xf0) >> 4)*10 + ((int)x & 0x0f)) + +int sr_cd_check(struct cdrom_device_info *cdi) +{ + unsigned long sector,min,sec,frame; + unsigned char *buffer; /* the buffer for the ioctl */ + unsigned char cmd[12]; /* the scsi-command */ + int rc,is_xa,no_multi,minor; + + minor = MINOR(cdi->dev); + + buffer = (unsigned char *) scsi_malloc(512); + if(!buffer) return -ENOMEM; + + sector = 0; /* the multisession sector offset goes here */ + is_xa = 0; /* flag: the CD uses XA-Sectors */ + no_multi = 0; /* flag: the drive can't handle multisession */ + rc = 0; + + switch(scsi_CDs[minor].vendor) { + + case VENDOR_NEC: + memset(cmd,0,12); + cmd[0] = 0xde; + cmd[1] = (scsi_CDs[minor].device->lun << 5) | 0x03; + cmd[2] = 0xb0; + rc = sr_do_ioctl(minor, cmd, buffer, 0x16); + if (rc != 0) + break; + if (buffer[14] != 0 && buffer[14] != 0xb0) { + printk(KERN_INFO "sr (nec): Hmm, seems the cdrom doesn't support multisession CD's\n"); + no_multi = 1; + break; + } + min = BCD_TO_BIN(buffer[15]); + sec = BCD_TO_BIN(buffer[16]); + frame = BCD_TO_BIN(buffer[17]); + sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame; + is_xa = (buffer[14] == 0xb0); + break; + + case VENDOR_TOSHIBA: + /* we request some disc information (is it a XA-CD ?, + * where starts the last session ?) */ + memset(cmd,0,12); + cmd[0] = 0xc7; + cmd[1] = (scsi_CDs[minor].device->lun << 5) | 3; + rc = sr_do_ioctl(minor, cmd, buffer, 4); + if (rc == 0x28000002 && + !scsi_ioctl(scsi_CDs[minor].device, + SCSI_IOCTL_TEST_UNIT_READY, NULL)) { + printk(KERN_INFO "sr (toshiba): Hmm, seems the drive doesn't support multisession CD's\n"); + no_multi = 1; + break; + } + if (rc != 0) + break; + min = BCD_TO_BIN(buffer[1]); + sec = BCD_TO_BIN(buffer[2]); + frame = BCD_TO_BIN(buffer[3]); + sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame; + if (sector) + sector -= CD_BLOCK_OFFSET; + is_xa = (buffer[0] == 0x20); +#if 0 + /* this is required for some CD's: + * - Enhanced-CD (Hardware tells wrong XA-flag) + * - these broken non-XA multisession CD's + */ + if (is_xa == 0 && sector != 0) { + printk(KERN_WARNING "Warning: multisession offset " + "found, setting XA-flag\n"); + is_xa = 1; + } +#endif + /* now the XA-Sector tweaking: set_density... */ + memset(cmd,0,12); + cmd[0] = MODE_SELECT; + cmd[1] = (scsi_CDs[minor].device->lun << 5) + | (1 << 4); + cmd[4] = 12; + memset(buffer,0,12); + buffer[ 3] = 0x08; + buffer[ 4] = 0x83; + buffer[10] = 0x08; + rc = sr_do_ioctl(minor, cmd, buffer, 12); + if (rc != 0) { + break; + } +#if 0 + /* shoult'nt be required any more */ + scsi_CDs[minor].needs_sector_size = 1; +#endif + break; + + case VENDOR_HP: + cmd[0] = READ_TOC; + cmd[1] = (scsi_CDs[minor].device->lun << 5); + cmd[8] = 0x04; + cmd[9] = 0x40; + rc = sr_do_ioctl(minor, cmd, buffer, 12); + if (rc != 0) { + break; + } + if ((rc = buffer[2]) == 0) { + printk (KERN_WARNING + "sr (hp): No finished session\n"); + 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; + } + +#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 + is_xa = !!sector; + break; + + case VENDOR_SONY_LIKE: + /* Thomas QUINOT */ +#ifdef DEBUG + printk(KERN_DEBUG + "sr: use \"Sony group\" multisession code\n"); +#endif + memset(cmd,0,12); + cmd[0] = READ_TOC; + cmd[1] = (scsi_CDs[minor].device->lun << 5); + cmd[8] = 12; + cmd[9] = 0x40; + rc = sr_do_ioctl(minor, cmd, buffer, 12); + if (rc != 0) { + break; + } + if ((buffer[0] << 8) + buffer[1] != 0x0a) { + printk(KERN_INFO "sr (sony): Hmm, seems the drive doesn't support multisession CD's\n"); + no_multi = 1; + break; + } + sector = buffer[11] + (buffer[10] << 8) + + (buffer[9] << 16) + (buffer[8] << 24); + if (buffer[6] <= 1) { + /* ignore sector offsets from first track */ + sector = 0; + } + is_xa = !!sector; + break; + + case VENDOR_CAN_NOT_HANDLE: + sector = 0; + no_multi = 1; + break; + + default: + /* should not happen */ + printk(KERN_WARNING + "sr: unknown vendor code (%i), not initialized ?\n", + scsi_CDs[minor].vendor); + sector = 0; + no_multi = 1; + break; + } + +#ifdef DEBUG + if (sector) + printk(KERN_DEBUG + "sr: multisession CD detected, offset: %lu\n",sector); +#endif + + scsi_CDs[minor].ms_offset = sector; + scsi_CDs[minor].xa_flag = is_xa; + if (no_multi) + cdi->mask |= CDC_MULTI_SESSION; + + scsi_free(buffer, 512); + + return rc; +} diff -u --recursive --new-file v2.1.9/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c --- v2.1.9/linux/fs/binfmt_elf.c Tue Oct 29 19:58:19 1996 +++ linux/fs/binfmt_elf.c Fri Nov 15 15:27:47 1996 @@ -144,20 +144,14 @@ __put_user((unsigned long)argc,--sp); current->mm->arg_start = (unsigned long) p; while (argc-->0) { - char c; __put_user(p,argv++); - do { - get_user(c,p++); - } while (c); + p += strlen_user(p); } __put_user(NULL, argv); current->mm->arg_end = current->mm->env_start = (unsigned long) p; while (envc-->0) { - char c; __put_user(p,envp++); - do { - get_user(c,p++); - } while (c); + p += strlen_user(p); } __put_user(NULL, envp); current->mm->env_end = (unsigned long) p; diff -u --recursive --new-file v2.1.9/linux/fs/buffer.c linux/fs/buffer.c --- v2.1.9/linux/fs/buffer.c Tue Oct 29 19:58:20 1996 +++ linux/fs/buffer.c Fri Nov 15 12:54:08 1996 @@ -35,6 +35,7 @@ #include #include #include +#include #define NR_SIZES 5 static char buffersize_index[17] = @@ -169,7 +170,7 @@ there to be dirty buffers on any of the other lists. */ bh = lru_list[BUF_DIRTY]; if (!bh) - break; + goto repeat2; for (i = nr_buffers_type[BUF_DIRTY]*2 ; i-- > 0 ; bh = next) { if (bh->b_list != BUF_DIRTY) goto repeat; @@ -1865,6 +1866,32 @@ return reassign_cluster(dev, b[0], size); } +unsigned long generate_cluster_swab32(kdev_t dev, int b[], int size) +{ + int i, offset; + + for (i = 0, offset = 0 ; offset < PAGE_SIZE ; i++, offset += size) { + if(i && le32_to_cpu(b[i])-1 != + le32_to_cpu(b[i-1])) return 0; /* No need to cluster */ + if(find_buffer(dev, le32_to_cpu(b[i]), size)) return 0; + }; + + /* OK, we have a candidate for a new cluster */ + + /* See if one size of buffer is over-represented in the buffer cache, + if so reduce the numbers of buffers */ + if(maybe_shrink_lav_buffers(size)) + { + int retval; + retval = try_to_generate_cluster(dev, le32_to_cpu(b[0]), size); + if(retval) return retval; + }; + + if (nr_free_pages > min_free_pages*2) + return try_to_generate_cluster(dev, le32_to_cpu(b[0]), size); + else + return reassign_cluster(dev, le32_to_cpu(b[0]), size); +} /* ===================== Init ======================= */ diff -u --recursive --new-file v2.1.9/linux/fs/exec.c linux/fs/exec.c --- v2.1.9/linux/fs/exec.c Tue Oct 29 19:58:20 1996 +++ linux/fs/exec.c Fri Nov 15 15:19:29 1996 @@ -178,27 +178,23 @@ /* * count() counts the number of arguments/envelopes - * - * We also do some limited EFAULT checking: this isn't complete, but - * it does cover most cases. I'll have to do this correctly some day.. */ static int count(char ** argv) { - int error, i = 0; - char ** tmp, *p; + int i = 0; - if ((tmp = argv) != NULL) { - error = verify_area(VERIFY_READ, tmp, sizeof(char *)); - if (error) - return error; + if (argv != NULL) { for (;;) { - get_user(p,tmp++); + char * p; + int error; + + error = get_user(p,argv); + if (error) + return error; if (!p) break; + argv++; i++; - error = verify_area(VERIFY_READ, p, 1); - if (error) - return error; } } return i; @@ -224,60 +220,51 @@ unsigned long copy_strings(int argc,char ** argv,unsigned long *page, unsigned long p, int from_kmem) { - char *tmp, *tmp1, *pag = NULL; - int len, offset = 0; - unsigned long old_fs, new_fs; + char *str; + unsigned long old_fs; if (!p) return 0; /* bullet-proofing */ - new_fs = get_ds(); old_fs = get_fs(); if (from_kmem==2) - set_fs(new_fs); + set_fs(KERNEL_DS); while (argc-- > 0) { + int len; + unsigned long pos; + if (from_kmem == 1) - set_fs(new_fs); - get_user(tmp, argv+argc); - if (!tmp) + set_fs(KERNEL_DS); + get_user(str, argv+argc); + if (!str) panic("VFS: argc is wrong"); - tmp1 = tmp; if (from_kmem == 1) set_fs(old_fs); - for (;;) { - char c; - get_user(c,tmp++); - if (!c) - break; - } - len = tmp - tmp1; + len = strlen_user(str); /* includes the '\0' */ if (p < len) { /* this shouldn't happen - 128kB */ set_fs(old_fs); return 0; } + p -= len; + pos = p; while (len) { - --p; --tmp; --len; - if (--offset < 0) { - offset = p % PAGE_SIZE; + char *pag; + int offset, bytes_to_copy; + + offset = pos % PAGE_SIZE; + if (!(pag = (char *) page[pos/PAGE_SIZE]) && + !(pag = (char *) page[pos/PAGE_SIZE] = + (unsigned long *) get_free_page(GFP_USER))) { if (from_kmem==2) set_fs(old_fs); - if (!(pag = (char *) page[p/PAGE_SIZE]) && - !(pag = (char *) page[p/PAGE_SIZE] = - (unsigned long *) get_free_page(GFP_USER))) - return 0; - if (from_kmem==2) - set_fs(new_fs); - - } - if (len == 0 || offset == 0) - get_user(*(pag + offset), tmp); - else { - int bytes_to_copy = (len > offset) ? offset : len; - tmp -= bytes_to_copy; - p -= bytes_to_copy; - offset -= bytes_to_copy; - len -= bytes_to_copy; - copy_from_user(pag + offset, tmp, bytes_to_copy + 1); + return 0; } + bytes_to_copy = PAGE_SIZE - offset; + if (bytes_to_copy > len) + bytes_to_copy = len; + copy_from_user(pag + offset, str, bytes_to_copy); + pos += bytes_to_copy; + str += bytes_to_copy; + len -= bytes_to_copy; } } if (from_kmem==2) diff -u --recursive --new-file v2.1.9/linux/fs/ext2/balloc.c linux/fs/ext2/balloc.c --- v2.1.9/linux/fs/ext2/balloc.c Thu Jan 4 14:14:20 1996 +++ linux/fs/ext2/balloc.c Thu Nov 14 10:27:37 1996 @@ -7,6 +7,8 @@ * Universite Pierre et Marie Curie (Paris VI) * * Enhanced block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993 + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 */ /* @@ -32,6 +34,7 @@ #include #include +#include #define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1) @@ -71,12 +74,12 @@ struct buffer_head * bh; gdp = get_group_desc (sb, block_group, NULL); - bh = bread (sb->s_dev, gdp->bg_block_bitmap, sb->s_blocksize); + bh = bread (sb->s_dev, le32_to_cpu(gdp->bg_block_bitmap), sb->s_blocksize); if (!bh) ext2_panic (sb, "read_block_bitmap", "Cannot read block bitmap - " "block_group = %d, block_bitmap = %lu", - block_group, (unsigned long) gdp->bg_block_bitmap); + block_group, (unsigned long) le32_to_cpu(gdp->bg_block_bitmap)); sb->u.ext2_sb.s_block_bitmap_number[bitmap_nr] = block_group; sb->u.ext2_sb.s_block_bitmap[bitmap_nr] = bh; } @@ -185,8 +188,8 @@ } lock_super (sb); es = sb->u.ext2_sb.s_es; - if (block < es->s_first_data_block || - (block + count) > es->s_blocks_count) { + if (block < le32_to_cpu(es->s_first_data_block) || + (block + count) > le32_to_cpu(es->s_blocks_count)) { ext2_error (sb, "ext2_free_blocks", "Freeing blocks not in datazone - " "block = %lu, count = %lu", block, count); @@ -196,9 +199,9 @@ ext2_debug ("freeing block %lu\n", block); - block_group = (block - es->s_first_data_block) / + block_group = (block - le32_to_cpu(es->s_first_data_block)) / EXT2_BLOCKS_PER_GROUP(sb); - bit = (block - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb); + bit = (block - le32_to_cpu(es->s_first_data_block)) % EXT2_BLOCKS_PER_GROUP(sb); if (bit + count > EXT2_BLOCKS_PER_GROUP(sb)) ext2_panic (sb, "ext2_free_blocks", "Freeing blocks across group boundary - " @@ -209,11 +212,11 @@ gdp = get_group_desc (sb, block_group, &bh2); if (test_opt (sb, CHECK_STRICT) && - (in_range (gdp->bg_block_bitmap, block, count) || - in_range (gdp->bg_inode_bitmap, block, count) || - in_range (block, gdp->bg_inode_table, + (in_range (le32_to_cpu(gdp->bg_block_bitmap), block, count) || + in_range (le32_to_cpu(gdp->bg_inode_bitmap), block, count) || + in_range (block, le32_to_cpu(gdp->bg_inode_table), sb->u.ext2_sb.s_itb_per_group) || - in_range (block + count - 1, gdp->bg_inode_table, + in_range (block + count - 1, le32_to_cpu(gdp->bg_inode_table), sb->u.ext2_sb.s_itb_per_group))) ext2_panic (sb, "ext2_free_blocks", "Freeing blocks in system zones - " @@ -221,15 +224,17 @@ block, count); for (i = 0; i < count; i++) { - if (!clear_bit (bit + i, bh->b_data)) + if (!ext2_clear_bit (bit + i, bh->b_data)) ext2_warning (sb, "ext2_free_blocks", "bit already cleared for block %lu", block); else { if (sb->dq_op) sb->dq_op->free_block(inode, fs_to_dq_blocks(1, sb->s_blocksize)); - gdp->bg_free_blocks_count++; - es->s_free_blocks_count++; + gdp->bg_free_blocks_count = + cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)+1); + es->s_free_blocks_count = + cpu_to_le32(le32_to_cpu(es->s_free_blocks_count)+1); } } @@ -276,7 +281,7 @@ } lock_super (sb); es = sb->u.ext2_sb.s_es; - if (es->s_free_blocks_count <= es->s_r_blocks_count && + if (le32_to_cpu(es->s_free_blocks_count) <= le32_to_cpu(es->s_r_blocks_count) && (!fsuser() && (sb->u.ext2_sb.s_resuid != current->fsuid) && (sb->u.ext2_sb.s_resgid == 0 || !in_group_p (sb->u.ext2_sb.s_resgid)))) { @@ -290,12 +295,13 @@ /* * First, test whether the goal block is free. */ - if (goal < es->s_first_data_block || goal >= es->s_blocks_count) - goal = es->s_first_data_block; - i = (goal - es->s_first_data_block) / EXT2_BLOCKS_PER_GROUP(sb); + if (goal < le32_to_cpu(es->s_first_data_block) || + goal >= le32_to_cpu(es->s_blocks_count)) + goal = le32_to_cpu(es->s_first_data_block); + i = (goal - le32_to_cpu(es->s_first_data_block)) / EXT2_BLOCKS_PER_GROUP(sb); gdp = get_group_desc (sb, i, &bh2); - if (gdp->bg_free_blocks_count > 0) { - j = ((goal - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb)); + if (le16_to_cpu(gdp->bg_free_blocks_count) > 0) { + j = ((goal - le32_to_cpu(es->s_first_data_block)) % EXT2_BLOCKS_PER_GROUP(sb)); #ifdef EXT2FS_DEBUG if (j) goal_attempts++; @@ -305,7 +311,7 @@ ext2_debug ("goal is at %d:%d.\n", i, j); - if (!test_bit(j, bh->b_data)) { + if (!ext2_test_bit(j, bh->b_data)) { #ifdef EXT2FS_DEBUG goal_hits++; ext2_debug ("goal bit allocated.\n"); @@ -322,7 +328,7 @@ * next 64-bit boundary is simple.. */ int end_goal = (j + 63) & ~63; - j = find_next_zero_bit(bh->b_data, end_goal, j); + j = ext2_find_next_zero_bit(bh->b_data, end_goal, j); if (j < end_goal) goto got_block; } @@ -345,7 +351,8 @@ j = k; goto search_back; } - k = find_next_zero_bit ((unsigned long *) bh->b_data, + + k = ext2_find_next_zero_bit ((unsigned long *) bh->b_data, EXT2_BLOCKS_PER_GROUP(sb), j); if (k < EXT2_BLOCKS_PER_GROUP(sb)) { @@ -365,7 +372,7 @@ if (i >= sb->u.ext2_sb.s_groups_count) i = 0; gdp = get_group_desc (sb, i, &bh2); - if (gdp->bg_free_blocks_count > 0) + if (le16_to_cpu(gdp->bg_free_blocks_count) > 0) break; } if (k >= sb->u.ext2_sb.s_groups_count) { @@ -379,7 +386,7 @@ if (j < EXT2_BLOCKS_PER_GROUP(sb)) goto search_back; else - j = find_first_zero_bit ((unsigned long *) bh->b_data, + j = ext2_find_first_zero_bit ((unsigned long *) bh->b_data, EXT2_BLOCKS_PER_GROUP(sb)); if (j >= EXT2_BLOCKS_PER_GROUP(sb)) { ext2_error (sb, "ext2_new_block", @@ -394,7 +401,7 @@ * bitmap. Now search backwards up to 7 bits to find the * start of this group of free blocks. */ - for (k = 0; k < 7 && j > 0 && !test_bit (j - 1, bh->b_data); k++, j--); + for (k = 0; k < 7 && j > 0 && !ext2_test_bit (j - 1, bh->b_data); k++, j--); got_block: @@ -410,17 +417,17 @@ return 0; } - tmp = j + i * EXT2_BLOCKS_PER_GROUP(sb) + es->s_first_data_block; + tmp = j + i * EXT2_BLOCKS_PER_GROUP(sb) + le32_to_cpu(es->s_first_data_block); if (test_opt (sb, CHECK_STRICT) && - (tmp == gdp->bg_block_bitmap || - tmp == gdp->bg_inode_bitmap || - in_range (tmp, gdp->bg_inode_table, sb->u.ext2_sb.s_itb_per_group))) + (tmp == le32_to_cpu(gdp->bg_block_bitmap) || + tmp == le32_to_cpu(gdp->bg_inode_bitmap) || + in_range (tmp, le32_to_cpu(gdp->bg_inode_table), sb->u.ext2_sb.s_itb_per_group))) ext2_panic (sb, "ext2_new_block", "Allocating block in system zone - " "block = %u", tmp); - if (set_bit (j, bh->b_data)) { + if (ext2_set_bit (j, bh->b_data)) { ext2_warning (sb, "ext2_new_block", "bit already set for block %d", j); if (sb->dq_op) @@ -442,15 +449,19 @@ if (sb->dq_op) if (sb->dq_op->alloc_block(inode, fs_to_dq_blocks(1, sb->s_blocksize))) break; - if (set_bit (j + k, bh->b_data)) { + if (ext2_set_bit (j + k, bh->b_data)) { if (sb->dq_op) sb->dq_op->free_block(inode, fs_to_dq_blocks(1, sb->s_blocksize)); - break; + break; } (*prealloc_count)++; } - gdp->bg_free_blocks_count -= *prealloc_count; - es->s_free_blocks_count -= *prealloc_count; + gdp->bg_free_blocks_count = + cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - + *prealloc_count); + es->s_free_blocks_count = + cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) - + *prealloc_count); ext2_debug ("Preallocated a further %lu bits.\n", *prealloc_count); } @@ -464,7 +475,7 @@ wait_on_buffer (bh); } - if (j >= es->s_blocks_count) { + if (j >= le32_to_cpu(es->s_blocks_count)) { ext2_error (sb, "ext2_new_block", "block >= blocks count - " "block_group = %d, block=%d", i, j); @@ -484,9 +495,9 @@ ext2_debug ("allocating block %d. " "Goal hits %d of %d.\n", j, goal_hits, goal_attempts); - gdp->bg_free_blocks_count--; + gdp->bg_free_blocks_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - 1); mark_buffer_dirty(bh2, 1); - es->s_free_blocks_count--; + es->s_free_blocks_count = cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) - 1); mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); sb->s_dirt = 1; unlock_super (sb); @@ -510,20 +521,20 @@ gdp = NULL; for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) { gdp = get_group_desc (sb, i, NULL); - desc_count += gdp->bg_free_blocks_count; + desc_count += le16_to_cpu(gdp->bg_free_blocks_count); bitmap_nr = load_block_bitmap (sb, i); x = ext2_count_free (sb->u.ext2_sb.s_block_bitmap[bitmap_nr], sb->s_blocksize); printk ("group %d: stored = %d, counted = %lu\n", - i, gdp->bg_free_blocks_count, x); + i, le16_to_cpu(gdp->bg_free_blocks_count), x); bitmap_count += x; } printk("ext2_count_free_blocks: stored = %lu, computed = %lu, %lu\n", - es->s_free_blocks_count, desc_count, bitmap_count); + le32_to_cpu(es->s_free_blocks_count), desc_count, bitmap_count); unlock_super (sb); return bitmap_count; #else - return sb->u.ext2_sb.s_es->s_free_blocks_count; + return le32_to_cpu(sb->u.ext2_sb.s_es->s_free_blocks_count); #endif } @@ -531,7 +542,7 @@ struct super_block * sb, unsigned char * map) { - return test_bit ((block - sb->u.ext2_sb.s_es->s_first_data_block) % + return ext2_test_bit ((block - le32_to_cpu(sb->u.ext2_sb.s_es->s_first_data_block)) % EXT2_BLOCKS_PER_GROUP(sb), map); } @@ -554,48 +565,48 @@ EXT2_DESC_PER_BLOCK(sb); for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) { gdp = get_group_desc (sb, i, NULL); - desc_count += gdp->bg_free_blocks_count; + desc_count += le16_to_cpu(gdp->bg_free_blocks_count); bitmap_nr = load_block_bitmap (sb, i); bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; - if (!test_bit (0, bh->b_data)) + if (!ext2_test_bit (0, bh->b_data)) ext2_error (sb, "ext2_check_blocks_bitmap", "Superblock in group %d is marked free", i); for (j = 0; j < desc_blocks; j++) - if (!test_bit (j + 1, bh->b_data)) + if (!ext2_test_bit (j + 1, bh->b_data)) ext2_error (sb, "ext2_check_blocks_bitmap", "Descriptor block #%d in group " "%d is marked free", j, i); - if (!block_in_use (gdp->bg_block_bitmap, sb, bh->b_data)) + if (!block_in_use (le32_to_cpu(gdp->bg_block_bitmap), sb, bh->b_data)) ext2_error (sb, "ext2_check_blocks_bitmap", "Block bitmap for group %d is marked free", i); - if (!block_in_use (gdp->bg_inode_bitmap, sb, bh->b_data)) + if (!block_in_use (le32_to_cpu(gdp->bg_inode_bitmap), sb, bh->b_data)) ext2_error (sb, "ext2_check_blocks_bitmap", "Inode bitmap for group %d is marked free", i); for (j = 0; j < sb->u.ext2_sb.s_itb_per_group; j++) - if (!block_in_use (gdp->bg_inode_table + j, sb, bh->b_data)) + if (!block_in_use (le32_to_cpu(gdp->bg_inode_table) + j, sb, bh->b_data)) ext2_error (sb, "ext2_check_blocks_bitmap", "Block #%d of the inode table in " "group %d is marked free", j, i); x = ext2_count_free (bh, sb->s_blocksize); - if (gdp->bg_free_blocks_count != x) + if (le16_to_cpu(gdp->bg_free_blocks_count) != x) ext2_error (sb, "ext2_check_blocks_bitmap", "Wrong free blocks count for group %d, " "stored = %d, counted = %lu", i, - gdp->bg_free_blocks_count, x); + le16_to_cpu(gdp->bg_free_blocks_count), x); bitmap_count += x; } - if (es->s_free_blocks_count != bitmap_count) + if (le32_to_cpu(es->s_free_blocks_count) != bitmap_count) ext2_error (sb, "ext2_check_blocks_bitmap", "Wrong free blocks count in super block, " "stored = %lu, counted = %lu", - (unsigned long) es->s_free_blocks_count, bitmap_count); + (unsigned long) le32_to_cpu(es->s_free_blocks_count), bitmap_count); unlock_super (sb); } diff -u --recursive --new-file v2.1.9/linux/fs/ext2/dir.c linux/fs/ext2/dir.c --- v2.1.9/linux/fs/ext2/dir.c Tue Oct 29 19:58:42 1996 +++ linux/fs/ext2/dir.c Thu Nov 14 10:27:37 1996 @@ -13,6 +13,9 @@ * Copyright (C) 1991, 1992 Linus Torvalds * * ext2 directory handling functions + * + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 */ #include @@ -77,23 +80,24 @@ { const char * error_msg = NULL; - if (de->rec_len < EXT2_DIR_REC_LEN(1)) + if (le16_to_cpu(de->rec_len) < EXT2_DIR_REC_LEN(1)) error_msg = "rec_len is smaller than minimal"; - else if (de->rec_len % 4 != 0) + else if (le16_to_cpu(de->rec_len) % 4 != 0) error_msg = "rec_len % 4 != 0"; - else if (de->rec_len < EXT2_DIR_REC_LEN(de->name_len)) + else if (le16_to_cpu(de->rec_len) < EXT2_DIR_REC_LEN(le16_to_cpu(de->name_len))) error_msg = "rec_len is too small for name_len"; - else if (dir && ((char *) de - bh->b_data) + de->rec_len > + else if (dir && ((char *) de - bh->b_data) + le16_to_cpu(de->rec_len) > dir->i_sb->s_blocksize) error_msg = "directory entry across blocks"; - else if (dir && de->inode > dir->i_sb->u.ext2_sb.s_es->s_inodes_count) + else if (dir && le32_to_cpu(de->inode) > le32_to_cpu(dir->i_sb->u.ext2_sb.s_es->s_inodes_count)) error_msg = "inode out of bounds"; if (error_msg != NULL) ext2_error (dir->i_sb, function, "bad entry in directory #%lu: %s - " "offset=%lu, inode=%lu, rec_len=%d, name_len=%d", - dir->i_ino, error_msg, offset, (unsigned long) de->inode, - de->rec_len, de->name_len); + dir->i_ino, error_msg, offset, + (unsigned long) le32_to_cpu(de->inode), + le16_to_cpu(de->rec_len), le16_to_cpu(de->name_len)); return error_msg == NULL ? 1 : 0; } @@ -161,9 +165,9 @@ * least that it is non-zero. A * failure will be detected in the * dirent test below. */ - if (de->rec_len < EXT2_DIR_REC_LEN(1)) + if (le16_to_cpu(de->rec_len) < EXT2_DIR_REC_LEN(1)) break; - i += de->rec_len; + i += le16_to_cpu(de->rec_len); } offset = i; filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) @@ -183,8 +187,8 @@ brelse (bh); return stored; } - offset += de->rec_len; - if (de->inode) { + offset += le16_to_cpu(de->rec_len); + if (le32_to_cpu(de->inode)) { /* We might block in the next section * if the data destination is * currently swapped out. So, use a @@ -192,16 +196,17 @@ * not the directory has been modified * during the copy operation. */ unsigned long version; - dcache_add(inode, de->name, de->name_len, de->inode); + dcache_add(inode, de->name, le16_to_cpu(de->name_len), + le32_to_cpu(de->inode)); version = inode->i_version; - error = filldir(dirent, de->name, de->name_len, filp->f_pos, de->inode); + error = filldir(dirent, de->name, le16_to_cpu(de->name_len), filp->f_pos, le32_to_cpu(de->inode)); if (error) break; if (version != inode->i_version) goto revalidate; stored ++; } - filp->f_pos += de->rec_len; + filp->f_pos += le16_to_cpu(de->rec_len); } offset = 0; brelse (bh); diff -u --recursive --new-file v2.1.9/linux/fs/ext2/fsync.c linux/fs/ext2/fsync.c --- v2.1.9/linux/fs/ext2/fsync.c Tue Oct 29 19:58:42 1996 +++ linux/fs/ext2/fsync.c Thu Nov 14 10:27:37 1996 @@ -10,6 +10,9 @@ * linux/fs/minix/truncate.c Copyright (C) 1991, 1992 Linus Torvalds * * ext2fs fsync primitive + * + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 */ #include @@ -27,7 +30,7 @@ #define blocksize (EXT2_BLOCK_SIZE(inode->i_sb)) #define addr_per_block (EXT2_ADDR_PER_BLOCK(inode->i_sb)) -static int sync_block (struct inode * inode, u32 * block, int wait) +static __inline__ int sync_block (struct inode * inode, u32 * block, int wait) { struct buffer_head * bh; int tmp; @@ -55,7 +58,35 @@ return 0; } -static int sync_iblock (struct inode * inode, u32 * iblock, +static __inline__ 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; + } + if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) { + brelse (bh); + return 0; + } + ll_rw_block (WRITE, 1, &bh); + bh->b_count--; + return 0; +} + +static __inline__ int sync_iblock (struct inode * inode, u32 * iblock, struct buffer_head ** bh, int wait) { int rc, tmp; @@ -78,8 +109,31 @@ return 0; } +static __inline__ int sync_iblock_swab32 (struct inode * inode, u32 * iblock, + struct buffer_head ** bh, int wait) +{ + int rc, tmp; + + *bh = NULL; + tmp = le32_to_cpu(*iblock); + if (!tmp) + return 0; + rc = sync_block_swab32 (inode, iblock, wait); + 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; +} + -static int sync_direct (struct inode * inode, int wait) +static __inline__ int sync_direct (struct inode * inode, int wait) { int i; int rc, err = 0; @@ -94,7 +148,7 @@ return err; } -static int sync_indirect (struct inode * inode, u32 * iblock, int wait) +static __inline__ int sync_indirect (struct inode * inode, u32 * iblock, int wait) { int i; struct buffer_head * ind_bh; @@ -105,9 +159,32 @@ return rc; for (i = 0; i < addr_per_block; i++) { - rc = sync_block (inode, - ((u32 *) ind_bh->b_data) + i, - wait); + rc = sync_block_swab32 (inode, + ((u32 *) ind_bh->b_data) + i, + wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + brelse (ind_bh); + return err; +} + +static __inline__ int sync_indirect_swab32 (struct inode * inode, u32 * iblock, int wait) +{ + int i; + struct buffer_head * ind_bh; + int rc, err = 0; + + rc = sync_iblock_swab32 (inode, iblock, &ind_bh, wait); + if (rc || !ind_bh) + return rc; + + for (i = 0; i < addr_per_block; i++) { + rc = sync_block_swab32 (inode, + ((u32 *) ind_bh->b_data) + i, + wait); if (rc > 0) break; if (rc) @@ -117,7 +194,7 @@ return err; } -static int sync_dindirect (struct inode * inode, u32 * diblock, int wait) +static __inline__ int sync_dindirect (struct inode * inode, u32 * diblock, int wait) { int i; struct buffer_head * dind_bh; @@ -128,9 +205,32 @@ return rc; for (i = 0; i < addr_per_block; i++) { - rc = sync_indirect (inode, - ((u32 *) dind_bh->b_data) + i, - wait); + rc = sync_indirect_swab32 (inode, + ((u32 *) dind_bh->b_data) + i, + wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + brelse (dind_bh); + return err; +} + +static __inline__ int sync_dindirect_swab32 (struct inode * inode, u32 * diblock, int wait) +{ + int i; + struct buffer_head * dind_bh; + int rc, err = 0; + + rc = sync_iblock_swab32 (inode, diblock, &dind_bh, wait); + if (rc || !dind_bh) + return rc; + + for (i = 0; i < addr_per_block; i++) { + rc = sync_indirect_swab32 (inode, + ((u32 *) dind_bh->b_data) + i, + wait); if (rc > 0) break; if (rc) @@ -140,7 +240,7 @@ return err; } -static int sync_tindirect (struct inode * inode, u32 * tiblock, int wait) +static __inline__ int sync_tindirect (struct inode * inode, u32 * tiblock, int wait) { int i; struct buffer_head * tind_bh; @@ -151,9 +251,9 @@ return rc; for (i = 0; i < addr_per_block; i++) { - rc = sync_dindirect (inode, - ((u32 *) tind_bh->b_data) + i, - wait); + rc = sync_dindirect_swab32 (inode, + ((u32 *) tind_bh->b_data) + i, + wait); if (rc > 0) break; if (rc) diff -u --recursive --new-file v2.1.9/linux/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c --- v2.1.9/linux/fs/ext2/ialloc.c Sat May 4 10:06:18 1996 +++ linux/fs/ext2/ialloc.c Thu Nov 14 10:27:37 1996 @@ -8,6 +8,8 @@ * * BSD ufs-inspired inode and directory allocation by * Stephen Tweedie (sct@dcs.ed.ac.uk), 1993 + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 */ /* @@ -33,6 +35,7 @@ #include #include +#include static struct ext2_group_desc * get_group_desc (struct super_block * sb, unsigned int block_group, @@ -70,12 +73,12 @@ struct buffer_head * bh; gdp = get_group_desc (sb, block_group, NULL); - bh = bread (sb->s_dev, gdp->bg_inode_bitmap, sb->s_blocksize); + bh = bread (sb->s_dev, le32_to_cpu(gdp->bg_inode_bitmap), sb->s_blocksize); if (!bh) ext2_panic (sb, "read_inode_bitmap", "Cannot read inode bitmap - " "block_group = %lu, inode_bitmap = %lu", - block_group, (unsigned long) gdp->bg_inode_bitmap); + block_group, (unsigned long) le32_to_cpu(gdp->bg_inode_bitmap)); sb->u.ext2_sb.s_inode_bitmap_number[bitmap_nr] = block_group; sb->u.ext2_sb.s_inode_bitmap[bitmap_nr] = bh; } @@ -188,7 +191,7 @@ sb = inode->i_sb; lock_super (sb); if (inode->i_ino < EXT2_FIRST_INO(sb) || - inode->i_ino > sb->u.ext2_sb.s_es->s_inodes_count) { + inode->i_ino > le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count)) { ext2_error (sb, "free_inode", "reserved inode or nonexistent inode"); unlock_super (sb); @@ -199,16 +202,19 @@ bit = (inode->i_ino - 1) % EXT2_INODES_PER_GROUP(sb); bitmap_nr = load_inode_bitmap (sb, block_group); bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr]; - if (!clear_bit (bit, bh->b_data)) + if (!ext2_clear_bit (bit, bh->b_data)) ext2_warning (sb, "ext2_free_inode", "bit already cleared for inode %lu", inode->i_ino); else { gdp = get_group_desc (sb, block_group, &bh2); - gdp->bg_free_inodes_count++; + gdp->bg_free_inodes_count = + cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) + 1); if (S_ISDIR(inode->i_mode)) - gdp->bg_used_dirs_count--; + gdp->bg_used_dirs_count = + cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) - 1); mark_buffer_dirty(bh2, 1); - es->s_free_inodes_count++; + es->s_free_inodes_count = + cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) + 1); mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); inode->i_dirt = 0; } @@ -273,14 +279,14 @@ *err = -ENOSPC; if (S_ISDIR(mode)) { - avefreei = es->s_free_inodes_count / + avefreei = le32_to_cpu(es->s_free_inodes_count) / sb->u.ext2_sb.s_groups_count; /* I am not yet convinced that this next bit is necessary. i = dir->u.ext2_i.i_block_group; for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) { tmp = get_group_desc (sb, i, &bh2); - if ((tmp->bg_used_dirs_count << 8) < - tmp->bg_free_inodes_count) { + if ((le16_to_cpu(tmp->bg_used_dirs_count) << 8) < + le16_to_cpu(tmp->bg_free_inodes_count)) { gdp = tmp; break; } @@ -291,11 +297,11 @@ if (!gdp) { for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) { tmp = get_group_desc (sb, j, &bh2); - if (tmp->bg_free_inodes_count && - tmp->bg_free_inodes_count >= avefreei) { + if (le16_to_cpu(tmp->bg_free_inodes_count) && + le16_to_cpu(tmp->bg_free_inodes_count) >= avefreei) { if (!gdp || - (tmp->bg_free_blocks_count > - gdp->bg_free_blocks_count)) { + (le16_to_cpu(tmp->bg_free_blocks_count) > + le16_to_cpu(gdp->bg_free_blocks_count))) { i = j; gdp = tmp; } @@ -310,7 +316,7 @@ */ i = dir->u.ext2_i.i_block_group; tmp = get_group_desc (sb, i, &bh2); - if (tmp->bg_free_inodes_count) + if (le16_to_cpu(tmp->bg_free_inodes_count)) gdp = tmp; else { @@ -323,7 +329,7 @@ if (i >= sb->u.ext2_sb.s_groups_count) i -= sb->u.ext2_sb.s_groups_count; tmp = get_group_desc (sb, i, &bh2); - if (tmp->bg_free_inodes_count) { + if (le16_to_cpu(tmp->bg_free_inodes_count)) { gdp = tmp; break; } @@ -338,7 +344,7 @@ if (++i >= sb->u.ext2_sb.s_groups_count) i = 0; tmp = get_group_desc (sb, i, &bh2); - if (tmp->bg_free_inodes_count) { + if (le16_to_cpu(tmp->bg_free_inodes_count)) { gdp = tmp; break; } @@ -353,10 +359,10 @@ } bitmap_nr = load_inode_bitmap (sb, i); bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr]; - if ((j = find_first_zero_bit ((unsigned long *) bh->b_data, + if ((j = ext2_find_first_zero_bit ((unsigned long *) bh->b_data, EXT2_INODES_PER_GROUP(sb))) < EXT2_INODES_PER_GROUP(sb)) { - if (set_bit (j, bh->b_data)) { + if (ext2_set_bit (j, bh->b_data)) { ext2_warning (sb, "ext2_new_inode", "bit already set for inode %d", j); goto repeat; @@ -367,7 +373,7 @@ wait_on_buffer (bh); } } else { - if (gdp->bg_free_inodes_count != 0) { + if (le16_to_cpu(gdp->bg_free_inodes_count) != 0) { ext2_error (sb, "ext2_new_inode", "Free inodes count corrupted in group %d", i); @@ -378,7 +384,7 @@ goto repeat; } j += i * EXT2_INODES_PER_GROUP(sb) + 1; - if (j < EXT2_FIRST_INO(sb) || j > es->s_inodes_count) { + if (j < EXT2_FIRST_INO(sb) || j > le32_to_cpu(es->s_inodes_count)) { ext2_error (sb, "ext2_new_inode", "reserved inode or inode > inodes count - " "block_group = %d,inode=%d", i, j); @@ -386,11 +392,14 @@ iput (inode); return NULL; } - gdp->bg_free_inodes_count--; + gdp->bg_free_inodes_count = + cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1); if (S_ISDIR(mode)) - gdp->bg_used_dirs_count++; + gdp->bg_used_dirs_count = + cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1); mark_buffer_dirty(bh2, 1); - es->s_free_inodes_count--; + es->s_free_inodes_count = + cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) - 1); mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); sb->s_dirt = 1; inode->i_mode = mode; @@ -463,20 +472,20 @@ gdp = NULL; for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) { gdp = get_group_desc (sb, i, NULL); - desc_count += gdp->bg_free_inodes_count; + desc_count += le16_to_cpu(gdp->bg_free_inodes_count); bitmap_nr = load_inode_bitmap (sb, i); x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr], EXT2_INODES_PER_GROUP(sb) / 8); printk ("group %d: stored = %d, counted = %lu\n", - i, gdp->bg_free_inodes_count, x); + i, le16_to_cpu(gdp->bg_free_inodes_count), x); bitmap_count += x; } printk("ext2_count_free_inodes: stored = %lu, computed = %lu, %lu\n", - es->s_free_inodes_count, desc_count, bitmap_count); + le32_to_cpu(es->s_free_inodes_count), desc_count, bitmap_count); unlock_super (sb); return desc_count; #else - return sb->u.ext2_sb.s_es->s_free_inodes_count; + return le32_to_cpu(sb->u.ext2_sb.s_es->s_free_inodes_count); #endif } @@ -495,21 +504,22 @@ gdp = NULL; for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) { gdp = get_group_desc (sb, i, NULL); - desc_count += gdp->bg_free_inodes_count; + desc_count += le16_to_cpu(gdp->bg_free_inodes_count); bitmap_nr = load_inode_bitmap (sb, i); x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr], EXT2_INODES_PER_GROUP(sb) / 8); - if (gdp->bg_free_inodes_count != x) + if (le16_to_cpu(gdp->bg_free_inodes_count) != x) ext2_error (sb, "ext2_check_inodes_bitmap", "Wrong free inodes count in group %d, " "stored = %d, counted = %lu", i, - gdp->bg_free_inodes_count, x); + le16_to_cpu(gdp->bg_free_inodes_count), x); bitmap_count += x; } - if (es->s_free_inodes_count != bitmap_count) + if (le32_to_cpu(es->s_free_inodes_count) != bitmap_count) ext2_error (sb, "ext2_check_inodes_bitmap", "Wrong free inodes count in super block, " "stored = %lu, counted = %lu", - (unsigned long) es->s_free_inodes_count, bitmap_count); + (unsigned long) le32_to_cpu(es->s_free_inodes_count), + bitmap_count); unlock_super (sb); } diff -u --recursive --new-file v2.1.9/linux/fs/ext2/inode.c linux/fs/ext2/inode.c --- v2.1.9/linux/fs/ext2/inode.c Tue Oct 29 19:58:42 1996 +++ linux/fs/ext2/inode.c Thu Nov 14 10:27:37 1996 @@ -13,6 +13,8 @@ * Copyright (C) 1991, 1992 Linus Torvalds * * Goal-directed block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993 + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 */ #include @@ -52,7 +54,7 @@ if (!bh) return 0; - tmp = ((u32 *) bh->b_data)[nr]; + tmp = le32_to_cpu(((u32 *) bh->b_data)[nr]); brelse (bh); return tmp; } @@ -115,7 +117,7 @@ ext2_debug ("preallocation miss (%lu/%lu).\n", alloc_hits, ++alloc_attempts); if (S_ISREG(inode->i_mode)) - result = ext2_new_block (inode, goal, + result = ext2_new_block (inode, goal, &inode->u.ext2_i.i_prealloc_count, &inode->u.ext2_i.i_prealloc_block, err); else @@ -224,7 +226,7 @@ if (!goal) goal = (inode->u.ext2_i.i_block_group * EXT2_BLOCKS_PER_GROUP(inode->i_sb)) + - inode->i_sb->u.ext2_sb.s_es->s_first_data_block; + le32_to_cpu(inode->i_sb->u.ext2_sb.s_es->s_first_data_block); } ext2_debug ("goal = %d.\n", goal); @@ -272,10 +274,10 @@ } p = (u32 *) bh->b_data + nr; repeat: - tmp = *p; + tmp = le32_to_cpu(*p); if (tmp) { result = getblk (bh->b_dev, tmp, blocksize); - if (tmp == *p) { + if (tmp == le32_to_cpu(*p)) { brelse (bh); return result; } @@ -293,8 +295,8 @@ goal = inode->u.ext2_i.i_next_alloc_goal; if (!goal) { for (tmp = nr - 1; tmp >= 0; tmp--) { - if (((u32 *) bh->b_data)[tmp]) { - goal = ((u32 *)bh->b_data)[tmp]; + if (le32_to_cpu(((u32 *) bh->b_data)[tmp])) { + goal = le32_to_cpu(((u32 *)bh->b_data)[tmp]); break; } } @@ -307,12 +309,12 @@ return NULL; } result = getblk (bh->b_dev, tmp, blocksize); - if (*p) { + if (le32_to_cpu(*p)) { ext2_free_blocks (inode, tmp, 1); brelse (result); goto repeat; } - *p = tmp; + *p = le32_to_cpu(tmp); mark_buffer_dirty(bh, 1); if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) { ll_rw_block (WRITE, 1, &bh); @@ -348,15 +350,15 @@ p = (u32 *) bh->b_data + nr + i; /* All blocks in cluster must already be allocated */ - if(*p == 0) goto out; + if(le32_to_cpu(*p) == 0) goto out; /* See if aligned correctly */ - if(i==0) firstblock = *p; - else if(*p != firstblock + i) goto out; + if(i==0) firstblock = le32_to_cpu(*p); + else if(le32_to_cpu(*p) != firstblock + i) goto out; } p = (u32 *) bh->b_data + nr; - result = generate_cluster(bh->b_dev, (int *) p, blocksize); + result = generate_cluster_swab32(bh->b_dev, (int *) p, blocksize); out: brelse(bh); @@ -506,7 +508,7 @@ if ((inode->i_ino != EXT2_ROOT_INO && inode->i_ino != EXT2_ACL_IDX_INO && inode->i_ino != EXT2_ACL_DATA_INO && inode->i_ino < EXT2_FIRST_INO(inode->i_sb)) || - inode->i_ino > inode->i_sb->u.ext2_sb.s_es->s_inodes_count) { + inode->i_ino > le32_to_cpu(inode->i_sb->u.ext2_sb.s_es->s_inodes_count)) { ext2_error (inode->i_sb, "ext2_read_inode", "bad inode number: %lu", inode->i_ino); return; @@ -527,7 +529,7 @@ */ offset = ((inode->i_ino - 1) % EXT2_INODES_PER_GROUP(inode->i_sb)) * EXT2_INODE_SIZE(inode->i_sb); - block = gdp[desc].bg_inode_table + + block = le32_to_cpu(gdp[desc].bg_inode_table) + (offset >> EXT2_BLOCK_SIZE_BITS(inode->i_sb)); if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize))) ext2_panic (inode->i_sb, "ext2_read_inode", @@ -536,27 +538,27 @@ offset &= (EXT2_BLOCK_SIZE(inode->i_sb) - 1); raw_inode = (struct ext2_inode *) (bh->b_data + offset); - inode->i_mode = raw_inode->i_mode; - inode->i_uid = raw_inode->i_uid; - inode->i_gid = raw_inode->i_gid; - inode->i_nlink = raw_inode->i_links_count; - inode->i_size = raw_inode->i_size; - inode->i_atime = raw_inode->i_atime; - inode->i_ctime = raw_inode->i_ctime; - inode->i_mtime = raw_inode->i_mtime; - inode->u.ext2_i.i_dtime = raw_inode->i_dtime; + inode->i_mode = le16_to_cpu(raw_inode->i_mode); + inode->i_uid = le16_to_cpu(raw_inode->i_uid); + inode->i_gid = le16_to_cpu(raw_inode->i_gid); + inode->i_nlink = le16_to_cpu(raw_inode->i_links_count); + inode->i_size = le32_to_cpu(raw_inode->i_size); + inode->i_atime = le32_to_cpu(raw_inode->i_atime); + inode->i_ctime = le32_to_cpu(raw_inode->i_ctime); + inode->i_mtime = le32_to_cpu(raw_inode->i_mtime); + inode->u.ext2_i.i_dtime = le32_to_cpu(raw_inode->i_dtime); inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */ - inode->i_blocks = raw_inode->i_blocks; + inode->i_blocks = le32_to_cpu(raw_inode->i_blocks); inode->i_version = ++event; inode->u.ext2_i.i_new_inode = 0; - inode->u.ext2_i.i_flags = raw_inode->i_flags; - inode->u.ext2_i.i_faddr = raw_inode->i_faddr; + inode->u.ext2_i.i_flags = le32_to_cpu(raw_inode->i_flags); + inode->u.ext2_i.i_faddr = le32_to_cpu(raw_inode->i_faddr); inode->u.ext2_i.i_frag_no = raw_inode->i_frag; inode->u.ext2_i.i_frag_size = raw_inode->i_fsize; inode->u.ext2_i.i_osync = 0; - inode->u.ext2_i.i_file_acl = raw_inode->i_file_acl; - inode->u.ext2_i.i_dir_acl = raw_inode->i_dir_acl; - inode->u.ext2_i.i_version = raw_inode->i_version; + inode->u.ext2_i.i_file_acl = le32_to_cpu(raw_inode->i_file_acl); + inode->u.ext2_i.i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl); + inode->u.ext2_i.i_version = le32_to_cpu(raw_inode->i_version); inode->u.ext2_i.i_block_group = block_group; inode->u.ext2_i.i_next_alloc_block = 0; inode->u.ext2_i.i_next_alloc_goal = 0; @@ -564,9 +566,12 @@ ext2_error (inode->i_sb, "ext2_read_inode", "New inode has non-zero prealloc count!"); if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) - inode->i_rdev = to_kdev_t(raw_inode->i_block[0]); + inode->i_rdev = to_kdev_t(le32_to_cpu(raw_inode->i_block[0])); + else if (S_ISLNK(inode->i_mode) && !inode->i_blocks) + for (block = 0; block < EXT2_N_BLOCKS; block++) + inode->u.ext2_i.i_data[block] = raw_inode->i_block[block]; else for (block = 0; block < EXT2_N_BLOCKS; block++) - inode->u.ext2_i.i_data[block] = raw_inode->i_block[block]; + inode->u.ext2_i.i_data[block] = le32_to_cpu(raw_inode->i_block[block]); brelse (bh); inode->i_op = NULL; if (inode->i_ino == EXT2_ACL_IDX_INO || @@ -606,7 +611,7 @@ if ((inode->i_ino != EXT2_ROOT_INO && inode->i_ino < EXT2_FIRST_INO(inode->i_sb)) || - inode->i_ino > inode->i_sb->u.ext2_sb.s_es->s_inodes_count) { + inode->i_ino > le32_to_cpu(inode->i_sb->u.ext2_sb.s_es->s_inodes_count)) { ext2_error (inode->i_sb, "ext2_write_inode", "bad inode number: %lu", inode->i_ino); return 0; @@ -627,7 +632,7 @@ */ offset = ((inode->i_ino - 1) % EXT2_INODES_PER_GROUP(inode->i_sb)) * EXT2_INODE_SIZE(inode->i_sb); - block = gdp[desc].bg_inode_table + + block = le32_to_cpu(gdp[desc].bg_inode_table) + (offset >> EXT2_BLOCK_SIZE_BITS(inode->i_sb)); if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize))) ext2_panic (inode->i_sb, "ext2_write_inode", @@ -636,27 +641,30 @@ offset &= EXT2_BLOCK_SIZE(inode->i_sb) - 1; raw_inode = (struct ext2_inode *) (bh->b_data + offset); - raw_inode->i_mode = inode->i_mode; - raw_inode->i_uid = inode->i_uid; - raw_inode->i_gid = inode->i_gid; - raw_inode->i_links_count = inode->i_nlink; - raw_inode->i_size = inode->i_size; - raw_inode->i_atime = inode->i_atime; - raw_inode->i_ctime = inode->i_ctime; - raw_inode->i_mtime = inode->i_mtime; - raw_inode->i_blocks = inode->i_blocks; - raw_inode->i_dtime = inode->u.ext2_i.i_dtime; - raw_inode->i_flags = inode->u.ext2_i.i_flags; - raw_inode->i_faddr = inode->u.ext2_i.i_faddr; + raw_inode->i_mode = cpu_to_le16(inode->i_mode); + raw_inode->i_uid = cpu_to_le16(inode->i_uid); + raw_inode->i_gid = cpu_to_le16(inode->i_gid); + raw_inode->i_links_count = cpu_to_le16(inode->i_nlink); + raw_inode->i_size = cpu_to_le32(inode->i_size); + raw_inode->i_atime = cpu_to_le32(inode->i_atime); + raw_inode->i_ctime = cpu_to_le32(inode->i_ctime); + raw_inode->i_mtime = cpu_to_le32(inode->i_mtime); + raw_inode->i_blocks = cpu_to_le32(inode->i_blocks); + raw_inode->i_dtime = cpu_to_le32(inode->u.ext2_i.i_dtime); + raw_inode->i_flags = cpu_to_le32(inode->u.ext2_i.i_flags); + raw_inode->i_faddr = cpu_to_le32(inode->u.ext2_i.i_faddr); raw_inode->i_frag = inode->u.ext2_i.i_frag_no; raw_inode->i_fsize = inode->u.ext2_i.i_frag_size; - raw_inode->i_file_acl = inode->u.ext2_i.i_file_acl; - raw_inode->i_dir_acl = inode->u.ext2_i.i_dir_acl; - raw_inode->i_version = inode->u.ext2_i.i_version; + raw_inode->i_file_acl = cpu_to_le32(inode->u.ext2_i.i_file_acl); + raw_inode->i_dir_acl = cpu_to_le32(inode->u.ext2_i.i_dir_acl); + raw_inode->i_version = cpu_to_le32(inode->u.ext2_i.i_version); if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) - raw_inode->i_block[0] = kdev_t_to_nr(inode->i_rdev); + raw_inode->i_block[0] = cpu_to_le32(kdev_t_to_nr(inode->i_rdev)); + else if (S_ISLNK(inode->i_mode) && !inode->i_blocks) + for (block = 0; block < EXT2_N_BLOCKS; block++) + raw_inode->i_block[block] = inode->u.ext2_i.i_data[block]; else for (block = 0; block < EXT2_N_BLOCKS; block++) - raw_inode->i_block[block] = inode->u.ext2_i.i_data[block]; + raw_inode->i_block[block] = cpu_to_le32(inode->u.ext2_i.i_data[block]); mark_buffer_dirty(bh, 1); inode->i_dirt = 0; if (do_sync) { diff -u --recursive --new-file v2.1.9/linux/fs/ext2/namei.c linux/fs/ext2/namei.c --- v2.1.9/linux/fs/ext2/namei.c Tue Oct 29 19:58:42 1996 +++ linux/fs/ext2/namei.c Thu Nov 14 10:27:38 1996 @@ -11,6 +11,9 @@ * linux/fs/minix/namei.c * * Copyright (C) 1991, 1992 Linus Torvalds + * + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 */ #include @@ -38,15 +41,15 @@ static int ext2_match (int len, const char * const name, struct ext2_dir_entry * de) { - if (!de || !de->inode || len > EXT2_NAME_LEN) + if (!de || !le32_to_cpu(de->inode) || len > EXT2_NAME_LEN) return 0; /* * "" means "." ---> so paths like "/usr/lib//libc.a" work */ - if (!len && de->name_len == 1 && (de->name[0] == '.') && + if (!len && le16_to_cpu(de->name_len) == 1 && (de->name[0] == '.') && (de->name[1] == '\0')) return 1; - if (len != de->name_len) + if (len != le16_to_cpu(de->name_len)) return 0; return !memcmp(name, de->name, len); } @@ -121,7 +124,7 @@ if (!ext2_check_dir_entry ("ext2_find_entry", dir, de, bh, offset)) goto failure; - if (de->inode != 0 && ext2_match (namelen, name, de)) { + if (le32_to_cpu(de->inode) != 0 && ext2_match (namelen, name, de)) { for (i = 0; i < NAMEI_RA_SIZE; ++i) { if (bh_use[i] != bh) brelse (bh_use[i]); @@ -129,9 +132,9 @@ *res_dir = de; return bh; } - offset += de->rec_len; + offset += le16_to_cpu(de->rec_len); de = (struct ext2_dir_entry *) - ((char *) de + de->rec_len); + ((char *) de + le16_to_cpu(de->rec_len)); } brelse (bh); @@ -188,7 +191,7 @@ iput (dir); return -ENOENT; } - ino = de->inode; + ino = le32_to_cpu(de->inode); dcache_add(dir, name, len, ino); brelse (bh); if (!(*result = iget (dir->i_sb, ino))) { @@ -265,8 +268,8 @@ ext2_debug ("creating next block\n"); de = (struct ext2_dir_entry *) bh->b_data; - de->inode = 0; - de->rec_len = sb->s_blocksize; + de->inode = le32_to_cpu(0); + de->rec_len = le16_to_cpu(sb->s_blocksize); dir->i_size = offset + sb->s_blocksize; dir->i_dirt = 1; } else { @@ -282,24 +285,24 @@ brelse (bh); return NULL; } - if (de->inode != 0 && ext2_match (namelen, name, de)) { + if (le32_to_cpu(de->inode) != 0 && ext2_match (namelen, name, de)) { *err = -EEXIST; brelse (bh); return NULL; } - if ((de->inode == 0 && de->rec_len >= rec_len) || - (de->rec_len >= EXT2_DIR_REC_LEN(de->name_len) + rec_len)) { - offset += de->rec_len; - if (de->inode) { + if ((le32_to_cpu(de->inode) == 0 && le16_to_cpu(de->rec_len) >= rec_len) || + (le16_to_cpu(de->rec_len) >= EXT2_DIR_REC_LEN(le16_to_cpu(de->name_len)) + rec_len)) { + offset += le16_to_cpu(de->rec_len); + if (le32_to_cpu(de->inode)) { de1 = (struct ext2_dir_entry *) ((char *) de + - EXT2_DIR_REC_LEN(de->name_len)); - de1->rec_len = de->rec_len - - EXT2_DIR_REC_LEN(de->name_len); - de->rec_len = EXT2_DIR_REC_LEN(de->name_len); + EXT2_DIR_REC_LEN(le16_to_cpu(de->name_len))); + de1->rec_len = cpu_to_le16(le16_to_cpu(de->rec_len) - + EXT2_DIR_REC_LEN(le16_to_cpu(de->name_len))); + de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(le16_to_cpu(de->name_len))); de = de1; } - de->inode = 0; - de->name_len = namelen; + de->inode = cpu_to_le32(0); + de->name_len = cpu_to_le16(namelen); memcpy (de->name, name, namelen); /* * XXX shouldn't update any times until successful @@ -320,8 +323,8 @@ *err = 0; return bh; } - offset += de->rec_len; - de = (struct ext2_dir_entry *) ((char *) de + de->rec_len); + offset += le16_to_cpu(de->rec_len); + de = (struct ext2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len)); } brelse (bh); return NULL; @@ -346,13 +349,15 @@ return -EIO; if (de == dir) { if (pde) - pde->rec_len += dir->rec_len; - dir->inode = 0; + pde->rec_len = + cpu_to_le16(le16_to_cpu(pde->rec_len) + + le16_to_cpu(dir->rec_len)); + dir->inode = le32_to_cpu(0); return 0; } - i += de->rec_len; + i += le16_to_cpu(de->rec_len); pde = de; - de = (struct ext2_dir_entry *) ((char *) de + de->rec_len); + de = (struct ext2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len)); } return -ENOENT; } @@ -384,9 +389,9 @@ iput (dir); return err; } - de->inode = inode->i_ino; + de->inode = cpu_to_le32(inode->i_ino); dir->i_version = ++event; - dcache_add(dir, de->name, de->name_len, de->inode); + dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode)); mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); @@ -453,9 +458,9 @@ iput (dir); return err; } - de->inode = inode->i_ino; + de->inode = cpu_to_le32(inode->i_ino); dir->i_version = ++event; - dcache_add(dir, de->name, de->name_len, de->inode); + dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode)); mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); @@ -507,14 +512,14 @@ } inode->i_blocks = inode->i_sb->s_blocksize / 512; de = (struct ext2_dir_entry *) dir_block->b_data; - de->inode = inode->i_ino; - de->name_len = 1; - de->rec_len = EXT2_DIR_REC_LEN(de->name_len); + de->inode = cpu_to_le32(inode->i_ino); + de->name_len = cpu_to_le16(1); + de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(le16_to_cpu(de->name_len))); strcpy (de->name, "."); - de = (struct ext2_dir_entry *) ((char *) de + de->rec_len); - de->inode = dir->i_ino; - de->rec_len = inode->i_sb->s_blocksize - EXT2_DIR_REC_LEN(1); - de->name_len = 2; + de = (struct ext2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len)); + de->inode = cpu_to_le32(dir->i_ino); + de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize - EXT2_DIR_REC_LEN(1)); + de->name_len = cpu_to_le16(2); strcpy (de->name, ".."); inode->i_nlink = 2; mark_buffer_dirty(dir_block, 1); @@ -531,9 +536,9 @@ iput (inode); return err; } - de->inode = inode->i_ino; + de->inode = cpu_to_le32(inode->i_ino); dir->i_version = ++event; - dcache_add(dir, de->name, de->name_len, de->inode); + dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode)); mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); @@ -567,16 +572,16 @@ return 1; } de = (struct ext2_dir_entry *) bh->b_data; - de1 = (struct ext2_dir_entry *) ((char *) de + de->rec_len); - if (de->inode != inode->i_ino || !de1->inode || + de1 = (struct ext2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len)); + if (le32_to_cpu(de->inode) != inode->i_ino || !le32_to_cpu(de1->inode) || strcmp (".", de->name) || strcmp ("..", de1->name)) { ext2_warning (inode->i_sb, "empty_dir", "bad directory (dir #%lu) - no `.' or `..'", inode->i_ino); return 1; } - offset = de->rec_len + de1->rec_len; - de = (struct ext2_dir_entry *) ((char *) de1 + de1->rec_len); + offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len); + de = (struct ext2_dir_entry *) ((char *) de1 + le16_to_cpu(de1->rec_len)); while (offset < inode->i_size ) { if ((void *) de >= (void *) (bh->b_data + sb->s_blocksize)) { brelse (bh); @@ -595,12 +600,12 @@ brelse (bh); return 1; } - if (de->inode) { + if (le32_to_cpu(de->inode)) { brelse (bh); return 0; } - offset += de->rec_len; - de = (struct ext2_dir_entry *) ((char *) de + de->rec_len); + offset += le16_to_cpu(de->rec_len); + de = (struct ext2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len)); } brelse (bh); return 1; @@ -626,7 +631,7 @@ if (!bh) goto end_rmdir; retval = -EPERM; - if (!(inode = iget (dir->i_sb, de->inode))) + if (!(inode = iget (dir->i_sb, le32_to_cpu(de->inode)))) goto end_rmdir; if (inode->i_sb->dq_op) inode->i_sb->dq_op->initialize (inode, -1); @@ -634,7 +639,7 @@ retval = -EBUSY; goto end_rmdir; } - if (de->inode != inode->i_ino) { + if (le32_to_cpu(de->inode) != inode->i_ino) { iput(inode); brelse(bh); current->counter = 0; @@ -654,7 +659,7 @@ down(&inode->i_sem); if (!empty_dir (inode)) retval = -ENOTEMPTY; - else if (de->inode != inode->i_ino) + else if (le32_to_cpu(de->inode) != inode->i_ino) retval = -ENOENT; else { if (inode->i_count > 1) { @@ -714,7 +719,7 @@ bh = ext2_find_entry (dir, name, len, &de); if (!bh) goto end_unlink; - if (!(inode = iget (dir->i_sb, de->inode))) + if (!(inode = iget (dir->i_sb, le32_to_cpu(de->inode)))) goto end_unlink; if (inode->i_sb->dq_op) inode->i_sb->dq_op->initialize (inode, -1); @@ -723,7 +728,7 @@ goto end_unlink; if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) goto end_unlink; - if (de->inode != inode->i_ino) { + if (le32_to_cpu(de->inode) != inode->i_ino) { iput(inode); brelse(bh); current->counter = 0; @@ -829,9 +834,9 @@ iput (dir); return err; } - de->inode = inode->i_ino; + de->inode = cpu_to_le32(inode->i_ino); dir->i_version = ++event; - dcache_add(dir, de->name, de->name_len, de->inode); + dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode)); mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); @@ -878,9 +883,9 @@ iput (oldinode); return err; } - de->inode = oldinode->i_ino; + de->inode = cpu_to_le32(oldinode->i_ino); dir->i_version = ++event; - dcache_add(dir, de->name, de->name_len, de->inode); + dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode)); mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); @@ -921,11 +926,11 @@ #define PARENT_INO(buffer) \ ((struct ext2_dir_entry *) ((char *) buffer + \ - ((struct ext2_dir_entry *) buffer)->rec_len))->inode + le16_to_cpu(((struct ext2_dir_entry *) buffer)->rec_len)))->inode #define PARENT_NAME(buffer) \ ((struct ext2_dir_entry *) ((char *) buffer + \ - ((struct ext2_dir_entry *) buffer)->rec_len))->name + le16_to_cpu(((struct ext2_dir_entry *) buffer)->rec_len)))->name /* * rename uses retrying to avoid race-conditions: at least they should be @@ -973,7 +978,7 @@ retval = -ENOENT; if (!old_bh) goto end_rename; - old_inode = __iget (old_dir->i_sb, old_de->inode, 0); /* don't cross mnt-points */ + old_inode = __iget (old_dir->i_sb, le32_to_cpu(old_de->inode), 0); /* don't cross mnt-points */ if (!old_inode) goto end_rename; if (must_be_dir && !S_ISDIR(old_inode->i_mode)) @@ -987,7 +992,7 @@ goto end_rename; new_bh = ext2_find_entry (new_dir, new_name, new_len, &new_de); if (new_bh) { - new_inode = __iget (new_dir->i_sb, new_de->inode, 0); /* no mntp cross */ + new_inode = __iget (new_dir->i_sb, le32_to_cpu(new_de->inode), 0); /* no mntp cross */ if (!new_inode) { brelse (new_bh); new_bh = NULL; @@ -1029,7 +1034,7 @@ dir_bh = ext2_bread (old_inode, 0, 0, &retval); if (!dir_bh) goto end_rename; - if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino) + if (le32_to_cpu(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino) goto end_rename; retval = -EMLINK; if (!new_inode && new_dir->i_nlink >= EXT2_LINK_MAX) @@ -1044,17 +1049,17 @@ /* * sanity checking before doing the rename - avoid races */ - if (new_inode && (new_de->inode != new_inode->i_ino)) + if (new_inode && (le32_to_cpu(new_de->inode) != new_inode->i_ino)) goto try_again; - if (new_de->inode && !new_inode) + if (le32_to_cpu(new_de->inode) && !new_inode) goto try_again; - if (old_de->inode != old_inode->i_ino) + if (le32_to_cpu(old_de->inode) != old_inode->i_ino) goto try_again; /* * ok, that's it */ - new_de->inode = old_inode->i_ino; - dcache_add(new_dir, new_de->name, new_de->name_len, new_de->inode); + new_de->inode = le32_to_cpu(old_inode->i_ino); + dcache_add(new_dir, new_de->name, le16_to_cpu(new_de->name_len), le32_to_cpu(new_de->inode)); retval = ext2_delete_entry (old_de, old_bh); if (retval == -ENOENT) goto try_again; @@ -1069,7 +1074,7 @@ old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; old_dir->i_dirt = 1; if (dir_bh) { - PARENT_INO(dir_bh->b_data) = new_dir->i_ino; + PARENT_INO(dir_bh->b_data) = le32_to_cpu(new_dir->i_ino); dcache_add(old_inode, "..", 2, new_dir->i_ino); mark_buffer_dirty(dir_bh, 1); old_dir->i_nlink--; diff -u --recursive --new-file v2.1.9/linux/fs/ext2/super.c linux/fs/ext2/super.c --- v2.1.9/linux/fs/ext2/super.c Tue Oct 29 19:58:42 1996 +++ linux/fs/ext2/super.c Thu Nov 14 10:27:38 1996 @@ -11,6 +11,9 @@ * linux/fs/minix/inode.c * * Copyright (C) 1991, 1992 Linus Torvalds + * + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 */ #include @@ -39,7 +42,8 @@ if (!(sb->s_flags & MS_RDONLY)) { sb->u.ext2_sb.s_mount_state |= EXT2_ERROR_FS; - sb->u.ext2_sb.s_es->s_state |= EXT2_ERROR_FS; + sb->u.ext2_sb.s_es->s_state = + cpu_to_le16(le16_to_cpu(sb->u.ext2_sb.s_es->s_state) | EXT2_ERROR_FS); mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); sb->s_dirt = 1; } @@ -47,14 +51,14 @@ vsprintf (error_buf, fmt, args); va_end (args); if (test_opt (sb, ERRORS_PANIC) || - (sb->u.ext2_sb.s_es->s_errors == EXT2_ERRORS_PANIC && + (le16_to_cpu(sb->u.ext2_sb.s_es->s_errors) == EXT2_ERRORS_PANIC && !test_opt (sb, ERRORS_CONT) && !test_opt (sb, ERRORS_RO))) panic ("EXT2-fs panic (device %s): %s: %s\n", kdevname(sb->s_dev), function, error_buf); printk (KERN_CRIT "EXT2-fs error (device %s): %s: %s\n", kdevname(sb->s_dev), function, error_buf); if (test_opt (sb, ERRORS_RO) || - (sb->u.ext2_sb.s_es->s_errors == EXT2_ERRORS_RO && + (le16_to_cpu(sb->u.ext2_sb.s_es->s_errors) == EXT2_ERRORS_RO && !test_opt (sb, ERRORS_CONT) && !test_opt (sb, ERRORS_PANIC))) { printk ("Remounting filesystem read-only\n"); sb->s_flags |= MS_RDONLY; @@ -68,7 +72,8 @@ if (!(sb->s_flags & MS_RDONLY)) { sb->u.ext2_sb.s_mount_state |= EXT2_ERROR_FS; - sb->u.ext2_sb.s_es->s_state |= EXT2_ERROR_FS; + sb->u.ext2_sb.s_es->s_state = + cpu_to_le16(le16_to_cpu(sb->u.ext2_sb.s_es->s_state) | EXT2_ERROR_FS); mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); sb->s_dirt = 1; } @@ -102,7 +107,7 @@ lock_super (sb); if (!(sb->s_flags & MS_RDONLY)) { - sb->u.ext2_sb.s_es->s_state = sb->u.ext2_sb.s_mount_state; + sb->u.ext2_sb.s_es->s_state = le16_to_cpu(sb->u.ext2_sb.s_mount_state); mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); } sb->s_dev = 0; @@ -270,7 +275,7 @@ static void ext2_setup_super (struct super_block * sb, struct ext2_super_block * es) { - if (es->s_rev_level > EXT2_MAX_SUPP_REV) { + if (le32_to_cpu(es->s_rev_level) > EXT2_MAX_SUPP_REV) { printk ("EXT2-fs warning: revision level too high, " "forcing read/only mode\n"); sb->s_flags |= MS_RDONLY; @@ -282,19 +287,20 @@ else if ((sb->u.ext2_sb.s_mount_state & EXT2_ERROR_FS)) printk ("EXT2-fs warning: mounting fs with errors, " "running e2fsck is recommended\n"); - else if (es->s_max_mnt_count >= 0 && - es->s_mnt_count >= (unsigned short) es->s_max_mnt_count) + else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 && + le16_to_cpu(es->s_mnt_count) >= + (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count)) printk ("EXT2-fs warning: maximal mount count reached, " "running e2fsck is recommended\n"); - else if (es->s_checkinterval && - (es->s_lastcheck + es->s_checkinterval <= CURRENT_TIME)) + else if (le32_to_cpu(es->s_checkinterval) && + (le32_to_cpu(es->s_lastcheck) + le32_to_cpu(es->s_checkinterval) <= CURRENT_TIME)) printk ("EXT2-fs warning: checktime reached, " "running e2fsck is recommended\n"); - es->s_state &= ~EXT2_VALID_FS; - if (!es->s_max_mnt_count) - es->s_max_mnt_count = EXT2_DFL_MAX_MNT_COUNT; - es->s_mnt_count++; - es->s_mtime = CURRENT_TIME; + es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT2_VALID_FS); + if (!(__s16) le16_to_cpu(es->s_max_mnt_count)) + es->s_max_mnt_count = (__s16) cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT); + es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1); + es->s_mtime = cpu_to_le32(CURRENT_TIME); mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); sb->s_dirt = 1; if (test_opt (sb, DEBUG)) @@ -317,7 +323,7 @@ { int i; int desc_block = 0; - unsigned long block = sb->u.ext2_sb.s_es->s_first_data_block; + unsigned long block = le32_to_cpu(sb->u.ext2_sb.s_es->s_first_data_block); struct ext2_group_desc * gdp = NULL; ext2_debug ("Checking group descriptors"); @@ -326,32 +332,32 @@ { if ((i % EXT2_DESC_PER_BLOCK(sb)) == 0) gdp = (struct ext2_group_desc *) sb->u.ext2_sb.s_group_desc[desc_block++]->b_data; - if (gdp->bg_block_bitmap < block || - gdp->bg_block_bitmap >= block + EXT2_BLOCKS_PER_GROUP(sb)) + if (le32_to_cpu(gdp->bg_block_bitmap) < block || + le32_to_cpu(gdp->bg_block_bitmap) >= block + EXT2_BLOCKS_PER_GROUP(sb)) { ext2_error (sb, "ext2_check_descriptors", "Block bitmap for group %d" " not in group (block %lu)!", - i, (unsigned long) gdp->bg_block_bitmap); + i, (unsigned long) le32_to_cpu(gdp->bg_block_bitmap)); return 0; } - if (gdp->bg_inode_bitmap < block || - gdp->bg_inode_bitmap >= block + EXT2_BLOCKS_PER_GROUP(sb)) + if (le32_to_cpu(gdp->bg_inode_bitmap) < block || + le32_to_cpu(gdp->bg_inode_bitmap) >= block + EXT2_BLOCKS_PER_GROUP(sb)) { ext2_error (sb, "ext2_check_descriptors", "Inode bitmap for group %d" " not in group (block %lu)!", - i, (unsigned long) gdp->bg_inode_bitmap); + i, (unsigned long) le32_to_cpu(gdp->bg_inode_bitmap)); return 0; } - if (gdp->bg_inode_table < block || - gdp->bg_inode_table + sb->u.ext2_sb.s_itb_per_group >= + if (le32_to_cpu(gdp->bg_inode_table) < block || + le32_to_cpu(gdp->bg_inode_table) + sb->u.ext2_sb.s_itb_per_group >= block + EXT2_BLOCKS_PER_GROUP(sb)) { ext2_error (sb, "ext2_check_descriptors", "Inode table for group %d" " not in group (block %lu)!", - i, (unsigned long) gdp->bg_inode_table); + i, (unsigned long) le32_to_cpu(gdp->bg_inode_table)); return 0; } block += EXT2_BLOCKS_PER_GROUP(sb); @@ -399,7 +405,7 @@ */ es = (struct ext2_super_block *) bh->b_data; sb->u.ext2_sb.s_es = es; - sb->s_magic = es->s_magic; + sb->s_magic = le16_to_cpu(es->s_magic); if (sb->s_magic != EXT2_SUPER_MAGIC) { if (!silent) printk ("VFS: Can't find an ext2 filesystem on dev " @@ -412,22 +418,22 @@ MOD_DEC_USE_COUNT; return NULL; } - if (es->s_rev_level > EXT2_GOOD_OLD_REV) { - if (es->s_feature_incompat & ~EXT2_FEATURE_INCOMPAT_SUPP) { + if (le32_to_cpu(es->s_rev_level) > EXT2_GOOD_OLD_REV) { + if (le32_to_cpu(es->s_feature_incompat) & ~EXT2_FEATURE_INCOMPAT_SUPP) { printk("EXT2-fs: %s: couldn't mount because of " "unsupported optional features.\n", kdevname(dev)); goto failed_mount; } if (!(sb->s_flags & MS_RDONLY) && - (es->s_feature_ro_compat & ~EXT2_FEATURE_RO_COMPAT_SUPP)) { + (le32_to_cpu(es->s_feature_ro_compat) & ~EXT2_FEATURE_RO_COMPAT_SUPP)) { printk("EXT2-fs: %s: couldn't mount RDWR because of " "unsupported optional features.\n", kdevname(dev)); goto failed_mount; } } - sb->s_blocksize_bits = sb->u.ext2_sb.s_es->s_log_block_size + 10; + sb->s_blocksize_bits = le32_to_cpu(sb->u.ext2_sb.s_es->s_log_block_size) + 10; sb->s_blocksize = 1 << sb->s_blocksize_bits; if (sb->s_blocksize != BLOCK_SIZE && (sb->s_blocksize == 1024 || sb->s_blocksize == 2048 || @@ -446,17 +452,17 @@ } es = (struct ext2_super_block *) (((char *)bh->b_data) + offset); sb->u.ext2_sb.s_es = es; - if (es->s_magic != EXT2_SUPER_MAGIC) { + if (es->s_magic != le16_to_cpu(EXT2_SUPER_MAGIC)) { printk ("EXT2-fs: Magic mismatch, very weird !\n"); goto failed_mount; } } - if (es->s_rev_level == EXT2_GOOD_OLD_REV) { + if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV) { sb->u.ext2_sb.s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; sb->u.ext2_sb.s_first_ino = EXT2_GOOD_OLD_FIRST_INO; } else { - sb->u.ext2_sb.s_inode_size = es->s_inode_size; - sb->u.ext2_sb.s_first_ino = es->s_first_ino; + sb->u.ext2_sb.s_inode_size = le16_to_cpu(es->s_inode_size); + sb->u.ext2_sb.s_first_ino = le32_to_cpu(es->s_first_ino); if (sb->u.ext2_sb.s_inode_size != EXT2_GOOD_OLD_INODE_SIZE) { printk ("EXT2-fs: unsupported inode size: %d\n", sb->u.ext2_sb.s_inode_size); @@ -464,15 +470,15 @@ } } sb->u.ext2_sb.s_frag_size = EXT2_MIN_FRAG_SIZE << - es->s_log_frag_size; + (__s32) le32_to_cpu(es->s_log_frag_size); if (sb->u.ext2_sb.s_frag_size) sb->u.ext2_sb.s_frags_per_block = sb->s_blocksize / sb->u.ext2_sb.s_frag_size; else sb->s_magic = 0; - sb->u.ext2_sb.s_blocks_per_group = es->s_blocks_per_group; - sb->u.ext2_sb.s_frags_per_group = es->s_frags_per_group; - sb->u.ext2_sb.s_inodes_per_group = es->s_inodes_per_group; + sb->u.ext2_sb.s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group); + sb->u.ext2_sb.s_frags_per_group = le32_to_cpu(es->s_frags_per_group); + sb->u.ext2_sb.s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group); sb->u.ext2_sb.s_inodes_per_block = sb->s_blocksize / EXT2_INODE_SIZE(sb); sb->u.ext2_sb.s_itb_per_group = sb->u.ext2_sb.s_inodes_per_group / @@ -483,12 +489,12 @@ if (resuid != EXT2_DEF_RESUID) sb->u.ext2_sb.s_resuid = resuid; else - sb->u.ext2_sb.s_resuid = es->s_def_resuid; + sb->u.ext2_sb.s_resuid = le16_to_cpu(es->s_def_resuid); if (resgid != EXT2_DEF_RESGID) sb->u.ext2_sb.s_resgid = resgid; else - sb->u.ext2_sb.s_resgid = es->s_def_resgid; - sb->u.ext2_sb.s_mount_state = es->s_state; + sb->u.ext2_sb.s_resgid = le16_to_cpu(es->s_def_resgid); + sb->u.ext2_sb.s_mount_state = le16_to_cpu(es->s_state); sb->u.ext2_sb.s_rename_lock = 0; sb->u.ext2_sb.s_rename_wait = NULL; sb->u.ext2_sb.s_addr_per_block_bits = @@ -531,8 +537,8 @@ goto failed_mount; } - sb->u.ext2_sb.s_groups_count = (es->s_blocks_count - - es->s_first_data_block + + sb->u.ext2_sb.s_groups_count = (le32_to_cpu(es->s_blocks_count) - + le32_to_cpu(es->s_first_data_block) + EXT2_BLOCKS_PER_GROUP(sb) - 1) / EXT2_BLOCKS_PER_GROUP(sb); db_count = (sb->u.ext2_sb.s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) / @@ -596,7 +602,7 @@ static void ext2_commit_super (struct super_block * sb, struct ext2_super_block * es) { - es->s_wtime = CURRENT_TIME; + es->s_wtime = cpu_to_le32(CURRENT_TIME); mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); sb->s_dirt = 0; } @@ -621,9 +627,9 @@ ext2_debug ("setting valid to 0\n"); - if (es->s_state & EXT2_VALID_FS) { - es->s_state &= ~EXT2_VALID_FS; - es->s_mtime = CURRENT_TIME; + if (le16_to_cpu(es->s_state) & EXT2_VALID_FS) { + es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT2_VALID_FS); + es->s_mtime = cpu_to_le32(CURRENT_TIME); } ext2_commit_super (sb, es); } @@ -653,15 +659,15 @@ if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) return 0; if (*flags & MS_RDONLY) { - if (es->s_state & EXT2_VALID_FS || + if (le16_to_cpu(es->s_state) & EXT2_VALID_FS || !(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS)) return 0; /* * OK, we are remounting a valid rw partition rdonly, so set * the rdonly flag and then mark the partition as valid again. */ - es->s_state = sb->u.ext2_sb.s_mount_state; - es->s_mtime = CURRENT_TIME; + es->s_state = cpu_to_le16(sb->u.ext2_sb.s_mount_state); + es->s_mtime = cpu_to_le32(CURRENT_TIME); mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); sb->s_dirt = 1; ext2_commit_super (sb, es); @@ -672,7 +678,7 @@ * store the current valid flag. (It may have been changed * by e2fsck since we originally mounted the partition.) */ - sb->u.ext2_sb.s_mount_state = es->s_state; + sb->u.ext2_sb.s_mount_state = le16_to_cpu(es->s_state); sb->s_flags &= ~MS_RDONLY; ext2_setup_super (sb, es); } @@ -722,18 +728,18 @@ 1 /* block bitmap */ + 1 /* inode bitmap */ + sb->u.ext2_sb.s_itb_per_group /* inode table */; - overhead = sb->u.ext2_sb.s_es->s_first_data_block + + overhead = le32_to_cpu(sb->u.ext2_sb.s_es->s_first_data_block) + sb->u.ext2_sb.s_groups_count * overhead_per_group; } tmp.f_type = EXT2_SUPER_MAGIC; tmp.f_bsize = sb->s_blocksize; - tmp.f_blocks = sb->u.ext2_sb.s_es->s_blocks_count - overhead; + tmp.f_blocks = le32_to_cpu(sb->u.ext2_sb.s_es->s_blocks_count) - overhead; tmp.f_bfree = ext2_count_free_blocks (sb); - tmp.f_bavail = tmp.f_bfree - sb->u.ext2_sb.s_es->s_r_blocks_count; - if (tmp.f_bfree < sb->u.ext2_sb.s_es->s_r_blocks_count) + tmp.f_bavail = tmp.f_bfree - le32_to_cpu(sb->u.ext2_sb.s_es->s_r_blocks_count); + if (tmp.f_bfree < le32_to_cpu(sb->u.ext2_sb.s_es->s_r_blocks_count)) tmp.f_bavail = 0; - tmp.f_files = sb->u.ext2_sb.s_es->s_inodes_count; + tmp.f_files = le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count); tmp.f_ffree = ext2_count_free_inodes (sb); tmp.f_namelen = EXT2_NAME_LEN; copy_to_user(buf, &tmp, bufsiz); diff -u --recursive --new-file v2.1.9/linux/fs/ext2/truncate.c linux/fs/ext2/truncate.c --- v2.1.9/linux/fs/ext2/truncate.c Mon Dec 11 06:56:35 1995 +++ linux/fs/ext2/truncate.c Thu Nov 14 10:27:38 1996 @@ -11,6 +11,9 @@ * linux/fs/minix/truncate.c * * Copyright (C) 1991, 1992 Linus Torvalds + * + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 */ /* @@ -140,7 +143,7 @@ if (i < indirect_block) goto repeat; ind = i + (u32 *) ind_bh->b_data; - tmp = *ind; + tmp = le32_to_cpu(*ind); if (!tmp) continue; bh = get_hash_table (inode->i_dev, tmp, @@ -149,12 +152,12 @@ brelse (bh); goto repeat; } - if ((bh && bh->b_count != 1) || tmp != *ind) { + if ((bh && bh->b_count != 1) || tmp != le32_to_cpu(*ind)) { retry = 1; brelse (bh); continue; } - *ind = 0; + *ind = cpu_to_le32(0); mark_buffer_dirty(ind_bh, 1); bforget(bh); if (free_count == 0) { @@ -175,7 +178,7 @@ ext2_free_blocks (inode, block_to_free, free_count); ind = (u32 *) ind_bh->b_data; for (i = 0; i < addr_per_block; i++) - if (*(ind++)) + if (le32_to_cpu(*(ind++))) break; if (i >= addr_per_block) if (ind_bh->b_count != 1) @@ -195,6 +198,93 @@ return retry; } +static int trunc_indirect_swab32 (struct inode * inode, int offset, u32 * p) +{ + int i, tmp; + struct buffer_head * bh; + struct buffer_head * ind_bh; + u32 * ind; + unsigned long block_to_free = 0; + unsigned long free_count = 0; + int retry = 0; + int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); + int blocks = inode->i_sb->s_blocksize / 512; + int indirect_block = INDIRECT_BLOCK; + + tmp = le32_to_cpu(*p); + if (!tmp) + return 0; + ind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize); + if (tmp != le32_to_cpu(*p)) { + brelse (ind_bh); + return 1; + } + if (!ind_bh) { + *p = cpu_to_le32(0); + return 0; + } +repeat: + for (i = indirect_block ; i < addr_per_block ; i++) { + if (i < 0) + i = 0; + if (i < indirect_block) + goto repeat; + ind = i + (u32 *) ind_bh->b_data; + tmp = le32_to_cpu(*ind); + if (!tmp) + continue; + bh = get_hash_table (inode->i_dev, tmp, + inode->i_sb->s_blocksize); + if (i < indirect_block) { + brelse (bh); + goto repeat; + } + if ((bh && bh->b_count != 1) || tmp != le32_to_cpu(*ind)) { + retry = 1; + brelse (bh); + continue; + } + *ind = cpu_to_le32(0); + mark_buffer_dirty(ind_bh, 1); + bforget(bh); + if (free_count == 0) { + block_to_free = tmp; + free_count++; + } else if (free_count > 0 && block_to_free == tmp - free_count) + free_count++; + else { + ext2_free_blocks (inode, block_to_free, free_count); + block_to_free = tmp; + free_count = 1; + } +/* ext2_free_blocks (inode, tmp, 1); */ + inode->i_blocks -= blocks; + inode->i_dirt = 1; + } + if (free_count > 0) + ext2_free_blocks (inode, block_to_free, free_count); + ind = (u32 *) ind_bh->b_data; + for (i = 0; i < addr_per_block; i++) + if (le32_to_cpu(*(ind++))) + break; + if (i >= addr_per_block) + if (ind_bh->b_count != 1) + retry = 1; + else { + tmp = le32_to_cpu(*p); + *p = cpu_to_le32(0); + inode->i_blocks -= blocks; + inode->i_dirt = 1; + ext2_free_blocks (inode, tmp, 1); + } + if (IS_SYNC(inode) && buffer_dirty(ind_bh)) { + ll_rw_block (WRITE, 1, &ind_bh); + wait_on_buffer (ind_bh); + } + brelse (ind_bh); + return retry; +} + static int trunc_dindirect (struct inode * inode, int offset, u32 * p) { @@ -226,16 +316,16 @@ if (i < dindirect_block) goto repeat; dind = i + (u32 *) dind_bh->b_data; - tmp = *dind; + tmp = le32_to_cpu(*dind); if (!tmp) continue; - retry |= trunc_indirect (inode, offset + (i * addr_per_block), - dind); + retry |= trunc_indirect_swab32 (inode, offset + (i * addr_per_block), + dind); mark_buffer_dirty(dind_bh, 1); } dind = (u32 *) dind_bh->b_data; for (i = 0; i < addr_per_block; i++) - if (*(dind++)) + if (le32_to_cpu(*(dind++))) break; if (i >= addr_per_block) if (dind_bh->b_count != 1) @@ -255,6 +345,65 @@ return retry; } +static int trunc_dindirect_swab32 (struct inode * inode, int offset, + u32 * p) +{ + int i, tmp; + struct buffer_head * dind_bh; + u32 * dind; + int retry = 0; + int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); + int blocks = inode->i_sb->s_blocksize / 512; + int dindirect_block = DINDIRECT_BLOCK; + + tmp = le32_to_cpu(*p); + if (!tmp) + return 0; + dind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize); + if (tmp != le32_to_cpu(*p)) { + brelse (dind_bh); + return 1; + } + if (!dind_bh) { + *p = cpu_to_le32(0); + return 0; + } +repeat: + for (i = dindirect_block ; i < addr_per_block ; i++) { + if (i < 0) + i = 0; + if (i < dindirect_block) + goto repeat; + dind = i + (u32 *) dind_bh->b_data; + tmp = le32_to_cpu(*dind); + if (!tmp) + continue; + retry |= trunc_indirect_swab32 (inode, offset + (i * addr_per_block), + dind); + mark_buffer_dirty(dind_bh, 1); + } + dind = (u32 *) dind_bh->b_data; + for (i = 0; i < addr_per_block; i++) + if (le32_to_cpu(*(dind++))) + break; + if (i >= addr_per_block) + if (dind_bh->b_count != 1) + retry = 1; + else { + tmp = le32_to_cpu(*p); + *p = cpu_to_le32(0); + inode->i_blocks -= blocks; + inode->i_dirt = 1; + ext2_free_blocks (inode, tmp, 1); + } + if (IS_SYNC(inode) && buffer_dirty(dind_bh)) { + ll_rw_block (WRITE, 1, &dind_bh); + wait_on_buffer (dind_bh); + } + brelse (dind_bh); + return retry; +} + static int trunc_tindirect (struct inode * inode) { int i, tmp; @@ -287,14 +436,14 @@ if (i < tindirect_block) goto repeat; tind = i + (u32 *) tind_bh->b_data; - retry |= trunc_dindirect(inode, EXT2_NDIR_BLOCKS + - addr_per_block + (i + 1) * addr_per_block * addr_per_block, - tind); + retry |= trunc_dindirect_swab32(inode, EXT2_NDIR_BLOCKS + + addr_per_block + (i + 1) * addr_per_block * addr_per_block, + tind); mark_buffer_dirty(tind_bh, 1); } tind = (u32 *) tind_bh->b_data; for (i = 0; i < addr_per_block; i++) - if (*(tind++)) + if (le32_to_cpu(*(tind++))) break; if (i >= addr_per_block) if (tind_bh->b_count != 1) diff -u --recursive --new-file v2.1.9/linux/include/asm-alpha/bitops.h linux/include/asm-alpha/bitops.h --- v2.1.9/linux/include/asm-alpha/bitops.h Wed May 29 18:47:38 1996 +++ linux/include/asm-alpha/bitops.h Thu Nov 14 10:28:59 1996 @@ -160,4 +160,14 @@ #define find_first_zero_bit(addr, size) \ find_next_zero_bit((addr), (size), 0) +#ifdef __KERNEL__ + +#define ext2_set_bit set_bit +#define ext2_clear_bit clear_bit +#define ext2_test_bit test_bit +#define ext2_find_first_zero_bit find_first_zero_bit +#define ext2_find_next_zero_bit find_next_zero_bit + +#endif /* __KERNEL__ */ + #endif /* _ALPHA_BITOPS_H */ diff -u --recursive --new-file v2.1.9/linux/include/asm-alpha/byteorder.h linux/include/asm-alpha/byteorder.h --- v2.1.9/linux/include/asm-alpha/byteorder.h Mon Jul 1 20:06:05 1996 +++ linux/include/asm-alpha/byteorder.h Thu Nov 14 15:36:13 1996 @@ -7,12 +7,30 @@ #undef htons #ifndef __LITTLE_ENDIAN -#define __LITTLE_ENDIAN +#define __LITTLE_ENDIAN 1234 #endif #ifndef __LITTLE_ENDIAN_BITFIELD #define __LITTLE_ENDIAN_BITFIELD #endif + +#ifdef __KERNEL__ + +/* + * In-kernel byte order macros to handle stuff like + * byte-order-dependent filesystems etc. + */ +#define cpu_to_le32(x) (x) +#define le32_to_cpu(x) (x) +#define cpu_to_le16(x) (x) +#define le16_to_cpu(x) (x) + +#define cpu_to_be32(x) htonl((x)) +#define be32_to_cpu(x) ntohl((x)) +#define cpu_to_be16(x) htons((x)) +#define be16_to_cpu(x) ntohs((x)) + +#endif /* __KERNEL__ */ extern unsigned long int ntohl(unsigned long int); extern unsigned short int ntohs(unsigned short int); diff -u --recursive --new-file v2.1.9/linux/include/asm-alpha/uaccess.h linux/include/asm-alpha/uaccess.h --- v2.1.9/linux/include/asm-alpha/uaccess.h Fri Nov 1 17:13:19 1996 +++ linux/include/asm-alpha/uaccess.h Fri Nov 15 15:43:32 1996 @@ -387,6 +387,16 @@ __sfu_ret; \ }) +/* Returns: 0 if bad, string length+1 (memory size) of string if ok */ +extern long __strlen_user(const char *); + +extern inline long strlen_user(const char *str) +{ + long len = __strlen_user(str); + if (!access_ok(VERIFY_READ, str, len)) + len = 0; + return len; +} /* * About the exception table: diff -u --recursive --new-file v2.1.9/linux/include/asm-i386/bitops.h linux/include/asm-i386/bitops.h --- v2.1.9/linux/include/asm-i386/bitops.h Thu Apr 11 13:22:13 1996 +++ linux/include/asm-i386/bitops.h Thu Nov 14 10:28:29 1996 @@ -134,4 +134,14 @@ return word; } +#ifdef __KERNEL__ + +#define ext2_set_bit set_bit +#define ext2_clear_bit clear_bit +#define ext2_test_bit test_bit +#define ext2_find_first_zero_bit find_first_zero_bit +#define ext2_find_next_zero_bit find_next_zero_bit + +#endif /* __KERNEL__ */ + #endif /* _I386_BITOPS_H */ diff -u --recursive --new-file v2.1.9/linux/include/asm-i386/byteorder.h linux/include/asm-i386/byteorder.h --- v2.1.9/linux/include/asm-i386/byteorder.h Mon Sep 30 11:19:00 1996 +++ linux/include/asm-i386/byteorder.h Fri Nov 15 15:55:00 1996 @@ -17,6 +17,21 @@ /* For avoiding bswap on i386 */ #ifdef __KERNEL__ #include + +/* + * In-kernel byte order macros to handle stuff like + * byte-order-dependent filesystems etc. + */ +#define cpu_to_le32(x) (x) +#define le32_to_cpu(x) (x) +#define cpu_to_le16(x) (x) +#define le16_to_cpu(x) (x) + +#define cpu_to_be32(x) htonl((x)) +#define be32_to_cpu(x) ntohl((x)) +#define cpu_to_be16(x) htons((x)) +#define be16_to_cpu(x) ntohs((x)) + #endif extern unsigned long int ntohl(unsigned long int); diff -u --recursive --new-file v2.1.9/linux/include/asm-i386/uaccess.h linux/include/asm-i386/uaccess.h --- v2.1.9/linux/include/asm-i386/uaccess.h Fri Nov 1 17:13:19 1996 +++ linux/include/asm-i386/uaccess.h Fri Nov 15 15:55:13 1996 @@ -407,5 +407,33 @@ return res; } +/* + * Return the size of a string (including the ending 0) + * + * Return 0 for error + */ +extern inline long strlen_user(const char * s) +{ + long res; + __asm__ __volatile__( + "\n" + "0:\trepne ; scasb\n\t" + "notl %0\n" + "1:\n" + ".section .fixup,\"ax\"\n" + "2:\txorl %0,%0\n\t" + "jmp 1b\n" + ".section __ex_table,\"a\"\n\t" + ".align 4\n\t" + ".long 0b,2b\n" + ".text" + :"=c" (res) + :"D" (s),"a" (0),"0" (0xffffffff) + :"di"); + if (!access_ok(VERIFY_READ, s, res)) + res = 0; + return res; +} + #endif /* __i386_UACCESS_H */ diff -u --recursive --new-file v2.1.9/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.1.9/linux/include/linux/fs.h Tue Oct 29 19:58:47 1996 +++ linux/include/linux/fs.h Fri Nov 15 15:55:00 1996 @@ -122,6 +122,7 @@ #ifdef __KERNEL__ #include +#include #include extern void buffer_init(void); @@ -665,6 +666,7 @@ extern void put_super(kdev_t dev); unsigned long generate_cluster(kdev_t dev, int b[], int size); +unsigned long generate_cluster_swab32(kdev_t dev, int b[], int size); extern kdev_t ROOT_DEV; extern void show_buffers(void); diff -u --recursive --new-file v2.1.9/linux/include/linux/in.h linux/include/linux/in.h --- v2.1.9/linux/include/linux/in.h Tue Nov 12 15:56:14 1996 +++ linux/include/linux/in.h Fri Nov 15 15:55:00 1996 @@ -118,6 +118,7 @@ #define INADDR_ALLHOSTS_GROUP 0xe0000001 /* 224.0.0.1 */ #define INADDR_MAX_LOCAL_GROUP 0xe00000ff /* 224.0.0.255 */ + /* contains the htonl type stuff.. */ #include diff -u --recursive --new-file v2.1.9/linux/include/linux/skbuff.h linux/include/linux/skbuff.h --- v2.1.9/linux/include/linux/skbuff.h Sun Nov 10 20:12:15 1996 +++ linux/include/linux/skbuff.h Fri Nov 15 15:55:11 1996 @@ -465,8 +465,8 @@ extern struct sk_buff * skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err); extern int datagram_select(struct sock *sk, int sel_type, select_table *wait); -extern void skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size); -extern void skb_copy_datagram_iovec(struct sk_buff *from, int offset, struct iovec *to,int size); +extern int skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size); +extern int skb_copy_datagram_iovec(struct sk_buff *from, int offset, struct iovec *to,int size); extern void skb_free_datagram(struct sock * sk, struct sk_buff *skb); #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.1.9/linux/include/linux/socket.h linux/include/linux/socket.h --- v2.1.9/linux/include/linux/socket.h Tue Nov 12 15:56:14 1996 +++ linux/include/linux/socket.h Thu Nov 14 18:26:16 1996 @@ -175,8 +175,8 @@ #define SOPRI_BACKGROUND 2 #ifdef __KERNEL__ -extern void memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len); -extern void memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, +extern int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len); +extern int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, int len); extern unsigned int csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov, @@ -184,7 +184,7 @@ int len, int csum); extern int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode); -extern void memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len); +extern int memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len); extern int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen); extern int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr); #endif diff -u --recursive --new-file v2.1.9/linux/include/net/ip.h linux/include/net/ip.h --- v2.1.9/linux/include/net/ip.h Mon Sep 30 11:24:39 1996 +++ linux/include/net/ip.h Fri Nov 15 16:00:27 1996 @@ -106,11 +106,11 @@ int free); extern void ip_init(void); extern int ip_build_xmit(struct sock *sk, - void getfrag (const void *, - __u32, - char *, - unsigned int, - unsigned int), + int getfrag (const void *, + __u32, + char *, + unsigned int, + unsigned int), const void *frag, unsigned short int length, __u32 daddr, diff -u --recursive --new-file v2.1.9/linux/include/net/ipv6.h linux/include/net/ipv6.h --- v2.1.9/linux/include/net/ipv6.h Sun Nov 10 20:12:15 1996 +++ linux/include/net/ipv6.h Fri Nov 15 16:00:29 1996 @@ -133,7 +133,7 @@ * Function prototype for build_xmit */ -typedef void (*inet_getfrag_t) (const void *data, +typedef int (*inet_getfrag_t) (const void *data, struct in6_addr *addr, char *, unsigned int, unsigned int); diff -u --recursive --new-file v2.1.9/linux/include/net/tcp.h linux/include/net/tcp.h --- v2.1.9/linux/include/net/tcp.h Tue Nov 12 15:56:15 1996 +++ linux/include/net/tcp.h Fri Nov 15 16:00:27 1996 @@ -382,7 +382,7 @@ * old_window - received_bytes_on_that_win */ - cur_win = tp->rcv_wup + tp->rcv_wnd - tp->rcv_nxt; + cur_win = tp->rcv_wup - (tp->rcv_nxt - tp->rcv_wnd); /* @@ -396,82 +396,7 @@ return res; } -/* - * This function returns the amount that we can raise the - * usable window based on the following constraints - * - * 1. The window can never be shrunk once it is offered (RFC 793) - * 2. We limit memory per socket - */ - - -static __inline__ unsigned short tcp_select_window(struct sock *sk) -{ - struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; - long free_space = sock_rspace(sk); - long window; - long cur_win; - long usable; - - if (sk->window_clamp) - free_space = min(sk->window_clamp, free_space); - - /* - * compute the actual window i.e. - * old_window - received_bytes_on_that_win - */ - - cur_win = tp->rcv_wup + tp->rcv_wnd - tp->rcv_nxt; - window = tp->rcv_wnd; - - if ( cur_win < 0 ) - { - cur_win = 0; - printk(KERN_DEBUG "TSW: win < 0 w=%d 1=%u 2=%u\n", - tp->rcv_wnd, tp->rcv_nxt, tp->rcv_wup); - } - - /* - * RFC 1122: - * "the suggested [SWS] avoidance algoritm for the receiver is to keep - * RECV.NEXT + RCV.WIN fixed until: - * RCV.BUFF - RCV.USER - RCV.WINDOW >= min(1/2 RCV.BUFF, MSS)" - * - * i.e. don't raise the right edge of the window until you can't raise - * it MSS bytes - */ - - /* - * It would be a good idea if it didn't break header prediction. - * and BSD made the header predition standard... - * It expects the same value in the header i.e. th->window to be - * constant - */ - - if (tp->rcv_wnd >= free_space) - { - if (cur_win > (sk->mss << 1)) - goto out; - } - - usable = free_space - cur_win; - -#define WROUND(X, Y) ((X + (Y-1)) & (Y-1)) - - window += WROUND(min(usable, sk->mss), 1024); - -#undef WROUND - - if (window < cur_win) - { - window = cur_win; - } - - out: - tp->rcv_wnd = window; - tp->rcv_wup = tp->rcv_nxt; - return window; -} +extern unsigned short tcp_select_window(struct sock *sk); /* * List all states of a TCP socket that can be viewed as a "connected" diff -u --recursive --new-file v2.1.9/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c --- v2.1.9/linux/net/appletalk/ddp.c Tue Nov 12 15:56:15 1996 +++ linux/net/appletalk/ddp.c Thu Nov 14 18:26:16 1996 @@ -736,16 +736,15 @@ struct device *dev; struct atalk_iface *atif; int ro=(cmd==SIOCSIFADDR); - int err=verify_area(ro?VERIFY_READ:VERIFY_WRITE, arg,sizeof(atreq)); + int err; int ct; int limit; struct rtentry rtdef; - if(err) - return err; - - copy_from_user(&atreq,arg,sizeof(atreq)); - + err = copy_from_user(&atreq,arg,sizeof(atreq)); + if (err) + return -EFAULT; + if((dev=dev_get(atreq.ifr_name))==NULL) return -ENODEV; @@ -855,8 +854,13 @@ ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr.s_node=ATADDR_BCAST; break; } - copy_to_user(arg,&atreq,sizeof(atreq)); - return 0; + err = copy_to_user(arg,&atreq,sizeof(atreq)); + + if (err) + { + err = -EFAULT; + } + return err; } /* @@ -868,11 +872,10 @@ int err; struct rtentry rt; - err=verify_area(VERIFY_READ, arg, sizeof(rt)); - if(err) - return err; - copy_from_user(&rt,arg,sizeof(rt)); - + err = copy_from_user(&rt,arg,sizeof(rt)); + if (err) + return -EFAULT; + switch(cmd) { case SIOCDELRT: @@ -1077,15 +1080,10 @@ default: return -EOPNOTSUPP; } - err=verify_area(VERIFY_WRITE,optlen,sizeof(int)); - if(err) - return err; - put_user(sizeof(int),optlen); - err=verify_area(VERIFY_WRITE,optval,sizeof(int)); - if (err) - return err; - put_user(val, (int *)optval); - return(0); + err = put_user(sizeof(int),optlen); + if (!err) + err = put_user(val, (int *) optval); + return err; } /* @@ -1736,8 +1734,13 @@ if(sk->debug) printk("SK %p: Copy user data (%d bytes).\n", sk, len); - memcpy_fromiovec(skb_put(skb,len),msg->msg_iov,len); - + err = memcpy_fromiovec(skb_put(skb,len),msg->msg_iov,len); + if (err) + { + kfree_skb(skb, FREE_WRITE); + return err; + } + if(sk->no_check==1) ddp->deh_sum=0; else @@ -1816,7 +1819,7 @@ struct ddpehdr *ddp = NULL; int copied = 0; struct sk_buff *skb; - int er; + int er = 0; if(sk->err) return sock_error(sk); @@ -1834,14 +1837,18 @@ copied=ddp->deh_len; if(copied > size) copied=size; - skb_copy_datagram_iovec(skb,0,msg->msg_iov,copied); + er = skb_copy_datagram_iovec(skb,0,msg->msg_iov,copied); + if (er) + goto out; } else { copied=ddp->deh_len - sizeof(*ddp); if (copied > size) copied = size; - skb_copy_datagram_iovec(skb,sizeof(*ddp),msg->msg_iov,copied); + er = skb_copy_datagram_iovec(skb,sizeof(*ddp),msg->msg_iov,copied); + if (er) + goto out; } if(sat) { @@ -1850,8 +1857,9 @@ sat->sat_addr.s_node=ddp->deh_snode; sat->sat_addr.s_net=ddp->deh_snet; } +out: skb_free_datagram(sk, skb); - return(copied); + return er ? er : (copied); } @@ -1900,11 +1908,7 @@ { if(sk->stamp.tv_sec==0) return -ENOENT; - err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval)); - if(err) - return err; - copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval)); - return 0; + return copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval)); } return -EINVAL; /* @@ -1950,11 +1954,7 @@ default: return -EINVAL; } - err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(int)); - if(err) - return err; - put_user(amount, (int *)arg); - return(0); + return put_user(amount, (int *)arg); } static struct proto_ops atalk_proto_ops = { diff -u --recursive --new-file v2.1.9/linux/net/bridge/br.c linux/net/bridge/br.c --- v2.1.9/linux/net/bridge/br.c Sun Nov 10 20:12:24 1996 +++ linux/net/bridge/br.c Thu Nov 14 18:26:16 1996 @@ -1442,22 +1442,20 @@ switch(cmd) { case SIOCGIFBR: /* get bridging control blocks */ - err = verify_area(VERIFY_WRITE, arg, - sizeof(struct br_stat)); - if(err) - return err; memcpy(&br_stats.bridge_data, &bridge_info, sizeof(Bridge_data)); memcpy(&br_stats.port_data, &port_info, sizeof(Port_data)*No_of_ports); - copy_to_user(arg, &br_stats, sizeof(struct br_stat)); - return(0); + err = copy_to_user(arg, &br_stats, sizeof(struct br_stat)); + if (err) + { + err = -EFAULT; + } + return err; case SIOCSIFBR: if (!suser()) return -EPERM; - err = verify_area(VERIFY_READ, arg, - sizeof(struct br_cf)); - if(err) - return err; - copy_from_user(&bcf, arg, sizeof(struct br_cf)); + err = copy_from_user(&bcf, arg, sizeof(struct br_cf)); + if (err) + return -EFAULT; switch (bcf.cmd) { case BRCMD_BRIDGE_ENABLE: if (br_stats.flags & BR_UP) diff -u --recursive --new-file v2.1.9/linux/net/core/datagram.c linux/net/core/datagram.c --- v2.1.9/linux/net/core/datagram.c Fri Nov 1 17:13:19 1996 +++ linux/net/core/datagram.c Thu Nov 14 18:26:16 1996 @@ -166,9 +166,15 @@ * Copy a datagram to a linear buffer. */ -void skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size) +int skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size) { - copy_to_user(to,skb->h.raw+offset,size); + int err; + err = copy_to_user(to, skb->h.raw+offset, size); + if (err) + { + err = -EFAULT; + } + return err; } @@ -176,9 +182,16 @@ * Copy a datagram to an iovec. */ -void skb_copy_datagram_iovec(struct sk_buff *skb, int offset, struct iovec *to, int size) +int skb_copy_datagram_iovec(struct sk_buff *skb, int offset, struct iovec *to, + int size) { - memcpy_toiovec(to,skb->h.raw+offset,size); + int err; + err = memcpy_toiovec(to, skb->h.raw+offset, size); + if (err) + { + err = -EFAULT; + } + return err; } /* diff -u --recursive --new-file v2.1.9/linux/net/core/dev.c linux/net/core/dev.c --- v2.1.9/linux/net/core/dev.c Tue Nov 12 15:56:15 1996 +++ linux/net/core/dev.c Thu Nov 14 18:26:16 1996 @@ -793,11 +793,10 @@ /* * Fetch the caller's info block. */ - - err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifconf)); - if(err) - return err; - copy_from_user(&ifc, arg, sizeof(struct ifconf)); + + err = copy_from_user(&ifc, arg, sizeof(struct ifconf)); + if (err) + return -EFAULT; len = ifc.ifc_len; pos = ifc.ifc_buf; @@ -805,11 +804,7 @@ * We now walk the device list filling each active device * into the array. */ - - err=verify_area(VERIFY_WRITE,pos,len); - if(err) - return err; - + /* * Loop over the interfaces, and write an info block for each. */ @@ -835,7 +830,9 @@ * Write this block to the caller's space. */ - copy_to_user(pos, &ifr, sizeof(struct ifreq)); + err = copy_to_user(pos, &ifr, sizeof(struct ifreq)); + if (err) + return -EFAULT; pos += sizeof(struct ifreq); len -= sizeof(struct ifreq); } @@ -846,8 +843,10 @@ ifc.ifc_len = (pos - ifc.ifc_buf); ifc.ifc_req = (struct ifreq *) ifc.ifc_buf; - copy_to_user(arg, &ifc, sizeof(struct ifconf)); - + err = copy_to_user(arg, &ifc, sizeof(struct ifconf)); + if (err) + return -EFAULT; + /* * Report how much was filled in */ @@ -956,17 +955,15 @@ { struct ifreq ifr; struct device *dev; - int ret; + int ret, err; /* * Fetch the caller's info block into kernel space */ - - int err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifreq)); - if(err) - return err; - copy_from_user(&ifr, arg, sizeof(struct ifreq)); + err = copy_from_user(&ifr, arg, sizeof(struct ifreq)); + if (err) + return -EFAULT; /* * See which interface the caller is talking about. @@ -1266,8 +1263,13 @@ (getset <= (SIOCDEVPRIVATE + 15))) { if(dev->do_ioctl==NULL) return -EOPNOTSUPP; - ret=dev->do_ioctl(dev, &ifr, getset); - copy_to_user(arg,&ifr,sizeof(struct ifreq)); + ret = dev->do_ioctl(dev, &ifr, getset); + if (!ret) + { + err = copy_to_user(arg,&ifr,sizeof(struct ifreq)); + if (err) + ret = -EFAULT; + } break; } @@ -1278,8 +1280,10 @@ * The load of calls that return an ifreq and ok (saves memory). */ rarok: - copy_to_user(arg, &ifr, sizeof(struct ifreq)); - return 0; + err = copy_to_user(arg, &ifr, sizeof(struct ifreq)); + if (err) + err = -EFAULT; + return err; } diff -u --recursive --new-file v2.1.9/linux/net/core/iovec.c linux/net/core/iovec.c --- v2.1.9/linux/net/core/iovec.c Sun Nov 10 20:12:24 1996 +++ linux/net/core/iovec.c Thu Nov 14 18:26:16 1996 @@ -11,6 +11,7 @@ * Andrew Lunn : Errors in iovec copying. * Pedro Roque : Added memcpy_fromiovecend and * csum_..._fromiovecend. + * Andi Kleen : fixed error handling for 2.1 */ @@ -29,6 +30,12 @@ return x>y?y:x; } + +/* + * Verify iovec + * verify area does a simple check for completly bogus addresses + */ + int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode) { int err=0; @@ -37,14 +44,20 @@ if(m->msg_name!=NULL) { - if(mode==VERIFY_READ) { + if(mode==VERIFY_READ) + { err=move_addr_to_kernel(m->msg_name, m->msg_namelen, address); - } else + } + else + { err=verify_area(mode, m->msg_name, m->msg_namelen); + } + if(err<0) return err; m->msg_name = address; } + if(m->msg_control!=NULL) { err=verify_area(mode, m->msg_control, m->msg_controllen); @@ -54,11 +67,12 @@ for(ct=0;ctmsg_iovlen;ct++) { - err=verify_area(VERIFY_READ, &m->msg_iov[ct], sizeof(struct iovec)); - if(err) + err = copy_from_user(&iov[ct], &m->msg_iov[ct], + sizeof(struct iovec)); + if (err) return err; - copy_from_user(&iov[ct], &m->msg_iov[ct], sizeof(struct iovec)); - err=verify_area(mode, iov[ct].iov_base, iov[ct].iov_len); + + err = verify_area(mode, iov[ct].iov_base, iov[ct].iov_len); if(err) return err; len+=iov[ct].iov_len; @@ -71,14 +85,18 @@ * Copy kernel to iovec. */ -void memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len) +int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len) { + int err; while(len>0) { if(iov->iov_len) { int copy = min(iov->iov_len,len); - copy_to_user(iov->iov_base,kdata,copy); + err = copy_to_user(iov->iov_base,kdata,copy); + if (err) { + return err; + } kdata+=copy; len-=copy; iov->iov_len-=copy; @@ -86,20 +104,26 @@ } iov++; } + return 0; } /* * Copy iovec to kernel. */ -void memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len) +int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len) { + int err; while(len>0) { if(iov->iov_len) { int copy=min(len,iov->iov_len); - copy_from_user(kdata, iov->iov_base, copy); + err = copy_from_user(kdata, iov->iov_base, copy); + if (err) + { + return err; + } len-=copy; kdata+=copy; iov->iov_base+=copy; @@ -107,6 +131,7 @@ } iov++; } + return 0; } @@ -114,9 +139,10 @@ * For use with ip_build_xmit */ -void memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, - int len) +int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, + int len) { + int err; while(offset>0) { if (offset > iov->iov_len) @@ -133,21 +159,30 @@ copy = min(len, iov->iov_len - offset); offset = 0; - copy_from_user(kdata, base, copy); + err = copy_from_user(kdata, base, copy); + if (err) + { + return err; + } len-=copy; kdata+=copy; } - iov++; + iov++; } while (len>0) { int copy=min(len, iov->iov_len); - copy_from_user(kdata, iov->iov_base, copy); + err = copy_from_user(kdata, iov->iov_base, copy); + if (err) + { + return err; + } len-=copy; kdata+=copy; iov++; } + return 0; } /* @@ -157,6 +192,9 @@ * * ip_build_xmit must ensure that when fragmenting only the last * call to this function will be unaligned also. + * + * FIXME: add an error handling path when a copy/checksum from + * user space failed because of a invalid pointer. */ unsigned int csum_partial_copy_fromiovecend(unsigned char *kdata, @@ -190,13 +228,18 @@ partial_cnt); } + /* + * FIXME: add exception handling to the + * csum functions and set *err when an + * exception occurs. + */ csum = csum_partial_copy_fromuser(base, kdata, copy, csum); len -= copy + partial_cnt; kdata += copy + partial_cnt; } - iov++; + iov++; } while (len>0) @@ -226,8 +269,7 @@ } } - csum = csum_partial_copy_fromuser(base, kdata, - copy, csum); + csum = csum_partial_copy_fromuser(base, kdata, copy, csum); len -= copy + partial_cnt; kdata += copy + partial_cnt; iov++; diff -u --recursive --new-file v2.1.9/linux/net/core/skbuff.c linux/net/core/skbuff.c --- v2.1.9/linux/net/core/skbuff.c Sun Nov 10 20:12:24 1996 +++ linux/net/core/skbuff.c Fri Nov 15 14:04:01 1996 @@ -634,7 +634,7 @@ struct sk_buff *alloc_skb(unsigned int size,int priority) { struct sk_buff *skb; - int len=size; + int len; unsigned char *bptr; if (intr_count && priority!=GFP_ATOMIC) @@ -648,6 +648,8 @@ } size=(size+15)&~15; /* Allow for alignments. Make a multiple of 16 bytes */ + len = size; + size+=sizeof(struct sk_buff); /* And stick the control itself on the end */ /* @@ -748,7 +750,7 @@ int inbuff = 0; IS_SKB(skb); - if (skb_tailroom(skb) >= sizeof(struct sk_buff)) + if (!skb->inclone && skb_tailroom(skb) >= sizeof(struct sk_buff)) { n = ((struct sk_buff *) skb->end) - 1; skb->end -= sizeof(struct sk_buff); diff -u --recursive --new-file v2.1.9/linux/net/core/sock.c linux/net/core/sock.c --- v2.1.9/linux/net/core/sock.c Sun Nov 10 20:12:24 1996 +++ linux/net/core/sock.c Thu Nov 14 18:26:17 1996 @@ -122,12 +122,13 @@ */ int sock_setsockopt(struct sock *sk, int level, int optname, - char *optval, int optlen) + char *optval, int optlen) { int val; int valbool; int err; struct linger ling; + int ret = 0; /* * Options without arguments @@ -144,33 +145,36 @@ if (optval == NULL) return(-EINVAL); - - err=verify_area(VERIFY_READ, optval, sizeof(int)); - if(err) - return err; - get_user(val, (int *)optval); + err = get_user(val, (int *)optval); + if (err) + return err; + valbool = val?1:0; switch(optname) { case SO_DEBUG: if(val && !suser()) - return(-EPERM); - sk->debug=valbool; - return 0; + { + ret = -EPERM; + } + else + sk->debug=valbool; + break; case SO_REUSEADDR: sk->reuse = valbool; - return(0); + break; case SO_TYPE: case SO_ERROR: - return(-ENOPROTOOPT); + ret = -ENOPROTOOPT; + break; case SO_DONTROUTE: sk->localroute=valbool; - return 0; + break; case SO_BROADCAST: sk->broadcast=valbool; - return 0; + break; case SO_SNDBUF: if(val > SK_WMEM_MAX*2) val = SK_WMEM_MAX*2; @@ -179,7 +183,7 @@ if(val > 65535) val = 65535; sk->sndbuf = val; - return 0; + break; case SO_RCVBUF: if(val > SK_RMEM_MAX*2) @@ -189,41 +193,45 @@ if(val > 65535) val = 65535; sk->rcvbuf = val; - return(0); + break; case SO_KEEPALIVE: +#ifdef CONFIG_INET if (sk->protocol == IPPROTO_TCP) { tcp_set_keepalive(sk, valbool); } +#endif sk->keepopen = valbool; - return(0); + break; case SO_OOBINLINE: sk->urginline = valbool; - return(0); + break; case SO_NO_CHECK: sk->no_check = valbool; - return(0); + break; case SO_PRIORITY: if (val >= 0 && val < DEV_NUMBUFFS) { sk->priority = val; } - else + else { return(-EINVAL); } - return(0); + break; case SO_LINGER: - err=verify_area(VERIFY_READ,optval,sizeof(ling)); - if(err) - return err; - copy_from_user(&ling,optval,sizeof(ling)); + err = copy_from_user(&ling,optval,sizeof(ling)); + if (err) + { + ret = -EFAULT; + break; + } if(ling.l_onoff==0) sk->linger=0; else @@ -231,15 +239,16 @@ sk->lingertime=ling.l_linger; sk->linger=1; } - return 0; + break; case SO_BSDCOMPAT: sk->bsdism = valbool; - return 0; + break; default: return(-ENOPROTOOPT); } + return ret; } @@ -303,17 +312,13 @@ break; case SO_LINGER: - err=verify_area(VERIFY_WRITE,optval,sizeof(ling)); - if(err) - return err; - err=verify_area(VERIFY_WRITE,optlen,sizeof(int)); - if(err) - return err; - put_user(sizeof(ling), optlen); - ling.l_onoff=sk->linger; - ling.l_linger=sk->lingertime; - copy_to_user(optval,&ling,sizeof(ling)); - return 0; + err = put_user(sizeof(ling), optlen); + if (!err) { + ling.l_onoff=sk->linger; + ling.l_linger=sk->lingertime; + err = copy_to_user(optval,&ling,sizeof(ling)); + } + return err; case SO_BSDCOMPAT: val = sk->bsdism; @@ -322,17 +327,11 @@ default: return(-ENOPROTOOPT); } - err=verify_area(VERIFY_WRITE, optlen, sizeof(int)); - if(err) - return err; - put_user(sizeof(int), optlen); - - err=verify_area(VERIFY_WRITE, optval, sizeof(int)); - if(err) - return err; - put_user(val,(unsigned int *)optval); + err = put_user(sizeof(int), optlen); + if (!err) + err = put_user(val,(unsigned int *)optval); - return(0); + return err; } struct sock *sk_alloc(int priority) diff -u --recursive --new-file v2.1.9/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- v2.1.9/linux/net/ipv4/af_inet.c Sun Nov 10 20:12:28 1996 +++ linux/net/ipv4/af_inet.c Thu Nov 14 18:26:17 1996 @@ -1208,10 +1208,9 @@ { case FIOSETOWN: case SIOCSPGRP: - err=verify_area(VERIFY_READ,(int *)arg,sizeof(long)); - if(err) - return err; - get_user(pid, (int *) arg); + err = get_user(pid, (int *) arg); + if (err) + return err; /* see inet_fcntl */ if (current->pid != pid && current->pgrp != -pid && !suser()) return -EPERM; @@ -1219,19 +1218,16 @@ return(0); case FIOGETOWN: case SIOCGPGRP: - err=verify_area(VERIFY_WRITE,(void *) arg, sizeof(int)); - if(err) - return err; - put_user(sk->proc, (int *)arg); - return(0); + return put_user(sk->proc, (int *)arg); case SIOCGSTAMP: if(sk->stamp.tv_sec==0) return -ENOENT; - err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval)); - if(err) - return err; - copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval)); - return 0; + err = copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval)); + if (err) + { + err = -EFAULT; + } + return err; case SIOCADDRT: case SIOCDELRT: return(ip_rt_ioctl(cmd,(void *) arg)); diff -u --recursive --new-file v2.1.9/linux/net/ipv4/arp.c linux/net/ipv4/arp.c --- v2.1.9/linux/net/ipv4/arp.c Tue Nov 12 15:56:16 1996 +++ linux/net/ipv4/arp.c Thu Nov 14 18:26:17 1996 @@ -2179,20 +2179,18 @@ if (!suser()) return -EPERM; case SIOCGARP: - err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq)); + err = copy_from_user(&r, arg, sizeof(struct arpreq)); if (err) - return err; - copy_from_user(&r, arg, sizeof(struct arpreq)); + return -EFAULT; break; case OLD_SIOCDARP: case OLD_SIOCSARP: if (!suser()) return -EPERM; case OLD_SIOCGARP: - err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq_old)); + err = copy_from_user(&r, arg, sizeof(struct arpreq_old)); if (err) - return err; - copy_from_user(&r, arg, sizeof(struct arpreq_old)); + return -EFAULT; memset(&r.arp_dev, 0, sizeof(r.arp_dev)); break; default: @@ -2250,17 +2248,15 @@ } return err; case SIOCGARP: - err = verify_area(VERIFY_WRITE, arg, sizeof(struct arpreq)); - if (err) - return err; err = arp_req_get(&r, dev); if (!err) - copy_to_user(arg, &r, sizeof(r)); + { + err = copy_to_user(arg, &r, sizeof(r)); + if (err) + err = -EFAULT; + } return err; case OLD_SIOCGARP: - err = verify_area(VERIFY_WRITE, arg, sizeof(struct arpreq_old)); - if (err) - return err; r.arp_flags &= ~ATF_PUBL; err = arp_req_get(&r, dev); if (err < 0) @@ -2269,7 +2265,11 @@ err = arp_req_get(&r, dev); } if (!err) - copy_to_user(arg, &r, sizeof(struct arpreq_old)); + { + err = copy_to_user(arg, &r, sizeof(struct arpreq_old)); + if (err) + err = -EFAULT; + } return err; } /*NOTREACHED*/ diff -u --recursive --new-file v2.1.9/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c --- v2.1.9/linux/net/ipv4/icmp.c Sun Nov 10 20:12:29 1996 +++ linux/net/ipv4/icmp.c Thu Nov 14 18:26:17 1996 @@ -474,16 +474,17 @@ * Checksum each fragment, and on the first include the headers and final checksum. */ -static void icmp_glue_bits(const void *p, __u32 saddr, char *to, unsigned int offset, unsigned int fraglen) +static int icmp_glue_bits(const void *p, __u32 saddr, char *to, unsigned int offset, unsigned int fraglen) { struct icmp_bxm *icmp_param = (struct icmp_bxm *)p; struct icmphdr *icmph; unsigned long csum; - if (offset) { + if (offset) + { icmp_param->csum=csum_partial_copy(icmp_param->data_ptr+offset-sizeof(struct icmphdr), to, fraglen,icmp_param->csum); - return; + return 0; } /* @@ -499,6 +500,8 @@ fraglen-sizeof(struct icmphdr), csum); icmph=(struct icmphdr *)to; icmph->checksum = csum_fold(csum); + + return 0; } /* diff -u --recursive --new-file v2.1.9/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c --- v2.1.9/linux/net/ipv4/ip_output.c Sun Nov 10 20:12:29 1996 +++ linux/net/ipv4/ip_output.c Thu Nov 14 18:26:17 1996 @@ -504,11 +504,11 @@ */ int ip_build_xmit(struct sock *sk, - void getfrag (const void *, - __u32, - char *, - unsigned int, - unsigned int), + int getfrag (const void *, + __u32, + char *, + unsigned int, + unsigned int), const void *frag, unsigned short int length, __u32 daddr, @@ -529,6 +529,7 @@ struct hh_cache * hh=NULL; int nfrags=0; __u32 true_daddr = daddr; + int err; if (opt && opt->srr && !sk->ip_hdrincl) daddr = opt->faddr; @@ -648,18 +649,31 @@ } iph->check=0; iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); - getfrag(frag,saddr,((char *)iph)+iph->ihl*4,0, length-iph->ihl*4); + err = getfrag(frag,saddr,((char *)iph)+iph->ihl*4,0, length-iph->ihl*4); } else - getfrag(frag,saddr,(void *)iph,0,length); + err = getfrag(frag, saddr, (void *)iph, 0, length); + dev_unlock_list(); + + if (err) + { + err = -EFAULT; + } + #ifdef CONFIG_FIREWALL - if(call_out_firewall(PF_INET, skb->dev, iph, NULL)< FW_ACCEPT) + if(!err && call_out_firewall(PF_INET, skb->dev, iph, NULL)< FW_ACCEPT) { - kfree_skb(skb, FREE_WRITE); - return -EPERM; + err = -EPERM; } #endif + + if (err) + { + kfree_skb(skb, FREE_WRITE); + return err; + } + #ifdef CONFIG_IP_ACCT ip_fw_chk(iph,dev,NULL,ip_acct_chain,0,IP_FW_MODE_ACCT_OUT); #endif @@ -675,7 +689,7 @@ if (!sk->ip_hdrincl) length -= sizeof(struct iphdr); - if(opt) + if(opt) { length -= opt->optlen; fragheaderlen = dev->hard_header_len + sizeof(struct iphdr) + opt->optlen; @@ -688,8 +702,8 @@ fragheaderlen += 20; /* - * Fragheaderlen is the size of 'overhead' on each buffer. Now work - * out the size of the frames to send. + * Fragheaderlen is the size of 'overhead' on each buffer. + * Now work out the size of the frames to send. */ maxfraglen = ((dev->mtu-20) & ~7) + fragheaderlen; @@ -758,7 +772,7 @@ { ip_statistics.IpOutDiscards++; if(nfrags>1) - ip_statistics.IpFragCreates++; + ip_statistics.IpFragCreates++; dev_unlock_list(); return(error); } @@ -795,7 +809,7 @@ skb->arp = 0; #if RT_CACHE_DEBUG >= 2 printk("ip_build_xmit: hh miss %08x via %08x\n", rt->rt_dst, rt->rt_gateway); -#endif +#endif } } else if (dev->hard_header) @@ -856,20 +870,29 @@ * User data callback */ - getfrag(frag, saddr, data, offset, fraglen-fragheaderlen); + err = getfrag(frag, saddr, data, offset, fraglen-fragheaderlen); + if (err) + { + err = -EFAULT; + } /* * Account for the fragment. */ #ifdef CONFIG_FIREWALL - if(!offset && call_out_firewall(PF_INET, skb->dev, iph, NULL) < FW_ACCEPT) + if(!err && !offset && call_out_firewall(PF_INET, skb->dev, iph, NULL) < FW_ACCEPT) + { + err = -EPERM; + } +#endif + if (err) { kfree_skb(skb, FREE_WRITE); dev_unlock_list(); - return -EPERM; + return err; } -#endif + #ifdef CONFIG_IP_ACCT if(!offset) ip_fw_chk(iph, dev, NULL, ip_acct_chain, 0, IP_FW_MODE_ACCT_OUT); diff -u --recursive --new-file v2.1.9/linux/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c --- v2.1.9/linux/net/ipv4/ip_sockglue.c Tue Oct 29 19:58:49 1996 +++ linux/net/ipv4/ip_sockglue.c Thu Nov 14 18:26:17 1996 @@ -123,11 +123,11 @@ } else { - err=verify_area(VERIFY_READ, optval, sizeof(int)); - if(err) - return err; - get_user(val, (int *) optval); - get_user(ucval, (unsigned char *) optval); + err = get_user(val, (int *) optval); + if (!err) + err = get_user(ucval, (unsigned char *) optval); + if (err) + return err; } if(level!=SOL_IP) @@ -147,15 +147,20 @@ struct options * old_opt; if (optlen > 40 || optlen < 0) return -EINVAL; - err = verify_area(VERIFY_READ, optval, optlen); - if (err) - return err; opt = kmalloc(sizeof(struct options)+((optlen+3)&~3), GFP_KERNEL); if (!opt) return -ENOMEM; memset(opt, 0, sizeof(struct options)); if (optlen) - copy_from_user(opt->__data, optval, optlen); + { + err = copy_from_user(opt->__data, optval, optlen); + if (err) + { + kfree_s(opt, sizeof(struct options) + ((optlen+3)&~3)); + return -EFAULT; + } + } + while (optlen & 3) opt->__data[optlen++] = IPOPT_END; opt->optlen = optlen; @@ -228,13 +233,11 @@ /* * Check the arguments are allowable */ - - err=verify_area(VERIFY_READ, optval, sizeof(addr)); - if(err) - return err; - copy_from_user(&addr,optval,sizeof(addr)); - + err = copy_from_user(&addr,optval,sizeof(addr)); + if (err) + return -EFAULT; + /* * What address has been requested @@ -278,11 +281,9 @@ * Check the arguments. */ - err=verify_area(VERIFY_READ, optval, sizeof(mreq)); - if(err) - return err; - - copy_from_user(&mreq,optval,sizeof(mreq)); + err = copy_from_user(&mreq,optval,sizeof(mreq)); + if (err) + return -EFAULT; /* * Get device for use later @@ -333,11 +334,9 @@ * Check the arguments */ - err=verify_area(VERIFY_READ, optval, sizeof(mreq)); - if(err) - return err; - - copy_from_user(&mreq,optval,sizeof(mreq)); + err = copy_from_user(&mreq,optval,sizeof(mreq)); + if (err) + return -EFAULT; /* * Get device for use later @@ -399,10 +398,9 @@ return -EPERM; if(optlen>sizeof(tmp_fw) || optlen<1) return -EINVAL; - err=verify_area(VERIFY_READ,optval,optlen); - if(err) - return err; - copy_from_user(&tmp_fw,optval,optlen); + err = copy_from_user(&tmp_fw,optval,optlen); + if (err) + return -EFAULT; err=ip_fw_ctl(optname, &tmp_fw,optlen); return -err; /* -0 is 0 after all */ @@ -417,10 +415,9 @@ return -EPERM; if(optlen>sizeof(tmp_fw) || optlen<1) return -EINVAL; - err=verify_area(VERIFY_READ,optval,optlen); - if(err) - return err; - copy_from_user(&tmp_fw, optval,optlen); + err = copy_from_user(&tmp_fw, optval,optlen); + if (err) + return -EFAULT; err=ip_acct_ctl(optname, &tmp_fw,optlen); return -err; /* -0 is 0 after all */ #endif @@ -458,9 +455,7 @@ { unsigned char optbuf[sizeof(struct options)+40]; struct options * opt = (struct options*)optbuf; - err = verify_area(VERIFY_WRITE, optlen, sizeof(int)); - if (err) - return err; + cli(); opt->optlen = 0; if (sk->opt) @@ -468,12 +463,8 @@ sti(); if (opt->optlen == 0) { - put_user(0, optlen); - return 0; + return put_user(0, optlen); } - err = verify_area(VERIFY_WRITE, optval, opt->optlen); - if (err) - return err; /* * Now we should undo all the changes done by ip_options_compile(). */ @@ -503,8 +494,10 @@ optptr[2] -= 4; } } - put_user(opt->optlen, optlen); - copy_to_user(optval, opt->__data, opt->optlen); + err = put_user(opt->optlen, optlen); + if (!err) + err = copy_to_user(optval, opt->__data, opt->optlen); + return err; } return 0; case IP_TOS: @@ -524,29 +517,17 @@ val=sk->ip_mc_loop; break; case IP_MULTICAST_IF: - err=verify_area(VERIFY_WRITE, optlen, sizeof(int)); - if(err) - return err; len=strlen(sk->ip_mc_name); - err=verify_area(VERIFY_WRITE, optval, len); - if(err) - return err; - put_user(len, optlen); - copy_to_user((void *)optval,sk->ip_mc_name, len); - return 0; + err = put_user(len, optlen); + if (!err) + err = copy_to_user((void *)optval,sk->ip_mc_name, len); + return err; #endif default: return(-ENOPROTOOPT); } - err=verify_area(VERIFY_WRITE, optlen, sizeof(int)); - if(err) - return err; - put_user(sizeof(int), optlen); - - err=verify_area(VERIFY_WRITE, optval, sizeof(int)); - if(err) - return err; - put_user(val,(int *) optval); - - return(0); + err = put_user(sizeof(int), optlen); + if (err) + return err; + return put_user(val,(int *) optval); } diff -u --recursive --new-file v2.1.9/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c --- v2.1.9/linux/net/ipv4/ipmr.c Tue Oct 29 19:58:50 1996 +++ linux/net/ipv4/ipmr.c Thu Nov 14 18:26:17 1996 @@ -447,11 +447,11 @@ return -EOPNOTSUPP; if(optlen!=sizeof(int)) return -ENOPROTOOPT; - if((err=verify_area(VERIFY_READ,optval,sizeof(int)))<0) - return err; { int opt; - get_user(opt,(int *)optval); + err = get_user(opt,(int *)optval); + if (err) + return err; if (opt != 1) return -ENOPROTOOPT; } @@ -468,9 +468,9 @@ case MRT_DEL_VIF: if(optlen!=sizeof(vif)) return -EINVAL; - if((err=verify_area(VERIFY_READ, optval, sizeof(vif)))<0) - return err; - copy_from_user(&vif,optval,sizeof(vif)); + err = copy_from_user(&vif,optval,sizeof(vif)); + if (err) + return -EFAULT; if(vif.vifc_vifi > MAXVIFS) return -ENFILE; if(optname==MRT_ADD_VIF) @@ -545,17 +545,16 @@ */ case MRT_ADD_MFC: case MRT_DEL_MFC: - err=verify_area(VERIFY_READ, optval, sizeof(mfc)); - if(err) - return err; - copy_from_user(&mfc,optval, sizeof(mfc)); - return ipmr_mfc_modify(optname, &mfc); + err = copy_from_user(&mfc,optval, sizeof(mfc)); + return err ? -EFAULT : ipmr_mfc_modify(optname, &mfc); /* * Control PIM assert. */ case MRT_ASSERT: if(optlen!=sizeof(int)) return -EINVAL; + + /* BUG BUG this is wrong IMHO -AK. */ if((err=verify_area(VERIFY_READ, optval,sizeof(int)))<0) return err; mroute_do_pim= (optval)?1:0; @@ -583,18 +582,19 @@ if(optname!=MRT_VERSION && optname!=MRT_ASSERT) return -EOPNOTSUPP; - get_user(olr, optlen); + err = get_user(olr, optlen); + if (err) + return err; if(olr!=sizeof(int)) return -EINVAL; - err=verify_area(VERIFY_WRITE, optval,sizeof(int)); - if(err) - return err; - put_user(sizeof(int),optlen); + err = put_user(sizeof(int),optlen); + if (err) + return err; if(optname==MRT_VERSION) - put_user(0x0305,(int *)optval); + err = put_user(0x0305,(int *)optval); else - put_user(mroute_do_pim,(int *)optval); - return 0; + err = put_user(mroute_do_pim,(int *)optval); + return err; } /* @@ -611,10 +611,9 @@ switch(cmd) { case SIOCGETVIFCNT: - err=verify_area(VERIFY_WRITE, (void *)arg, sizeof(vr)); - if(err) - return err; - copy_from_user(&vr,(void *)arg,sizeof(vr)); + err = copy_from_user(&vr,(void *)arg,sizeof(vr)); + if (err) + return -EFAULT; if(vr.vifi>=MAXVIFS) return -EINVAL; vif=&vif_table[vr.vifi]; @@ -624,17 +623,19 @@ vr.ocount=vif->pkt_out; vr.ibytes=vif->bytes_in; vr.obytes=vif->bytes_out; - copy_to_user((void *)arg,&vr,sizeof(vr)); - return 0; + err = copy_to_user((void *)arg,&vr,sizeof(vr)); + if (err) + err = -EFAULT; + return err; } return -EADDRNOTAVAIL; case SIOCGETSGCNT: - err=verify_area(VERIFY_WRITE, (void *)arg, sizeof(sr)); - if(err) - return err; - copy_from_user(&sr,(void *)arg,sizeof(sr)); - copy_to_user((void *)arg,&sr,sizeof(sr)); - return 0; + err = copy_from_user(&sr,(void *)arg,sizeof(sr)); + if (!err) + err = copy_to_user((void *)arg,&sr,sizeof(sr)); + if (err) + err = -EFAULT; + return err; default: return -EINVAL; } diff -u --recursive --new-file v2.1.9/linux/net/ipv4/packet.c linux/net/ipv4/packet.c --- v2.1.9/linux/net/ipv4/packet.c Sun Nov 10 20:12:29 1996 +++ linux/net/ipv4/packet.c Thu Nov 14 18:26:17 1996 @@ -120,7 +120,8 @@ struct device *dev; struct sockaddr_pkt *saddr=(struct sockaddr_pkt *)msg->msg_name; unsigned short proto=0; - + int err; + /* * Check the flags. */ @@ -180,18 +181,33 @@ skb->sk = sk; skb->free = 1; - memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len); - skb->arp = 1; /* No ARP needs doing on this (complete) frame */ + err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len); + skb->arp = 1; /* No ARP needs doing on this (complete) frame */ skb->protocol = proto; /* * Now send it */ - if (dev->flags & IFF_UP) - dev_queue_xmit(skb, dev, sk->priority); + if (err) + { + err = -EFAULT; + } else + { + if (!(dev->flags & IFF_UP)) + { + err = -ENODEV; + } + } + + if (err) + { kfree_skb(skb, FREE_WRITE); + return err; + } + + dev_queue_xmit(skb, dev, sk->priority); return(len); } @@ -436,7 +452,13 @@ copied = min(len, skb->len); - memcpy_toiovec(msg->msg_iov, skb->data, copied); /* We can't use skb_copy_datagram here */ + /* We can't use skb_copy_datagram here */ + err = memcpy_toiovec(msg->msg_iov, skb->data, copied); + if (err) + { + return -EFAULT; + } + sk->stamp=skb->stamp; /* diff -u --recursive --new-file v2.1.9/linux/net/ipv4/rarp.c linux/net/ipv4/rarp.c --- v2.1.9/linux/net/ipv4/rarp.c Tue Nov 12 15:56:16 1996 +++ linux/net/ipv4/rarp.c Thu Nov 14 18:26:17 1996 @@ -289,9 +289,12 @@ unsigned long ip; struct rtable *rt; struct device * dev; + int err; - copy_from_user(&r, req, sizeof(r)); - + err = copy_from_user(&r, req, sizeof(r)); + if (err) + return -EFAULT; + /* * We only understand about IP addresses... */ @@ -390,13 +393,16 @@ struct rarp_table *entry; struct sockaddr_in *si; unsigned long ip; - + int err; + /* * We only understand about IP addresses... */ - copy_from_user(&r, req, sizeof(r)); - + err = copy_from_user(&r, req, sizeof(r)); + if (err) + return -EFAULT; + if (r.arp_pa.sa_family != AF_INET) return -EPFNOSUPPORT; @@ -430,8 +436,7 @@ * Copy the information back */ - copy_to_user(req, &r, sizeof(r)); - return 0; + return copy_to_user(req, &r, sizeof(r)); } @@ -450,10 +455,9 @@ case SIOCDRARP: if (!suser()) return -EPERM; - err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq)); - if(err) - return err; - copy_from_user(&r, arg, sizeof(r)); + err = copy_from_user(&r, arg, sizeof(r)); + if (err) + return -EFAULT; if (r.arp_pa.sa_family != AF_INET) return -EPFNOSUPPORT; si = (struct sockaddr_in *) &r.arp_pa; @@ -461,16 +465,11 @@ return 0; case SIOCGRARP: - err = verify_area(VERIFY_WRITE, arg, sizeof(struct arpreq)); - if(err) - return err; + return rarp_req_get((struct arpreq *)arg); case SIOCSRARP: if (!suser()) return -EPERM; - err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq)); - if(err) - return err; return rarp_req_set((struct arpreq *)arg); default: return -EINVAL; diff -u --recursive --new-file v2.1.9/linux/net/ipv4/raw.c linux/net/ipv4/raw.c --- v2.1.9/linux/net/ipv4/raw.c Sun Nov 10 20:12:29 1996 +++ linux/net/ipv4/raw.c Thu Nov 14 18:26:17 1996 @@ -161,18 +161,22 @@ * Callback support is trivial for SOCK_RAW */ -static void raw_getfrag(const void *p, __u32 saddr, char *to, unsigned int offset, unsigned int fraglen) +static int raw_getfrag(const void *p, __u32 saddr, char *to, + unsigned int offset, unsigned int fraglen) { - copy_from_user(to, (const unsigned char *)p+offset, fraglen); + return copy_from_user(to, (const unsigned char *)p+offset, fraglen); } /* * IPPROTO_RAW needs extra work. */ -static void raw_getrawfrag(const void *p, __u32 saddr, char *to, unsigned int offset, unsigned int fraglen) +static int raw_getrawfrag(const void *p, __u32 saddr, char *to, unsigned int offset, unsigned int fraglen) { - copy_from_user(to, (const unsigned char *)p+offset, fraglen); + int err; + err = copy_from_user(to, (const unsigned char *)p+offset, fraglen); + if (err) + return err; if(offset==0) { struct iphdr *iph=(struct iphdr *)to; @@ -189,6 +193,7 @@ iph->id = htons(ip_id_count++); iph->check=ip_fast_csum((unsigned char *)iph, iph->ihl); } + return 0; } static int raw_sendto(struct sock *sk, const unsigned char *from, @@ -283,11 +288,17 @@ buf=kmalloc(len, GFP_KERNEL); if(buf==NULL) return -ENOBUFS; - memcpy_fromiovec(buf, msg->msg_iov, len); - fs=get_fs(); - set_fs(get_ds()); - err=raw_sendto(sk,buf,len, noblock, flags, msg->msg_name, msg->msg_namelen); - set_fs(fs); + err = memcpy_fromiovec(buf, msg->msg_iov, len); + if (!err) + { + fs=get_fs(); + set_fs(get_ds()); + err=raw_sendto(sk,buf,len, noblock, flags, msg->msg_name, msg->msg_namelen); + set_fs(fs); + } + else + err = -EFAULT; + kfree_s(buf,len); return err; } @@ -341,7 +352,7 @@ copied = min(len, skb->len); - skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); sk->stamp=skb->stamp; /* Copy the address. */ @@ -351,7 +362,7 @@ sin->sin_addr.s_addr = skb->daddr; } skb_free_datagram(sk, skb); - return (copied); + return err ? err : (copied); } diff -u --recursive --new-file v2.1.9/linux/net/ipv4/route.c linux/net/ipv4/route.c --- v2.1.9/linux/net/ipv4/route.c Tue Oct 29 19:58:50 1996 +++ linux/net/ipv4/route.c Thu Nov 14 18:26:17 1996 @@ -1696,10 +1696,9 @@ case SIOCDELRT: /* Delete a route */ if (!suser()) return -EPERM; - err=verify_area(VERIFY_READ, arg, sizeof(struct rtentry)); + err = copy_from_user(&rt, arg, sizeof(struct rtentry)); if (err) - return err; - copy_from_user(&rt, arg, sizeof(struct rtentry)); + return -EFAULT; return (cmd == SIOCDELRT) ? ip_rt_kill(&rt) : ip_rt_new(&rt); } diff -u --recursive --new-file v2.1.9/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v2.1.9/linux/net/ipv4/tcp.c Tue Nov 12 15:56:16 1996 +++ linux/net/ipv4/tcp.c Fri Nov 15 14:04:01 1996 @@ -658,7 +658,6 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg) { - int err; switch(cmd) { @@ -675,21 +674,12 @@ lock_sock(sk); amount = tcp_readable(sk); release_sock(sk); - err=verify_area(VERIFY_WRITE,(void *)arg, sizeof(int)); - if(err) - return err; - put_user(amount, (int *)arg); - return(0); + return put_user(amount, (int *)arg); } case SIOCATMARK: { int answ = sk->urg_data && sk->urg_seq == sk->copied_seq; - - err = verify_area(VERIFY_WRITE,(void *) arg, sizeof(int)); - if (err) - return err; - put_user(answ,(int *) arg); - return(0); + return put_user(answ,(int *) arg); } case TIOCOUTQ: { @@ -697,11 +687,7 @@ if (sk->state == TCP_LISTEN) return(-EINVAL); amount = sock_wspace(sk); - err=verify_area(VERIFY_WRITE,(void *)arg, sizeof(int)); - if(err) - return err; - put_user(amount, (int *)arg); - return(0); + return put_user(amount, (int *)arg); } default: return(-EINVAL); @@ -718,9 +704,9 @@ struct tcp_opt *tp=&(sk->tp_pinfo.af_tcp); memcpy(th,(void *) &(sk->dummy_th), sizeof(*th)); th->seq = htonl(sk->write_seq); -#if 0 + th->psh =(push == 0) ? 1 : 0; -#endif + sk->bytes_rcv = 0; sk->ack_timed = 0; th->ack_seq = htonl(tp->rcv_nxt); @@ -986,7 +972,7 @@ { tmp += copy; } - + skb = sock_wmalloc(sk, tmp, 0, GFP_KERNEL); /* @@ -1106,6 +1092,7 @@ struct msghdr *msg, int len, int flags, int *addr_len) { + int err; struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); /* @@ -1138,7 +1125,7 @@ char c = sk->urg_data; if (!(flags & MSG_PEEK)) sk->urg_data = URG_READ; - memcpy_toiovec(msg->msg_iov, &c, 1); + err = memcpy_toiovec(msg->msg_iov, &c, 1); if(msg->msg_name) { tp->af_specific->addr2sockaddr(sk, (struct sockaddr *) @@ -1148,7 +1135,7 @@ *addr_len= tp->af_specific->sockaddr_len; release_sock(sk); - return 1; + return err ? -EFAULT : 1; } release_sock(sk); @@ -1226,6 +1213,7 @@ u32 peek_seq; volatile u32 *seq; /* So gcc doesn't overoptimise */ unsigned long used; + int err = 0; /* * This error should be checked. @@ -1274,6 +1262,8 @@ if (copied) break; copied = -ERESTARTSYS; + if (nonblock) + copied = -EAGAIN; break; } @@ -1398,13 +1388,28 @@ *seq += used; /* - * This memcpy_tofs can sleep. If it sleeps and we + * This memcpy_toiovec can sleep. If it sleeps and we * do a second read it relies on the skb->users to avoid * a crash when cleanup_rbuf() gets called. */ - memcpy_toiovec(msg->msg_iov,((unsigned char *)skb->h.th) + - skb->h.th->doff*4 + offset, used); + /* + * FIXME: should break out of the loop early when an + * error occurs + */ + + err = memcpy_toiovec(msg->msg_iov, ((unsigned char *)skb->h.th) + skb->h.th->doff*4 + offset, used); + + if (err) + { + /* + * exception. bailout! + */ + *seq -= err; + skb->users--; + return -EFAULT; + } + copied += used; len -= used; @@ -1414,7 +1419,7 @@ * but you'll just have to fix it neatly ;) */ - skb->users --; + skb->users--; if (after(sk->copied_seq,sk->urg_seq)) sk->urg_data = 0; @@ -1824,17 +1829,12 @@ default: return(-ENOPROTOOPT); } - err=verify_area(VERIFY_WRITE, optlen, sizeof(int)); - if(err) - return err; - put_user(sizeof(int),(int *) optlen); - - err=verify_area(VERIFY_WRITE, optval, sizeof(int)); - if(err) - return err; - put_user(val,(int *)optval); - return(0); + err = put_user(sizeof(int),(int *) optlen); + if (!err) + err = put_user(val,(int *)optval); + + return err; } void tcp_set_keepalive(struct sock *sk, int val) @@ -1847,6 +1847,104 @@ { tcp_dec_slow_timer(TCP_SLT_KEEPALIVE); } +} + + +/* + * This function returns the amount that we can raise the + * usable window based on the following constraints + * + * 1. The window can never be shrunk once it is offered (RFC 793) + * 2. We limit memory per socket + */ + + +unsigned short tcp_select_window(struct sock *sk) +{ + struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; + long free_space = sock_rspace(sk); + long window; + long cur_win; + long usable; + int mss = sk->mss; + + if (sk->window_clamp) + { + free_space = min(sk->window_clamp, free_space); + mss = min(sk->window_clamp, mss); + } + + /* + * compute the actual window i.e. + * old_window - received_bytes_on_that_win + */ + + cur_win = tp->rcv_wup - (tp->rcv_nxt - tp->rcv_wnd); + window = tp->rcv_wnd; + + if ( cur_win < 0 ) + { + cur_win = 0; + printk(KERN_DEBUG "TSW: win < 0 w=%d 1=%u 2=%u\n", + tp->rcv_wnd, tp->rcv_nxt, tp->rcv_wup); + } + + /* + * RFC 1122: + * "the suggested [SWS] avoidance algoritm for the receiver is to keep + * RECV.NEXT + RCV.WIN fixed until: + * RCV.BUFF - RCV.USER - RCV.WINDOW >= min(1/2 RCV.BUFF, MSS)" + * + * i.e. don't raise the right edge of the window until you can't raise + * it MSS bytes + */ + + /* + * It would be a good idea if it didn't break header prediction. + * and BSD made the header predition standard... + * It expects the same value in the header i.e. th->window to be + * constant + */ + + usable = free_space - cur_win; + if (usable < 0) + { + usable = 0; + } + + if ( window < usable ) + { + /* + * Window is not blocking the sender + * and we have enought free space for it + */ + + if (cur_win > (sk->mss << 1)) + goto out; + } + + + if (window >= usable) + { + /* + * We are offering too much, cut it down... + * but don't shrink the window + */ + + window = max(usable, cur_win); + } + else + { + if ((usable - window) >= mss) + { + window += mss; + } + } + + out: + tp->rcv_wnd = window; + tp->rcv_wup = tp->rcv_nxt; + return window; } /* diff -u --recursive --new-file v2.1.9/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c --- v2.1.9/linux/net/ipv4/tcp_input.c Sun Nov 10 20:12:29 1996 +++ linux/net/ipv4/tcp_input.c Wed Nov 13 07:59:31 1996 @@ -194,11 +194,18 @@ /* * We want the right error as BSD sees it (and indeed as we do). */ - sk->err = ECONNRESET; - if (sk->state == TCP_SYN_SENT) - sk->err = ECONNREFUSED; - if (sk->state == TCP_CLOSE_WAIT) - sk->err = EPIPE; + switch (sk->state) { + case TCP_TIME_WAIT: + break; + case TCP_SYN_SENT: + sk->err = ECONNREFUSED; + break; + case TCP_CLOSE_WAIT: + sk->err = EPIPE; + break; + default: + sk->err = ECONNRESET; + } #ifdef CONFIG_TCP_RFC1337 /* * Time wait assassination protection [RFC1337] diff -u --recursive --new-file v2.1.9/linux/net/ipv4/udp.c linux/net/ipv4/udp.c --- v2.1.9/linux/net/ipv4/udp.c Sun Nov 10 20:12:30 1996 +++ linux/net/ipv4/udp.c Thu Nov 14 18:26:17 1996 @@ -227,14 +227,14 @@ * for direct user->board I/O transfers. That one will be fun. */ -static void udp_getfrag(const void *p, __u32 saddr, char * to, unsigned int offset, unsigned int fraglen) +static int udp_getfrag(const void *p, __u32 saddr, char * to, unsigned int offset, unsigned int fraglen) { struct udpfakehdr *ufh = (struct udpfakehdr *)p; const char *src; char *dst; unsigned int len; - if (offset) + if (offset) { len = fraglen; src = ufh->from+(offset-sizeof(struct udphdr)); @@ -258,6 +258,7 @@ ufh->uh.check = -1; memcpy(to, ufh, sizeof(struct udphdr)); } + return 0; } /* @@ -267,12 +268,13 @@ * this is a valid decision. */ -static void udp_getfrag_nosum(const void *p, __u32 saddr, char * to, unsigned int offset, unsigned int fraglen) +static int udp_getfrag_nosum(const void *p, __u32 saddr, char * to, unsigned int offset, unsigned int fraglen) { struct udpfakehdr *ufh = (struct udpfakehdr *)p; const char *src; char *dst; unsigned int len; + int err; if (offset) { @@ -286,9 +288,10 @@ src = ufh->from; dst = to+sizeof(struct udphdr); } - copy_from_user(dst,src,len); + err = copy_from_user(dst,src,len); if (offset == 0) memcpy(to, ufh, sizeof(struct udphdr)); + return err; } @@ -458,11 +461,16 @@ buf=kmalloc(len, GFP_KERNEL); if(buf==NULL) return -ENOBUFS; - memcpy_fromiovec(buf, msg->msg_iov, len); - fs=get_fs(); - set_fs(get_ds()); - err=udp_sendto(sk,buf,len, noblock, flags, msg->msg_name, msg->msg_namelen); - set_fs(fs); + err = memcpy_fromiovec(buf, msg->msg_iov, len); + if (err) + err = -EFAULT; + if (!err) + { + fs=get_fs(); + set_fs(get_ds()); + err=udp_sendto(sk,buf,len, noblock, flags, msg->msg_name, msg->msg_namelen); + set_fs(fs); + } kfree_s(buf,len); return err; } @@ -474,7 +482,6 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) { - int err; switch(cmd) { case TIOCOUTQ: @@ -483,12 +490,7 @@ if (sk->state == TCP_LISTEN) return(-EINVAL); amount = sock_wspace(sk); - err=verify_area(VERIFY_WRITE,(void *)arg, - sizeof(unsigned long)); - if(err) - return(err); - put_user(amount, (int *)arg); - return(0); + return put_user(amount, (int *)arg); } case TIOCINQ: @@ -507,12 +509,7 @@ */ amount = skb->len-sizeof(struct udphdr); } - err=verify_area(VERIFY_WRITE,(void *)arg, - sizeof(unsigned long)); - if(err) - return(err); - put_user(amount, (int *)arg); - return(0); + return put_user(amount, (int *)arg); } default: @@ -559,7 +556,9 @@ * FIXME : should use udp header size info value */ - skb_copy_datagram_iovec(skb,sizeof(struct udphdr),msg->msg_iov,copied); + er = skb_copy_datagram_iovec(skb,sizeof(struct udphdr),msg->msg_iov,copied); + if (er) + return er; sk->stamp=skb->stamp; /* Copy the address. */ diff -u --recursive --new-file v2.1.9/linux/net/ipv6/Makefile linux/net/ipv6/Makefile --- v2.1.9/linux/net/ipv6/Makefile Sun Nov 10 20:12:30 1996 +++ linux/net/ipv6/Makefile Wed Nov 13 11:07:41 1996 @@ -13,6 +13,7 @@ protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \ exthdrs.o sysctl_net_ipv6.o datagram.o +MOD_LIST_NAME := IPV6_MODULES M_OBJS := $(O_TARGET) include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.9/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c --- v2.1.9/linux/net/ipv6/addrconf.c Tue Nov 12 15:56:16 1996 +++ linux/net/ipv6/addrconf.c Thu Nov 14 18:26:17 1996 @@ -774,7 +774,7 @@ } -static void addrconf_ifdown(struct device *dev) +static int addrconf_ifdown(struct device *dev) { struct inet6_dev *idev, **bidev; struct inet6_ifaddr *ifa, **bifa; @@ -796,8 +796,9 @@ if (idev == NULL) { - printk(KERN_DEBUG "addrconf_ifdown: device not found\n"); - return; + printk(KERN_DEBUG "addrconf_ifdown: device not found\n"); + end_bh_atomic(); + return -ENODEV; } /* @@ -828,6 +829,7 @@ kfree(idev); end_bh_atomic(); + return 0; } /* @@ -1024,9 +1026,12 @@ * Remove all addresses from this interface * and take the interface out of the list. */ - addrconf_ifdown(dev); - rt6_ifdown(dev); - rt6_sndmsg(RTMSG_NEWDEVICE, NULL, NULL, 0, 0, dev->name, 0); + if (addrconf_ifdown(dev) == 0) + { + rt6_ifdown(dev); + rt6_sndmsg(RTMSG_NEWDEVICE, NULL, NULL, 0, 0, + dev->name, 0); + } break; } diff -u --recursive --new-file v2.1.9/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c --- v2.1.9/linux/net/ipv6/af_inet6.c Sun Nov 10 20:12:30 1996 +++ linux/net/ipv6/af_inet6.c Thu Nov 14 18:26:17 1996 @@ -107,7 +107,7 @@ struct proto *prot; int err; - sk = (struct sock *) kmalloc(sizeof(*sk), GFP_KERNEL); + sk = sk_alloc(GFP_KERNEL); if (sk == NULL) return(-ENOBUFS); diff -u --recursive --new-file v2.1.9/linux/net/ipv6/icmp.c linux/net/ipv6/icmp.c --- v2.1.9/linux/net/ipv6/icmp.c Sun Nov 10 20:12:30 1996 +++ linux/net/ipv6/icmp.c Thu Nov 14 18:26:17 1996 @@ -15,6 +15,12 @@ * 2 of the License, or (at your option) any later version. */ +/* + * Changes: + * + * Andi Kleen : exception handling + */ + #define __NO_VERSION__ #include #include @@ -95,7 +101,7 @@ * not static because it's needed in ndisc.c */ -static void icmpv6_getfrag(const void *data, struct in6_addr *saddr, +static int icmpv6_getfrag(const void *data, struct in6_addr *saddr, char *buff, unsigned int offset, unsigned int len) { struct icmpv6_msg *msg = (struct icmpv6_msg *) data; @@ -114,7 +120,7 @@ offset - sizeof(struct icmpv6hdr), buff, len, msg->csum); msg->csum = csum; - return; + return 0; } csum = csum_partial_copy((void *) &msg->icmph, buff, @@ -128,6 +134,7 @@ icmph->checksum = csum_ipv6_magic(saddr, msg->daddr, msg->len, IPPROTO_ICMPV6, csum); + return 0; } /* diff -u --recursive --new-file v2.1.9/linux/net/ipv6/ipv6_output.c linux/net/ipv6/ipv6_output.c --- v2.1.9/linux/net/ipv6/ipv6_output.c Tue Nov 12 15:56:16 1996 +++ linux/net/ipv6/ipv6_output.c Thu Nov 14 18:26:17 1996 @@ -15,6 +15,11 @@ * 2 of the License, or (at your option) any later version. */ +/* + * Changes: + * + * Andi Kleen : exception handling + */ #include #include @@ -440,7 +445,7 @@ int pktlength; int pmtu = 0; int rt_flags = 0; - + int error; if (opt && opt->srcrt) { @@ -568,8 +573,6 @@ if (pktlength <= pmtu) { - int error; - struct sk_buff *skb = sock_alloc_send_skb(sk, pktlength+15+ dev->hard_header_len, @@ -624,14 +627,22 @@ } skb_put(skb, length); - getfrag(data, &hdr->saddr, - ((char *) hdr) + (pktlength - length), 0, length); + error = getfrag(data, &hdr->saddr, + ((char *) hdr) + (pktlength - length), + 0, length); - ipv6_statistics.Ip6OutRequests++; - (*output_method)(skb, (struct rt6_info *) dc); + if (!error) + { + ipv6_statistics.Ip6OutRequests++; + (*output_method)(skb, (struct rt6_info *) dc); + } else + { + error = -EFAULT; + kfree_skb(skb, FREE_WRITE); + } dev_unlock_list(); - return 0; + return error; } else { @@ -763,31 +774,52 @@ fhdr_dist = (unsigned char *) fhdr - last_skb->data; - getfrag(data, &hdr->saddr, last_skb->tail, nfrags * frag_len, - last_len); + error = getfrag(data, &hdr->saddr, last_skb->tail, + nfrags * frag_len, last_len); - while (nfrags--) - { - struct sk_buff *skb; - - struct frag_hdr *fhdr2; - - printk(KERN_DEBUG "sending frag %d\n", nfrags); - skb = skb_copy(last_skb, sk->allocation); - - fhdr2 = (struct frag_hdr *) (skb->data + fhdr_dist); - /* more flag on */ - fhdr2->frag_off = ntohs(nfrags * frag_len + 1); - - /* if (nfrags == 0) - put rest of headers - */ + if (!error) + { + while (nfrags--) + { + struct sk_buff *skb; + + struct frag_hdr *fhdr2; + + printk(KERN_DEBUG "sending frag %d\n", nfrags); + skb = skb_copy(last_skb, sk->allocation); + + fhdr2 = (struct frag_hdr *) + (skb->data + fhdr_dist); + + /* more flag on */ + fhdr2->frag_off = ntohs(nfrags * frag_len + 1); + + /* + * FIXME: + * if (nfrags == 0) + * put rest of headers + */ + + error = getfrag(data, &hdr->saddr, + skb_put(skb, frag_len), + nfrags * frag_len, frag_len); + + if (error) + { + kfree_skb(skb, FREE_WRITE); + break; + } - getfrag(data, &hdr->saddr, skb_put(skb, frag_len), - nfrags * frag_len, frag_len); + ipv6_statistics.Ip6OutRequests++; + (*output_method)(skb, (struct rt6_info *) dc); + } + } - ipv6_statistics.Ip6OutRequests++; - (*output_method)(skb, (struct rt6_info *) dc); + if (error) + { + kfree_skb(last_skb, FREE_WRITE); + dev_unlock_list(); + return -EFAULT; } printk(KERN_DEBUG "sending last frag \n"); diff -u --recursive --new-file v2.1.9/linux/net/ipv6/ipv6_sockglue.c linux/net/ipv6/ipv6_sockglue.c --- v2.1.9/linux/net/ipv6/ipv6_sockglue.c Tue Nov 12 15:56:16 1996 +++ linux/net/ipv6/ipv6_sockglue.c Thu Nov 14 18:26:17 1996 @@ -164,10 +164,6 @@ { struct in6_addr addr; - err=verify_area(VERIFY_READ, optval, sizeof(struct in6_addr)); - if(err) - return err; - err = copy_from_user(&addr, optval, sizeof(struct in6_addr)); if(err) return -EFAULT; diff -u --recursive --new-file v2.1.9/linux/net/ipv6/raw.c linux/net/ipv6/raw.c --- v2.1.9/linux/net/ipv6/raw.c Sun Nov 10 20:12:31 1996 +++ linux/net/ipv6/raw.c Thu Nov 14 18:26:17 1996 @@ -124,9 +124,12 @@ copied = min(len, skb->tail - skb->h.raw); - skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); sk->stamp=skb->stamp; + if (err) + return err; + /* Copy the address. */ if (sin6) { @@ -166,15 +169,15 @@ struct in6_addr *daddr; }; -static void rawv6_getfrag(const void *data, struct in6_addr *saddr, +static int rawv6_getfrag(const void *data, struct in6_addr *saddr, char *buff, unsigned int offset, unsigned int len) { struct iovec *iov = (struct iovec *) data; - memcpy_fromiovecend(buff, iov, offset, len); + return memcpy_fromiovecend(buff, iov, offset, len); } -static void rawv6_frag_cksum(const void *data, struct in6_addr *addr, +static int rawv6_frag_cksum(const void *data, struct in6_addr *addr, char *buff, unsigned int offset, unsigned int len) { @@ -220,6 +223,7 @@ printk(KERN_DEBUG "icmp: cksum offset too big\n"); } } + return 0; } @@ -354,8 +358,10 @@ switch (optname) { case ICMPV6_FILTER: - copy_from_user(&opt->filter, optval, + err = copy_from_user(&opt->filter, optval, sizeof(struct icmp6_filter)); + if (err) + err = -EFAULT; break; default: err = -ENOPROTOOPT; diff -u --recursive --new-file v2.1.9/linux/net/ipv6/udp.c linux/net/ipv6/udp.c --- v2.1.9/linux/net/ipv6/udp.c Tue Nov 12 15:56:16 1996 +++ linux/net/ipv6/udp.c Thu Nov 14 18:26:18 1996 @@ -172,7 +172,7 @@ int copied = 0; int truesize; struct sk_buff *skb; - int er; + int err; /* @@ -187,9 +187,9 @@ * the finished NET3, it will do _ALL_ the work! */ - skb = skb_recv_datagram(sk, flags, noblock, &er); + skb = skb_recv_datagram(sk, flags, noblock, &err); if(skb==NULL) - return er; + return err; truesize = skb->tail - skb->h.raw - sizeof(struct udphdr); copied = min(len, truesize); @@ -198,7 +198,11 @@ * FIXME : should use udp header size info value */ - skb_copy_datagram_iovec(skb,sizeof(struct udphdr),msg->msg_iov,copied); + err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), + msg->msg_iov, copied); + if (err) + return err; + sk->stamp=skb->stamp; /* Copy the address. */ @@ -428,8 +432,8 @@ * with checksum */ -static void udpv6_getfrag(const void *data, struct in6_addr *addr, - char *buff, unsigned int offset, unsigned int len) +static int udpv6_getfrag(const void *data, struct in6_addr *addr, + char *buff, unsigned int offset, unsigned int len) { struct udpv6fakehdr *udh = (struct udpv6fakehdr *) data; char *dst; @@ -479,6 +483,7 @@ memcpy(buff, udh, sizeof(struct udphdr)); } + return 0; } static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen, diff -u --recursive --new-file v2.1.9/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c --- v2.1.9/linux/net/ipx/af_ipx.c Tue Oct 29 19:58:50 1996 +++ linux/net/ipx/af_ipx.c Thu Nov 14 18:26:18 1996 @@ -141,8 +141,7 @@ vals.ipxcfg_auto_create_interfaces = ipxcfg_auto_create_interfaces; vals.ipxcfg_auto_select_primary = ipxcfg_auto_select_primary; - copy_to_user(arg, &vals, sizeof(vals)); - return 0; + return copy_to_user(arg, &vals, sizeof(vals)); } @@ -1062,7 +1061,8 @@ struct sockaddr_ipx *sipx; ipx_interface *ipxif; struct device *dev; - + int err; + if (copy_from_user(&ifr,arg,sizeof(ifr))) return -EFAULT; sipx=(struct sockaddr_ipx *)&ifr.ifr_addr; @@ -1075,9 +1075,10 @@ sipx->sipx_family=AF_IPX; sipx->sipx_network=ipxif->if_netnum; memcpy(sipx->sipx_node, ipxif->if_node, sizeof(sipx->sipx_node)); - if (copy_to_user(arg,&ifr,sizeof(ifr))) + err = copy_to_user(arg,&ifr,sizeof(ifr)); + if (err) return -EFAULT; - return 0; + return err; } case SIOCAIPXITFCRT: { int err, val; @@ -1333,7 +1334,12 @@ memcpy(ipx->ipx_dest.node,usipx->sipx_node,IPX_NODE_LEN); ipx->ipx_dest.sock=usipx->sipx_port; - memcpy_fromiovec(skb_put(skb,len),iov,len); + err = memcpy_fromiovec(skb_put(skb,len),iov,len); + if (err) + { + kfree_skb(skb, FREE_WRITE); + return -EFAULT; + } /* * Apply checksum. Not allowed on 802.3 links. @@ -1384,13 +1390,11 @@ int err; struct rtentry rt; /* Use these to behave like 'other' stacks */ struct sockaddr_ipx *sg,*st; - - err=verify_area(VERIFY_READ,arg,sizeof(rt)); - if(err) - return err; - copy_from_user(&rt,arg,sizeof(rt)); - + err = copy_from_user(&rt,arg,sizeof(rt)); + if (err) + return -EFAULT; + sg=(struct sockaddr_ipx *)&rt.rt_gateway; st=(struct sockaddr_ipx *)&rt.rt_dst; @@ -1677,14 +1681,10 @@ default: return -EOPNOTSUPP; } - err=verify_area(VERIFY_WRITE,optlen,sizeof(int)); - if(err) - return err; - put_user(sizeof(int), optlen); - err=verify_area(VERIFY_WRITE,optval,sizeof(int)); - if (err) return err; - put_user(val, (int *)optval); - return(0); + err = put_user(sizeof(int), optlen); + if (!err) + err = put_user(val, (int *)optval); + return err; } static int ipx_listen(struct socket *sock, int backlog) @@ -2168,8 +2168,11 @@ ipx = (ipx_packet *)(skb->h.raw); truesize=ntohs(ipx->ipx_pktsize) - sizeof(ipx_packet); copied = (truesize > size) ? size : truesize; - skb_copy_datagram_iovec(skb,sizeof(struct ipx_packet),msg->msg_iov,copied); + err = skb_copy_datagram_iovec(skb,sizeof(struct ipx_packet),msg->msg_iov,copied); + if (err) + return err; + if(sipx) { sipx->sipx_family=AF_IPX; @@ -2203,25 +2206,17 @@ switch(cmd) { case TIOCOUTQ: - err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(int)); - if(err) - return err; amount=sk->sndbuf-sk->wmem_alloc; if(amount<0) amount=0; - put_user(amount, (int *)arg); - return 0; + return put_user(amount, (int *)arg); 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 ipx_packet); - err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(int)); - if(err) - return err; - put_user(amount, (int *)arg); - return 0; + return put_user(amount, (int *)arg); } case SIOCADDRT: case SIOCDELRT: @@ -2237,23 +2232,21 @@ return(ipxitf_ioctl(cmd,(void *)arg)); case SIOCIPXCFGDATA: { - err=verify_area(VERIFY_WRITE,(void *)arg, - sizeof(ipx_config_data)); - if(err) return err; return(ipxcfg_get_config_data((void *)arg)); } case SIOCGSTAMP: + { + int ret = -EINVAL; if (sk) { if(sk->stamp.tv_sec==0) return -ENOENT; - err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval)); - if(err) - return err; - copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval)); - return 0; + ret = copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval)); + if (ret) + ret = -EFAULT; } - return -EINVAL; + return 0; + } case SIOCGIFDSTADDR: case SIOCSIFDSTADDR: case SIOCGIFBRDADDR: diff -u --recursive --new-file v2.1.9/linux/net/netlink.c linux/net/netlink.c --- v2.1.9/linux/net/netlink.c Sun Nov 10 20:12:31 1996 +++ linux/net/netlink.c Thu Nov 14 18:26:16 1996 @@ -85,12 +85,13 @@ static long netlink_write(struct inode * inode, struct file * file, const char * buf, unsigned long count) { + int err; unsigned int minor = MINOR(inode->i_rdev); struct sk_buff *skb; skb=alloc_skb(count, GFP_KERNEL); skb->free=1; - copy_from_user(skb_put(skb,count),buf, count); - return (netlink_handler[minor])(skb); + err = copy_from_user(skb_put(skb,count),buf, count); + return err ? -EFAULT : (netlink_handler[minor])(skb); } /* @@ -100,6 +101,7 @@ static long netlink_read(struct inode * inode, struct file * file, char * buf, unsigned long count) { + int err; unsigned int minor = MINOR(inode->i_rdev); struct sk_buff *skb; cli(); @@ -121,9 +123,9 @@ sti(); if(skb->lenlen; - copy_to_user(buf,skb->data,count); + err = copy_to_user(buf,skb->data,count); kfree_skb(skb, FREE_READ); - return count; + return err ? -EFAULT : count; } static loff_t netlink_lseek(struct inode * inode, struct file * file, diff -u --recursive --new-file v2.1.9/linux/net/socket.c linux/net/socket.c --- v2.1.9/linux/net/socket.c Tue Nov 12 15:56:17 1996 +++ linux/net/socket.c Thu Nov 14 18:26:16 1996 @@ -159,8 +159,7 @@ if(copy_to_user(uaddr,kaddr,len)) return -EFAULT; } - put_user(len, ulen); - return 0; + return put_user(len, ulen); } /* @@ -649,17 +648,14 @@ sock1->state = SS_CONNECTED; sock2->state = SS_CONNECTED; - er=verify_area(VERIFY_WRITE, usockvec, sizeof(usockvec)); - if(er) - { + er = put_user(fd1, &usockvec[0]); + if (!er) + er = put_user(fd2, &usockvec[1]); + if (er) { sys_close(fd1); sys_close(fd2); - return er; } - put_user(fd1, &usockvec[0]); - put_user(fd2, &usockvec[1]); - - return(0); + return er; } @@ -1133,12 +1129,8 @@ if(sock->ops->sendmsg==NULL) return -EOPNOTSUPP; - - err=verify_area(VERIFY_READ, msg,sizeof(struct msghdr)); - if(err) - return err; - - copy_from_user(&msg_sys,msg,sizeof(struct msghdr)); + if ((err = copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))) + return -EFAULT; /* do not move before msg_sys is valid */ if(msg_sys.msg_iovlen>UIO_MAXIOV) @@ -1200,11 +1192,8 @@ if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); - err=verify_area(VERIFY_READ, msg,sizeof(struct msghdr)); - if(err) - return err; - - copy_from_user(&msg_sys,msg,sizeof(struct msghdr)); + if ((err = copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))) + return -EFAULT; if(msg_sys.msg_iovlen>UIO_MAXIOV) return -EINVAL; @@ -1240,19 +1229,24 @@ if(len<0) return len; - if (uaddr != NULL) { + if (uaddr != NULL) + { err = move_addr_to_user(addr, addr_len, uaddr, uaddr_len); - if (err) - return err; } if (msg_sys.msg_control) { - copy_to_user(usr_msg_ctl, krn_msg_ctl, msg_sys.msg_controllen); - kfree(krn_msg_ctl); + if (!err) + { + int ret; + ret = copy_to_user(usr_msg_ctl, krn_msg_ctl, + msg_sys.msg_controllen); + err = -EFAULT; + } + kfree(krn_msg_ctl); } - return len; + return err ? err : len; } @@ -1285,7 +1279,6 @@ asmlinkage int sys_socketcall(int call, unsigned long *args) { - int er; unsigned char nargs[18]={0,3,3,3,2,3,3,3, 4,4,4,6,6,2,5,5,3,3}; unsigned long a[6]; @@ -1294,10 +1287,8 @@ if(call<1||call>SYS_RECVMSG) return -EINVAL; - er=verify_area(VERIFY_READ, args, nargs[call] * sizeof(unsigned long)); - if(er) - return er; - copy_from_user(a, args, nargs[call] * sizeof(unsigned long)); + if ((copy_from_user(a, args, nargs[call] * sizeof(unsigned long)))) + return -EFAULT; a0=a[0]; a1=a[1]; diff -u --recursive --new-file v2.1.9/linux/net/unix/af_unix.c linux/net/unix/af_unix.c --- v2.1.9/linux/net/unix/af_unix.c Sun Nov 10 20:12:31 1996 +++ linux/net/unix/af_unix.c Thu Nov 14 18:26:18 1996 @@ -925,7 +925,15 @@ } return err; } - size=skb_tailroom(skb); /* If we dropped back on a limit then our skb is smaller */ + + /* + * If you pass two values to the sock_alloc_send_skb + * it tries to grab the large buffer with GFP_BUFFER + * (which can fail easily), and if it fails grab the + * fallback size buffer which is under a page and will + * succeed. [Alan] + */ + size = min(size, skb_tailroom(skb)); skb->sk=sk; skb->free=1; @@ -1024,6 +1032,7 @@ struct iovec *iov=msg->msg_iov; struct cmsghdr *cm=NULL; int ct=msg->msg_iovlen; + int err = 0; if(flags&MSG_OOB) return -EOPNOTSUPP; @@ -1098,8 +1107,13 @@ } num=min(skb->len,len-done); - copy_to_user(sp, skb->data, num); + err = copy_to_user(sp, skb->data, num); + if (err) + { + goto out; + } + if (skb->h.filp!=NULL) unix_detach_fds(skb,cm); @@ -1121,7 +1135,7 @@ out: up(&sk->protinfo.af_unix.readsem); - return copied; + return err ? -EFAULT : copied; } static int unix_shutdown(struct socket *sock, int mode) @@ -1161,34 +1175,28 @@ static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { unix_socket *sk=sock->data; - int err; long amount=0; switch(cmd) { case TIOCOUTQ: - err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(int)); - if(err) - return err; amount=sk->sndbuf-sk->wmem_alloc; if(amount<0) amount=0; - put_user(amount, (int *)arg); - return 0; + return put_user(amount, (int *)arg); case TIOCINQ: { struct sk_buff *skb; if(sk->state==TCP_LISTEN) return -EINVAL; - /* These two are safe on a single CPU system as only user tasks fiddle here */ + /* + * 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; - err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(int)); - if(err) - return err; - put_user(amount, (int *)arg); - return 0; + return put_user(amount, (int *)arg); } default: