Commit 942f4576 authored by Linus Torvalds's avatar Linus Torvalds

Import 1.3.90

parent b4dfb143
...@@ -202,6 +202,14 @@ S: 14509 NE 39th Street #1096 ...@@ -202,6 +202,14 @@ S: 14509 NE 39th Street #1096
S: Bellevue, Washington 98007 S: Bellevue, Washington 98007
S: USA S: USA
N: Stuart Cheshire
E: cheshire@cs.stanford.edu
D: Author of Starmode Radio IP (STRIP) driver
D: Originator of design for new combined interrupt handlers
S: William Gates Department
S: Stanford University
S: Stanford, California 94305, USA
N: Juan Jose Ciarlante N: Juan Jose Ciarlante
E: jjciarla@raiz.uncu.edu.ar E: jjciarla@raiz.uncu.edu.ar
D: Network driver alias support D: Network driver alias support
...@@ -264,10 +272,9 @@ E: davison@borland.com ...@@ -264,10 +272,9 @@ E: davison@borland.com
D: Second extended file system co-designer D: Second extended file system co-designer
N: Terry Dawson N: Terry Dawson
E: terryd@extro.ucc.su.oz.au E: terry@perf.no.itg.telecom.com.au
E: vk2ktj@gw.vk2ktj.ampr.org (Amateur Radio use only) E: terry@albert.vk2ktj.ampr.org (Amateur Radio use only)
D: NET-2-HOWTO author. D: AX25-HOWTO, HAM-HOWTO, IPX-HOWTO, NET-2-HOWTO
D: RADIOLINUX Amateur Radio software for Linux list collator.
N: Todd J. Derr N: Todd J. Derr
E: tjd@fore.com E: tjd@fore.com
......
This document contains a list of the latest releases of the most This document contains a list of the latest releases of the most
important packages for Linux. important packages for Linux as well as instructions for newcomers to
the 1.3.x series of kernels.
The installation information were removed because redundant. Last updated: Apr 15, 1996.
Authors: Alessandro Sigala (ssigala@globalnet.it) and Chris Ricker
Last updated: 14 Apr 1996.
Author: Alessandro Sigala (ssigala@globalnet.it).
Section "Upgrading to 1.3.x kernel" contributed by Chris Ricker
(gt1355b@prism.gatech.edu). (gt1355b@prism.gatech.edu).
Note: Due to time constraints, Alessandro is getting out of the Changes
business and I'll be picking up the job. Be gentle while I get my feet
wet ;-).
Current Releases Current Releases
**************** ****************
- Kernel modules Broken: 1.3.57, Exp: 1.3.69f - Kernel modules Stable: 1.3.57, Exp: 1.3.69f
- PPP daemon Stable: 2.2.0e, Exp: 2.2.0f-BETA6 - PPP daemon Stable: 2.2.0e, Exp: 2.2.0f-BETA6
- Dynamic linker (ld.so) 1.7.14 - Dynamic linker (ld.so) 1.7.14
- GNU CC 2.7.2 - GNU CC 2.7.2
- Binutils 2.6.0.12 - Binutils 2.6.0.12
- Linux C Library Latest: 5.3.9, Stable: 5.2.18 - Linux C Library Stable: 5.2.18, Exp: 5.3.9
- Linux C++ Library 2.7.1.4 - Linux C++ Library 2.7.1.4
- Termcap 2.0.7 - Termcap 2.0.7
- Procps 0.99a - Procps 0.99a
...@@ -31,14 +32,14 @@ What you really need to upgrade ...@@ -31,14 +32,14 @@ What you really need to upgrade
Dynamic linker Dynamic linker
============== ==============
You may upgrade the dynamic linker to the latest release only to You might upgrade the dynamic linker to the latest release, but only
solve some bugs. to solve some bugs.
SysVinit SysVinit
======== ========
The FIFO behavior is changed in latest 1.3.x kernel releases. You may The FIFO behavior is changed in the latest 1.3.x kernel releases.
upgrade to 2.60 if the older version breaks. Upgrade to 2.60 if the older version seems broken.
PPP daemon and utilities PPP daemon and utilities
======================== ========================
...@@ -65,12 +66,22 @@ modules compiled with new binutils can't be loaded by modules 1.3.57. ...@@ -65,12 +66,22 @@ modules compiled with new binutils can't be loaded by modules 1.3.57.
The Linux C Library The Linux C Library
=================== ===================
The current Linux C Library release is 5.3.9. In this release there The latest stable Linux C Library release is 5.2.18. If you upgrade
are some important changes that may break other programs, then read the to this from 5.0.9 or earlier, be sure to read the `release.libc-5.2.18'
`release.libc-5.3.9' file carefully! You need to patch and recompile file, since GNU make and a few other fairly important utils can be
the `make' utility, or get it precompiled from the address written at broken by the upgrade.
the end of this file. If you don't want to patch and recompile the
binaries you may try the release 5.2.18. The current (beta) Linux C Library release is 5.3.9. 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) then read
the `release.libc-5.3.9' 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).
The Termcap Library The Termcap Library
=================== ===================
...@@ -79,68 +90,71 @@ The Termcap Library ...@@ -79,68 +90,71 @@ The Termcap Library
read the `README' file contained into the package to get some important read the `README' file contained into the package to get some important
information about the `tgetent' function changes! information about the `tgetent' function changes!
Upgrading to 1.3.x kernel Upgrading to 1.3.x kernel from 1.2.13
************************* *************************************
This section was prepared by Chris Ricker and based on material from This section was based on material from the linux-kernel mailing
the linux-kernel mailing list, Jared Mauch's web page "Software Victims list, Jared Mauch's web page "Software Victims of the 1.3 Kernel
of the 1.3 Kernel Development" Development" (http://www2.nether.net/~jared/victim.html), and Axel
(http://www2.nether.net/~jared/victim.html), and Axel Boldt's Boldt's (boldt@math.ucsb.edu) Configure.help file, among other sources.
(boldt@math.ucsb.edu) Configure.help file, among other sources.
This section is intended primarily to help those that are new to the This section is intended primarily to help those that are new to the
1.3.x series of Linux kernels. In the ongoing effort to make a faster, 1.3.x series of Linux kernels. In the ongoing effort to make a faster,
better kernel and eventually achieve complete world domination, several better kernel and eventually achieve total world domination, several
features of the kernel have changed. As a result, when you first features of the Linux kernel have been improved. As a result, when you
upgrade to 1.3.x from 1.2.13, you will also have to upgrade several first upgrade to 1.3.x from 1.2.13, you will also have to upgrade
utilities that are closely associated with the kernel. several utilities that are closely associated with the kernel and make
use of these features.
Proc filesystem Proc filesystem
=============== ===============
Various changes in the /proc filesystem have been made, affecting ps, Various changes in the /proc filesystem have been made, affecting
top, etc. Running `top' or `ps -auwwx' will now give you a floating ps, top, etc. Running `top' or `ps -auwwx' will now give you a floating
point exception. To fix the problem, upgrade to procps-0.99a.tar.gz, point exception. To fix the problem, upgrade to procps-0.99a.tar.gz,
available at available at
ftp://tsx-11.mit.edu/pub/linux/BETA/procps/procps-0.99a.tar.gz (or else ftp://tsx-11.mit.edu/pub/linux/BETA/procps/procps-0.99a.tar.gz.
don't run top or ps with fancy switches and live with the incorrect
values ;-).
Modules Modules
======= =======
1.3.x is almost completely modularized, and kerneld is now 1.3.x is almost completely modularized, and kerneld is now
incorporated into the kernel. To take advantage of this, you'll need incorporated into the kernel. To take advantage of this, you'll need
the latest version of the module support apps. The latest non-beta the latest version of the module support apps. The latest non-beta is
(works fine for me) is modules-1.3.57.tar.gz, and the latest beta is modules-1.3.57.tar.gz, and the latest beta is modules-1.3.69f.tar.gz.
modules-1.3.69f.tar.gz. These should be available at the same place These should be available at the same place you picked up your kernel
you picked up your kernel (ftp://ftp.cc.gatech.edu/pub/linux/kernel/) (ftp://ftp.cc.gatech.edu/pub/linux/kernel/) and the home page is
and the home page is http://www.pi.se/blox/modules/index.html. Note: http://www.pi.se/blox/modules/index.html. Note: If you try to load a
If you try to load a module and get a message like module and get a message like
gcc2_compiled, undefined Failed to load module! The symbols from `gcc2_compiled, undefined Failed to load module! The symbols from
kernel 1.3.foo don't match 1.3.foo kernel 1.3.foo don't match 1.3.foo'
where foo is a number between 1 and 87, then it's time to upgrade where `foo' is a number between 1 and 89, then it's time to upgrade
module utilities from 1.3.57 to 1.3.69f (you'll only get this if you're module utilities from 1.3.57 to 1.3.69f; you'll only get this error if
running the latest binutils as well). Another little tip: you can't you're running the latest binutils, so most people don't need to
have both a.out *and* ELF support compiled as modules. Otherwise, you upgrade.
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 Another little tip: you can't have both a.out *and* ELF support
need a.out for the occasional Netscape session, then you can do a.out compiled as modules. Otherwise, you get a nice Catch-22 when you try
support as a module. Otherwise, you should probably leave it in the to run insmod to install a.out/ELF support so you can run insmod ;-).
kernel. Similarly, any partitions that you have to mount at startup If you have an all-ELF system, but need a.out for the occasional
have to have their necessary drivers compiled into the kernel, so don't Netscape session, then you can do a.out support as a module.
get grandiose ideas about going completely modular and then forget to Otherwise, you should probably leave it in the kernel, and if you
compile ext2fs support into your kernel ;-). 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 drive support into your
kernel ;-).
PPP driver PPP driver
========== ==========
The PPP driver was upgraded (and is still in somewhat of a a state of You need to be running a pppd from ppp-2.2.0.tar.gz or greater. The
flux). You need to be running a pppd from ppp-2.2.0.tar.gz or greater. latest stable release is 2.2.0e and is available at
The latest is 2.2.0e and is available at ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/ppp-2.2.0e.tar.gz,
ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/ppp-2.2.0e.tar.gz. along with a patch necessary to make it compile.
Named pipes Named pipes
=========== ===========
...@@ -148,7 +162,7 @@ Named pipes ...@@ -148,7 +162,7 @@ Named pipes
Linux's handling of named pipes changed (it now does it The Right Way 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 instead of the SunOS way ;-). This broke some programs that depended
on the SunOS behavior, most notably SysVinit. If you're running 2.59 on the SunOS behavior, most notably SysVinit. If you're running 2.59
or earlier, you will probably get a wierd error on shutdown in which or earlier, you will probably get a weird error on shutdown in which
your computer shuts down fine but "INIT: error reading initrequest" or your computer shuts down fine but "INIT: error reading initrequest" or
words to that effect scroll across your screen hundreds of times. To words to that effect scroll across your screen hundreds of times. To
fix, upgrade to fix, upgrade to
...@@ -173,11 +187,14 @@ the following as root: ...@@ -173,11 +187,14 @@ the following as root:
ln -s /usr/lib/terminfo/l/linux /usr/lib/terminfo/c/console 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.7.tar.gz
Hdparm Hdparm
====== ======
Hdparm has been upgraded to take advantage of the latest features of Hdparm has been upgraded to take advantage of the latest features of
the kernel drivers. The latest can be found at the kernel drivers. The latest non-beta version can be found at
ftp://sunsite.unc.edu/pub/Linux/kernel/patches/diskdrives/hdparm-2.7.tar.gz. ftp://sunsite.unc.edu/pub/Linux/kernel/patches/diskdrives/hdparm-2.7.tar.gz.
IP Accounting IP Accounting
...@@ -228,17 +245,19 @@ libc you upgraded to. The latest libc and release notes can be found at ...@@ -228,17 +245,19 @@ 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 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 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. 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. 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 Loop device
=========== ===========
1.3.x kernels include loop device support which lets you mount a file 1.3.x kernels include loop device support which lets you mount a
as a file system, which can allow for all sorts of cool things like file as a file system, which can allow for all sorts of cool things
encrypted file systems and such. To use it, you'll need a modified like encrypted file systems and such. To use it, you'll need a
version of mount from modified version of mount from
ftp://ftp.win.tue.nl:/pub/linux/util/mount-2.5X.tar.gz and work on ftp://ftp.win.tue.nl:/pub/linux/util/mount-2.5X.tar.gz and preliminary
encrypted file system support can be found in work on encrypted file system support can be found in
ftp.funet.fi:/pub/OS/Linux/BETA/loop/des.1.tar.gz. ftp.funet.fi:/pub/OS/Linux/BETA/loop/des.1.tar.gz.
Multiple device Multiple device
...@@ -259,15 +278,14 @@ arpd. ...@@ -259,15 +278,14 @@ arpd.
Quota Quota
===== =====
Quota support has also been added. You need to get Quota support has also been added. You need to get quotas-1.51 from
ftp://sunsite.unc.edu/pub/Linux/system/Admin/quota_acct.tar.gz to enable ftp://ftp.funet.fi/pub/Linux/PEOPLE/Linus/subsystems/quota/all.tar.gz.
quotas. The version that is currently there does not compile, though I This will compile just fine after you copy its mntent.h over to
am uploading a patched one that will compile as I write this (look for /usr/include/mntent.h.
quota-acct-modified.tgz).
Please send info about any other packages that 1.3.x "broke" or about Please send info about any other packages that 1.3.x "broke" or about
any new features of 1.3.x that require extra packages for use to Chris any new features of 1.3.x that require extra packages for use to Chris
Ricker (gt1355b@prism.gatech.edu) or me. Ricker (gt1355b@prism.gatech.edu).
How to know the version of the installed programs How to know the version of the installed programs
************************************************* *************************************************
...@@ -310,6 +328,8 @@ ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.3.9.bin.tar.gz ...@@ -310,6 +328,8 @@ ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.3.9.bin.tar.gz
Installation notes: Installation notes:
ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.3.9 ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.3.9
Patched make sources:
ftp://sunsite.unc.edu/pub/Linux/devel/make/make-3.74.patched.tar.gz
Patched make binary: Patched make binary:
ftp://sunsite.unc.edu/pub/Linux/devel/make/make-3.74-direntfix-elf.tgz ftp://sunsite.unc.edu/pub/Linux/devel/make/make-3.74-direntfix-elf.tgz
......
...@@ -1241,7 +1241,7 @@ EATA-PIO (old DPT PM2001, PM2012A) support ...@@ -1241,7 +1241,7 @@ EATA-PIO (old DPT PM2001, PM2012A) support
CONFIG_SCSI_EATA_PIO CONFIG_SCSI_EATA_PIO
This driver supports all EATA-PIO protocol compliant SCSI Host Adaptors This driver supports all EATA-PIO protocol compliant SCSI Host Adaptors
like the DPT PM2001 and the PM2012A. EATA-DMA compliant HBAs can also use like the DPT PM2001 and the PM2012A. EATA-DMA compliant HBAs can also use
this driver but are discuraged from doing so, since this driver only this driver but are discouraged from doing so, since this driver only
supports harddisks and lacks numerous features. supports harddisks and lacks numerous features.
You might want to have a look at the SCSI-HOWTO, available via ftp You might want to have a look at the SCSI-HOWTO, available via ftp
(user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO. (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO.
...@@ -1334,9 +1334,12 @@ CONFIG_SCSI_IN2000 ...@@ -1334,9 +1334,12 @@ CONFIG_SCSI_IN2000
explained in section 3.6 of the SCSI-HOWTO, available via ftp (user: explained in section 3.6 of the SCSI-HOWTO, available via ftp (user:
anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO. If it doesn't anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO. If it doesn't
work out of the box, you may have to change some settings in work out of the box, you may have to change some settings in
drivers/scsi/inn2000.h. If you want to compile this as a module ( = drivers/scsi/in2000.h. You may also want to drop in a rewritten,
code which can be inserted in and removed from the running kernel and probably more reliable, driver from John Shifflett, which you
whenever you want), say M here and read Documentation/modules.txt. can get from ftp://ftp.netcom.com/pub/js/jshiffle/in2000/ . If you
want to compile this as a module ( = code which can be inserted in
and removed from the running kernel whenever you want), say M here
and read Documentation/modules.txt.
PAS16 SCSI support PAS16 SCSI support
CONFIG_SCSI_PAS16 CONFIG_SCSI_PAS16
...@@ -1357,7 +1360,7 @@ CONFIG_SCSI_QLOGIC ...@@ -1357,7 +1360,7 @@ CONFIG_SCSI_QLOGIC
Seagate ST-02 and Future Domain TMC-8xx SCSI support Seagate ST-02 and Future Domain TMC-8xx SCSI support
CONFIG_SCSI_SEAGATE CONFIG_SCSI_SEAGATE
These are 8-bit SCSI controller; the ST-01 is also supported by this These are 8-bit SCSI controllers; the ST-01 is also supported by this
driver. It is explained in section 3.9 of the SCSI-HOWTO, available driver. It is explained in section 3.9 of the SCSI-HOWTO, available
via ftp (user: anonymous) at via ftp (user: anonymous) at
sunsite.unc.edu:/pub/Linux/docs/HOWTO. If it doesn't work out of the sunsite.unc.edu:/pub/Linux/docs/HOWTO. If it doesn't work out of the
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
Andy Walker <andy@lysaker.kvaerner.no> Andy Walker <andy@lysaker.kvaerner.no>
06 April 1996 15 April 1996
What is mandatory locking? What is mandatory locking?
...@@ -41,7 +41,8 @@ to entire files, so the mandatory locking rules also have byte level ...@@ -41,7 +41,8 @@ to entire files, so the mandatory locking rules also have byte level
granularity. granularity.
Note 2: POSIX.1 does not specify any scheme for mandatory locking, despite Note 2: POSIX.1 does not specify any scheme for mandatory locking, despite
borrowing the fcntl() locking scheme from System V. borrowing the fcntl() locking scheme from System V. The mandatory locking
scheme is defined by the System V Interface Definition (SVID) Version 3.
Marking a file for mandatory locking Marking a file for mandatory locking
------------------------------------ ------------------------------------
...@@ -66,25 +67,23 @@ SunOS 4.1.x, Solaris 2.x and HP-UX 9.x. ...@@ -66,25 +67,23 @@ SunOS 4.1.x, Solaris 2.x and HP-UX 9.x.
Generally I have tried to make the most sense out of the behaviour exhibited Generally I have tried to make the most sense out of the behaviour exhibited
by these three reference systems. There are many anomalies. by these three reference systems. There are many anomalies.
Originally I wrote (about SunOS): All the reference systems reject all calls to open() for a file on which
"For one thing, calls to open() for a file fail with EAGAIN if another another process has outstanding mandatory locks. This is in direct
process holds a mandatory lock on the file. However, processes already contravention of SVID 3, which states that only calls to open() with the
holding open file descriptors can carry on using them. Weird!" O_TRUNC flag set should be rejected. The Linux implementation follows the SVID
definition, which is the "Right Thing", since only calls with O_TRUNC can
Well, all my reference systems do it, so I decided to go with the flow. modify the contents of the file.
My gut feeling is that only calls to open() and creat() with O_TRUNC should be
rejected, as these are the only ones that try to modify the file contents as
part of the open() call.
HP-UX even disallows open() with O_TRUNC for a file with advisory locks, not HP-UX even disallows open() with O_TRUNC for a file with advisory locks, not
just mandatory locks. That to me contravenes POSIX.1. just mandatory locks. That would appear to contravene POSIX.1.
mmap() is another interesting case. All the operating systems mentioned mmap() is another interesting case. All the operating systems mentioned
prevent mandatory locks from being applied to an mmap()'ed file, but HP-UX prevent mandatory locks from being applied to an mmap()'ed file, but HP-UX
also disallows advisory locks for such a file. also disallows advisory locks for such a file. SVID actually specifies the
paranoid HP-UX behaviour.
My opinion is that only MAP_SHARED mappings should be immune from locking, and In my opinion only MAP_SHARED mappings should be immune from locking, and then
then only from mandatory locks - that is what is currently implemented. only from mandatory locks - that is what is currently implemented.
SunOS is so hopeless that it doesn't even honour the O_NONBLOCK flag for SunOS is so hopeless that it doesn't even honour the O_NONBLOCK flag for
mandatory locks, so reads and writes to locked files always block when they mandatory locks, so reads and writes to locked files always block when they
...@@ -113,8 +112,9 @@ Semantics ...@@ -113,8 +112,9 @@ Semantics
unless a process has opened the file with the O_NONBLOCK flag in which case unless a process has opened the file with the O_NONBLOCK flag in which case
the system call will return immediately with the error status EAGAIN. the system call will return immediately with the error status EAGAIN.
4. Calls to open() or creat() on a file that has any mandatory locks owned 4. Calls to open() with O_TRUNC, or to creat(), on a existing file that has
by other processes will be rejected with the error status EAGAIN. any mandatory locks owned by other processes will be rejected with the
error status EAGAIN.
5. Attempts to apply a mandatory lock to a file that is memory mapped and 5. Attempts to apply a mandatory lock to a file that is memory mapped and
shared (via mmap() with MAP_SHARED) will be rejected with the error status shared (via mmap() with MAP_SHARED) will be rejected with the error status
......
...@@ -193,6 +193,12 @@ M: longyear@netcom.com, Cc: longyear@sii.com ...@@ -193,6 +193,12 @@ M: longyear@netcom.com, Cc: longyear@sii.com
L: linux-ppp@vger.rutgers.edu L: linux-ppp@vger.rutgers.edu
S: Maintained S: Maintained
STARMODE RADIO IP (STRIP) PROTOCOL DRIVER
P: Stuart Cheshire
M: cheshire@cs.stanford.edu
W: http://mosquitonet.Stanford.EDU/strip.html
S: Maintained
SMB FILESYSTEM: SMB FILESYSTEM:
P: Volker Lendecke P: Volker Lendecke
M: lendecke@namu01.gwdg.de M: lendecke@namu01.gwdg.de
......
...@@ -82,55 +82,98 @@ if (!(context.x & 0xfffc) || (context.x & 3) != 3) goto badframe; COPY(x); ...@@ -82,55 +82,98 @@ if (!(context.x & 0xfffc) || (context.x & 3) != 3) goto badframe; COPY(x);
* Set up a signal frame... Make the stack look the way iBCS2 expects * Set up a signal frame... Make the stack look the way iBCS2 expects
* it to look. * it to look.
*/ */
void setup_frame(struct sigaction * sa, unsigned long ** fp, unsigned long eip, static void setup_frame(struct sigaction * sa,
struct pt_regs * regs, int signr, unsigned long oldmask) struct pt_regs * regs, int signr,
unsigned long oldmask)
{ {
unsigned long * frame; unsigned long * frame;
#define __CODE ((unsigned long)(frame+24)) frame = (unsigned long *) regs->esp;
#define CODE(x) ((unsigned long *) ((x)+__CODE))
frame = *fp;
if (regs->ss != USER_DS && sa->sa_restorer) if (regs->ss != USER_DS && sa->sa_restorer)
frame = (unsigned long *) sa->sa_restorer; frame = (unsigned long *) sa->sa_restorer;
frame -= 32; frame -= 32;
if (verify_area(VERIFY_WRITE,frame,32*4)) if (verify_area(VERIFY_WRITE,frame,32*4))
do_exit(SIGSEGV); do_exit(SIGSEGV);
/* set up the "normal" stack seen by the signal handler (iBCS2) */ /* set up the "normal" stack seen by the signal handler (iBCS2) */
put_fs_long(__CODE,frame); #define __CODE ((unsigned long)(frame+24))
#define CODE(x) ((unsigned long *) ((x)+__CODE))
put_user(__CODE,frame);
if (current->exec_domain && current->exec_domain->signal_invmap) if (current->exec_domain && current->exec_domain->signal_invmap)
put_fs_long(current->exec_domain->signal_invmap[signr], frame+1); put_user(current->exec_domain->signal_invmap[signr], frame+1);
else else
put_fs_long(signr, frame+1); put_user(signr, frame+1);
put_fs_long(regs->gs, frame+2); put_user(regs->gs, frame+2);
put_fs_long(regs->fs, frame+3); put_user(regs->fs, frame+3);
put_fs_long(regs->es, frame+4); put_user(regs->es, frame+4);
put_fs_long(regs->ds, frame+5); put_user(regs->ds, frame+5);
put_fs_long(regs->edi, frame+6); put_user(regs->edi, frame+6);
put_fs_long(regs->esi, frame+7); put_user(regs->esi, frame+7);
put_fs_long(regs->ebp, frame+8); put_user(regs->ebp, frame+8);
put_fs_long((long)*fp, frame+9); put_user(regs->esp, frame+9);
put_fs_long(regs->ebx, frame+10); put_user(regs->ebx, frame+10);
put_fs_long(regs->edx, frame+11); put_user(regs->edx, frame+11);
put_fs_long(regs->ecx, frame+12); put_user(regs->ecx, frame+12);
put_fs_long(regs->eax, frame+13); put_user(regs->eax, frame+13);
put_fs_long(current->tss.trap_no, frame+14); put_user(current->tss.trap_no, frame+14);
put_fs_long(current->tss.error_code, frame+15); put_user(current->tss.error_code, frame+15);
put_fs_long(eip, frame+16); put_user(regs->eip, frame+16);
put_fs_long(regs->cs, frame+17); put_user(regs->cs, frame+17);
put_fs_long(regs->eflags, frame+18); put_user(regs->eflags, frame+18);
put_fs_long(regs->esp, frame+19); put_user(regs->esp, frame+19);
put_fs_long(regs->ss, frame+20); put_user(regs->ss, frame+20);
put_fs_long(0,frame+21); /* 387 state pointer - not implemented*/ put_user(NULL,frame+21);
/* non-iBCS2 extensions.. */ /* non-iBCS2 extensions.. */
put_fs_long(oldmask, frame+22); put_user(oldmask, frame+22);
put_fs_long(current->tss.cr2, frame+23); put_user(current->tss.cr2, frame+23);
/* set up the return code... */ /* set up the return code... */
put_fs_long(0x0000b858, CODE(0)); /* popl %eax ; movl $,%eax */ put_user(0x0000b858, CODE(0)); /* popl %eax ; movl $,%eax */
put_fs_long(0x80cd0000, CODE(4)); /* int $0x80 */ put_user(0x80cd0000, CODE(4)); /* int $0x80 */
put_fs_long(__NR_sigreturn, CODE(2)); put_user(__NR_sigreturn, CODE(2));
*fp = frame;
#undef __CODE #undef __CODE
#undef CODE #undef CODE
/* Set up registers for signal handler */
regs->esp = (unsigned long) frame;
regs->eip = (unsigned long) sa->sa_handler;
regs->cs = USER_CS; regs->ss = USER_DS;
regs->ds = USER_DS; regs->es = USER_DS;
regs->gs = USER_DS; regs->fs = USER_DS;
regs->eflags &= ~TF_MASK;
}
/*
* OK, we're invoking a handler
*/
static void handle_signal(unsigned long signr, struct sigaction *sa,
unsigned long oldmask, struct pt_regs * regs)
{
/* are we from a system call? */
if (regs->orig_eax >= 0) {
/* If so, check system call restarting.. */
switch (regs->eax) {
case -ERESTARTNOHAND:
regs->eax = -EINTR;
break;
case -ERESTARTSYS:
if (!(sa->sa_flags & SA_RESTART)) {
regs->eax = -EINTR;
break;
}
/* fallthrough */
case -ERESTARTNOINTR:
regs->eax = regs->orig_eax;
regs->eip -= 2;
}
}
/* set up the stack frame */
setup_frame(sa, regs, signr, oldmask);
if (sa->sa_flags & SA_ONESHOT)
sa->sa_handler = NULL;
current->blocked |= sa->sa_mask;
} }
/* /*
...@@ -145,9 +188,6 @@ void setup_frame(struct sigaction * sa, unsigned long ** fp, unsigned long eip, ...@@ -145,9 +188,6 @@ void setup_frame(struct sigaction * sa, unsigned long ** fp, unsigned long eip,
asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
{ {
unsigned long mask = ~current->blocked; unsigned long mask = ~current->blocked;
unsigned long handler_signal = 0;
unsigned long *frame = NULL;
unsigned long eip = 0;
unsigned long signr; unsigned long signr;
struct sigaction * sa; struct sigaction * sa;
...@@ -219,48 +259,19 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) ...@@ -219,48 +259,19 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
do_exit(signr); do_exit(signr);
} }
} }
/* handle_signal(signr, sa, oldmask, regs);
* OK, we're invoking a handler return 1;
*/
if (regs->orig_eax >= 0) {
if (regs->eax == -ERESTARTNOHAND ||
(regs->eax == -ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))
regs->eax = -EINTR;
}
handler_signal |= 1 << (signr-1);
mask &= ~sa->sa_mask;
} }
if (regs->orig_eax >= 0 &&
(regs->eax == -ERESTARTNOHAND || /* Did we come from a system call? */
regs->eax == -ERESTARTSYS || if (regs->orig_eax >= 0) {
regs->eax == -ERESTARTNOINTR)) { /* Restart the system call - no handlers present */
regs->eax = regs->orig_eax; if (regs->eax == -ERESTARTNOHAND ||
regs->eip -= 2; regs->eax == -ERESTARTSYS ||
} regs->eax == -ERESTARTNOINTR) {
if (!handler_signal) /* no handler will be called - return 0 */ regs->eax = regs->orig_eax;
return 0; regs->eip -= 2;
eip = regs->eip; }
frame = (unsigned long *) regs->esp;
signr = 1;
sa = current->sig->action;
for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
if (mask > handler_signal)
break;
if (!(mask & handler_signal))
continue;
setup_frame(sa,&frame,eip,regs,signr,oldmask);
eip = (unsigned long) sa->sa_handler;
if (sa->sa_flags & SA_ONESHOT)
sa->sa_handler = NULL;
regs->cs = USER_CS; regs->ss = USER_DS;
regs->ds = USER_DS; regs->es = USER_DS;
regs->gs = USER_DS; regs->fs = USER_DS;
current->blocked |= sa->sa_mask;
oldmask |= sa->sa_mask;
} }
regs->esp = (unsigned long) frame; return 0;
regs->eip = eip; /* "return" to the first handler */
regs->eflags &= ~TF_MASK;
current->tss.trap_no = current->tss.error_code = 0;
return 1;
} }
...@@ -442,39 +442,6 @@ struct request *get_md_request (int max_req, kdev_t dev) ...@@ -442,39 +442,6 @@ struct request *get_md_request (int max_req, kdev_t dev)
#endif #endif
/*
* Swap partitions are now read via brw_page. ll_rw_page is an
* asynchronous function now --- we must call wait_on_page afterwards
* if synchronous IO is required.
*/
void ll_rw_page(int rw, kdev_t dev, unsigned long page, char * buffer)
{
unsigned int major = MAJOR(dev);
int block = page;
if (major >= MAX_BLKDEV || !(blk_dev[major].request_fn)) {
printk("Trying to read nonexistent block-device %s (%ld)\n",
kdevname(dev), page);
return;
}
switch (rw) {
case READ:
break;
case WRITE:
if (is_read_only(dev)) {
printk("Can't page to read-only device %s\n",
kdevname(dev));
return;
}
break;
default:
panic("ll_rw_page: bad block dev cmd, must be R/W");
}
if (set_bit(PG_locked, &mem_map[MAP_NR(buffer)].flags))
panic ("ll_rw_page: page already locked");
brw_page(rw, (unsigned long) buffer, dev, &block, PAGE_SIZE, 0);
}
/* This function can be used to request a number of buffers from a block /* This function can be used to request a number of buffers from a block
device. Currently the only restriction is that all buffers must belong to device. Currently the only restriction is that all buffers must belong to
the same device */ the same device */
......
...@@ -692,7 +692,7 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev) ...@@ -692,7 +692,7 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev)
dev->tbusy = 0; dev->tbusy = 0;
} else } else
/* Interrupt us when the FIFO has room for max-sized packet. */ /* Interrupt us when the FIFO has room for max-sized packet. */
outw(SetTxThreshold + 1536, ioaddr + EL3_CMD); outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
} }
#else #else
/* ... and the packet rounded to a doubleword. */ /* ... and the packet rounded to a doubleword. */
...@@ -702,7 +702,7 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev) ...@@ -702,7 +702,7 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev)
dev->tbusy = 0; dev->tbusy = 0;
} else } else
/* Interrupt us when the FIFO has room for max-sized packet. */ /* Interrupt us when the FIFO has room for max-sized packet. */
outw(SetTxThreshold + 1536, ioaddr + EL3_CMD); outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
#endif /* bus master */ #endif /* bus master */
dev->trans_start = jiffies; dev->trans_start = jiffies;
......
...@@ -626,7 +626,7 @@ int dlci_setup(void) ...@@ -626,7 +626,7 @@ int dlci_setup(void)
} }
#ifdef MODULE #ifdef MODULE
static struct device dlci = {devname, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, dlci_init, }; static struct device dlci = {"dlci", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, dlci_init, };
int init_module(void) int init_module(void)
{ {
......
/* /* $Id: eexpress.c,v 1.12 1996/04/15 17:27:30 phil Exp $
* eexpress2.c: Intel EtherExpress device driver for Linux *
* Intel EtherExpress device driver for Linux
* *
* Original version written 1993 by Donald Becker * Original version written 1993 by Donald Becker
* Modularized by Pauline Middelink <middelin@polyware.iaf.nl> * Modularized by Pauline Middelink <middelin@polyware.iaf.nl>
* Changed to support io= irq= by Alan Cox <Alan.Cox@linux.org> * Changed to support io= irq= by Alan Cox <Alan.Cox@linux.org>
* Reworked 1995 by John Sullivan <js10039@cam.ac.uk> * Reworked 1995 by John Sullivan <js10039@cam.ac.uk>
* * More fixes by Philip Blundell <pjb27@cam.ac.uk>
* 06mar96 Philip Blundell <pjb27@cam.ac.uk>
* - move started, buffer sizes, and so on into private data area.
* - fix module loading for multiple cards
*
* 31jan96 Philip Blundell <pjb27@cam.ac.uk>
* - Tidy up
* - Some debugging. Now works with 1.3 kernels.
*
* Still to do:
* - rationalise debugging
* - fix detect/autoprobe and module routines
* - test under high load, try to chase CU lockups
* - look at RAM size check
*
* ToDo:
* Multicast/Promiscuous mode handling
* Put back debug reporting?
* More documentation
* Some worry about whether statistics are reported accurately
*
*/ */
/* /*
...@@ -76,6 +57,9 @@ ...@@ -76,6 +57,9 @@
* occasionally (or buy a new NIC). By the way, this looks like a * occasionally (or buy a new NIC). By the way, this looks like a
* definite card bug, since Intel's own driver for DOS does exactly the * definite card bug, since Intel's own driver for DOS does exactly the
* same. * same.
*
* This bug makes switching in and out of promiscuous mode a risky
* business, since we must do a 586 reset each time.
*/ */
/* /*
...@@ -101,8 +85,8 @@ ...@@ -101,8 +85,8 @@
*/ */
static char version[] = static char version[] =
"eexpress.c: v0.07 1/19/94 Donald Becker <becker@super.org>\n" "eexpress.c: v0.10 04-May-95 John Sullivan <js10039@cam.ac.uk>\n"
" v0.10 4th May 1995 John Sullivan <js10039@cam.ac.uk>\n"; " v0.13 10-Apr-96 Philip Blundell <phil@tazenda.demon.co.uk>\n";
#include <linux/module.h> #include <linux/module.h>
...@@ -141,8 +125,6 @@ static char version[] = ...@@ -141,8 +125,6 @@ static char version[] =
* 7 Report function entry/exit * 7 Report function entry/exit
*/ */
#undef NET_DEBUG
#ifndef NET_DEBUG #ifndef NET_DEBUG
#define NET_DEBUG 4 #define NET_DEBUG 4
#endif #endif
...@@ -171,6 +153,7 @@ struct net_local ...@@ -171,6 +153,7 @@ struct net_local
unsigned short tx_link; /* last known-executing tx buf */ unsigned short tx_link; /* last known-executing tx buf */
unsigned short last_tx_restart; /* set to tx_link when we restart the CU */ unsigned short last_tx_restart; /* set to tx_link when we restart the CU */
unsigned char started; unsigned char started;
unsigned char promisc;
unsigned short rx_buf_start; unsigned short rx_buf_start;
unsigned short rx_buf_end; unsigned short rx_buf_end;
unsigned short num_tx_bufs; unsigned short num_tx_bufs;
...@@ -230,6 +213,7 @@ static struct enet_statistics *eexp_stats(struct device *dev); ...@@ -230,6 +213,7 @@ static struct enet_statistics *eexp_stats(struct device *dev);
static int eexp_xmit (struct sk_buff *buf, struct device *dev); static int eexp_xmit (struct sk_buff *buf, struct device *dev);
static void eexp_irq (int irq, void *dev_addr, struct pt_regs *regs); static void eexp_irq (int irq, void *dev_addr, struct pt_regs *regs);
static void eexp_set_multicast(struct device *dev);
/* /*
* Prototypes for hardware access functions * Prototypes for hardware access functions
...@@ -245,7 +229,6 @@ static void eexp_hw_txrestart (struct device *dev); ...@@ -245,7 +229,6 @@ static void eexp_hw_txrestart (struct device *dev);
static void eexp_hw_txinit (struct device *dev); static void eexp_hw_txinit (struct device *dev);
static void eexp_hw_rxinit (struct device *dev); static void eexp_hw_rxinit (struct device *dev);
static void eexp_hw_rxmap (struct device *dev,unsigned short rx_buf);
static void eexp_hw_init586 (struct device *dev); static void eexp_hw_init586 (struct device *dev);
static void eexp_hw_ASICrst (struct device *dev); static void eexp_hw_ASICrst (struct device *dev);
...@@ -294,7 +277,7 @@ static int eexp_open(struct device *dev) ...@@ -294,7 +277,7 @@ static int eexp_open(struct device *dev)
unsigned short ioaddr = dev->base_addr; unsigned short ioaddr = dev->base_addr;
#if NET_DEBUG > 6 #if NET_DEBUG > 6
printk("%s: eexp_open()\n", dev->name); printk(KERN_DEBUG "%s: eexp_open()\n", dev->name);
#endif #endif
if (!irq || !irqrmap[irq]) if (!irq || !irqrmap[irq])
...@@ -311,6 +294,10 @@ static int eexp_open(struct device *dev) ...@@ -311,6 +294,10 @@ static int eexp_open(struct device *dev)
dev->interrupt = 0; dev->interrupt = 0;
eexp_hw_init586(dev); eexp_hw_init586(dev);
dev->start = 1; dev->start = 1;
MOD_INC_USE_COUNT;
#if NET_DEBUG > 6
printk(KERN_DEBUG "%s: leaving eexp_open()\n", dev->name);
#endif
return 0; return 0;
} }
...@@ -334,6 +321,7 @@ static int eexp_close(struct device *dev) ...@@ -334,6 +321,7 @@ static int eexp_close(struct device *dev)
irq2dev_map[irq] = NULL; irq2dev_map[irq] = NULL;
outb(i586_RST,ioaddr+EEPROM_Ctrl); outb(i586_RST,ioaddr+EEPROM_Ctrl);
release_region(ioaddr,16); release_region(ioaddr,16);
MOD_DEC_USE_COUNT;
return 0; return 0;
} }
...@@ -365,7 +353,7 @@ static int eexp_xmit(struct sk_buff *buf, struct device *dev) ...@@ -365,7 +353,7 @@ static int eexp_xmit(struct sk_buff *buf, struct device *dev)
unsigned short ioaddr = dev->base_addr; unsigned short ioaddr = dev->base_addr;
#if NET_DEBUG > 6 #if NET_DEBUG > 6
printk("%s: eexp_xmit()\n", dev->name); printk(KERN_DEBUG "%s: eexp_xmit()\n", dev->name);
#endif #endif
outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ); outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
...@@ -382,7 +370,7 @@ static int eexp_xmit(struct sk_buff *buf, struct device *dev) ...@@ -382,7 +370,7 @@ static int eexp_xmit(struct sk_buff *buf, struct device *dev)
if (lp->tx_link==lp->last_tx_restart) if (lp->tx_link==lp->last_tx_restart)
{ {
unsigned short boguscount=200,rsst; unsigned short boguscount=200,rsst;
printk("%s: Retransmit timed out, status %04x, resetting...\n", printk(KERN_WARNING "%s: Retransmit timed out, status %04x, resetting...\n",
dev->name,inw(ioaddr+SCB_STATUS)); dev->name,inw(ioaddr+SCB_STATUS));
eexp_hw_txinit(dev); eexp_hw_txinit(dev);
lp->last_tx_restart = 0; lp->last_tx_restart = 0;
...@@ -395,7 +383,7 @@ static int eexp_xmit(struct sk_buff *buf, struct device *dev) ...@@ -395,7 +383,7 @@ static int eexp_xmit(struct sk_buff *buf, struct device *dev)
if (!--boguscount) if (!--boguscount)
{ {
boguscount=200; boguscount=200;
printk("%s: Reset timed out status %04x, retrying...\n", printk(KERN_WARNING "%s: Reset timed out status %04x, retrying...\n",
dev->name,rsst); dev->name,rsst);
outw(lp->tx_link,ioaddr+SCB_CBL); outw(lp->tx_link,ioaddr+SCB_CBL);
outw(0,ioaddr+SCB_STATUS); outw(0,ioaddr+SCB_STATUS);
...@@ -412,7 +400,7 @@ static int eexp_xmit(struct sk_buff *buf, struct device *dev) ...@@ -412,7 +400,7 @@ static int eexp_xmit(struct sk_buff *buf, struct device *dev)
if (SCB_CUdead(status)) if (SCB_CUdead(status))
{ {
unsigned short txstatus = eexp_hw_lasttxstat(dev); unsigned short txstatus = eexp_hw_lasttxstat(dev);
printk("%s: Transmit timed out, CU not active status %04x %04x, restarting...\n", printk(KERN_WARNING "%s: Transmit timed out, CU not active status %04x %04x, restarting...\n",
dev->name, status, txstatus); dev->name, status, txstatus);
eexp_hw_txrestart(dev); eexp_hw_txrestart(dev);
} }
...@@ -421,7 +409,7 @@ static int eexp_xmit(struct sk_buff *buf, struct device *dev) ...@@ -421,7 +409,7 @@ static int eexp_xmit(struct sk_buff *buf, struct device *dev)
unsigned short txstatus = eexp_hw_lasttxstat(dev); unsigned short txstatus = eexp_hw_lasttxstat(dev);
if (dev->tbusy && !txstatus) if (dev->tbusy && !txstatus)
{ {
printk("%s: CU wedged, status %04x %04x, resetting...\n", printk(KERN_WARNING "%s: CU wedged, status %04x %04x, resetting...\n",
dev->name,status,txstatus); dev->name,status,txstatus);
eexp_hw_init586(dev); eexp_hw_init586(dev);
dev->tbusy = 0; dev->tbusy = 0;
...@@ -436,7 +424,7 @@ static int eexp_xmit(struct sk_buff *buf, struct device *dev) ...@@ -436,7 +424,7 @@ static int eexp_xmit(struct sk_buff *buf, struct device *dev)
if ((jiffies-lp->init_time)>10) if ((jiffies-lp->init_time)>10)
{ {
unsigned short status = inw(ioaddr+SCB_STATUS); unsigned short status = inw(ioaddr+SCB_STATUS);
printk("%s: i82586 startup timed out, status %04x, resetting...\n", printk(KERN_WARNING "%s: i82586 startup timed out, status %04x, resetting...\n",
dev->name, status); dev->name, status);
eexp_hw_init586(dev); eexp_hw_init586(dev);
dev->tbusy = 0; dev->tbusy = 0;
...@@ -451,7 +439,7 @@ static int eexp_xmit(struct sk_buff *buf, struct device *dev) ...@@ -451,7 +439,7 @@ static int eexp_xmit(struct sk_buff *buf, struct device *dev)
unsigned short txstatus = eexp_hw_lasttxstat(dev); unsigned short txstatus = eexp_hw_lasttxstat(dev);
if (SCB_CUdead(status)) if (SCB_CUdead(status))
{ {
printk("%s: CU has died! status %04x %04x, attempting to restart...\n", printk(KERN_WARNING "%s: CU has died! status %04x %04x, attempting to restart...\n",
dev->name, status, txstatus); dev->name, status, txstatus);
lp->stats.tx_errors++; lp->stats.tx_errors++;
eexp_hw_txrestart(dev); eexp_hw_txrestart(dev);
...@@ -463,7 +451,6 @@ static int eexp_xmit(struct sk_buff *buf, struct device *dev) ...@@ -463,7 +451,6 @@ static int eexp_xmit(struct sk_buff *buf, struct device *dev)
if (set_bit(0,(void *)&dev->tbusy)) if (set_bit(0,(void *)&dev->tbusy))
{ {
/* printk("%s: Transmitter busy or access conflict\n",dev->name); */
lp->stats.tx_dropped++; lp->stats.tx_dropped++;
} }
else else
...@@ -496,12 +483,12 @@ static void eexp_irq(int irq, void *dev_info, struct pt_regs *regs) ...@@ -496,12 +483,12 @@ static void eexp_irq(int irq, void *dev_info, struct pt_regs *regs)
if (dev==NULL) if (dev==NULL)
{ {
printk("net_interrupt(): irq %d for unknown device caught by EExpress\n",irq); printk(KERN_WARNING "net_interrupt(): irq %d for unknown device caught by EExpress\n",irq);
return; return;
} }
#if NET_DEBUG > 6 #if NET_DEBUG > 6
printk("%s: interrupt\n", dev->name); printk(KERN_DEBUG "%s: interrupt\n", dev->name);
#endif #endif
dev->interrupt = 1; /* should this be reset on exit? */ dev->interrupt = 1; /* should this be reset on exit? */
...@@ -517,11 +504,17 @@ static void eexp_irq(int irq, void *dev_info, struct pt_regs *regs) ...@@ -517,11 +504,17 @@ static void eexp_irq(int irq, void *dev_info, struct pt_regs *regs)
if (PRIV(dev)->started==0 && SCB_complete(status)) if (PRIV(dev)->started==0 && SCB_complete(status))
{ {
if (SCB_CUstat(status)==2) #if NET_DEBUG > 4
while (SCB_CUstat(inw(ioaddr+SCB_STATUS))==2); printk(KERN_DEBUG "%s: SCBcomplete event received\n", dev->name);
#endif
while (SCB_CUstat(status)==2)
status = inw_p(ioaddr+SCB_STATUS);
#if NET_DEBUG > 4
printk(KERN_DEBUG "%s: CU went non-active (status = %08x)\n", dev->name, status);
#endif
PRIV(dev)->started=1; PRIV(dev)->started=1;
outw(lp->tx_link,ioaddr+SCB_CBL); outw_p(lp->tx_link,ioaddr+SCB_CBL);
outw(PRIV(dev)->rx_buf_start,ioaddr+SCB_RFA); outw_p(PRIV(dev)->rx_buf_start,ioaddr+SCB_RFA);
ack_cmd |= SCB_CUstart | SCB_RUstart; ack_cmd |= SCB_CUstart | SCB_RUstart;
} }
else if (PRIV(dev)->started) else if (PRIV(dev)->started)
...@@ -537,7 +530,7 @@ static void eexp_irq(int irq, void *dev_info, struct pt_regs *regs) ...@@ -537,7 +530,7 @@ static void eexp_irq(int irq, void *dev_info, struct pt_regs *regs)
if ((PRIV(dev)->started&2)!=0 && SCB_RUstat(status)!=4) if ((PRIV(dev)->started&2)!=0 && SCB_RUstat(status)!=4)
{ {
printk("%s: RU stopped status %04x, restarting...\n", printk(KERN_WARNING "%s: RU stopped status %04x, restarting...\n",
dev->name,status); dev->name,status);
lp->stats.rx_errors++; lp->stats.rx_errors++;
eexp_hw_rxinit(dev); eexp_hw_rxinit(dev);
...@@ -552,6 +545,10 @@ static void eexp_irq(int irq, void *dev_info, struct pt_regs *regs) ...@@ -552,6 +545,10 @@ static void eexp_irq(int irq, void *dev_info, struct pt_regs *regs)
outw(old_rp,ioaddr+READ_PTR); outw(old_rp,ioaddr+READ_PTR);
outw(old_wp,ioaddr+WRITE_PTR); outw(old_wp,ioaddr+WRITE_PTR);
outb(SIRQ_en|irqrmap[irq],ioaddr+SET_IRQ); outb(SIRQ_en|irqrmap[irq],ioaddr+SET_IRQ);
dev->interrupt = 0;
#if NET_DEBUG > 6
printk(KERN_DEBUG "%s: leaving eexp_irq()\n", dev->name);
#endif
return; return;
} }
...@@ -575,7 +572,7 @@ static void eexp_hw_rx(struct device *dev) ...@@ -575,7 +572,7 @@ static void eexp_hw_rx(struct device *dev)
unsigned short boguscount = lp->num_rx_bufs; unsigned short boguscount = lp->num_rx_bufs;
#if NET_DEBUG > 6 #if NET_DEBUG > 6
printk("%s: eexp_hw_rx()\n", dev->name); printk(KERN_DEBUG "%s: eexp_hw_rx()\n", dev->name);
#endif #endif
while (outw(rx_block,ioaddr+READ_PTR),boguscount--) while (outw(rx_block,ioaddr+READ_PTR),boguscount--)
...@@ -594,10 +591,9 @@ static void eexp_hw_rx(struct device *dev) ...@@ -594,10 +591,9 @@ static void eexp_hw_rx(struct device *dev)
if (rfd_cmd!=0x0000 || pbuf!=rx_block+0x16 if (rfd_cmd!=0x0000 || pbuf!=rx_block+0x16
|| (pkt_len & 0xc000)!=0xc000) || (pkt_len & 0xc000)!=0xc000)
{ {
printk("%s: Rx frame at %04x corrupted, status %04x, cmd %04x, " printk(KERN_WARNING "%s: Rx frame at %04x corrupted, status %04x, cmd %04x, "
"next %04x, pbuf %04x, len %04x\n",dev->name,rx_block, "next %04x, pbuf %04x, len %04x\n",dev->name,rx_block,
status,rfd_cmd,rx_next,pbuf,pkt_len); status,rfd_cmd,rx_next,pbuf,pkt_len);
eexp_hw_rxmap(dev,rx_block);
boguscount++; boguscount++;
continue; continue;
} }
...@@ -622,7 +618,7 @@ static void eexp_hw_rx(struct device *dev) ...@@ -622,7 +618,7 @@ static void eexp_hw_rx(struct device *dev)
skb = dev_alloc_skb(pkt_len+16); skb = dev_alloc_skb(pkt_len+16);
if (skb == NULL) if (skb == NULL)
{ {
printk("%s: Memory squeeze, dropping packet\n",dev->name); printk(KERN_WARNING "%s: Memory squeeze, dropping packet\n",dev->name);
lp->stats.rx_dropped++; lp->stats.rx_dropped++;
break; break;
} }
...@@ -793,6 +789,7 @@ static int eexp_hw_probe(struct device *dev, unsigned short ioaddr) ...@@ -793,6 +789,7 @@ static int eexp_hw_probe(struct device *dev, unsigned short ioaddr)
dev->stop = eexp_close; dev->stop = eexp_close;
dev->hard_start_xmit = eexp_xmit; dev->hard_start_xmit = eexp_xmit;
dev->get_stats = eexp_stats; dev->get_stats = eexp_stats;
dev->set_multicast_list = &eexp_set_multicast;
ether_setup(dev); ether_setup(dev);
return 0; return 0;
} }
...@@ -930,7 +927,7 @@ static void eexp_hw_txrestart(struct device *dev) ...@@ -930,7 +927,7 @@ static void eexp_hw_txrestart(struct device *dev)
{ {
if (--failcount) if (--failcount)
{ {
printk("%s: CU start timed out, status %04x, cmd %04x\n", printk(KERN_WARNING "%s: CU start timed out, status %04x, cmd %04x\n",
dev->name, inw(ioaddr+SCB_STATUS), inw(ioaddr+SCB_CMD)); dev->name, inw(ioaddr+SCB_STATUS), inw(ioaddr+SCB_CMD));
outw(lp->tx_link,ioaddr+SCB_CBL); outw(lp->tx_link,ioaddr+SCB_CBL);
outw(0,ioaddr+SCB_STATUS); outw(0,ioaddr+SCB_STATUS);
...@@ -940,7 +937,7 @@ static void eexp_hw_txrestart(struct device *dev) ...@@ -940,7 +937,7 @@ static void eexp_hw_txrestart(struct device *dev)
} }
else else
{ {
printk("%s: Failed to restart CU, resetting board...\n",dev->name); printk(KERN_WARNING "%s: Failed to restart CU, resetting board...\n",dev->name);
eexp_hw_init586(dev); eexp_hw_init586(dev);
dev->tbusy = 0; dev->tbusy = 0;
mark_bh(NET_BH); mark_bh(NET_BH);
...@@ -1045,32 +1042,6 @@ static void eexp_hw_rxinit(struct device *dev) ...@@ -1045,32 +1042,6 @@ static void eexp_hw_rxinit(struct device *dev)
outw(old_wp,ioaddr+WRITE_PTR); outw(old_wp,ioaddr+WRITE_PTR);
} }
/*
* This really ought not to be necessary now. Repairs a single
* damaged receive buffer. If buffer memory is getting bashed
* enough to call this, we probably have bigger problems that can
* be fixed here.
*/
static void eexp_hw_rxmap(struct device *dev, unsigned short rx_buf)
{
struct net_local *lp = (struct net_local *)dev->priv;
unsigned short ioaddr = dev->base_addr;
unsigned short old_wp = inw(ioaddr+WRITE_PTR);
outw(rx_buf,ioaddr+WRITE_PTR);
outw(0x0000,ioaddr);
outw(0x0000,ioaddr);
outw((rx_buf==lp->rx_last)?lp->rx_first:(rx_buf+RX_BUF_SIZE),ioaddr);
outw(rx_buf+0x16,ioaddr);
outsw(ioaddr, rx_words, sizeof(rx_words)>>1);
outw(0x8000,ioaddr);
outw(-1,ioaddr);
outw(rx_buf+0x20,ioaddr);
outw(0x0000,ioaddr);
outw(0x8000|(RX_BUF_SIZE-0x20),ioaddr);
outw(old_wp,ioaddr+WRITE_PTR);
}
/* /*
* Reset the 586, fill memory (including calls to * Reset the 586, fill memory (including calls to
* eexp_hw_[(rx)(tx)]init()) unreset, and start * eexp_hw_[(rx)(tx)]init()) unreset, and start
...@@ -1085,21 +1056,20 @@ static void eexp_hw_init586(struct device *dev) ...@@ -1085,21 +1056,20 @@ static void eexp_hw_init586(struct device *dev)
struct net_local *lp = (struct net_local *)dev->priv; struct net_local *lp = (struct net_local *)dev->priv;
unsigned short ioaddr = dev->base_addr; unsigned short ioaddr = dev->base_addr;
#if NET_DEBUG > 6
printk("%s: eexp_hw_init586()\n", dev->name);
#endif
PRIV(dev)->started = 0; PRIV(dev)->started = 0;
set_loopback; set_loopback;
outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ); outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
outb(i586_RST,ioaddr+EEPROM_Ctrl); outb_p(i586_RST,ioaddr+EEPROM_Ctrl);
{ outw_p(lp->rx_buf_end,ioaddr+WRITE_PTR);
unsigned short wcnt; start_code[28] = (dev->flags & IFF_PROMISC)?(start_code[28] | 1):(start_code[28] & ~1);
wcnt = 0; PRIV(dev)->promisc = dev->flags & IFF_PROMISC;
outw(0,ioaddr+WRITE_PTR); /* We may die here */
while ((wcnt+=2) != lp->rx_buf_end+12)
outw(0,ioaddr);
}
outw(lp->rx_buf_end,ioaddr+WRITE_PTR);
outsw(ioaddr, start_code, sizeof(start_code)>>1); outsw(ioaddr, start_code, sizeof(start_code)>>1);
outw(CONF_HW_ADDR,ioaddr+WRITE_PTR); outw(CONF_HW_ADDR,ioaddr+WRITE_PTR);
outsw(ioaddr,dev->dev_addr,3); outsw(ioaddr,dev->dev_addr,3);
...@@ -1116,14 +1086,14 @@ static void eexp_hw_init586(struct device *dev) ...@@ -1116,14 +1086,14 @@ static void eexp_hw_init586(struct device *dev)
{ {
if (!--rboguscount) if (!--rboguscount)
{ {
printk("%s: i82586 reset timed out, kicking...\n", printk(KERN_WARNING "%s: i82586 reset timed out, kicking...\n",
dev->name); dev->name);
outw(0,ioaddr+SCB_CMD); outw(0,ioaddr+SCB_CMD);
outb(0,ioaddr+SIGNAL_CA); outb(0,ioaddr+SIGNAL_CA);
rboguscount = 100; rboguscount = 100;
if (!--rfailcount) if (!--rfailcount)
{ {
printk("%s: i82586 not responding, giving up.\n", printk(KERN_WARNING "%s: i82586 not responding, giving up.\n",
dev->name); dev->name);
return; return;
} }
...@@ -1143,7 +1113,7 @@ static void eexp_hw_init586(struct device *dev) ...@@ -1143,7 +1113,7 @@ static void eexp_hw_init586(struct device *dev)
{ {
if (--ifailcount) if (--ifailcount)
{ {
printk("%s: i82586 initialization timed out, status %04x, cmd %04x\n", printk(KERN_WARNING "%s: i82586 initialization timed out, status %04x, cmd %04x\n",
dev->name, inw(ioaddr+SCB_STATUS), inw(ioaddr+SCB_CMD)); dev->name, inw(ioaddr+SCB_STATUS), inw(ioaddr+SCB_CMD));
outw(CONF_LINK,ioaddr+SCB_CBL); outw(CONF_LINK,ioaddr+SCB_CBL);
outw(0,ioaddr+SCB_STATUS); outw(0,ioaddr+SCB_STATUS);
...@@ -1153,7 +1123,7 @@ static void eexp_hw_init586(struct device *dev) ...@@ -1153,7 +1123,7 @@ static void eexp_hw_init586(struct device *dev)
} }
else else
{ {
printk("%s: Failed to initialize i82586, giving up.\n",dev->name); printk(KERN_WARNING "%s: Failed to initialize i82586, giving up.\n",dev->name);
return; return;
} }
} }
...@@ -1163,8 +1133,9 @@ static void eexp_hw_init586(struct device *dev) ...@@ -1163,8 +1133,9 @@ static void eexp_hw_init586(struct device *dev)
outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ); outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);
clear_loopback; clear_loopback;
lp->init_time = jiffies; lp->init_time = jiffies;
if (PRIV(dev)->started) #if NET_DEBUG > 6
printk("%s: Uh? We haven't started yet\n",dev->name); printk("%s: leaving eexp_hw_init586()\n", dev->name);
#endif
return; return;
} }
...@@ -1181,9 +1152,6 @@ static void eexp_hw_ASICrst(struct device *dev) ...@@ -1181,9 +1152,6 @@ static void eexp_hw_ASICrst(struct device *dev)
outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ); outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
set_loopback; /* yet more paranoia - since we're resetting the ASIC
* that controls this function, how can it possibly work?
*/
PRIV(dev)->started = 0; PRIV(dev)->started = 0;
outb(ASIC_RST|i586_RST,ioaddr+EEPROM_Ctrl); outb(ASIC_RST|i586_RST,ioaddr+EEPROM_Ctrl);
while (succount<20) while (succount<20)
...@@ -1211,6 +1179,20 @@ static void eexp_hw_ASICrst(struct device *dev) ...@@ -1211,6 +1179,20 @@ static void eexp_hw_ASICrst(struct device *dev)
outb(i586_RST,ioaddr+EEPROM_Ctrl); outb(i586_RST,ioaddr+EEPROM_Ctrl);
} }
/*
* Set or clear the multicast filter for this adaptor.
* We have to do a complete 586 restart for this to take effect.
* At the moment only promiscuous mode is supported.
*/
static void
eexp_set_multicast(struct device *dev)
{
if ((dev->flags & IFF_PROMISC) != PRIV(dev)->promisc)
eexp_hw_init586(dev);
}
/* /*
* MODULE stuff * MODULE stuff
*/ */
...@@ -1272,3 +1254,11 @@ void cleanup_module(void) ...@@ -1272,3 +1254,11 @@ void cleanup_module(void)
} }
} }
#endif #endif
/*
* Local Variables:
* c-file-style: "linux"
* tab-width: 8
* compile-command: "gcc -D__KERNEL__ -I/discs/bibble/src/linux-1.3.69/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strength-reduce -pipe -m486 -DCPU=486 -DMODULE -c 3c505.c"
* End:
*/
...@@ -797,7 +797,7 @@ static void sdla_receive(struct device *dev) ...@@ -797,7 +797,7 @@ static void sdla_receive(struct device *dev)
if (i == CONFIG_DLCI_MAX) if (i == CONFIG_DLCI_MAX)
{ {
printk(KERN_NOTICE "%s: Recieved packet from invalid DLCI %i, ignoring.", dev->name, dlci); printk(KERN_NOTICE "%s: Received packet from invalid DLCI %i, ignoring.", dev->name, dlci);
flp->stats.rx_errors++; flp->stats.rx_errors++;
success = 0; success = 0;
} }
...@@ -876,7 +876,7 @@ static void sdla_isr(int irq, void *dev_id, struct pt_regs * regs) ...@@ -876,7 +876,7 @@ static void sdla_isr(int irq, void *dev_id, struct pt_regs * regs)
if (!flp->initialized) if (!flp->initialized)
{ {
printk(KERN_WARNING "%s: irq %d for unintialiazed device.\n", dev->name, irq); printk(KERN_WARNING "%s: irq %d for uninitialized device.\n", dev->name, irq);
return; return;
} }
...@@ -1176,7 +1176,7 @@ static int sdla_config(struct device *dev, struct frad_conf *conf, int get) ...@@ -1176,7 +1176,7 @@ static int sdla_config(struct device *dev, struct frad_conf *conf, int get)
if (err) if (err)
return(err); return(err);
/* no sense reading if the CPU isnt' started */ /* no sense reading if the CPU isn't started */
if (dev->start) if (dev->start)
{ {
size = sizeof(data); size = sizeof(data);
......
...@@ -1534,7 +1534,7 @@ static void SK_rxintr(struct device *dev) ...@@ -1534,7 +1534,7 @@ static void SK_rxintr(struct device *dev)
if (rmdstat & RX_STP) if (rmdstat & RX_STP)
{ {
p->stats.rx_errors++; /* bad packet received */ p->stats.rx_errors++; /* bad packet received */
p->stats.rx_length_errors++; /* packet to long */ p->stats.rx_length_errors++; /* packet too long */
printk("%s: packet too long\n", dev->name); printk("%s: packet too long\n", dev->name);
} }
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
* in the text. * in the text.
* *
* *
* OPTION_NOASYNC * OPTION_NO_ASYNC
* Don't negotiate for asynchronous transfers on the first command * Don't negotiate for asynchronous transfers on the first command
* when OPTION_ALWAYS_SYNCHRONOUS is set. Useful for dain bramaged * when OPTION_ALWAYS_SYNCHRONOUS is set. Useful for dain bramaged
* devices which do something bad rather than sending a MESSAGE * devices which do something bad rather than sending a MESSAGE
......
...@@ -639,7 +639,7 @@ static void BusLogic_InitializeAddressProbeList(void) ...@@ -639,7 +639,7 @@ static void BusLogic_InitializeAddressProbeList(void)
if (AutoSCSIByte45.ForceBusDeviceScanningOrder) if (AutoSCSIByte45.ForceBusDeviceScanningOrder)
{ {
/* /*
Sort the I/O Addresses such that the corrseponding PCI devices Sort the I/O Addresses such that the corresponding PCI devices
are in ascending order by Bus Number and Device Number. are in ascending order by Bus Number and Device Number.
*/ */
int LastInterchange = DestinationIndex-1, Bound, j; int LastInterchange = DestinationIndex-1, Bound, j;
......
...@@ -6,8 +6,6 @@ ...@@ -6,8 +6,6 @@
(c) 1995,1996 Grant R. Guenther, grant@torque.net, (c) 1995,1996 Grant R. Guenther, grant@torque.net,
under the terms of the GNU Public License. under the terms of the GNU Public License.
THIS IS BETA SOFTWARE - PLEASE TAKE ALL NECESSARY PRECAUTIONS
*/ */
/* This driver was developed without the benefit of any technical /* This driver was developed without the benefit of any technical
......
...@@ -2207,7 +2207,7 @@ static int update_timeout(Scsi_Cmnd * SCset, int timeout) ...@@ -2207,7 +2207,7 @@ static int update_timeout(Scsi_Cmnd * SCset, int timeout)
* called, and again when scsi_done completes the command. To limit * called, and again when scsi_done completes the command. To limit
* the load this routine can cause, we shortcut processing if no clock * the load this routine can cause, we shortcut processing if no clock
* ticks have occurred since the last time it was called. This may * ticks have occurred since the last time it was called. This may
* cause the computation of least below to be inaccurrate, but it will * cause the computation of least below to be inaccurate, but it will
* be corrected after the next clock tick. * be corrected after the next clock tick.
*/ */
......
...@@ -394,7 +394,7 @@ typedef struct scsi_cmnd { ...@@ -394,7 +394,7 @@ typedef struct scsi_cmnd {
passes it to the driver's queue command function. The serial_number passes it to the driver's queue command function. The serial_number
is cleared when scsi_done is entered indicating that the command has is cleared when scsi_done is entered indicating that the command has
been completed. If a timeout occurs, the serial number at the moment been completed. If a timeout occurs, the serial number at the moment
of timeout is copied into serial_number_at_timeout. By subseuqently of timeout is copied into serial_number_at_timeout. By subsequently
comparing the serial_number and serial_number_at_timeout fields comparing the serial_number and serial_number_at_timeout fields
during abort or reset processing, we can detect whether the command during abort or reset processing, we can detect whether the command
has already completed. This also detects cases where the command has has already completed. This also detects cases where the command has
......
...@@ -147,7 +147,7 @@ static int sd_open(struct inode * inode, struct file * filp) ...@@ -147,7 +147,7 @@ static int sd_open(struct inode * inode, struct file * filp)
static void sd_release(struct inode * inode, struct file * file) static void sd_release(struct inode * inode, struct file * file)
{ {
int target; int target;
sync_dev(inode->i_rdev); fsync_dev(inode->i_rdev);
target = DEVICE_NR(inode->i_rdev); target = DEVICE_NR(inode->i_rdev);
......
...@@ -803,6 +803,10 @@ void set_writetime(struct buffer_head * buf, int flag) ...@@ -803,6 +803,10 @@ void set_writetime(struct buffer_head * buf, int flag)
} }
/*
* A buffer may need to be moved from one buffer list to another
* (e.g. in case it is not shared any more). Handle this.
*/
void refile_buffer(struct buffer_head * buf) void refile_buffer(struct buffer_head * buf)
{ {
int dispose; int dispose;
...@@ -1088,6 +1092,46 @@ static struct buffer_head * create_buffers(unsigned long page, unsigned long siz ...@@ -1088,6 +1092,46 @@ static struct buffer_head * create_buffers(unsigned long page, unsigned long siz
return NULL; return NULL;
} }
/* Run the hooks that have to be done when a page I/O has completed. */
static inline void after_unlock_page (struct page * page)
{
if (clear_bit(PG_decr_after, &page->flags))
nr_async_pages--;
if (clear_bit(PG_free_after, &page->flags))
free_page(page_address(page));
if (clear_bit(PG_swap_unlock_after, &page->flags))
swap_after_unlock_page(page->swap_unlock_entry);
}
/* Free all temporary buffers belonging to a page. */
static inline void free_async_buffers (struct buffer_head * bh)
{
struct buffer_head * tmp;
unsigned long flags;
tmp = bh;
save_flags(flags);
cli();
do {
if (!test_bit(BH_FreeOnIO, &tmp->b_state)) {
printk ("Whoops: unlock_buffer: "
"async IO mismatch on page.\n");
restore_flags(flags);
return;
}
tmp->b_next_free = reuse_list;
reuse_list = tmp;
clear_bit(BH_FreeOnIO, &tmp->b_state);
tmp = tmp->b_this_page;
} while (tmp != bh);
restore_flags(flags);
}
/*
* Start I/O on a page.
* This function expects the page to be locked and may return before I/O is complete.
* You then have to check page->locked, page->uptodate, and maybe wait on page->wait.
*/
int brw_page(int rw, unsigned long address, kdev_t dev, int b[], int size, int bmap) int brw_page(int rw, unsigned long address, kdev_t dev, int b[], int size, int bmap)
{ {
struct buffer_head *bh, *prev, *next, *arr[MAX_BUF_PER_PAGE]; struct buffer_head *bh, *prev, *next, *arr[MAX_BUF_PER_PAGE];
...@@ -1095,10 +1139,20 @@ int brw_page(int rw, unsigned long address, kdev_t dev, int b[], int size, int b ...@@ -1095,10 +1139,20 @@ int brw_page(int rw, unsigned long address, kdev_t dev, int b[], int size, int b
struct page *page; struct page *page;
page = mem_map + MAP_NR(address); page = mem_map + MAP_NR(address);
if (!PageLocked(page))
panic("brw_page: page not locked for I/O");
clear_bit(PG_uptodate, &page->flags); clear_bit(PG_uptodate, &page->flags);
/*
* Allocate buffer heads pointing to this page, just for I/O.
* They do _not_ show up in the buffer hash table!
* They are _not_ registered in page->buffers either!
*/
bh = create_buffers(address, size); bh = create_buffers(address, size);
if (!bh) if (!bh) {
clear_bit(PG_locked, &page->flags);
wake_up(&page->wait);
return -ENOMEM; return -ENOMEM;
}
nr = 0; nr = 0;
next = bh; next = bh;
do { do {
...@@ -1148,33 +1202,32 @@ int brw_page(int rw, unsigned long address, kdev_t dev, int b[], int size, int b ...@@ -1148,33 +1202,32 @@ int brw_page(int rw, unsigned long address, kdev_t dev, int b[], int size, int b
} while (prev = next, (next = next->b_this_page) != NULL); } while (prev = next, (next = next->b_this_page) != NULL);
prev->b_this_page = bh; prev->b_this_page = bh;
if (nr) if (nr) {
ll_rw_block(rw, nr, arr); ll_rw_block(rw, nr, arr);
else { /* The rest of the work is done in mark_buffer_uptodate()
unsigned long flags; * and unlock_buffer(). */
} else {
clear_bit(PG_locked, &page->flags); clear_bit(PG_locked, &page->flags);
set_bit(PG_uptodate, &page->flags); set_bit(PG_uptodate, &page->flags);
wake_up(&page->wait); wake_up(&page->wait);
next = bh; free_async_buffers(bh);
save_flags(flags); after_unlock_page(page);
cli();
do {
next->b_next_free = reuse_list;
reuse_list = next;
next = next->b_this_page;
} while (next != bh);
restore_flags(flags);
} }
++current->maj_flt; ++current->maj_flt;
return 0; return 0;
} }
/*
* This is called by end_request() when I/O has completed.
*/
void mark_buffer_uptodate(struct buffer_head * bh, int on) void mark_buffer_uptodate(struct buffer_head * bh, int on)
{ {
if (on) { if (on) {
struct buffer_head *tmp = bh; struct buffer_head *tmp = bh;
int page_uptodate = 1; int page_uptodate = 1;
set_bit(BH_Uptodate, &bh->b_state); set_bit(BH_Uptodate, &bh->b_state);
/* If a page has buffers and all these buffers are uptodate,
* then the page is uptodate. */
do { do {
if (!test_bit(BH_Uptodate, &tmp->b_state)) { if (!test_bit(BH_Uptodate, &tmp->b_state)) {
page_uptodate = 0; page_uptodate = 0;
...@@ -1188,10 +1241,12 @@ void mark_buffer_uptodate(struct buffer_head * bh, int on) ...@@ -1188,10 +1241,12 @@ void mark_buffer_uptodate(struct buffer_head * bh, int on)
clear_bit(BH_Uptodate, &bh->b_state); clear_bit(BH_Uptodate, &bh->b_state);
} }
/*
* This is called by end_request() when I/O has completed.
*/
void unlock_buffer(struct buffer_head * bh) void unlock_buffer(struct buffer_head * bh)
{ {
struct buffer_head *tmp; struct buffer_head *tmp;
unsigned long flags;
struct page *page; struct page *page;
clear_bit(BH_Lock, &bh->b_state); clear_bit(BH_Lock, &bh->b_state);
...@@ -1199,6 +1254,7 @@ void unlock_buffer(struct buffer_head * bh) ...@@ -1199,6 +1254,7 @@ void unlock_buffer(struct buffer_head * bh)
if (!test_bit(BH_FreeOnIO, &bh->b_state)) if (!test_bit(BH_FreeOnIO, &bh->b_state))
return; return;
/* This is a temporary buffer used for page I/O. */
page = mem_map + MAP_NR(bh->b_data); page = mem_map + MAP_NR(bh->b_data);
if (!PageLocked(page)) { if (!PageLocked(page)) {
printk ("Whoops: unlock_buffer: " printk ("Whoops: unlock_buffer: "
...@@ -1218,31 +1274,11 @@ void unlock_buffer(struct buffer_head * bh) ...@@ -1218,31 +1274,11 @@ void unlock_buffer(struct buffer_head * bh)
if (test_bit(BH_Lock, &tmp->b_state) || tmp->b_count) if (test_bit(BH_Lock, &tmp->b_state) || tmp->b_count)
return; return;
} }
/* OK, the async IO on this page is complete. */
/* OK, go ahead and complete the async IO on this page. */
save_flags(flags);
clear_bit(PG_locked, &page->flags); clear_bit(PG_locked, &page->flags);
wake_up(&page->wait); wake_up(&page->wait);
cli(); free_async_buffers(bh);
tmp = bh; after_unlock_page(page);
do {
if (!test_bit(BH_FreeOnIO, &tmp->b_state)) {
printk ("Whoops: unlock_buffer: "
"async IO mismatch on page.\n");
restore_flags(flags);
return;
}
tmp->b_next_free = reuse_list;
reuse_list = tmp;
clear_bit(BH_FreeOnIO, &tmp->b_state);
tmp = tmp->b_this_page;
} while (tmp != bh);
restore_flags(flags);
if (clear_bit(PG_freeafter, &page->flags)) {
extern int nr_async_pages;
nr_async_pages--;
free_page(page_address(page));
}
wake_up(&buffer_wait); wake_up(&buffer_wait);
} }
...@@ -1262,6 +1298,7 @@ int generic_readpage(struct inode * inode, struct page * page) ...@@ -1262,6 +1298,7 @@ int generic_readpage(struct inode * inode, struct page * page)
address = page_address(page); address = page_address(page);
page->count++; page->count++;
set_bit(PG_locked, &page->flags); set_bit(PG_locked, &page->flags);
set_bit(PG_free_after, &page->flags);
i = PAGE_SIZE >> inode->i_sb->s_blocksize_bits; i = PAGE_SIZE >> inode->i_sb->s_blocksize_bits;
block = page->offset >> inode->i_sb->s_blocksize_bits; block = page->offset >> inode->i_sb->s_blocksize_bits;
...@@ -1275,7 +1312,6 @@ int generic_readpage(struct inode * inode, struct page * page) ...@@ -1275,7 +1312,6 @@ int generic_readpage(struct inode * inode, struct page * page)
/* IO start */ /* IO start */
brw_page(READ, address, inode->i_dev, nr, inode->i_sb->s_blocksize, 1); brw_page(READ, address, inode->i_dev, nr, inode->i_sb->s_blocksize, 1);
free_page(address);
return 0; return 0;
} }
......
...@@ -390,7 +390,7 @@ static int check_idq(struct dquot *dquot, short type, u_long short inodes) ...@@ -390,7 +390,7 @@ static int check_idq(struct dquot *dquot, short type, u_long short inodes)
(dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit && (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit &&
dquot->dq_itime && CURRENT_TIME >= dquot->dq_itime && !fsuser()) { dquot->dq_itime && CURRENT_TIME >= dquot->dq_itime && !fsuser()) {
if (need_print_warning(type, dquot)) { if (need_print_warning(type, dquot)) {
sprintf(quotamessage, "%s: warning, %s file quota exceeded to long.\r\n", sprintf(quotamessage, "%s: warning, %s file quota exceeded too long.\r\n",
dquot->dq_mnt->mnt_dirname, quotatypes[type]); dquot->dq_mnt->mnt_dirname, quotatypes[type]);
tty_write_message(current->tty, quotamessage); tty_write_message(current->tty, quotamessage);
} }
...@@ -428,7 +428,7 @@ static int check_bdq(struct dquot *dquot, short type, u_long blocks) ...@@ -428,7 +428,7 @@ static int check_bdq(struct dquot *dquot, short type, u_long blocks)
(dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit && (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit &&
dquot->dq_btime && CURRENT_TIME >= dquot->dq_btime && !fsuser()) { dquot->dq_btime && CURRENT_TIME >= dquot->dq_btime && !fsuser()) {
if (need_print_warning(type, dquot)) { if (need_print_warning(type, dquot)) {
sprintf(quotamessage, "%s: write failed, %s disk quota exceeded to long.\r\n", sprintf(quotamessage, "%s: write failed, %s disk quota exceeded too long.\r\n",
dquot->dq_mnt->mnt_dirname, quotatypes[type]); dquot->dq_mnt->mnt_dirname, quotatypes[type]);
tty_write_message(current->tty, quotamessage); tty_write_message(current->tty, quotamessage);
} }
......
...@@ -385,14 +385,6 @@ int open_namei(const char * pathname, int flag, int mode, ...@@ -385,14 +385,6 @@ int open_namei(const char * pathname, int flag, int mode,
iput(dir); iput(dir);
return error; return error;
} }
/* SunOS, Solaris 2.x and HPUX all deny open() on
* an existing file with mandatory locks.
*/
error = locks_verify_locked(inode);
if (error) {
iput(inode);
return error;
}
error = follow_link(dir,inode,flag,mode,&inode); error = follow_link(dir,inode,flag,mode,&inode);
if (error) if (error)
return error; return error;
...@@ -438,18 +430,14 @@ int open_namei(const char * pathname, int flag, int mode, ...@@ -438,18 +430,14 @@ int open_namei(const char * pathname, int flag, int mode,
iput(inode); iput(inode);
return error; return error;
} }
#if 0
/* /*
* In my opinion the mandatory lock check should really be * Refuse to truncate files with mandatory locks held on them
* here. Only O_TRUNC calls can modify the file contents -
* but none of the commercial OS'es seem to do it this way.
*/ */
error = locks_verify_locked(inode); error = locks_verify_locked(inode);
if (error) { if (error) {
iput(inode); iput(inode);
return error; return error;
} }
#endif
if (inode->i_sb && inode->i_sb->dq_op) if (inode->i_sb && inode->i_sb->dq_op)
inode->i_sb->dq_op->initialize(inode, -1); inode->i_sb->dq_op->initialize(inode, -1);
......
...@@ -47,6 +47,10 @@ ...@@ -47,6 +47,10 @@
* from being used (thanks to Leo Spiekman) * from being used (thanks to Leo Spiekman)
* Andy Walker : Allow to specify the NFS server in nfs_root * Andy Walker : Allow to specify the NFS server in nfs_root
* without giving a path name * without giving a path name
* Swen Th=FCmmler : Allow to specify the NFS options in nfs_root
* without giving a path name. Fix BOOTP request
* for domainname (domainname is NIS domain, not
* DNS domain!). Skip dummy devices for BOOTP.
* *
*/ */
...@@ -168,6 +172,7 @@ static int root_dev_open(void) ...@@ -168,6 +172,7 @@ static int root_dev_open(void)
if (dev->type < ARPHRD_SLIP && if (dev->type < ARPHRD_SLIP &&
dev->family == AF_INET && dev->family == AF_INET &&
!(dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) && !(dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) &&
(0 != strncmp(dev->name, "dummy", 5)) &&
(!user_dev_name[0] || !strcmp(dev->name, user_dev_name))) { (!user_dev_name[0] || !strcmp(dev->name, user_dev_name))) {
/* First up the interface */ /* First up the interface */
old_flags = dev->flags; old_flags = dev->flags;
...@@ -622,7 +627,7 @@ static void root_bootp_init_ext(u8 *e) ...@@ -622,7 +627,7 @@ static void root_bootp_init_ext(u8 *e)
*e++ = 12; /* Host name request */ *e++ = 12; /* Host name request */
*e++ = 32; *e++ = 32;
e += 32; e += 32;
*e++ = 15; /* Domain name request */ *e++ = 40; /* NIS Domain name request */
*e++ = 32; *e++ = 32;
e += 32; e += 32;
*e++ = 17; /* Boot path */ *e++ = 17; /* Boot path */
...@@ -756,7 +761,6 @@ static int root_bootp_string(char *dest, char *src, int len, int max) ...@@ -756,7 +761,6 @@ static int root_bootp_string(char *dest, char *src, int len, int max)
static void root_do_bootp_ext(u8 *ext) static void root_do_bootp_ext(u8 *ext)
{ {
u8 *c; u8 *c;
static int got_bootp_domain = 0;
#ifdef NFSROOT_BOOTP_DEBUG #ifdef NFSROOT_BOOTP_DEBUG
printk("BOOTP: Got extension %02x",*ext); printk("BOOTP: Got extension %02x",*ext);
...@@ -775,20 +779,9 @@ static void root_do_bootp_ext(u8 *ext) ...@@ -775,20 +779,9 @@ static void root_do_bootp_ext(u8 *ext)
memcpy(&gateway.sin_addr.s_addr, ext+1, 4); memcpy(&gateway.sin_addr.s_addr, ext+1, 4);
break; break;
case 12: /* Host name */ case 12: /* Host name */
if (root_bootp_string(system_utsname.nodename, ext+1, *ext, __NEW_UTS_LEN)) { root_bootp_string(system_utsname.nodename, ext+1, *ext, __NEW_UTS_LEN);
c = strchr(system_utsname.nodename, '.');
if (c) {
*c++ = 0;
if (!system_utsname.domainname[0]) {
strcpy(system_utsname.domainname, c);
got_bootp_domain = 1;
}
}
}
break; break;
case 15: /* Domain name */ case 40: /* NIS Domain name */
if (got_bootp_domain && *ext && ext[1])
system_utsname.domainname[0] = '\0';
root_bootp_string(system_utsname.domainname, ext+1, *ext, __NEW_UTS_LEN); root_bootp_string(system_utsname.domainname, ext+1, *ext, __NEW_UTS_LEN);
break; break;
case 17: /* Root path */ case 17: /* Root path */
...@@ -1094,7 +1087,9 @@ static int root_nfs_name(char *name) ...@@ -1094,7 +1087,9 @@ static int root_nfs_name(char *name)
printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n"); printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n");
return -1; return -1;
} }
sprintf(nfs_path, buf, cp); /* update nfs_path with path from nfsroot=... command line parameter */
if (*buf)
sprintf(nfs_path, buf, cp);
/* Set some default values */ /* Set some default values */
nfs_port = -1; nfs_port = -1;
......
...@@ -117,30 +117,31 @@ struct vm_operations_struct { ...@@ -117,30 +117,31 @@ struct vm_operations_struct {
*/ */
typedef struct page { typedef struct page {
atomic_t count; atomic_t count;
unsigned dirty:16,
age:8;
unsigned flags; /* atomic flags, some possibly updated asynchronously */ unsigned flags; /* atomic flags, some possibly updated asynchronously */
struct wait_queue *wait; struct wait_queue *wait;
struct page *next; struct page *next;
struct page *next_hash; struct page *next_hash;
unsigned long offset; unsigned long offset;
struct inode *inode; struct inode *inode;
struct page *write_list;
struct page *prev; struct page *prev;
struct page *prev_hash; struct page *prev_hash;
struct buffer_head * buffers; struct buffer_head * buffers;
unsigned dirty:16, unsigned long swap_unlock_entry;
age:8; unsigned long map_nr; /* page->map_nr == page - mem_map */
} mem_map_t; } mem_map_t;
/* Page flag bit values */ /* Page flag bit values */
#define PG_locked 0 #define PG_locked 0
#define PG_error 1 #define PG_error 1
#define PG_referenced 2 #define PG_referenced 2
#define PG_uptodate 3 #define PG_uptodate 3
#define PG_freeafter 4 #define PG_free_after 4
#define PG_DMA 5 #define PG_decr_after 5
#define PG_reserved 31 #define PG_swap_unlock_after 6
#define PG_DMA 7
#define PG_reserved 31
/* Make it prettier to test the above... */ /* Make it prettier to test the above... */
#define PageLocked(page) (test_bit(PG_locked, &(page)->flags)) #define PageLocked(page) (test_bit(PG_locked, &(page)->flags))
...@@ -148,10 +149,79 @@ typedef struct page { ...@@ -148,10 +149,79 @@ typedef struct page {
#define PageReferenced(page) (test_bit(PG_referenced, &(page)->flags)) #define PageReferenced(page) (test_bit(PG_referenced, &(page)->flags))
#define PageDirty(page) (test_bit(PG_dirty, &(page)->flags)) #define PageDirty(page) (test_bit(PG_dirty, &(page)->flags))
#define PageUptodate(page) (test_bit(PG_uptodate, &(page)->flags)) #define PageUptodate(page) (test_bit(PG_uptodate, &(page)->flags))
#define PageFreeafter(page) (test_bit(PG_freeafter, &(page)->flags)) #define PageFreeAfter(page) (test_bit(PG_free_after, &(page)->flags))
#define PageDecrAfter(page) (test_bit(PG_decr_after, &(page)->flags))
#define PageSwapUnlockAfter(page) (test_bit(PG_swap_unlock_after, &(page)->flags))
#define PageDMA(page) (test_bit(PG_DMA, &(page)->flags)) #define PageDMA(page) (test_bit(PG_DMA, &(page)->flags))
#define PageReserved(page) (test_bit(PG_reserved, &(page)->flags)) #define PageReserved(page) (test_bit(PG_reserved, &(page)->flags))
/*
* page->reserved denotes a page which must never be accessed (which
* may not even be present).
*
* page->dma is set for those pages which lie in the range of
* physical addresses capable of carrying DMA transfers.
*
* Multiple processes may "see" the same page. E.g. for untouched
* mappings of /dev/null, all processes see the same page full of
* zeroes, and text pages of executables and shared libraries have
* only one copy in memory, at most, normally.
*
* For the non-reserved pages, page->count denotes a reference count.
* page->count == 0 means the page is free.
* page->count == 1 means the page is used for exactly one purpose
* (e.g. a private data page of one process).
*
* A page may be used for kmalloc() or anyone else who does a
* get_free_page(). In this case the page->count is at least 1, and
* all other fields are unused but should be 0 or NULL. The
* managament of this page is the responsibility of the one who uses
* it.
*
* The other pages (we may call them "process pages") are completely
* managed by the Linux memory manager: I/O, buffers, swapping etc.
* The following discussion applies only to them.
*
* A page may belong to an inode's memory mapping. In this case,
* page->inode is the inode, and page->offset is the file offset
* of the page (not necessarily a multiple of PAGE_SIZE).
*
* A page may have buffers allocated to it. In this case,
* page->buffers is a circular list of these buffer heads. Else,
* page->buffers == NULL.
*
* For pages belonging to inodes, the page->count is the number of
* attaches, plus 1 if buffers are allocated to the page.
*
* All pages belonging to an inode make up a doubly linked list
* inode->i_pages, using the fields page->next and page->prev. (These
* fields are also used for freelist management when page->count==0.)
* There is also a hash table mapping (inode,offset) to the page
* in memory if present. The lists for this hash table use the fields
* page->next_hash and page->prev_hash.
*
* All process pages can do I/O:
* - inode pages may need to be read from disk,
* - inode pages which have been modified and are MAP_SHARED may need
* to be written to disk,
* - private pages which have been modified may need to be swapped out
* to swap space and (later) to be read back into memory.
* During disk I/O, page->locked is true. This bit is set before I/O
* and reset when I/O completes. page->wait is a wait queue of all
* tasks waiting for the I/O on this page to complete.
* page->uptodate tells whether the page's contents is valid.
* When a read completes, the page becomes uptodate, unless a disk I/O
* error happened.
* When a write completes, and page->free_after is true, the page is
* freed without any further delay.
*
* For choosing which pages to swap out, inode pages carry a
* page->referenced bit, which is set any time the system accesses
* that page through the (inode,offset) hash table.
* There is also the page->age counter, which implements a linear
* decay (why not an exponential decay?), see swapctl.h.
*/
extern mem_map_t * mem_map; extern mem_map_t * mem_map;
/* /*
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
static inline unsigned long page_address(struct page * page) static inline unsigned long page_address(struct page * page)
{ {
return PAGE_OFFSET + PAGE_SIZE*(page - mem_map); return PAGE_OFFSET + PAGE_SIZE * page->map_nr;
} }
#define PAGE_HASH_BITS 10 #define PAGE_HASH_BITS 10
...@@ -22,7 +22,7 @@ static inline unsigned long page_address(struct page * page) ...@@ -22,7 +22,7 @@ static inline unsigned long page_address(struct page * page)
#define PAGE_AGE_VALUE 16 #define PAGE_AGE_VALUE 16
extern unsigned long page_cache_size; extern unsigned long page_cache_size; /* # of pages currently in the hash table */
extern struct page * page_hash_table[PAGE_HASH_SIZE]; extern struct page * page_hash_table[PAGE_HASH_SIZE];
/* /*
...@@ -33,7 +33,7 @@ extern struct page * page_hash_table[PAGE_HASH_SIZE]; ...@@ -33,7 +33,7 @@ extern struct page * page_hash_table[PAGE_HASH_SIZE];
*/ */
static inline unsigned long _page_hashfn(struct inode * inode, unsigned long offset) static inline unsigned long _page_hashfn(struct inode * inode, unsigned long offset)
{ {
#define i (((unsigned long) inode)/sizeof(unsigned long)) #define i (((unsigned long) inode)/(sizeof(struct inode) & ~ (sizeof(struct inode) - 1)))
#define o (offset >> PAGE_SHIFT) #define o (offset >> PAGE_SHIFT)
#define s(x) ((x)+((x)>>PAGE_HASH_BITS)) #define s(x) ((x)+((x)>>PAGE_HASH_BITS))
return s(i+o) & (PAGE_HASH_SIZE-1); return s(i+o) & (PAGE_HASH_SIZE-1);
......
...@@ -54,6 +54,7 @@ extern void rw_swap_page(int, unsigned long, char *, int); ...@@ -54,6 +54,7 @@ extern void rw_swap_page(int, unsigned long, char *, int);
rw_swap_page(READ,(nr),(buf),1) rw_swap_page(READ,(nr),(buf),1)
#define write_swap_page(nr,buf) \ #define write_swap_page(nr,buf) \
rw_swap_page(WRITE,(nr),(buf),1) rw_swap_page(WRITE,(nr),(buf),1)
extern void swap_after_unlock_page (unsigned long entry);
/* linux/mm/page_alloc.c */ /* linux/mm/page_alloc.c */
extern void swap_in(struct task_struct *, struct vm_area_struct *, extern void swap_in(struct task_struct *, struct vm_area_struct *,
......
...@@ -521,7 +521,7 @@ static void parse_options(char *line) ...@@ -521,7 +521,7 @@ static void parse_options(char *line)
int n; int n;
line += 8; line += 8;
ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255); ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255);
if (line[0] == '/' || (line[0] >= '0' && line[0] <= '9')) { if (line[0] == '/' || line[0] == ',' || (line[0] >= '0' && line[0] <= '9')) {
strncpy(nfs_root_name, line, sizeof(nfs_root_name)); strncpy(nfs_root_name, line, sizeof(nfs_root_name));
nfs_root_name[sizeof(nfs_root_name)-1] = '\0'; nfs_root_name[sizeof(nfs_root_name)-1] = '\0';
continue; continue;
......
...@@ -421,6 +421,7 @@ static int shm_map (struct vm_area_struct *shmd) ...@@ -421,6 +421,7 @@ static int shm_map (struct vm_area_struct *shmd)
pmd_t *page_middle; pmd_t *page_middle;
pte_t *page_table; pte_t *page_table;
unsigned long tmp, shm_sgn; unsigned long tmp, shm_sgn;
int error;
/* clear old mappings */ /* clear old mappings */
do_munmap(shmd->vm_start, shmd->vm_end - shmd->vm_start); do_munmap(shmd->vm_start, shmd->vm_end - shmd->vm_start);
...@@ -431,6 +432,7 @@ static int shm_map (struct vm_area_struct *shmd) ...@@ -431,6 +432,7 @@ static int shm_map (struct vm_area_struct *shmd)
merge_segments(current, shmd->vm_start, shmd->vm_end); merge_segments(current, shmd->vm_start, shmd->vm_end);
/* map page range */ /* map page range */
error = 0;
shm_sgn = shmd->vm_pte + shm_sgn = shmd->vm_pte +
SWP_ENTRY(0, (shmd->vm_offset >> PAGE_SHIFT) << SHM_IDX_SHIFT); SWP_ENTRY(0, (shmd->vm_offset >> PAGE_SHIFT) << SHM_IDX_SHIFT);
flush_cache_range(shmd->vm_mm, shmd->vm_start, shmd->vm_end); flush_cache_range(shmd->vm_mm, shmd->vm_start, shmd->vm_end);
...@@ -440,11 +442,15 @@ static int shm_map (struct vm_area_struct *shmd) ...@@ -440,11 +442,15 @@ static int shm_map (struct vm_area_struct *shmd)
{ {
page_dir = pgd_offset(shmd->vm_mm,tmp); page_dir = pgd_offset(shmd->vm_mm,tmp);
page_middle = pmd_alloc(page_dir,tmp); page_middle = pmd_alloc(page_dir,tmp);
if (!page_middle) if (!page_middle) {
return -ENOMEM; error = -ENOMEM;
break;
}
page_table = pte_alloc(page_middle,tmp); page_table = pte_alloc(page_middle,tmp);
if (!page_table) if (!page_table) {
return -ENOMEM; error = -ENOMEM;
break;
}
set_pte(page_table, __pte(shm_sgn)); set_pte(page_table, __pte(shm_sgn));
} }
flush_tlb_range(shmd->vm_mm, shmd->vm_start, shmd->vm_end); flush_tlb_range(shmd->vm_mm, shmd->vm_start, shmd->vm_end);
...@@ -712,7 +718,7 @@ int shm_swap (int prio, int dma) ...@@ -712,7 +718,7 @@ int shm_swap (int prio, int dma)
pte_val(page) = shp->shm_pages[idx]; pte_val(page) = shp->shm_pages[idx];
if (!pte_present(page)) if (!pte_present(page))
goto check_table; goto check_table;
if (dma && !PageDMA(MAP_NR(pte_page(page)) + mem_map)) if (dma && !PageDMA(&mem_map[MAP_NR(pte_page(page))]))
goto check_table; goto check_table;
swap_attempts++; swap_attempts++;
......
...@@ -246,7 +246,7 @@ asmlinkage int sys_setregid(gid_t rgid, gid_t egid) ...@@ -246,7 +246,7 @@ asmlinkage int sys_setregid(gid_t rgid, gid_t egid)
(current->egid == egid) || (current->egid == egid) ||
(current->sgid == egid) || (current->sgid == egid) ||
suser()) suser())
current->egid = egid; current->fsgid = current->egid = egid;
else { else {
current->gid = old_rgid; current->gid = old_rgid;
return(-EPERM); return(-EPERM);
...@@ -455,7 +455,7 @@ asmlinkage int sys_setreuid(uid_t ruid, uid_t euid) ...@@ -455,7 +455,7 @@ asmlinkage int sys_setreuid(uid_t ruid, uid_t euid)
(current->euid == euid) || (current->euid == euid) ||
(current->suid == euid) || (current->suid == euid) ||
suser()) suser())
current->euid = euid; current->fsuid = current->euid = euid;
else { else {
current->uid = old_ruid; current->uid = old_ruid;
return(-EPERM); return(-EPERM);
......
...@@ -464,7 +464,7 @@ if (count > 0) ccount += count; ...@@ -464,7 +464,7 @@ if (count > 0) ccount += count;
* Will try asynchronous read-ahead. * Will try asynchronous read-ahead.
* Double the max read ahead size each time. * Double the max read ahead size each time.
* That heuristic avoid to do some large IO for files that are not really * That heuristic avoid to do some large IO for files that are not really
* accessed sequentialy. * accessed sequentially.
*/ */
} else { } else {
try_async = 1; try_async = 1;
......
...@@ -569,7 +569,7 @@ unsigned long put_dirty_page(struct task_struct * tsk, unsigned long page, unsig ...@@ -569,7 +569,7 @@ unsigned long put_dirty_page(struct task_struct * tsk, unsigned long page, unsig
return 0; return 0;
} }
set_pte(pte, pte_mkwrite(pte_mkdirty(mk_pte(page, PAGE_COPY)))); set_pte(pte, pte_mkwrite(pte_mkdirty(mk_pte(page, PAGE_COPY))));
/* no need for invalidate */ /* no need for flush_tlb */
return page; return page;
} }
......
...@@ -37,7 +37,7 @@ int nr_free_pages = 0; ...@@ -37,7 +37,7 @@ int nr_free_pages = 0;
struct free_area_struct { struct free_area_struct {
struct page list; struct page list;
unsigned int * map; unsigned int * map;
}; };
static struct free_area_struct free_area[NR_MEM_LISTS]; static struct free_area_struct free_area[NR_MEM_LISTS];
...@@ -143,7 +143,7 @@ do { struct free_area_struct * area = free_area+order; \ ...@@ -143,7 +143,7 @@ do { struct free_area_struct * area = free_area+order; \
do { struct page *prev = &area->list, *ret; \ do { struct page *prev = &area->list, *ret; \
while (&area->list != (ret = prev->next)) { \ while (&area->list != (ret = prev->next)) { \
if (!dma || CAN_DMA(ret)) { \ if (!dma || CAN_DMA(ret)) { \
unsigned long map_nr = ret - mem_map; \ unsigned long map_nr = ret->map_nr; \
(prev->next = ret->next)->prev = prev; \ (prev->next = ret->next)->prev = prev; \
MARK_USED(map_nr, new_order, area); \ MARK_USED(map_nr, new_order, area); \
nr_free_pages -= 1 << order; \ nr_free_pages -= 1 << order; \
...@@ -263,6 +263,7 @@ unsigned long free_area_init(unsigned long start_mem, unsigned long end_mem) ...@@ -263,6 +263,7 @@ unsigned long free_area_init(unsigned long start_mem, unsigned long end_mem)
do { do {
--p; --p;
p->flags = (1 << PG_DMA) | (1 << PG_reserved); p->flags = (1 << PG_DMA) | (1 << PG_reserved);
p->map_nr = p - mem_map;
} while (p > mem_map); } while (p > mem_map);
for (i = 0 ; i < NR_MEM_LISTS ; i++) { for (i = 0 ; i < NR_MEM_LISTS ; i++) {
...@@ -310,6 +311,7 @@ void swap_in(struct task_struct * tsk, struct vm_area_struct * vma, ...@@ -310,6 +311,7 @@ void swap_in(struct task_struct * tsk, struct vm_area_struct * vma,
vma->vm_mm->rss++; vma->vm_mm->rss++;
tsk->maj_flt++; tsk->maj_flt++;
if (!write_access && add_to_swap_cache(MAP_NR(page), entry)) { if (!write_access && add_to_swap_cache(MAP_NR(page), entry)) {
/* keep swap page allocated for the moment (swap cache) */
set_pte(page_table, mk_pte(page, vma->vm_page_prot)); set_pte(page_table, mk_pte(page, vma->vm_page_prot));
return; return;
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* *
* Swap reorganised 29.12.95, * Swap reorganised 29.12.95,
* Asynchronous swapping added 30.12.95. Stephen Tweedie * Asynchronous swapping added 30.12.95. Stephen Tweedie
* Removed race in async swapping. 14.4.1996. Bruno Haible
*/ */
#include <linux/mm.h> #include <linux/mm.h>
...@@ -28,6 +29,18 @@ ...@@ -28,6 +29,18 @@
static struct wait_queue * lock_queue = NULL; static struct wait_queue * lock_queue = NULL;
/*
* Reads or writes a swap page.
* wait=1: start I/O and wait for completion. wait=0: start asynchronous I/O.
*
* Important prevention of race condition: The first thing we do is set a lock
* on this swap page, which lasts until I/O completes. This way a
* write_swap_page(entry) immediately followed by a read_swap_page(entry)
* on the same entry will first complete the write_swap_page(). Fortunately,
* not more than one write_swap_page() request can be pending per entry. So
* all races the caller must catch are: multiple read_swap_page() requests
* on the same entry.
*/
void rw_swap_page(int rw, unsigned long entry, char * buf, int wait) void rw_swap_page(int rw, unsigned long entry, char * buf, int wait)
{ {
unsigned long type, offset; unsigned long type, offset;
...@@ -53,6 +66,7 @@ void rw_swap_page(int rw, unsigned long entry, char * buf, int wait) ...@@ -53,6 +66,7 @@ void rw_swap_page(int rw, unsigned long entry, char * buf, int wait)
printk("Trying to swap to unused swap-device\n"); printk("Trying to swap to unused swap-device\n");
return; return;
} }
/* Make sure we are the only process doing I/O with this swap page. */
while (set_bit(offset,p->swap_lockmap)) while (set_bit(offset,p->swap_lockmap))
sleep_on(&lock_queue); sleep_on(&lock_queue);
if (rw == READ) if (rw == READ)
...@@ -64,12 +78,16 @@ void rw_swap_page(int rw, unsigned long entry, char * buf, int wait) ...@@ -64,12 +78,16 @@ void rw_swap_page(int rw, unsigned long entry, char * buf, int wait)
if (p->swap_device) { if (p->swap_device) {
if (!wait) { if (!wait) {
page->count++; page->count++;
set_bit(PG_freeafter, &page->flags); set_bit(PG_free_after, &page->flags);
set_bit(PG_decr_after, &page->flags);
set_bit(PG_swap_unlock_after, &page->flags);
page->swap_unlock_entry = entry;
nr_async_pages++; nr_async_pages++;
} }
ll_rw_page(rw,p->swap_device,offset,buf); ll_rw_page(rw,p->swap_device,offset,buf);
if (wait) if (!wait)
wait_on_page(page); return;
wait_on_page(page);
} else if (p->swap_file) { } else if (p->swap_file) {
struct inode *swapf = p->swap_file; struct inode *swapf = p->swap_file;
unsigned int zones[PAGE_SIZE/512]; unsigned int zones[PAGE_SIZE/512];
...@@ -114,3 +132,52 @@ void rw_swap_page(int rw, unsigned long entry, char * buf, int wait) ...@@ -114,3 +132,52 @@ void rw_swap_page(int rw, unsigned long entry, char * buf, int wait)
printk("rw_swap_page: lock already cleared\n"); printk("rw_swap_page: lock already cleared\n");
wake_up(&lock_queue); wake_up(&lock_queue);
} }
/* This is run when asynchronous page I/O has completed. */
void swap_after_unlock_page (unsigned long entry)
{
unsigned long type, offset;
struct swap_info_struct * p;
type = SWP_TYPE(entry);
if (type >= nr_swapfiles) {
printk("swap_after_unlock_page: bad swap-device\n");
return;
}
p = &swap_info[type];
offset = SWP_OFFSET(entry);
if (offset >= p->max) {
printk("swap_after_unlock_page: weirdness\n");
return;
}
if (!clear_bit(offset,p->swap_lockmap))
printk("swap_after_unlock_page: lock already cleared\n");
wake_up(&lock_queue);
}
/*
* Swap partitions are now read via brw_page. ll_rw_page is an
* asynchronous function now --- we must call wait_on_page afterwards
* if synchronous IO is required.
*/
void ll_rw_page(int rw, kdev_t dev, unsigned long page, char * buffer)
{
int block = page;
switch (rw) {
case READ:
break;
case WRITE:
if (is_read_only(dev)) {
printk("Can't page to read-only device %s\n",
kdevname(dev));
return;
}
break;
default:
panic("ll_rw_page: bad block dev cmd, must be R/W");
}
if (set_bit(PG_locked, &mem_map[MAP_NR(buffer)].flags))
panic ("ll_rw_page: page already locked");
brw_page(rw, (unsigned long) buffer, dev, &block, PAGE_SIZE, 0);
}
...@@ -636,46 +636,58 @@ int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev) ...@@ -636,46 +636,58 @@ int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev)
static int ip_msqhst_procinfo(char *buffer, char **start, off_t offset, static int ip_msqhst_procinfo(char *buffer, char **start, off_t offset,
int length, int unused) int length, int unused)
{ {
off_t pos=0, begin=0; off_t pos=0, begin;
struct ip_masq *ms; struct ip_masq *ms;
unsigned long flags; unsigned long flags;
char temp[129];
int idx = 0; int idx = 0;
int len=0; int len=0;
len=sprintf(buffer,"Prc FromIP FPrt ToIP TPrt Masq Init-seq Delta PDelta Expires (free=%d,%d)\n", if (offset < 128)
ip_masq_free_ports[0], ip_masq_free_ports[1]); {
sprintf(temp,
"Prc FromIP FPrt ToIP TPrt Masq Init-seq Delta PDelta Expires (free=%d,%d)",
ip_masq_free_ports[0], ip_masq_free_ports[1]);
len = sprintf(buffer, "%-127s\n", temp);
}
pos = 128;
save_flags(flags); save_flags(flags);
cli(); cli();
for(idx = 0; idx < IP_MASQ_TAB_SIZE; idx++) for(idx = 0; idx < IP_MASQ_TAB_SIZE; idx++)
for(ms = ip_masq_m_tab[idx]; ms ; ms = ms->m_link) for(ms = ip_masq_m_tab[idx]; ms ; ms = ms->m_link)
{ {
int timer_active = del_timer(&ms->timer); int timer_active;
pos += 128;
if (pos <= offset)
continue;
timer_active = del_timer(&ms->timer);
if (!timer_active) if (!timer_active)
ms->timer.expires = jiffies; ms->timer.expires = jiffies;
len+=sprintf(buffer+len,"%s %08lX:%04X %08lX:%04X %04X %08X %6d %6d %lu\n", sprintf(temp,"%s %08lX:%04X %08lX:%04X %04X %08X %6d %6d %7lu",
masq_proto_name(ms->protocol), masq_proto_name(ms->protocol),
ntohl(ms->saddr),ntohs(ms->sport), ntohl(ms->saddr), ntohs(ms->sport),
ntohl(ms->daddr),ntohs(ms->dport), ntohl(ms->daddr), ntohs(ms->dport),
ntohs(ms->mport), ntohs(ms->mport),
ms->out_seq.init_seq,ms->out_seq.delta,ms->out_seq.previous_delta,ms->timer.expires-jiffies); ms->out_seq.init_seq,
ms->out_seq.delta,
ms->out_seq.previous_delta,
ms->timer.expires-jiffies);
if (timer_active) if (timer_active)
add_timer(&ms->timer); add_timer(&ms->timer);
len += sprintf(buffer+len, "%-127s\n", temp);
pos=begin+len; if(len >= length)
if(pos<offset) goto done;
{
len=0;
begin=pos;
}
if(pos>offset+length)
break;
} }
done:
restore_flags(flags); restore_flags(flags);
*start=buffer+(offset-begin); begin = len - (pos - offset);
len-=(offset-begin); *start = buffer + begin;
len -= begin;
if(len>length) if(len>length)
len=length; len = length;
return len; return len;
} }
......
...@@ -394,7 +394,7 @@ static void tcp_conn_request(struct sock *sk, struct sk_buff *skb, ...@@ -394,7 +394,7 @@ static void tcp_conn_request(struct sock *sk, struct sk_buff *skb,
skb_queue_head_init(&newsk->back_log); skb_queue_head_init(&newsk->back_log);
newsk->rtt = 0; /*TCP_CONNECT_TIME<<3*/ newsk->rtt = 0; /*TCP_CONNECT_TIME<<3*/
newsk->rto = TCP_TIMEOUT_INIT; newsk->rto = TCP_TIMEOUT_INIT;
newsk->mdev = 0; newsk->mdev = TCP_TIMEOUT_INIT<<1;
newsk->max_window = 0; newsk->max_window = 0;
newsk->cong_window = 1; newsk->cong_window = 1;
newsk->cong_count = 0; newsk->cong_count = 0;
...@@ -598,7 +598,6 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len) ...@@ -598,7 +598,6 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
* in shutdown state * in shutdown state
* 2 - data from retransmit queue was acked and removed * 2 - data from retransmit queue was acked and removed
* 4 - window shrunk or data from retransmit queue was acked and removed * 4 - window shrunk or data from retransmit queue was acked and removed
* 8 - we want to do a fast retransmit. One packet only.
*/ */
if(sk->zapped) if(sk->zapped)
...@@ -709,18 +708,52 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len) ...@@ -709,18 +708,52 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
* This will allow us to do fast retransmits. * This will allow us to do fast retransmits.
*/ */
if (sk->rcv_ack_seq == ack && sk->window_seq == window_seq && !(flag&1)) /* We are looking for duplicate ACKs here.
* An ACK is a duplicate if:
* (1) it has the same sequence number as the largest number we've seen,
* (2) it has the same window as the last ACK,
* (3) we have outstanding data that has not been ACKed
* (4) The packet was not carrying any data.
* I've tried to order these in occurance of most likely to fail
* to least likely to fail.
* [These are the rules BSD stacks use to determine if an ACK is a
* duplicate.]
*/
if (sk->rcv_ack_seq == ack
&& sk->window_seq == window_seq
&& !(flag&1)
&& before(ack, sk->sent_seq))
{ {
/* /* See draft-stevens-tcpca-spec-01 for explanation
* We only want to short cut this once, many * of what we are doing here.
* ACKs may still come, we'll do a normal transmit
* for these ACKs.
*/ */
if (++sk->rcv_ack_cnt == MAX_DUP_ACKS+1) sk->rcv_ack_cnt++;
flag |= 8; /* flag for a fast retransmit */ if (sk->rcv_ack_cnt == MAX_DUP_ACKS+1) {
sk->ssthresh = max(sk->cong_window >> 1, 2);
sk->cong_window = sk->ssthresh+MAX_DUP_ACKS+1;
tcp_do_retransmit(sk,0);
/* reduce the count. We don't want to be
* seen to be in "retransmit" mode if we
* are doing a fast retransmit.
*/
sk->retransmits--;
} else if (sk->rcv_ack_cnt > MAX_DUP_ACKS+1) {
sk->cong_window++;
/*
* At this point we are suppose to transmit a NEW
* packet (not retransmit the missing packet,
* this would only get us into a retransmit war.)
* I think that having just adjusted cong_window
* we will transmit the new packet below.
*/
}
} }
else else
{ {
if (sk->rcv_ack_cnt > MAX_DUP_ACKS) {
sk->cong_window = sk->ssthresh;
}
sk->window_seq = window_seq; sk->window_seq = window_seq;
sk->rcv_ack_seq = ack; sk->rcv_ack_seq = ack;
sk->rcv_ack_cnt = 1; sk->rcv_ack_cnt = 1;
...@@ -1046,8 +1079,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len) ...@@ -1046,8 +1079,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
if (((!flag) || (flag&4)) && sk->send_head != NULL && if (((!flag) || (flag&4)) && sk->send_head != NULL &&
(((flag&2) && sk->retransmits) || (((flag&2) && sk->retransmits) ||
(flag&8) || (sk->send_head->when + sk->rto < jiffies)))
(sk->send_head->when + sk->rto < jiffies)))
{ {
if(sk->send_head->when + sk->rto < jiffies) if(sk->send_head->when + sk->rto < jiffies)
tcp_retransmit(sk,0); tcp_retransmit(sk,0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment