@@ -713,6+713,10 @@ S: 2a, rue de l'Acier 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
-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.
-
- Voyez le site http://www.linux-kheops.com/traduc/kernels/ pour la
-traduction francais (merci, David Bourgin). (French translation)
-
-Last updated: November 5, 1996.
-Current Author: Chris Ricker (gt1355b@prism.gatech.edu).
-
-Current Releases
-****************
-
-- Kernel modules 2.0.0
-- PPP daemon 2.2.0f
-- Dynamic linker (ld.so) 1.7.14
-- GNU CC 2.7.2.1
-- Binutils 2.7.0.3
-- Linux C Library Stable: 5.2.18, Beta: 5.4.10
-- 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
-- Net-tools 1.32-alpha
-- Kbd 0.91
-
-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
-===================
-
- 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
-
- 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
-====
-
- 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 <AD> 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.
-
-How to know the version of the installed programs
-*************************************************
-
- There are some simple methods useful to know the version of the
-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
-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 ~
-/INIT_VERSION/ {print}'
-
-Where to get the files
-**********************
-
-Binutils
-========
-
-ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/binutils-2.7.0.3.bin.tar.gz
-Installation notes:
-ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/release.binutils-2.7.0.3
-
-GNU CC
-======
-
-ftp://sunsite.unc.edu/pub/Linux/GCC/gcc-2.7.2.1.bin.tar.gz
-Installation notes:
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.gcc-2.7.2.1
-
-Linux C Library
-===============
-
-The stable 5.2.18 release:
-ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.2.18.bin.tar.gz
-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
-
-Linux C++ Library
-=================
-
-ftp://sunsite.unc.edu/pub/Linux/GCC/libg++-2.7.2.1.bin.tar.gz
-Installation notes:
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.libg++-2.7.2.1
-
-Dynamic Linker
-==============
-
-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
-==================
-
-ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.64.tar.gz
-
-Util-linux
-==========
-
-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
-==========
-
- Please remember that most of these utils are available on your
-favorite local linux mirror. If you can, please get them from a closer
-site before checking sunsite.
-
- Also, for those of you running Red Hat (or RPM on a different
-distribution), most of these are available in RPM format. Check around
-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.
-
- 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.
-
+Intro
+=====
+
+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 ;-).
+
+Last updated: November 13, 1996.
+Current Author: Chris Ricker (gt1355b@prism.gatech.edu).
+
+Current Minimal Requirements
+****************************
+
+ Upgrade to at *least* these software revisions before thinking you've
+encountered a bug!
+
+- Kernel modules 2.0.0
+- Gnu C 2.7.2.1
+- Binutils 2.7.0.3
+- Linux C Library 5.4.12
+- Linux C++ Library 2.7.2.1
+- Procps 1.01
+- SysVinit 2.64
+- Util-linux 2.5
+- Mount 2.5p
+- Net-tools 1.32-alpha
+- Kbd 0.91
+
+Upgrade notes
+*************
+
+General Information
+===================
+
+ <CTRL><ALT><DEL> 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.
+
+Libc
+====
+
+ 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
+*************************************************
+
+ There are some simple methods useful to know the version of the
+installed programs and libraries. The SysVinit version display
+requires that you be logged in as root.
+
+Gnu C: gcc -v or gcc --version
+Libc: ls -l /lib/libc.so.*
+Libc++: ls -l /usr/lib/libg++.so.*
+Binutils: ld -v
+modules: insmod -V
+procps: ps --version
+SysVinit: cat /proc/`cat /var/run/syslog.pid`/environ|strings|awk '$1 ~
+/INIT_VERSION/ {print}'
+
+Where to get the files
+**********************
+
+Binutils
+========
+
+ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/binutils-2.7.0.3.bin.tar.gz
+Installation notes:
+ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/release.binutils-2.7.0.3
+
+Gnu C
+=====
+
+ftp://sunsite.unc.edu/pub/Linux/GCC/gcc-2.7.2.1.bin.tar.gz
+Installation notes:
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.gcc-2.7.2.1
+
+Linux C Library
+===============
+
+The stable 5.2.18 release:
+ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.2.18.bin.tar.gz
+Installation notes for 5.2.18:
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.2.18
+
+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
+=================
+
+ftp://sunsite.unc.edu/pub/Linux/GCC/libg++-2.7.2.1.bin.tar.gz
+Installation notes:
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.libg++-2.7.2.1
+
+Dynamic Linker
+==============
+
+ftp://sunsite.unc.edu/pub/Linux/GCC/ld.so-1.7.14.tar.gz
+
+Modules utilities
+=================
+
+ftp://sunsite.unc.edu/pub/Linux/kernel/modules-2.0.0.tar.gz
+
+Procps utilities
+================
+
+ftp://sunsite.unc.edu/pub/Linux/system/Status/ps/procps-1.01.tgz
+
+SysVinit utilities
+==================
+
+ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.64.tar.gz
+
+Util-linux
+==========
+
+ftp://sunsite.unc.edu/pub/Linux/system/Misc/util-linux-2.5.tar.gz
+
+Other Info
+==========
+
+ Please remember that most of these utils are available on your
+favorite local linux mirror. If you can, please get them from a closer
+site before checking sunsite.
+
+ Also, for those of you running Red Hat (or RPM on a different
+distribution), most of these are available in RPM format. Check around
+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/contrib/
+
+ For others, David Bourgin has put together a package of everything
+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).
+
@@ -1243,6+1243,13 @@ CONFIG_BLK_DEV_SR 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
@@ -42,7+42,7 @@ foo \kill}% %
\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 @@ reply. \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 @@ physical disks. \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 @@ $<$mseritan@ottonel.pub.ro$>$ to transfer data from Holter 24-hour 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 @@ It is recommended that these links exist on all systems: \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}
Maintained by H. Peter Anvin <hpa@zytor.com>
- 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 @@ reply. 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 @@ reply. <mseritan@ottonel.pub.ro> 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
VERSION = 2
PATCHLEVEL = 1
-SUBLEVEL = 9
+SUBLEVEL = 10
ARCH = i386
@@ -285,6+285,7 @@ modules_install: 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; \
@@ -102,6+102,7 @@ CONFIG_SCSI=y 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_CONSTANTS=y # 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_NFS_FS=y 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
#
/*
- * 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.
99: x,##y; \
.section __ex_table,"a"; \
.gprel32 99b; \
- lda zero, $exception-99b(v0); \
+ lda zero, $exception-99b(zero); \
.text
.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 @@ strlen_user: 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 @@ $found: negq t1, t2 # clear all but least set bit 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
@@ -25,7+25,7 @@ zImage: $(CONFIGURE) bootsect setup compressed/vmlinux tools/build
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
@@ -20,6+20,7 @@ static struct symbol_table arch_symbol_table = { X(dump_thread),
X(dump_fpu),
X(ioremap),
+ X(iounmap),
XNOVERS(__down_failed),
XNOVERS(__up_wakeup),
#ifdef __SMP__
@@ -1013,7+1013,7 @@ static void setup_DMA(void) 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 @@ static int make_raw_rw_request(void) }
/* 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
@@ -2647,8+2647,8 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive) 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 @@ void ide_cdrom_setup (ide_drive_t *drive)
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_ioctl (ide_drive_t *drive,
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_check_media_change (ide_drive_t *drive) 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 @@ int ide_cdrom_cleanup(ide_drive_t *drive) 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 @@ int ide_cdrom_init (void) 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;
@@ -90,11+90,11 @@ endif #CONFIG_GSCD
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
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
else
@@ -268,13+268,11 @@ int cdrom_media_changed(kdev_t dev) 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 @@ void sanitize_format(union cdrom_addr *addr, 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!
07 July 1995 Modifications by Andrew J. Kroll
Bjorn Ekwall <bj0rn@blox.se> added unregister_blkdev to mcd_init()
+
+ Michael K. Johnson <johnsonm@redhat.com> added retries on open
+ for slow drives which take a while to recognize that they contain
+ a CD.
*/
#include <linux/module.h>
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_open(struct inode *ip, struct file *fp)
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 */
{
+Thu Nov 14 00:06:09 1996 Theodore Ts'o <tytso@rsts-11.mit.edu>
+
+ * 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 <tytso@rsts-11.mit.edu>
* n_tty.c (n_tty_flush_buffer): Only call driver->unthrottle() if
#include <asm/bitops.h>
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 @@ static int get_auto_irq(struct async_struct *info) (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 @@ static void autoconfig(struct serial_state * state) 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 @@ static void autoconfig(struct serial_state * state) 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);
--- /dev/null
+/* $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
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 @@ struct tulip_private { 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 int tulip_rx(struct device *dev); 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 void cogent21140_select(struct device *dev); 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 @@ static struct {
#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 @@ static void set_multicast_list(struct device *dev) *setup_frm++ = eaddrs[2];
} while (++i < 15);
+#ifndef __alpha__
/* Now add this frame to the Tx list. */
{
unsigned long flags;
@@ -1152,46+1158,8 @@ static void set_multicast_list(struct device *dev) /* 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 @@ tulip_hwinit(struct device *dev, int ioaddr, {
/* 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 @@ tulip_hwinit(struct device *dev, int ioaddr, 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 @@ tulip_hwinit(struct device *dev, int ioaddr, 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 @@ int tulip_probe(struct device *dev)
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 @@ int tulip_probe(struct device *dev) &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 @@ int tulip_probe(struct device *dev) 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 */
\f
@@ -3,6+3,9 @@ comment 'SCSI support type (disk, tape, CD-ROM)' 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'
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 @@ scsi_mod.o: $(MX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o \ 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
-/* $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
*
/*
* 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 */
/*
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)
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.
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
#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 @@ typedef unsigned char uchar; #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 @@ AscMemWordCopyToLram(iop_base, s_addr, outbuf, words) #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 @@ typedef struct asc_risc_sg_list_q { #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 @@ int AscRestoreNewMicroCode(ASC_DVC_VAR asc_ptr_type *, ASC_MC_SA #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 @@ typedef Scsi_Cmnd REQ, *REQP; #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 @@ struct asc_stats { 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 @@ typedef struct asc_board { 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 struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { 0 }; 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 @@ advansys_detect(Scsi_Host_Template *tpnt) 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 @@ advansys_detect(Scsi_Host_Template *tpnt) /*
* 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 @@ advansys_detect(Scsi_Host_Template *tpnt) */
/* 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 @@ advansys_detect(Scsi_Host_Template *tpnt) */
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 @@ advansys_info(struct Scsi_Host *shp) 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 @@ advansys_select_queue_depths(struct Scsi_Host *shp, Scsi_Device *devicelist) 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_execute_scsi_cmnd(Scsi_Cmnd *scp) {
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 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
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_execute_scsi_cmnd(Scsi_Cmnd *scp) 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 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp) * 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 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp) */
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_execute_scsi_cmnd(Scsi_Cmnd *scp) 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->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.
*/
- boardp->rcnt[scp->target]++;
+ 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(Scsi_Cmnd *scp) "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 @@ STATIC int 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 @@ asc_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp) 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 @@ asc_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp) 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 @@ asc_prt_board_devices(struct Scsi_Host *shp, char *cp, int cplen) 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_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen) 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_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen) 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_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen) 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_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen) 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 @@ asc_prt_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen) 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_prt_driver_conf(struct Scsi_Host *shp, char *cp, int cplen) 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_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen) 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_board_info(struct Scsi_Host *shp, char *cp, int cplen) 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_board_info(struct Scsi_Host *shp, char *cp, int cplen) 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_board_info(struct Scsi_Host *shp, char *cp, int cplen) 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_board_info(struct Scsi_Host *shp, char *cp, int cplen) 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 @@ asc_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen) 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 @@ asc_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen) }
len = asc_prt_line(cp, leftlen, "\n");
ASC_PRT_NEXT();
-#endif /* ADVANSYS_STATS */
return totlen;
}
@@ -6103,11+6235,11 @@ DvcGetPhyAddr(uchar *buf_addr, ulong buf_len) {
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 @@ DvcGetSGList(ASC_DVC_VAR *asc_dvc_sg, uchar *buf_addr, ulong buf_len,
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 @@ DvcWritePCIConfigByte( /*
* 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 @@ AscGetChipBiosAddress( 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 @@ AscIsrChipHalted( 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 @@ AscIsrChipHalted( 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 @@ AscIsrChipHalted( (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 @@ AscScsiSetupCmdQ( 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 @@ AscScsiSetupCmdQ( }
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 @@ AscGetSynPeriodIndex( {
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 @@ AscInitAscDvcVar( 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 @@ AscInitPollIsrCallBack( 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 @@ AscInitPollTarget( 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 @@ PollQueueDone( 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 @@ PollQueueDone( 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 @@ PollQueueDone( 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 @@ InitTestUnitReady( 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 @@ InitTestUnitReady( } 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 @@ AscPollQDone( 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 @@ AscPollQDone( }
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 @@ AscPollQDone( loop = 0;
} else {
if (AscIsIntPending(iop_base)) {
+ ASC_DBG(1, "AscPollQDone: AscIsIntPending()\n");
#if !CC_ASCISR_CHECK_INT_PENDING
AscAckInterrupt(iop_base);
#endif
@@ -642,26+642,6 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun, 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);
@@ -123,19+123,6 @@ extern const unsigned char scsi_command_size[8]; */
/*
- * 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.
#include <linux/interrupt.h>
#include <asm/system.h>
+#include <asm/io.h>
#define MAJOR_NR SCSI_DISK_MAJOR
#include <linux/blk.h>
@@ -660,10+661,10 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) * 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 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) 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 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) }
#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 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) 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 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) && 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 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) /* 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;
* Modified by Thomas Quinot thomas@melchior.cuivre.fdn.fr to
* provide auto-eject.
*
+ * Modified by Gerd Knorr <kraxel@cs.tu-berlin.de> to support the
+ * generic cdrom interface
+ *
*/
#include <linux/module.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/cdrom.h>
+#include <linux/ucdrom.h>
#include <linux/interrupt.h>
+#include <linux/config.h>
#include <asm/system.h>
#define MAJOR_NR SCSI_CDROM_MAJOR
@@ -49,53+54,48 @@ static int sr_detect(Scsi_Device *); 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 @@ static struct file_operations sr_fops = * 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 @@ static void rw_intr (Scsi_Cmnd * SCpnt) }
}
-/*
- * 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 <kraxel@cs.tu-berlin.de>
- */
-/*
- * 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 <thomas@melchior.cuivre.fdn.fr> */
- 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 @@ static int sr_attach(Scsi_Device * SDp){
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 @@ static int sr_init() 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 @@ static int sr_init()
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 @@ void sr_finish() 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 @@ void sr_finish() 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 @@ static void sr_detach(Scsi_Device * SDp) * 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 @@ static void sr_detach(Scsi_Device * SDp) #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,
#ifndef _SR_H
#define _SR_H
+#include <linux/config.h>
+
#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
#include <linux/blk.h>
#include "scsi.h"
#include "hosts.h"
-#include "sr.h"
#include <scsi/scsi_ioctl.h>
#include <linux/cdrom.h>
+#include <linux/ucdrom.h>
+#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 @@ static void sr_ioctl_done(Scsi_Cmnd * SCpnt) 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 @@ static int do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned 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 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne 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 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne 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;
+ struct cdrom_msf* msf = (struct cdrom_msf*)arg;
- err = verify_area (VERIFY_READ, (void *) arg, sizeof (msf));
- if (err) return err;
-
- 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;
-
- err = verify_area (VERIFY_READ, (void *) arg, sizeof (ti));
- if (err) return err;
+ struct cdrom_ti* ti = (struct cdrom_ti*)arg;
- 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 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne 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 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne buffer = (unsigned char *) scsi_malloc(512);
if(!buffer) return -ENOMEM;
- result = 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)
+ 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)
+ 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 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne 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 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne 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;
-
- 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;
+ result = sr_do_ioctl(target, sr_cmd, NULL, 255);
+ break;
- 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 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne 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 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne 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 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne 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 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne 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 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne 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_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_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 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne 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);
--- /dev/null
+/* -*-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 <kraxel@cs.tu-berlin.de>
+ */
+
+#include <linux/errno.h>
+#include <linux/string.h>
+
+#include <linux/blk.h>
+#include "scsi.h"
+#include "hosts.h"
+#include <scsi/scsi_ioctl.h>
+
+#include <linux/cdrom.h>
+#include <linux/ucdrom.h>
+#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 <operator@melchior.cuivre.fdn.fr>
+ *
+ * - 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 <thomas@melchior.cuivre.fdn.fr> */
+#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;
+}
@@ -144,20+144,14 @@ unsigned long * create_elf_tables(char *p, int argc, int envc, __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;
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/io.h>
+#include <asm/bitops.h>
#define NR_SIZES 5
static char buffersize_index[17] =
@@ -169,7+170,7 @@ repeat: 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 @@ unsigned long generate_cluster(kdev_t dev, int b[], int size) 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 ======================= */
@@ -178,27+178,23 @@ asmlinkage int sys_uselib(const char * library)
/*
* 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 @@ static int count(char ** argv) 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)
* 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
*/
/*
#include <linux/locks.h>
#include <asm/bitops.h>
+#include <asm/byteorder.h>
#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1)
@@ -71,12+74,12 @@ static void read_block_bitmap (struct super_block * sb, 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 @@ void ext2_free_blocks (const struct inode * inode, unsigned long block, }
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 @@ void ext2_free_blocks (const struct inode * inode, unsigned long block,
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 @@ void ext2_free_blocks (const struct inode * inode, unsigned long block, 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 @@ void ext2_free_blocks (const struct inode * inode, unsigned long block, 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 @@ int ext2_new_block (const struct inode * inode, unsigned long goal, }
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 @@ repeat: /*
* 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 @@ repeat:
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 @@ repeat: * 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 @@ repeat: 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 @@ repeat: 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 @@ repeat: 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 @@ search_back: * 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 @@ got_block: 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 @@ got_block: 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 @@ got_block: 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 @@ got_block: 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 @@ unsigned long ext2_count_free_blocks (struct super_block * sb) 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 @@ static inline int block_in_use (unsigned long block, 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 @@ void ext2_check_blocks_bitmap (struct super_block * sb) 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);
}
* 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 <asm/uaccess.h>
@@ -77,23+80,24 @@ int ext2_check_dir_entry (const char * function, struct inode * dir, {
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 @@ revalidate: * 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 @@ revalidate: 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 @@ revalidate: * 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);
* 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 <asm/uaccess.h>
#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 @@ static int sync_block (struct inode * inode, u32 * block, int wait) 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 @@ static int sync_iblock (struct inode * inode, u32 * iblock, 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 @@ static int sync_direct (struct inode * inode, int wait) 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,9 @@ static int sync_indirect (struct inode * inode, u32 * iblock, int wait) 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)
@@ -117,7+171,30 @@ static int sync_indirect (struct inode * inode, u32 * iblock, int wait) return err;
}
-static int sync_dindirect (struct inode * inode, u32 * diblock, int wait)
+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)
+ err = rc;
+ }
+ brelse (ind_bh);
+ return err;
+}
+
+static __inline__ int sync_dindirect (struct inode * inode, u32 * diblock, int wait)
{
int i;
struct buffer_head * dind_bh;
@@ -128,9+205,32 @@ static int sync_dindirect (struct inode * inode, u32 * diblock, int wait) 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 @@ static int sync_dindirect (struct inode * inode, u32 * diblock, int wait) 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 @@ static int sync_tindirect (struct inode * inode, u32 * tiblock, int wait) 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)
*
* 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
*/
/*
#include <linux/locks.h>
#include <asm/bitops.h>
+#include <asm/byteorder.h>
static struct ext2_group_desc * get_group_desc (struct super_block * sb,
unsigned int block_group,
@@ -70,12+73,12 @@ static void read_inode_bitmap (struct super_block * sb, 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 @@ void ext2_free_inode (struct inode * inode) 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 @@ void ext2_free_inode (struct inode * inode) 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 @@ repeat:
*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 @@ repeat: 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 @@ repeat: */
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 @@ repeat: 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 @@ repeat: 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 @@ repeat: }
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 @@ repeat: 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 @@ repeat: 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 @@ repeat: 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 @@ unsigned long ext2_count_free_inodes (struct super_block * sb) 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 @@ void ext2_check_inodes_bitmap (struct super_block * sb) 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);
}
* 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 <asm/uaccess.h>
@@ -52,7+54,7 @@ static inline int block_bmap (struct buffer_head * bh, int nr)
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 @@ static int ext2_alloc_block (struct inode * inode, unsigned long goal, int * err 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 @@ repeat: 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 @@ static struct buffer_head * block_getblk (struct inode * inode, }
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 @@ repeat: 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 @@ repeat: 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 @@ static int block_getcluster (struct inode * inode, struct buffer_head * bh, 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 @@ void ext2_read_inode (struct inode * inode) 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 @@ void ext2_read_inode (struct inode * inode) */
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 @@ void ext2_read_inode (struct inode * inode) 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 @@ void ext2_read_inode (struct inode * inode) 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 @@ static int ext2_update_inode(struct inode * inode, int do_sync)
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 @@ static int ext2_update_inode(struct inode * inode, int do_sync) */
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 @@ static int ext2_update_inode(struct inode * inode, int do_sync) 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) {
* 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 <asm/uaccess.h>
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 @@ static struct buffer_head * ext2_find_entry (struct inode * dir, 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 @@ static struct buffer_head * ext2_find_entry (struct inode * dir, *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 @@ int ext2_lookup (struct inode * dir, const char * name, int len, 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 @@ static struct buffer_head * ext2_add_entry (struct inode * dir, 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 @@ static struct buffer_head * ext2_add_entry (struct inode * dir, 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 @@ static struct buffer_head * ext2_add_entry (struct inode * dir, *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 @@ static int ext2_delete_entry (struct ext2_dir_entry * dir, 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 @@ int ext2_create (struct inode * dir,const char * name, int len, int mode, 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 @@ int ext2_mknod (struct inode * dir, const char * name, int len, int mode, 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 @@ int ext2_mkdir (struct inode * dir, const char * name, int len, int mode) }
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 @@ int ext2_mkdir (struct inode * dir, const char * name, int len, int mode) 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 @@ static int empty_dir (struct inode * inode) 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 @@ static int empty_dir (struct inode * inode) 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 @@ repeat: 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 @@ repeat: 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 @@ repeat: 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 @@ repeat: 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 @@ repeat: 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 @@ int ext2_symlink (struct inode * dir, const char * name, int len, 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 @@ int ext2_link (struct inode * oldinode, struct inode * dir, 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 @@ static int subdir (struct inode * new_inode, struct inode * old_inode)
#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 @@ start_up: 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 @@ start_up: 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 @@ start_up: 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 @@ start_up: /*
* 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 @@ start_up: 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--;
* 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 <linux/module.h>
@@ -39,7+42,8 @@ void ext2_error (struct super_block * sb, const char * function,
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 @@ void ext2_error (struct super_block * sb, const char * function, 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 @@ NORET_TYPE void ext2_panic (struct super_block * sb, const char * function,
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 @@ void ext2_put_super (struct super_block * sb)
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 int parse_options (char * options, unsigned long * sb_block, 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 @@ static void ext2_setup_super (struct super_block * sb, 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 @@ static int ext2_check_descriptors (struct super_block * sb) {
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 @@ static int ext2_check_descriptors (struct super_block * sb) {
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 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data, */
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 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data, 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 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data, }
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 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data, }
}
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 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data, 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 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data, 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 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data, 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 @@ void ext2_write_super (struct super_block * sb)
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 @@ int ext2_remount (struct super_block * sb, int * flags, char * data) 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 @@ int ext2_remount (struct super_block * sb, int * flags, char * data) * 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 @@ void ext2_statfs (struct super_block * sb, struct statfs * buf, int bufsiz) 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);
* 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 @@ repeat: 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 @@ repeat: 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 @@ repeat: 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 @@ repeat: 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 @@ repeat: 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 @@ repeat: 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 @@ repeat: 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)
@@ -160,4+160,14 @@ found_middle: #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 */
#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);
extern unsigned long int htonl(unsigned long int);
@@ -387,6+387,16 @@ extern long __strncpy_from_user(char *__to, const char *__from, long __to_len); __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:
@@ -134,4+134,14 @@ extern __inline__ unsigned long ffz(unsigned long word) 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 */
/* For avoiding bswap on i386 */
#ifdef __KERNEL__
#include <linux/config.h>
+
+/*
+ * 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);
@@ -407,5+407,33 @@ strncpy_from_user(char *dst, const char *src, long count) 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 */
@@ -122,6+122,7 @@ extern int max_files, nr_files; #ifdef __KERNEL__
#include <asm/semaphore.h>
+#include <asm/byteorder.h>
#include <asm/bitops.h>
extern void buffer_init(void);
@@ -665,6+666,7 @@ extern long generic_file_read(struct inode *, struct file *, char *, unsigned lo
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);
@@ -118,6+118,7 @@ struct sockaddr_in { #define INADDR_ALLHOSTS_GROUP 0xe0000001 /* 224.0.0.1 */
#define INADDR_MAX_LOCAL_GROUP 0xe00000ff /* 224.0.0.255 */
+
/* <asm/byteorder.h> contains the htonl type stuff.. */
#include <asm/byteorder.h>
@@ -465,8+465,8 @@ extern __inline__ void skb_trim(struct sk_buff *skb, int len)
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__ */
@@ -175,8+175,8 @@ extern __inline__ struct cmsghdr * cmsg_nxthdr(struct msghdr *mhdr, #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 @@ extern unsigned int csum_partial_copy_fromiovecend(unsigned char *kdata, 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
@@ -106,11+106,11 @@ extern void ip_queue_xmit(struct sock *sk, 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,
@@ -133,7+133,7 @@ extern int ipv6_reassembly(struct sk_buff **skb, * 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);
@@ -382,7+382,7 @@ static __inline__ unsigned short tcp_raise_window(struct sock *sk) * 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 @@ static __inline__ unsigned short tcp_raise_window(struct sock *sk) 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"
@@ -736,16+736,15 @@ int atif_ioctl(int cmd, void *arg) 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 @@ int atif_ioctl(int cmd, void *arg) ((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 @@ static int atrtr_ioctl(unsigned int cmd, void *arg) 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 @@ static int atalk_getsockopt(struct socket *sock, int level, int optname, 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 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len, int n 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 @@ static int atalk_recvmsg(struct socket *sock, struct msghdr *msg, int size, int 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 @@ static int atalk_recvmsg(struct socket *sock, struct msghdr *msg, int size, int 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 @@ static int atalk_recvmsg(struct socket *sock, struct msghdr *msg, int size, int 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 @@ static int atalk_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg) {
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 @@ static int atalk_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg) 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 = {
@@ -1442,22+1442,20 @@ int br_ioctl(unsigned int cmd, void *arg) 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)
@@ -166,9+166,15 @@ void skb_free_datagram(struct sock * sk, struct sk_buff *skb) * 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 @@ void skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size) * 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;
}
/*
@@ -793,11+793,10 @@ static int dev_ifconf(char *arg) /*
* 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 @@ static int dev_ifconf(char *arg) * 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 @@ static int dev_ifconf(char *arg) * 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 @@ static int dev_ifconf(char *arg)
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 @@ static int dev_ifsioc(void *arg, unsigned int getset) {
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 @@ static int dev_ifsioc(void *arg, unsigned int getset) (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 @@ static int dev_ifsioc(void *arg, unsigned int getset) * 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;
}
* 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 @@ extern inline int min(int x, int y) 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 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode)
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 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode)
for(ct=0;ct<m->msg_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 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode) * 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 @@ void memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len) }
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 @@ void memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len) }
iov++;
}
+ return 0;
}
@@ -114,9+139,10 @@ void memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len) * 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 @@ void memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, 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 @@ void memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, *
* 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 @@ unsigned int csum_partial_copy_fromiovecend(unsigned char *kdata, 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 @@ unsigned int csum_partial_copy_fromiovecend(unsigned char *kdata, }
}
- 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++;
@@ -634,7+634,7 @@ void kfree_skb(struct sk_buff *skb, int rw) 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 @@ struct sk_buff *alloc_skb(unsigned int size,int priority) }
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 @@ struct sk_buff *skb_clone(struct sk_buff *skb, int priority) 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);
*/
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 @@ int sock_setsockopt(struct sock *sk, int level, int optname,
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 @@ int sock_setsockopt(struct sock *sk, int level, int optname, if(val > 65535)
val = 65535;
sk->sndbuf = val;
- return 0;
+ break;
case SO_RCVBUF:
if(val > SK_RMEM_MAX*2)
@@ -189,41+193,45 @@ int sock_setsockopt(struct sock *sk, int level, int optname, 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 @@ int sock_setsockopt(struct sock *sk, int level, int optname, 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 @@ int sock_getsockopt(struct sock *sk, int level, int optname, 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 @@ int sock_getsockopt(struct sock *sk, int level, int optname, 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)
@@ -1208,10+1208,9 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) {
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 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) 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));
@@ -2179,20+2179,18 @@ int arp_ioctl(unsigned int cmd, void *arg) 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 @@ int arp_ioctl(unsigned int cmd, void *arg) }
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 @@ int arp_ioctl(unsigned int cmd, void *arg) 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*/
@@ -474,16+474,17 @@ static void icmp_out_count(int type) * 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 @@ static void icmp_glue_bits(const void *p, __u32 saddr, char *to, unsigned int of fraglen-sizeof(struct icmphdr), csum);
icmph=(struct icmphdr *)to;
icmph->checksum = csum_fold(csum);
+
+ return 0;
}
/*
@@ -504,11+504,11 @@ fragment: */
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 @@ int ip_build_xmit(struct sock *sk, 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 @@ int ip_build_xmit(struct sock *sk, }
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 @@ int ip_build_xmit(struct sock *sk, 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 @@ int ip_build_xmit(struct sock *sk, 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 @@ int ip_build_xmit(struct sock *sk, {
ip_statistics.IpOutDiscards++;
if(nfrags>1)
- ip_statistics.IpFragCreates++;
+ ip_statistics.IpFragCreates++;
dev_unlock_list();
return(error);
}
@@ -795,7+809,7 @@ int ip_build_xmit(struct sock *sk, 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 @@ int ip_build_xmit(struct sock *sk, * 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);
@@ -123,11+123,11 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt }
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 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt 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 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt /*
* 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 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt * 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 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt * 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 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt 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 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt 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 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *op {
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 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *op 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 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *op 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 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *op 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);
}
@@ -447,11+447,11 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char *optval,int optlen) 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 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char *optval,int optlen) 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 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char *optval,int optlen) */
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 @@ int ip_mroute_getsockopt(struct sock *sk,int optname,char *optval,int *optlen) 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 @@ int ipmr_ioctl(struct sock *sk, int cmd, unsigned long arg) 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 @@ int ipmr_ioctl(struct sock *sk, int cmd, unsigned long arg) 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;
}
@@ -120,7+120,8 @@ static int packet_sendmsg(struct sock *sk, struct msghdr *msg, int len, 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 @@ static int packet_sendmsg(struct sock *sk, struct msghdr *msg, int len,
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 @@ int packet_recvmsg(struct sock *sk, struct msghdr *msg, int len,
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;
/*
@@ -289,9+289,12 @@ static int rarp_req_set(struct arpreq *req) 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 @@ static int rarp_req_get(struct arpreq *req) 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 @@ static int rarp_req_get(struct arpreq *req) * 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 @@ int rarp_ioctl(unsigned int cmd, void *arg) 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 @@ int rarp_ioctl(unsigned int cmd, void *arg) 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;
@@ -161,18+161,22 @@ int raw_rcv(struct sock *sk, struct sk_buff *skb, struct device *dev, __u32 sadd * 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 @@ static void raw_getrawfrag(const void *p, __u32 saddr, char *to, unsigned int of 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 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, int len, int noblock 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 @@ int raw_recvmsg(struct sock *sk, struct msghdr *msg, int len,
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 @@ int raw_recvmsg(struct sock *sk, struct msghdr *msg, int len, sin->sin_addr.s_addr = skb->daddr;
}
skb_free_datagram(sk, skb);
- return (copied);
+ return err ? err : (copied);
}
@@ -1696,10+1696,9 @@ int ip_rt_ioctl(unsigned int cmd, void *arg) 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);
}
@@ -658,7+658,6 @@ int tcp_select(struct sock *sk, int sel_type, select_table *wait)
int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
{
- int err;
switch(cmd)
{
@@ -675,21+674,12 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg) 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 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
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 @@ extern __inline int tcp_build_header(struct tcphdr *th, struct sock *sk, int pus 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 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, {
tmp += copy;
}
-
+
skb = sock_wmalloc(sk, tmp, 0, GFP_KERNEL);
/*
@@ -1106,6+1092,7 @@ static int tcp_recv_urg(struct sock * sk, int nonblock, 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 @@ static int tcp_recv_urg(struct sock * sk, int nonblock, 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 @@ static int tcp_recv_urg(struct sock * sk, int nonblock, *addr_len= tp->af_specific->sockaddr_len;
release_sock(sk);
- return 1;
+ return err ? -EFAULT : 1;
}
release_sock(sk);
@@ -1226,6+1213,7 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, 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 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, if (copied)
break;
copied = -ERESTARTSYS;
+ if (nonblock)
+ copied = -EAGAIN;
break;
}
@@ -1398,13+1388,28 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, *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 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, * 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 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char *optval, 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);
+ err = put_user(sizeof(int),(int *) optlen);
+ if (!err)
+ err = put_user(val,(int *)optval);
- return(0);
+ return err;
}
void tcp_set_keepalive(struct sock *sk, int val)
@@ -1849,6+1849,104 @@ void tcp_set_keepalive(struct sock *sk, int val) }
}
+
+/*
+ * 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;
+}
+
/*
* Local variables:
* compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strength-reduce -pipe -m486 -DCPU=486 -c -o tcp.o tcp.c"
@@ -194,11+194,18 @@ static int tcp_reset(struct sock *sk, struct sk_buff *skb) /*
* 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]
@@ -227,14+227,14 @@ struct udpfakehdr * 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 @@ static void udp_getfrag(const void *p, __u32 saddr, char * to, unsigned int offs ufh->uh.check = -1;
memcpy(to, ufh, sizeof(struct udphdr));
}
+ return 0;
}
/*
@@ -267,12+268,13 @@ static void udp_getfrag(const void *p, __u32 saddr, char * to, unsigned int offs * 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 @@ static void udp_getfrag_nosum(const void *p, __u32 saddr, char * to, unsigned in 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 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len, int noblock, 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_sendmsg(struct sock *sk, struct msghdr *msg, int len, int noblock,
int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
{
- int err;
switch(cmd)
{
case TIOCOUTQ:
@@ -483,12+490,7 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
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 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) */
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 @@ int udp_recvmsg(struct sock *sk, struct msghdr *msg, int len, * 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. */
@@ -13,6+13,7 @@ O_OBJS := af_inet6.o ipv6_output.o ipv6_input.o addrconf.o sit.o \ 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
@@ -774,7+774,7 @@ void addrconf_prefix_rcv(struct device *dev, u8 *opt, int len)
}
-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 @@ static void addrconf_ifdown(struct device *dev)
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 @@ static void addrconf_ifdown(struct device *dev)
kfree(idev);
end_bh_atomic();
+ return 0;
}
/*
@@ -1024,9+1026,12 @@ int addrconf_notify(struct notifier_block *this, unsigned long event, * 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;
}
@@ -107,7+107,7 @@ static int inet6_create(struct socket *sock, int protocol) struct proto *prot;
int err;
- sk = (struct sock *) kmalloc(sizeof(*sk), GFP_KERNEL);
+ sk = sk_alloc(GFP_KERNEL);
if (sk == NULL)
return(-ENOBUFS);
* 2 of the License, or (at your option) any later version.
*/
+/*
+ * Changes:
+ *
+ * Andi Kleen : exception handling
+ */
+
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/errno.h>
@@ -95,7+101,7 @@ struct icmpv6_msg { * 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 @@ static void icmpv6_getfrag(const void *data, struct in6_addr *saddr, 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 @@ static void icmpv6_getfrag(const void *data, struct in6_addr *saddr,
icmph->checksum = csum_ipv6_magic(saddr, msg->daddr, msg->len,
IPPROTO_ICMPV6, csum);
+ return 0;
}
/*
* 2 of the License, or (at your option) any later version.
*/
+/*
+ * Changes:
+ *
+ * Andi Kleen : exception handling
+ */
#include <linux/errno.h>
#include <linux/types.h>
@@ -440,7+445,7 @@ int ipv6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data, int pktlength;
int pmtu = 0;
int rt_flags = 0;
-
+ int error;
if (opt && opt->srcrt)
{
@@ -568,8+573,6 @@ int ipv6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data,
if (pktlength <= pmtu)
{
- int error;
-
struct sk_buff *skb =
sock_alloc_send_skb(sk, pktlength+15+
dev->hard_header_len,
@@ -624,14+627,22 @@ int ipv6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data, }
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 @@ int ipv6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data,
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
- */
-
- getfrag(data, &hdr->saddr, skb_put(skb, frag_len),
- nfrags * frag_len, frag_len);
+ 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;
+ }
+
+ 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");
@@ -164,10+164,6 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval, {
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;
@@ -124,9+124,12 @@ int rawv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
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 rawv6_fakehdr { 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 @@ static void rawv6_frag_cksum(const void *data, struct in6_addr *addr, printk(KERN_DEBUG "icmp: cksum offset too big\n");
}
}
+ return 0;
}
@@ -354,8+358,10 @@ static int rawv6_seticmpfilter(struct sock *sk, int level, int optname,
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;
@@ -172,7+172,7 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, int len, int copied = 0;
int truesize;
struct sk_buff *skb;
- int er;
+ int err;
/*
@@ -187,9+187,9 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, int len, * 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 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, int len, * 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 @@ struct udpv6fakehdr * 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 @@ static void udpv6_getfrag(const void *data, struct in6_addr *addr,
memcpy(buff, udh, sizeof(struct udphdr));
}
+ return 0;
}
static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen,
@@ -141,8+141,7 @@ ipxcfg_get_config_data(ipx_config_data *arg)
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 @@ ipxitf_ioctl_real(unsigned int cmd, void *arg) 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 @@ ipxitf_ioctl_real(unsigned int cmd, void *arg) 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 @@ static int ipxrtr_route_packet(ipx_socket *sk, struct sockaddr_ipx *usipx, struc 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 @@ static int ipxrtr_ioctl(unsigned int cmd, void *arg) 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 @@ static int ipx_getsockopt(struct socket *sock, int level, int optname, 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 @@ static int ipx_recvmsg(struct socket *sock, struct msghdr *msg, int size, int no 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 @@ static int ipx_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg) 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 @@ static int ipx_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg) 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:
@@ -85,12+85,13 @@ static int netlink_select(struct inode *inode, struct file *file, int sel_type, 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_write(struct inode * inode, struct file * file, 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 @@ static long netlink_read(struct inode * inode, struct file * file, char * buf, sti();
if(skb->len<count)
count=skb->len;
- 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,
@@ -159,8+159,7 @@ int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen) if(copy_to_user(uaddr,kaddr,len))
return -EFAULT;
}
- put_user(len, ulen);
- return 0;
+ return put_user(len, ulen);
}
/*
@@ -649,17+648,14 @@ asmlinkage int sys_socketpair(int family, int type, int protocol, int usockvec[2 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 @@ asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned int flags) 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 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags) 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 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags) 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 @@ int sock_fcntl(struct file *filp, unsigned int cmd, unsigned long arg)
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 @@ asmlinkage int sys_socketcall(int call, unsigned long *args) 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];
@@ -925,7+925,15 @@ static int unix_sendmsg(struct socket *sock, struct msghdr *msg, int len, int no }
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 @@ static int unix_recvmsg(struct socket *sock, struct msghdr *msg, int size, int n 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 @@ static int unix_recvmsg(struct socket *sock, struct msghdr *msg, int size, int n }
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 @@ static int unix_recvmsg(struct socket *sock, struct msghdr *msg, int size, int n 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_select(struct socket *sock, int sel_type, select_table *wait) 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: