]> git.neil.brown.name Git - history.git/commitdiff
Import 1.3.57 1.3.57
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:30 +0000 (15:10 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:30 +0000 (15:10 -0500)
76 files changed:
Documentation/Configure.help
Documentation/networking/arcnet-hardware.txt
Documentation/networking/arcnet.txt
Makefile
Rules.make
arch/alpha/config.in
arch/alpha/kernel/irq.c
arch/alpha/mm/init.c
arch/i386/boot/compressed/misc.c
arch/i386/config.in
arch/i386/defconfig
arch/i386/kernel/entry.S
arch/i386/mm/init.c
arch/mips/config.in
arch/ppc/config.in
drivers/char/Config.in
drivers/char/wd501p.h [new file with mode: 0644]
drivers/char/wdt.c [new file with mode: 0644]
drivers/net/arcnet.c
drivers/net/net_init.c
drivers/net/sk_g16.c
drivers/scsi/aha152x.c
drivers/scsi/aha152x.h
drivers/scsi/sg.c
fs/buffer.c
fs/devices.c
fs/exec.c
fs/file_table.c
fs/inode.c
fs/msdos/inode.c
fs/nfs/nfsroot.c
fs/nfs/sock.c
fs/proc/array.c
fs/proc/root.c
fs/super.c
include/asm-alpha/byteorder.h
include/asm-i386/smp_lock.h
include/asm-i386/unistd.h
include/linux/fs.h
include/linux/kerneld.h [new file with mode: 0644]
include/linux/lists.h [new file with mode: 0644]
include/linux/mm.h
include/linux/module.h
include/linux/pagemap.h
include/linux/proc_fs.h
include/linux/swap.h
include/linux/swapctl.h
include/linux/sysctl.h [new file with mode: 0644]
include/linux/timer.h
include/net/route.h
init/main.c
ipc/Makefile
ipc/msg.c
ipc/shm.c
ipc/util.c
kernel/Makefile
kernel/exit.c
kernel/info.c
kernel/ksyms.c
kernel/module.c
kernel/sys.c
kernel/sysctl.c [new file with mode: 0644]
mm/Makefile
mm/filemap.c
mm/memory.c
mm/page_alloc.c [new file with mode: 0644]
mm/page_io.c [new file with mode: 0644]
mm/swap.c
mm/swap_state.c [new file with mode: 0644]
mm/swapfile.c [new file with mode: 0644]
mm/vmscan.c [new file with mode: 0644]
net/core/dev.c
net/ipv4/ip_input.c
net/ipv4/ip_sockglue.c
net/ipv4/route.c
net/ipv4/udp.c

index 2b1449a4648da0094cd3897167fde7fea5066cb3..de9864ef069f05c920af939175bfe83c6d5e6caa 100644 (file)
@@ -30,8 +30,8 @@ CONFIG_MATH_EMULATION
   Linux can emulate a math coprocessor (used for floating point
   operations) if you don't have one. 486DX and Pentium processors have
   a math coprocessor built in, 486SX and 386 do not, unless you added
-  a 487DX or 387, respectively.  (The messages during boot time can
-  give you some hints here.) Everyone needs either a coprocessor or
+  a 487DX or 387, respectively.  (The messages during boot time can give
+  you some hints here ["man dmesg"]) Everyone needs either a coprocessor or
   this emulation. If you enable this emulation even though you have a
   coprocessor, the coprocessor will be used nevertheless. (This
   behavior can be changed with the kernel command line option
@@ -63,7 +63,12 @@ CONFIG_BLK_DEV_RAM
   write to it and do all the other things that normal block devices can do.
   It is usually used to load and store a copy of a minimal root file
   system off of a floppy into RAM during the initial install of Linux.
-  Most normal users won't need this functionality, and can thus say N here.
+  Note that the kernel command line option "ramdisk=XX" is now obsolete.
+  For details, read Documentation/ramdisk.txt. 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 and read Documentation/modules.txt.
+  Most normal users won't need the RAM disk functionality, and can thus say 
+  N here.
 
 Normal (MFM/RLL) disk and IDE disk/cdrom support
 CONFIG_ST506                              
@@ -90,7 +95,7 @@ CONFIG_BLK_DEV_HD
   As you might have guessed, there are now two drivers for IDE
   harddrives around: the old one and the new improved one. The old one
   is not any longer more reliable than the new one. The new driver can
-  also handle IDE/ATAPI CDROM drives (ATAPI = AT Attachment Packet
+  also handle IDE/ATAPI CDROM and tape drives (ATAPI = AT Attachment Packet
   Interface is a new protocol currently used for controlling CDROM and
   tape drives, similar to the SCSI protocol. Some newer CDROM drives
   such as NEC 260 and MITSUMI triple/quad speed drives use it, but
@@ -164,9 +169,10 @@ CONFIG_DECSTATION
 
 Generate code for R4x00
 CONFIG_R4X00
-#####
-##### Anyone have details? It's for the MIPS architecture.
-#####
+  If your computer uses the 64 bit R4X00 processor (as opposed to the
+  32 bit R3000), you need to say Y here, otherwise N. Note that these
+  processors are not compatible and the kernel can only work on the
+  processor type it was compiled for.
 
 Networking support
 CONFIG_NET
@@ -180,13 +186,23 @@ CONFIG_NET
 Network aliasing
 CONFIG_NET_ALIAS
   This is for setting several network addresses on the same low-level network
-  device driver. Typically used for services that act different based
-  on the address they listen (eg. Apache httpd) or for connecting to
+  device driver. Typically used for services that act differently based
+  on the address they listen on (e.g. Apache httpd) or for connecting to
   different logical networks through the same physical interface.
   This is the generic part, later when configuring network protocol
   options you will be asked for protocol-specific aliasing support.
-  See net/core/README.alias for more info.
-  If you need this features (for any protocol, like IP) say Y.  
+  See Documentation/networking/alias.txt for more info.
+  If you need this features (for any protocol, like IP) say Y; if unsure, 
+  say N.  
+
+Network firewalls
+CONFIG_FIREWALL
+  A firewall is a computer which protects a local network from the
+  rest of the World: all traffic to and from computers on the local
+  net is inspected by the firewall first. If you want to configure
+  your Linux box as a firewall for a local network, say Y here. If
+  your local network is TCP/IP based, you will have to say Y to "IP:
+  firewalling", below. Chances are that you don't want this, so say N.
 
 Sun floppy controller support
 CONFIG_BLK_DEV_SUNFD
@@ -195,7 +211,7 @@ CONFIG_BLK_DEV_SUNFD
 
 Alpha system type
 CONFIG_ALPHA_AVANTI
-  Find out what type of Alpha system you are running. If you can't
+  Find out what type of Alpha motherboard you have. If you can't
   find one of the given names, then try "Noname". For this question,
   it suffices to give a unique prefix of the option you want to
   choose. 
@@ -205,7 +221,7 @@ CONFIG_MAX_16M
   This is for some buggy motherboards which cannot properly deal with
   the memory above 16MB. If you have more than 16MB of RAM and
   experience weird problems, you might want to try Y, everyone else
-  says N. Note for machines with more that 64MB: in order for the
+  says N. Note for machines with more that 64MB of RAM: in order for the
   kernel to be able to use the memory above 64MB, pass the command
   line option "mem=XXXM" (where XXX is the memory size in
   megabytes) to your kernel. See the documentation of your boot loader
@@ -214,6 +230,12 @@ CONFIG_MAX_16M
   (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO.
   You also need at least 512kB of RAM cache if you have more than 64MB
   of RAM.
+  Some other things to try when experiencing seemingly random, "weird"
+  problems: 1) passing the "no-hlt" option to the kernel 2) passing
+  the "no-387" option to the kernel 3) passing the "mem=4M" option to
+  the kernel (will disable all but the first 4M of RAM) 4) disabling
+  the cache from your BIOS settings 5) exchanging RAM chips 6)
+  exchanging the motherboard 7) committing suicide.
 
 Using SRM as bootloader
 CONFIG_ALPHA_SRM
@@ -244,9 +266,9 @@ CONFIG_PCI
   without this option). The PCI-HOWTO, available via ftp (user:
   anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO, contains
   valuable information about which PCI hardware works under Linux and
-  which doesn't.  If some of PCI devices don't work and you get a
-  warning during boot time, please follow the instructions at the top of
-  include/linux/pci.h. The buggy PCTech RZ 1000 IDE
+  which doesn't.  If some of your PCI devices don't work and you get a
+  warning during boot time ("man dmesg"), please follow the instructions 
+  at the top of include/linux/pci.h. The buggy PCTech RZ 1000 IDE
   harddrive controller which is used in some PCI systems is detected
   and correctly handled by this driver.
 
@@ -292,8 +314,8 @@ CONFIG_BINFMT_ELF
   (this does *not* mean that you will be able to run executables from
   different architectures or operating systems!) and makes building
   run-time libraries very easy. Many new executables are distributed
-  solely in ELF format. You definitely want to say Y here. Information
-  about ELF is on the WWW at http://sable.ox.ac.uk/~jo95004/elf.html
+  solely in ELF format. You definitely want to say Y here. Information about
+  ELF is on the WWW at http://www.sjc.ox.ac.uk/users/barlow/elf-howto.html
   (To browse the WWW, you need to have access to a machine on the
   Internet that has one of the programs lynx, netscape or Mosaic).  If
   you find that after upgrading to Linux kernel 1.3 and saying Y here,
@@ -320,22 +342,16 @@ CONFIG_KERNEL_ELF
   kernel in ELF by saying Y here and editing the variables CC
   and LD in the toplevel Makefile.
 
-Use 486-specific optimizations (does NOT work on i386)
-CONFIG_M486
-  If you have a 486 or better, as opposed to a 386, say Y here:
-  things will be slightly faster. However, it is not required: the
-  kernel will run on all CPUs without this option. If you are
-  not sure, say N; This option will make the kernel use some
-  instructions that are only available on 486+ machines.
-
-Use Pentium optimizations
-CONFIG_M586 
-  If you have a 586 or better, as opposed to a 486, or if you have a
-  486 and are very short on memory, say Y here.
-  Things will be slightly faster for a 586, and your kernel will be
-  smaller.  A kernel with this option enabled will still run on a 486,
-  although slightly slower.
-
+Processor type
+CONFIG_M386
+  This is the processor type of your CPU. It is used for optimizing
+  purposes. In order to compile a kernel that can run on all three CPU
+  types (albeit not optimally fast), you can specify "386" here.  If
+  you specify "486" or "Pentium", then the kernel will run on
+  both 486 and Pentium CPUs. In rare cases, it can make sense to
+  specify "Pentium" here even if running a 486: the kernel will be
+  smaller but slower.
+  
 Enable loadable module support
 CONFIG_MODULES
   Kernel modules are small pieces of compiled code which can be 
@@ -344,7 +360,7 @@ CONFIG_MODULES
   Documentation/modules.txt. Modules can be device drivers, file 
   systems, binary executable formats, and so on. If you think that 
   you may want to make use of modules with this kernel in the future, 
-  then say Y here.
+  then say Y here. If unsure, say Y.
 
 Set version information on all symbols for modules
 CONFIG_MODVERSIONS
@@ -361,6 +377,19 @@ CONFIG_MODVERSIONS
   option is to compile it as a module (PPP is a protocol for sending
   internet traffic over telephone lines). Therefore, N is a safe bet.
 
+Kernel daemon support
+CONFIG_KERNELD
+  Normally when you have seleceted some drivers and/or filesystems
+  to be created as loadable modules, you also have the responsibility
+  to load the corresponding module (via insmod/modprobe) before you
+  use it.  If you select Y here, the kernel will take care of this
+  all by itself, together with a user level daemon; "kerneld".
+  Note that "kerneld" will also automatically unload all unused
+  modules, so you don't have to use "rmmod" either.
+  There are some other "kernel callouts" that will be available
+  later on, such as a user level "beeper" and a generic screen blanker.
+  The "kerneld" daemon is included in "modules-1.2.8" and later.
+
 TCP/IP networking
 CONFIG_INET
   These are the protocols used on the Internet and on most local
@@ -425,10 +454,10 @@ IP: firewalling
 CONFIG_IP_FIREWALL
   A firewall is a computer which protects a local network from the
   rest of the internet: all traffic to and from computers on the local
-  net is inspected by the firewall first. If you want to enlarge your
-  kernel by about 2kB and configure your Linux box as a firewall for a
-  local network, say Y here. You will need to read the FIREWALL-HOWTO,
-  available via ftp (user: anonymous) in
+  net is inspected by the firewall first. If you want to configure
+  your Linux box as a firewall for a local TCP/IP based network, say Y
+  here. This will enlarge your kernel by about 2kB. You will need to
+  read the FIREWALL-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. Also, you will have to use
   the ipfw tool from the net-tools package, available via ftp (user:
   anonymous) from
@@ -436,10 +465,10 @@ CONFIG_IP_FIREWALL
   preferably ipfwadm from ftp.xos.nl:/pub/linux/ipfwadm/. These
   programs allow selective blocking of internet traffic based on type,
   origin and destination.  You need to enable IP firewalling in order
-  to be able to use IP masquerading (i.e. IP traffic from one of the
-  local computers and destined for an outside host is changed by your
-  box so that it appears to come from you). Chances are that you don't
-  want this, so say N.
+  to be able to use IP masquerading (i.e. local computers can chat
+  with an outside host, but that outside host is made to think that it
+  is talking to the firewall box. Makes the local network completely
+  invisible). Chances are that you don't want this, so say N.
 
 IP: accounting
 CONFIG_IP_ACCT
@@ -460,7 +489,7 @@ CONFIG_IP_ACCT
 
 IP: tunneling
 CONFIG_NET_IPIP
-  Tunneling means to encapsulating data of one protocol type within
+  Tunneling means encapsulating data of one protocol type within
   another protocol and sending it over a channel that understands the
   encapsulating protocol. This particular tunneling driver implements
   encapsulation of IP within IP, which sounds kind of pointless, but
@@ -485,7 +514,7 @@ CONFIG_IP_MASQUERADE
   box acts as a firewall wants to send something to the outside, your
   box can "masquerade" as that host, i.e. it forwards the traffic to
   the intended destination, but makes it look like it came from the
-  firewall host itself. It works both ways: if the outside host
+  firewall box itself. It works both ways: if the outside host
   answers, the firewall will silently forward the traffic to the
   corresponding local computer. This way, the computers on your local
   net are completely invisible to the outside world, even though they
@@ -505,9 +534,19 @@ CONFIG_IP_MASQUERADE
 
 IP: aliasing support
 CONFIG_IP_ALIAS
-  You need this to enable IP layer network aliasing. This will also
-  enable ARP resolution for alias devices. If you don't need several
-  IP addresses per interface, answer N.
+  Sometimes it is useful to give several addresses to a single network
+  interface (= serial port or ethernet card). The most common case is
+  that you want to serve different WWW documents to the outside
+  according to which of your host names they used to connect to
+  you. This is explained in detail on the WWW at
+  http://www.thesphere.com/~dlp/TwoServers/ (to browse the WWW, you
+  need to have access to a machine on the Internet that has one of the
+  programs lynx, netscape or Mosaic). Another scenario would be that
+  there are two logical networks living on your local ethernet and you
+  want to access them both with the same ethernet card. The
+  configuration of these alias addresses is done with a special name
+  syntax explained in Documentation/networking/alias.txt. If you want
+  this, say Y. Most people don't need it and say N.
 
 IP: multicast routing(in progress)
 CONFIG_IP_MROUTE
@@ -526,13 +565,15 @@ CONFIG_INET_PCTCP
 
 Reverse ARP
 CONFIG_INET_RARP
-  Since you asked: if there are diskless machines on your network that
-  know their hardware ethernet address but don't know their IP
+  Since you asked: if there are diskless machines on your local network 
+  that know their hardware ethernet address but don't know their IP
   addresses upon startup, they send out a Reverse
   Address Resolution Protocol request to find out their own IP
   addresses. If you want your Linux box to be able to *answer* such
-  requests, say Y here; you'd use the program rarp ("man rarp"). If
-  you want to compile this as a module ( = code which can be inserted
+  requests, say Y here; you'd use the program rarp ("man rarp"). 
+  Superior solutions to the same problem are given by the 
+  protocols BOOTP and DHCP. If you want to compile RARP support 
+  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.  If you don't understand a
   word, say N and rest in peace.
@@ -557,10 +598,10 @@ Disable NAGLE algorithm (normally enabled)
 CONFIG_TCP_NAGLE_OFF
   The NAGLE algorithm works by requiring an acknowledgment before
   sending small IP frames (= packets).  This keeps tiny telnet and
-  rlogin packets from congesting Wide Area Networks.  Most people strongly
-  recommend to say N here, though, thereby leaving NAGLE enabled. Those
-  programs that benefit by disabling the facility should do it on a per
-  connection basis themselves anyway.
+  rlogin packets from congesting Wide Area Networks.  Most people
+  strongly recommend to say N here, thereby leaving NAGLE
+  enabled. Those programs that would benefit from disabling this
+  facility can do it on a per connection basis themselves.
 
 IP: Drop source routed frames
 CONFIG_IP_NOSR
@@ -581,8 +622,8 @@ CONFIG_SKB_LARGE
   This option can speed up network performance. It works by increasing
   the size of socket buffers, thereby reducing overhead but increasing
   memory usage. Say N if you have less than 16Mb of RAM, otherwise Y.
-  Note for machines with more that 64MB: in order for the kernel to be
-  able to use the memory above 64MB, pass the command line option
+  Note for machines with more that 64MB of RAM: in order for the kernel 
+  to be able to use the memory above 64MB, pass the command line option
   "mem=XXXM" (where XXX is the memory size in megabytes) to your
   kernel. See the documentation of your boot loader (lilo or loadlin)
   about how to pass options to the kernel. The lilo procedure is also
@@ -593,9 +634,10 @@ CONFIG_SKB_LARGE
 The IPX protocol
 CONFIG_IPX
   This is support for the Novell networking protocol, IPX. You need it
-  if you want to access Novell Netware servers by using ncpfs or from
-  within the Linux DOS emulator dosemu (read the DOSEMU-HOWTO,
-  available via ftp (user: anonymous) in
+  if you want to access Novell Netware servers by using the Linux
+  Novell client ncpfs (available via ftp (user: anonymous) from 
+  sunsite.unc.edu:/pub/Linux/system/Filesystem/) or from within the 
+  Linux DOS emulator dosemu (read the DOSEMU-HOWTO, available in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO). To turn your Linux box into
   a fully featured Netware file server and IPX router, say Y here and
   fetch lwared from
@@ -606,8 +648,6 @@ CONFIG_IPX
   the programs lynx, netscape or Mosaic). This driver would enlarge
   your kernel by about 5 kB. Unless you have Novell computers on your
   local network, say N.
-  BTW: Although it still doesn't work with this release of the kernel you 
-  can also find ncpfs (a free Novell client) on linux01.gwdg.de.
 
 Appletalk DDP
 CONFIG_ATALK
@@ -668,6 +708,14 @@ CONFIG_NETROM
   might want to get the very latest 1.3 kernel if you intend to use
   this.
 
+AX.25 over Ethernet
+CONFIG_BPQETHER
+  AX.25 is the protocol used for computer communication over amateur
+  radio. If you say Y here, you will be able to send and receive AX.25
+  traffic over ethernet (also called "BPQ AX.25"), which could be
+  useful if some other computer on your local network has a direct
+  amateur radio connection.
+
 Kernel/User network link driver(ALPHA)
 CONFIG_NETLINK
   This driver allows for two-way communication between certain parts
@@ -696,7 +744,8 @@ CONFIG_SCSI
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. This driver is also available
   as a module ( = code which can be inserted in and removed from the
   running kernel whenever you want). If you want to compile it as a
-  module, say M here and read Documentation/modules.txt.
+  module, say M here and read Documentation/modules.txt and
+  Documentation/scsi.txt. 
 
 SCSI disk support
 CONFIG_BLK_DEV_SD
@@ -706,7 +755,7 @@ CONFIG_BLK_DEV_SD
   CDROMs. This driver is also available as a module ( = code which can
   be inserted in and removed from the running kernel whenever you
   want). If you want to compile it as a module, say M here and read
-  Documentation/modules.txt.
+  Documentation/modules.txt and Documentation/scsi.txt.
   
 SCSI tape support
 CONFIG_CHR_DEV_ST
@@ -716,7 +765,8 @@ CONFIG_CHR_DEV_ST
   the kernel source. This is NOT for SCSI CDROMs. This driver is also
   available as a module ( = code which can be inserted in and removed
   from the running kernel whenever you want). If you want to compile
-  it as a module, say M here and read Documentation/modules.txt.
+  it as a module, say M here and read Documentation/modules.txt and
+  Documentation/scsi.txt .
 
 SCSI CDROM support
 CONFIG_BLK_DEV_SR
@@ -726,7 +776,8 @@ CONFIG_BLK_DEV_SR
   ISO9660 filesystem later. This driver is also available as a module
   ( = code which can be inserted in and removed from the running
   kernel whenever you want). If you want to compile it as a module,
-  say M here and read Documentation/modules.txt.
+  say M here and read Documentation/modules.txt and
+  Documentation/scsi.txt .
 
 SCSI generic support
 CONFIG_CHR_DEV_SG
@@ -740,7 +791,7 @@ CONFIG_CHR_DEV_SG
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. 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.
+  Documentation/modules.txt and Documentation/scsi.txt.
 
 Probe all LUNs on each SCSI device
 CONFIG_SCSI_MULTI_LUN
@@ -771,7 +822,9 @@ Adaptec AHA1542 support
 CONFIG_SCSI_AHA1542
   This is support for an SCSI host adaptor. It is explained in section
   3.4 of the SCSI-HOWTO, available via ftp (user: anonymous) at
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If it doesn't work out of
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  Note that Trantor was
+  recently purchased by Adaptec, and some former Trantor products are
+  being sold under the Adaptec name. If it doesn't work out of
   the box, you may have to change some settings in
   drivers/scsi/aha1542.h.  If you want to compile this as a module ( =
   code which can be inserted in and removed from the running kernel
@@ -996,9 +1049,9 @@ Dummy net driver support
 CONFIG_DUMMY
   This is essentially a loopback device (i.e. traffic you send to this
   device is immediately returned back to you) with a configurable IP
-  address different from the usual 127.0.0.1. Can be used to give you
-  more than one IP address or make your currently inactive SLIP
-  address seem like a real address. If you use SLIP or PPP, you might
+  address different from the usual 127.0.0.1. It is most commonly used
+  in order to make your currently inactive SLIP address seem like a
+  real address for local programs. If you use SLIP or PPP, you might
   want to enable it. Read about it in the Network Administrator's
   Guide, available via ftp (user: anonymous) from
   sunsite.unc.edu:/pub/Linux/docs/LDP. Since this thing comes often
@@ -1071,7 +1124,12 @@ CONFIG_PPP
   then you cannot compile the PPP driver into the kernel; you can only
   compile it as a module. If you want to compile it as a module, say M
   here and read Documentation/modules.txt as well as
-  Documentation/networking/net-modules.txt. If unsure, say N.
+  Documentation/networking/net-modules.txt. Note that, no matter what
+  you do, the BSD compression code (used to compress the IP packets
+  sent over the serial line; has to be supported at the other end as
+  well) can only be compiled as a module; it is called bsd_comp.o and
+  will show up in the directory modules once you have said "make
+  modules". If unsure, say N.
 
 16 channels instead of 4 
 CONFIG_PPP_LOTS
@@ -1083,7 +1141,7 @@ Z8530 SCC kiss emulation driver for AX.2
 CONFIG_SCC
   These cards are used to connect your Linux box to an amateur radio
   and communicate with other computers.  If you want to use this, read
-  drivers/char/README.scc and the HAM-HOWTO, available available via
+  Documentation/networking/z8530drv.txt and the HAM-HOWTO, available via
   ftp (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO.
 
 PLIP (parallel port) support
@@ -1129,12 +1187,13 @@ CONFIG_EQUALIZER
 Sun LANCE Ethernet support
 CONFIG_SUN_LANCE
   This is support for lance ethernet cards on Sun workstations such as
-  the Sparcstation IPC (any Sparc with an 'le0' under SunOS basically).
+  the Sparcstation IPC (any Sparc with a network interface 'le0' under
+  SunOS basically).
 
 Sun Intel Ethernet support
 CONFIG_SUN_INTEL
   This is support for the intel ethernet cards on some Sun workstations
-  (all those with an ie0 interface under SunOS).
+  (all those with a network interface 'ie0' under SunOS).
 
 Do you want to be offered ALPHA test drivers
 CONFIG_NET_ALPHA
@@ -1426,8 +1485,8 @@ CONFIG_NI65
 Ottawa PI and PI/2 support
 CONFIG_PI
   This is a driver for the Ottawa Amateur Radio Club PI and PI2 cards,
-  which are commonly used to send internet traffic over radio. More
-  information about these cards is on the WWW at
+  which are commonly used to send internet traffic over amateur radio. 
+  More information about these cards is on the WWW at
   http://hydra.carleton.ca/info/pi2.html (To browse the WWW, you need
   to have access to a machine on the Internet that has one of the
   programs lynx, netscape or Mosaic). If you have one of these cards,
@@ -1439,10 +1498,10 @@ CONFIG_PI
 Gracilis PackeTwin support
 CONFIG_PT
   This card is similar to the PI card (mentioned above).  It is used mainly
-  by amateur radio operators for packet radio.  You should of already said Y
-  to "AX.25 support" as this card uses that protocol. 
-  Other than the code and the PT user documentation, there is no other
-  information on this card.
+  by amateur radio operators for packet radio.  You should have already 
+  said Y to "AX.25 support" as this card uses that protocol. 
+  More information about this driver can be found in the file 
+  drivers/net/README.pt. 
   NOTE: The card is capable of DMA and full duplex but neither of these have
   been coded in the driver as yet.
 
@@ -1738,7 +1797,7 @@ CONFIG_SBPCD
   This driver supports most of the drives which use the Panasonic or
   SoundBlaster interface.
   The Matsushita CR-521, CR-522, CR-523, CR-562, CR-563 drives (sometimes
-  labelled "Creative"), the CreativeLabs CD200, the Longshine LCS-7260,
+  labeled "Creative"), the CreativeLabs CD200, the Longshine LCS-7260,
   the "IBM External ISA CDROM" (in fact a CR-56x model), the TEAC CD-55A
   fall under this category. Some other "electrically compatible" drives
   (Vertos, Genoa, some Funai models) are currently not supported; for the
@@ -1795,6 +1854,16 @@ Sanyo H94A CDROM support
 CONFIG_SJCD
   If this is your CDROM drive, say Y here.
 
+Quota support
+CONFIG_QUOTA
+  If you say Y here, you will be able to set per user limits for disk
+  usage (also called diskquotas). Currently, it works only for the
+  ext2 filesystem; you need the software available via ftp (user:
+  anonymous) from
+  sunsite.unc.edu:/pub/Linux/systm/Admin/quota_acct.tar.gz in order to
+  use it. Obviously, this is only useful for multi user systems. If
+  unsure, say N.
+
 Standard (minix) fs support
 CONFIG_MINIX_FS
   Minix is a simple operating system used in many classes about
@@ -1806,7 +1875,7 @@ CONFIG_MINIX_FS
   built-in restrictions. This option will enlarge your kernel by about
   25 kB. Everyone should say Y or M so that they are able to read this
   common floppy format.  If you want to compile this as a module
-  however ( = code which can be inserted in and removed from the
+  ( = code which can be inserted in and removed from the
   running kernel whenever you want), say M here and read
   Documentation/modules.txt. Note that the filesystem of your root
   partition cannot be compiled as a module.
@@ -1946,7 +2015,9 @@ CONFIG_ROOT_NFS
 
 ISO9660 cdrom filesystem support
 CONFIG_ISO9660_FS
-  If you have a CDROM and want to do more with it than just listen to
+  This is the standard filesystem used on CDROMs. It was previously known 
+  as "High Sierra Filesystem" and is called "hsfs" on other Unix systems. 
+  If you have a CDROM drive and want to do more with it than just listen to
   audio CDs and watch its LEDs, say Y (and read the CDROM-HOWTO,
   available via ftp (user: anonymous) from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO), thereby enlarging your
@@ -2171,24 +2242,20 @@ CONFIG_QIC02_DYNCONF
 
 QIC-117 tape support
 CONFIG_FTAPE
-  Most tape drives using the floppy disk controller will need
-  this. Colorado Jumbo, Conner Tape-Stor would be two models of this.
-  If you have a non-SCSI tape device like that, say Y. QIC-40 users
-  say Y too. And everyone read the Ftape-HOWTO, available via ftp
-  (user: anonymous) from sunsite.unc.edu:/pub/Linux/docs/HOWTO. Tape
-  drives that attach to the parallel port, like the Colorado Tracker,
-  are not yet supported by Linux.  Note that saying Y here will not
-  insert the code into the kernel: instead, a module will be compiled
-  ( = code which can be inserted in and removed from the running
-  kernel whenever you want). Read Documentation/modules.txt to find
-  out how to use it.
+  This option is obsolete as of Linux v1.3.34. If you would like to
+  use a tape drive that uses the floppy disk controller, like QIC-40,
+  QIC-80, QIC-117, QIC-3010 (examples: Colorado Jumbo or Conner
+  Tape-Stor), you want to read the Ftape-HOWTO, available via ftp
+  (user: anonymous) from sunsite.unc.edu:/pub/Linux/docs/HOWTO. Then
+  get the ftape distribution v2.04 or higher from
+  sunsite.unc.edu:/pub/Linux/kernel/tapes/. Tape drives that attach to
+  the parallel port, like the Colorado Tracker, are not yet supported
+  by Linux.
 
 number of ftape buffers
 NR_FTAPE_BUFFERS 3
-  The floppy tape drive needs some memory allocated in the kernel.
-  n buffers, each having 32 kB, will be allocated if you enter n
-  here. Consequently, your kernel size increases by n*32 kB. You
-  should accept the default unless you know what you're doing.
+  This option is obsolete since Linux v1.3.34. Upgrade your ftape
+  distribution to v2.04.
 
 Zilog serial support
 CONFIG_SUN_ZS
@@ -2197,21 +2264,20 @@ CONFIG_SUN_ZS
 
 Advanced Power Management
 CONFIG_APM
-  This driver provides APM support on machines with an APM-compliant 32-bit
-  BIOS.  Specifically, the time will be reset after a USER RESUME
-  operation, the /proc/apm device will provide battery status information,
-  and ioctls are provided to put the machine in STANDBY or SUSPEND mode.
-  This is most useful on laptops with a compliant BIOS.
+  APM is a BIOS standard for saving power using several different
+  techniques. This is mostly useful for battery powered laptops with
+  APM compliant BIOSes.  Specifically, the time will be reset after a
+  USER RESUME operation, the /proc/apm device will provide battery
+  status information, and ioctls are provided to put the machine in
+  STANDBY or SUSPEND mode.  This driver does not work for the TI 4000M
+  TravelMate and the ACER 486/DX4/75 because they don't follow the
+  standard. Say Y if you have a different laptop.
 
 Ignore USER SUSPEND
 CONFIG_APM_IGNORE_USER_SUSPEND
   This option will ignore USER SUSPEND requests.  On machines with a
-  compliant APM BIOS, this is never what you want to do.  However, this is
-  necessary on the NEC Versa M series, which generates these when resuming
-  from SYSTEM SUSPEND.  Enabling this on other laptops may cause the laptop
-  to generate a CRITICAL SUSPEND when an appropriate USER SUSPEND is
-  ignored -- this may prevent the APM driver from updating the system time
-  on a RESUME.
+  compliant APM BIOS, you want to say N.  However, on the NEC Versa M
+  series notebooks, it is necessary to say Y because of a BIOS bug.
 
 Enable APM features
 CONFIG_APM_DO_ENABLE
@@ -2227,6 +2293,17 @@ CONFIG_APM_DO_ENABLE
   this off if you have a NEC UltraLite Versa 33/C or a Toshiba T400CDT.
   This is off by default since most machines do fine without this feature.
 
+Watchdog Timer Support 
+CONFIG_WATCHDOG
+  If you enable this option and create a character special file
+  /dev/watchdog with major number 10 and minor number 130 using mknod
+  ("man mknod"), you will get a software watchdog, i.e.: subsequently
+  opening the file and failing to write to it for longer than 1 minute
+  will result in rebooting the machine. This could be useful for a
+  networked machine that needs to come back online as fast as possible
+  after a lock-up. For details, read Documentation/watchdog.txt in the
+  kernel source. If unsure, say N.
+
 Do CPU IDLE calls
 CONFIG_APM_CPU_IDLE
   Enable calls to APM CPU Idle/CPU Busy inside the kernel's idle loop.  On
@@ -2330,4 +2407,9 @@ CONFIG_PROFILE_SHIFT
 # LocalWords:  pppd Zilog ZS soundcards SRM bootloader ez mainmenu rarp ipfwadm
 # LocalWords:  RTNETLINK mknod xos MTU lwared Macs mac netatalk macs cs Wolff
 # LocalWords:  dartmouth flowerpt MultiMaster FlashPoint tudelft etherexpress
-# LocalWords:  ICL EtherTeam ETH IDESCSI TXC
+# LocalWords:  ICL EtherTeam ETH IDESCSI TXC dmesg httpd hlt sjc barlow dlp mtu
+# LocalWords:  thesphere TwoServers BOOTP DHCP ncpfs BPQETHER BPQ chipsets MG
+# LocalWords:  bsd comp Sparcstation le SunOS ie Gracilis PackeTwin PT pt LU FX
+# LocalWords:  FX TEAC SoundBlaster CR CreativeLabs LCS mS
+# LocalWords:  Vertos Genoa Funai hsfs NCP NetWare tgz APM apm ioctls UltraLite
+# LocalWords:  TravelMate CDT LCD backlight VC
index cb9598d119e9314476631079261372c84ac113bc..5a903b4e70688d56fd3a7094941f77d822c3d9a4 100644 (file)
@@ -1,7 +1,10 @@
 
 -----------------------------------------------------------------------------
-This file is a supplement to README.arcnet.  Please read that for general
-driver configuration help.
+1) This file is a supplement to arcnet.txt.  Please read that for general
+   driver configuration help.
+-----------------------------------------------------------------------------
+2) This file is no longer Linux-specific.  It should probably be moved out of
+   the kernel sources.  Ideas?
 -----------------------------------------------------------------------------
 
 Because so many people (myself included) seem to have obtained ARCnet cards
@@ -17,18 +20,19 @@ INTRODUCTION TO ARCNET
 ARCnet is a network type which works in a way similar to popular "ethernet"
 networks but which is also different in some very important ways.
 
-First of all, you can get ARCnet cards in two speeds: 2.5Mbps (slower than
-ethernet) and 100Mbps (faster than ethernet).  The two hardware types, as
-far as I'm aware, are not compatible and so you cannot wire a 100Mbps card
-to a 2.5Mbps card, and so on.  From what I hear, my driver does work with
-100Mbps cards, but I haven't been able to verify this myself, since I only
-have the 2.5Mbps variety.
+First of all, you can get ARCnet cards in at least two speeds: 2.5Mbps
+(slower than ethernet) and 100Mbps (faster than normal ethernet).  In fact,
+there are others as well, but these are less common.  The different hardware
+types, as far as I'm aware, are not compatible and so you cannot wire a
+100Mbps card to a 2.5Mbps card, and so on.  From what I hear, my driver does
+work with 100Mbps cards, but I haven't been able to verify this myself,
+since I only have the 2.5Mbps variety.
 
 You also cannot connect an ARCnet card to any kind of ethernet card and
 expect it to work.  
 
 There are two "types" of ARCnet - STAR topology and BUS topology.  This
-refers to how the cards are meant to be wired together.  According to all
+refers to how the cards are meant to be wired together.  According to most
 available documentation, you can only connect STAR cards to STAR cards and
 BUS cards to BUS cards.  That makes sense, right?  Well, it's not quite
 true; see below under "Cabling."
@@ -36,7 +40,7 @@ true; see below under "Cabling."
 Once you get past these little stumbling blocks, ARCnet is actually quite a
 well-designed standard.  It uses something called "modified token passing"
 which makes it completely incompatible with so-called "Token Ring" cards,
-but which makes transfers much more reliable than with ethernet.  In fact,
+but which makes transfers much more reliable than ethernet does.  In fact,
 ARCnet will guarantee that a packet arrives safely at the destination, and
 even if it can't possibly be delivered properly (ie. because of a cable
 break, or because the destination computer does not exist) it will at least
@@ -49,7 +53,7 @@ completely different programming interface, leading to a lot of different,
 sometimes very similar, ethernet drivers.  Of course, always using the same
 programming interface also means that when high-performance hardware
 facilities like PCI busmastering DMA appear, it's hard to take advantage of
-them.
+them.  Let's not go into that.
 
 One thing that makes ARCnet cards difficult to program for, however, is the
 limit on their packet sizes; standard ARCnet can only send packets that are
@@ -62,134 +66,176 @@ although they are generally kept down to the ethernet-style 1500 bytes.
 
 CABLING ARCNET NETWORKS
 -----------------------
- - Information in this section is from several contributors, including:
-       Stephen A. Wood <saw@hallc1.cebaf.gov>
-       John Paul Morrison <jmorriso@bogomips.ee.ubc.ca>
-       Joachim Koenig <jojo@repas.de>
-       Vojtech Pavlik <vpav4328@Diana.troja.mff.cuni.cz>
-
- - I, Avery Pennarun, tried to arrange it into something that makes sense
-   when all put together.  All mistakes, then, are most likely my fault.
-   Bug me about them, and they will probably get fixed.
-
-Ideally, according to documentation, ARCnet networks should be connected
-with 93 Ohm cables with 93 Ohm resistors as terminators.  I use TV cable and
-no resistors to connect two STAR cards.  Blah.  Your mileage may vary.
-
-Here's some more specific information about cables, sent in by Joachim
-Koenig (slight touchups by me):
-
-       The following cables are valid for ARCnet:
-               RG-62  93 Ohm  up to 610 m
-               RG-59/U 75 Ohm up to 457 m
-               RG-11/U 75 Ohm up to 533 m
-               IBM Typ 1 150 Ohm up to 200 m
-               IBM Typ 3 100 Ohm up to 100 m
-               
-So you can see that while 93 Ohms is ideal, you can still go half a
-kilometer with 75 Ohm TV cable.  A rule of thumb might be handy here, to
-help you remember:
-       Basically any coax cable, up to a ridiculously large distance.
-
-The above applies to all known ARCnet cards.  Specific to STAR cards,
-though, Stephen A. Wood has some information:
-
-       When I bought my two cards at a garage sale, they came with little
-       box with four BNC connectors on the outside.  The shields of the
-       four connectors are all grounded together, and the center conductors
-       were connected by the following resistor network.
-
-                     |
-                     |
-                     R
-                     |
-                ---R-+-R---
-                     | 
-                     R
-                     |
-                     |
-
-       Where R is 47 Ohms.  A little math shows that if you terminate three
-       of the outputs with 90 ohms (A cable or a terminator), the remaining
-       input sees 90 Ohms.  Therefore this box is impedance matched to 90
-       Ohm cable.  So this box can be used to connect 2 to 4 nodes
-       together.
-
-If you really use your imagination, you can see how the above diagram kind
-of looks like a "star."  John Paul Morrison makes a few notes about the
-above:
-
-       The "little box with four BNC connectors on the outside" is an
-       Arcnet passive hub. They're worth about $5 (just so you don't get
-       ripped off).
-
-       I don't have specs at my fingertips. Basically, don't use too many
-       passive hubs (or none at all, apparently passive hubs are A Bad
-       Thing.  On the other hand, they're a really cheap way to do things.)
-
-       Arcnet active hubs are available; they are analogous to Ethernet
-       twisted pair hubs. You can plug either a single station or a passive
-       hub into each port on the active hub. If you plug in a passive hub,
-       that lets you connect three more stations.
-       
-According to Vojtech Pavlik, there shouldn't be more than one passive hub
-between two "active ends", an active end being an active hub or an ARCnet
-card.  That makes sense to me.
-       
-As for BUS cards, they're even easier (for more than two cards, anyway; you
-can't get much simpler than direct-connecting two STAR cards with a TV
-cable).  They work just like Thinnet ethernet; it looks like this:
-
-       R------+------+------+------R
-              |      |      |
-              NODE   NODE   NODE
-
-Where R is the terminator as usual, and '+' represents a T connector.
-
-Okay, then, what if you have a combination of BUS cards and STAR cards?  You
-probably can't do ANY combination you want, but Vojtech Pavlik explains what
-works for him (WARNING: I, Avery, haven't tried anything this weird myself):
-
-       All that I need is to terminate each end with a STAR card. I think I
-       can even connect the cards like this:
-
-       STAR------+-----+-----STAR
-                BUS   BUS
-
-       Where "-" stands for coax, "+" for T connector, "STAR" for star-type
-       arcnet card and BUS for bus-type arcnet cards. I think there will be
-       no terminators necessary.
-
-He also explains (I paraphrase slightly here):
-
-       R-+----------STAR
-        BUS
-       In this case, I have to terminate the end with the bus card
-       using a terminator. ("R" - terminator, "+" - T connector "-" - coax,
-       everything other is probably clear)
-       
-       [...]
-       And _MAYBE_ you can do even more complicated and insane combinations 
-       when just thinking of the STAR card as a BUS one with an inside 
-       installed terminator. (STAR cards are NOT bus ones with terminator, 
-       but I believe that they electrically act like them). 
-
-And finally, he gives a shortcut for BUS users that are low on supplies:
-
-       When you have really short cables (about four meters in total) and have lack
-       of terminators or T's you can leave one of the terminators out .... or put
-       it in the middle like this:
-       BUS-----T-----BUS
-               R
-       It's ugly, but it works.
-       
-I don't pretend to understand what's happening there, but then again, I
-don't have BUS cards either.
 
+This section was rewritten by 
+        Vojtech Pavlik     <Vojtech.Pavlik@st.mff.cuni.cz>
+using information from several people, including:
+        Avery Pennraun     <apenwarr@foxnet.net>
+       Stephen A. Wood    <saw@hallc1.cebaf.gov>
+       John Paul Morrison <jmorriso@bogomips.ee.ubc.ca>
+       Joachim Koenig     <jojo@repas.de>
+and Avery touched it up a bit, at Vojtech's request.
+
+ARCnet (the classic 2.5 Mbps version) can be connected by two different
+types of cabling: coax and twisted pair.  The other ARCnet-type networks
+(100 Mbps TCNS and 320 kbps - 32 Mbps ARCnet Plus) use different types of
+cabling (Type1, Fiber, C1, C4, C5).
+
+For a coax network, you "should" use 93 Ohm RG-62 cable.  But other cables
+also work fine, because ARCnet is a very stable network. I personally use 75
+Ohm TV antenna cable.
+
+Cards for coax cabling are shipped in two different variants: for BUS and
+STAR network topologies.  They are mostly the same.  The only difference
+lies in the hybrid chip installed.  BUS cards use high impedance output,
+while STAR use low impedance.  Low impedance card (STAR) is electrically
+equal to a high impedance one with a terminator installed.
+
+Usually, the ARCnet networks are built up from STAR cards and hubs.  There
+are two types of hubs - active and passive.  Passive hubs are small boxes
+with four BNC connectors containing four 47 Ohm resistors:
+
+   |         | wires
+   R         + junction
+-R-+-R-      R 47 Ohm resistors
+   R
+   |
+
+The shielding is connected together.  Active hubs are much more complicated;
+they are powered and contain electronics to amplify the signal and send it
+to other segments of the net.  They usually have eight connectors.  Active
+hubs come in two variants - dumb and smart.  The dumb variant just
+amplifies, but the smart one decodes to digital and encodes back all packets
+coming through.  This is much better if you have several hubs in the net,
+since many dumb active hubs may worsen the signal quality.
+
+And now to the cabling.  What you can connect together:
+
+1. A card to a card.  This is the simplest way of creating a 2-computer
+   network.
+
+2. A card to a passive hub.  Remember that all unused connectors on the hub
+   must be properly terminated with 93 Ohm (or something else if you don't
+   have the right ones) terminators.
+       (Avery's note: oops, I didn't know that.  Mine (TV cable) works
+       anyway, though.)
+
+3. A card to an active hub.  Here is no need to terminate the unused
+   connectors except some kind of aesthetic feeling.  But, there may not be
+   more than eleven active hubs between any two computers.  That of course
+   doesn't limit the number of active hubs on the network.
+   
+4. An active hub to another.
+
+5. An active hub to passive hub.
+
+Remember, that you can not connect two passive hubs together.  The power loss
+implied by such connection is too high for the net to operate reliably.
+
+An example of a typical ARCnet network:
+
+           R                     S - STAR type card              
+    S------H--------A-------S    R - Terminator
+           |        |            H - Hub                         
+           |        |            A - Active hub                  
+           |   S----H----S                                       
+           S        |                                            
+                    |                                            
+                    S                                            
+                                                                          
+The BUS topology is very similar to the one used by Ethernet.  The only
+difference is in cable and terminators: they should be 93 Ohm.  Ethernet
+uses 50 Ohm impedance. You use T connectors to put the computers on a single
+line of cable, the bus. You have to put terminators at both ends of the
+cable. A typical BUS ARCnet network looks like:
+
+    RT----T------T------T------T------TR
+     B    B      B      B      B      B
+
+  B - BUS type card
+  R - Terminator
+  T - T connector
+
+But that is not all! The two types can be connected together.  According to
+the official documentation the only way of conecting them is using an active
+hub:
+
+         A------T------T------TR
+         |      B      B      B
+     S---H---S
+         |
+         S
+
+The official docs also state that you can use STAR cards at the ends of
+BUS network in place of a BUS card and a terminator:
+
+     S------T------T------S
+            B      B
+
+But, according to my own experiments, you can simply hang a BUS type card
+anywhere in middle of a cable in a STAR topology network.  And more - you
+can use the bus card in place of any star card if you use a terminator. Then
+you can build very complicated networks fulfilling all your needs!  An
+example:
+
+                                  S
+                                  |
+           RT------T-------T------H------S
+            B      B       B      |
+                                  |       R
+    S------A------T-------T-------A-------H------TR                    
+           |      B       B       |       |      B                         
+           |   S                 BT       |                                 
+           |   |                  |  S----A-----S
+    S------H---A----S             |       | 
+           |   |      S------T----H---S   |
+           S   S             B    R       S  
+                                                               
+A basicaly different cabling scheme is used with Twisted Pair cabling. Each
+of the TP cards has two RJ (phone-cord style) connectors.  The cards are
+then daisy-chained together using a cable connecting every two neighboring
+cards.  The ends are terminated with RJ 93 Ohm terminators which plug into
+the empty connectors of cards on the ends of the chain.  An example:
+
+          ___________   ___________
+      _R_|_         _|_|_         _|_R_  
+     |     |       |     |       |     |      
+     |Card |       |Card |       |Card |     
+     |_____|       |_____|       |_____|          
+
+
+There are also hubs for the TP topology.  There is nothing difficult
+involved in using them; you just connect a TP chain to a hub on any end or
+even at both.  This way you can create almost any network configuration. 
+The maximum of 11 hubs between any two computers on the net applies here as
+well.  An example:
+
+    RP-------P--------P--------H-----P------P-----PR
+                               |
+      RP-----H--------P--------H-----P------PR
+             |                 |
+             PR                PR
+
+    R - RJ Terminator
+    P - TP Card
+    H - TP Hub
+
+Like any network, ARCnet has a limited cable length.  These are the maximum
+cable lengths between two active ends (an active end being an active hub or
+a STAR card).
+
+               RG-62       93 Ohm up to 650 m
+               RG-59/U     75 Ohm up to 457 m
+               RG-11/U     75 Ohm up to 533 m
+               IBM Type 1 150 Ohm up to 200 m
+               IBM Type 3 100 Ohm up to 100 m
+
+The maximum length of all cables connected to a passive hub is limited to 65
+meters for RG-62 cabling; less for others.  You can see that using passive
+hubs in a large network is a bad idea. The maximum length of a single "BUS
+Trunk" is about 300 meters for RG-62. The maximum distance between the two
+most distant points of the net is limited to 3000 meters. The maximum length
+of a TP cable between two cards/hubs is 650 meters.
 
 
 SETTING THE JUMPERS
@@ -208,10 +254,33 @@ All ARCnet cards should have a total of four or five different settings:
        - Avery's favourite: 0x300.
 
   - the IRQ: on  8-bit cards, it might be 2 (9), 3, 4, 5, or 7.
-             on 16-bit cards, it might be 2 (9), 3, 4, 5, 7, or 10-15.  Make
-    sure this is different from any other card on your system.  Note that
-    IRQ2 is the same as IRQ9, as far as Linux is concerned.
-       - Avery's favourite: IRQ2 (actually IRQ9).
+             on 16-bit cards, it might be 2 (9), 3, 4, 5, 7, or 10-15.
+             
+    Make sure this is different from any other card on your system.  Note
+    that IRQ2 is the same as IRQ9, as far as Linux is concerned.  You can
+    "cat /proc/interrupts" for a somewhat complete list of which ones are in
+    use at any given time.  Here is a list of common usages from Vojtech
+    Pavlik <vpav4328@diana.troja.mff.cuni.cz>:
+       ("Not on bus" means there is no way for a card to generate this
+       interrupt)
+       IRQ  0 - Timer 0 (Not on bus)
+       IRQ  1 - Keyboard (Not on bus)
+       IRQ  2 - IRQ Controller 2 (Not on bus, nor does interrupt the CPU)
+       IRQ  3 - COM2
+       IRQ  4 - COM1
+       IRQ  5 - FREE (LPT2 if you have it; sometimes COM3)
+       IRQ  6 - Floppy disk controller
+       IRQ  7 - FREE (LPT1 if you don't use the polling driver or PLIP) 
+       IRQ  8 - Realtime Clock Interrupt (Not on bus)
+       IRQ  9 - FREE (VGA vertical sync interrupt if enabled)
+       IRQ 10 - FREE
+       IRQ 11 - FREE
+       IRQ 12 - FREE
+       IRQ 13 - Numeric Coprocessor (Not on bus)
+       IRQ 14 - Fixed Disk Controller
+       IRQ 15 - FREE (Fixed Disk Controller 2 if you have it) 
+
+       - Avery's favourite: IRQ2 (actually IRQ9).  Watch that VGA, though.
 
   - the memory address:  Unlike most cards, ARCnets use "shared memory" for
     copying buffers around.  Make SURE it doesn't conflict with any other
@@ -230,28 +299,54 @@ All ARCnet cards should have a total of four or five different settings:
     address from 0 to 255.  Unlike ethernet, you can set this address
     yourself with a jumper or switch (or on some cards, with special
     software).  Since it's only 8 bits, you can only have 254 ARCnet cards
-    on a network.  DON'T use 0 or 255, since these are reserved. (although
+    on a network.  DON'T use 0 or 255, since these are reserved (although
     neat stuff will probably happen if you DO use them).  By the way, if you
     haven't already guessed, don't set this the same as any other ARCnet on
     your network!
        - Avery's favourite:  3 and 4.  Not that it matters.
-       
-  - There may be ETS1 and ETS2 settings.  These may or may not make a
-    difference on your card, but are used to change the delays used when
-    powering up a computer on the network.  This is only necessary when
-    wiring VERY long range ARCnet networks, on the order of 4km or so; in
-    any case, the only real requirement here is that all cards on the
-    network with ETS1 and ETS2 jumpers have them in the same position.
-
 
-Here's the all the jumper information I could obtain for individual card
-types.  The format of this list has changed somewhat; I finally got around
-to unduplicating some of the information and making a few other changes, but
-didn't get very far yet.  If you notice any problems with the info, it's now
-officially my fault :(
+  - There may be ETS1 and ETS2 settings.  These may or may not make a
+    difference on your card (many manuals call them "reserved"), but are
+    used to change the delays used when powering up a computer on the
+    network.  This is only necessary when wiring VERY long range ARCnet
+    networks, on the order of 4km or so; in any case, the only real
+    requirement here is that all cards on the network with ETS1 and ETS2
+    jumpers have them in the same position.  Chris Hindy <chrish@io.org>
+    sent in a chart with actual values for this:
+       ET1     ET2     Response Time   Reconfiguration Time
+       ---     ---     -------------   --------------------
+       open    open    74.7us          840us
+       open    closed  283.4us         1680us
+       closed  open    561.8us         1680us
+       closed  closed  1118.6us        1680us
+    
+    Make sure you set ETS1 and ETS2 to the SAME VALUE for all cards on your
+    network.
+    
+Also, on many cards (not mine, though) there are red and green LED's. 
+Vojtech Pavlik <vpav4328@diana.troja.mff.cuni.cz> tells me this is what they
+mean:
+       GREEN           RED             Status
+       -----           ---             ------
+       OFF             OFF             Power off
+       OFF             Short flashes   Cabling problems (broken cable or not
+                                         terminated)
+       OFF (short)     ON              Card init
+       ON              ON              Normal state - everything OK, nothing
+                                         happens
+       ON              Long flashes    Data transfer
+       ON              OFF             Never happens (maybe when wrong ID)
+
+
+The following is all the specific information people have sent me about
+their own particular ARCnet cards.  It is officially a mess, and contains
+huge amounts of duplicated information.  I have no time to fix it.  If you
+want to, PLEASE DO!  Just send me a 'diff -u' of all your changes.
 
 The model # is listed right above specifics for that card, so you should be
 able to use your text viewer's "search" function to find the entry you want. 
+If you don't KNOW what kind of card you have, try looking through the
+various diagrams to see if you can tell.
 
 If your model isn't listed and/or has different settings, PLEASE PLEASE
 tell me.  I had to figure mine out without the manual, and it WASN'T FUN!
@@ -261,24 +356,32 @@ model that is, please e-mail me to say so.
 
 Cards Listed in this file (in this order, mostly):
 
-       Manufacturer    Model #         Bits
-       ------------    -------         ----
-       SMC             PC100           8
-       SMC             PC110           8
-       SMC             PC120           8
-       SMC             PC130           8
-       SMC             PC270E          8
-       SMC             PC500           16
-       SMC             PC500Longboard  16
-       SMC             PC550Longboard  16
-       SMC             PC600           16
-       SMC?            LCS-8830-T      16?
-       Puredata        PDI507          8
-       CNet Tech       CN120-Series    8
-       CNet Tech       CN160-Series    16
-       No Name         --              8/16
-       No Name         Taiwan R.O.C(?) 8
-       Tiara           Tiara Lancard(?)
+       Manufacturer    Model #                 Bits
+       ------------    -------                 ----
+       SMC             PC100                   8
+       SMC             PC110                   8
+       SMC             PC120                   8
+       SMC             PC130                   8
+       SMC             PC270E                  8
+       SMC             PC500                   16
+       SMC             PC500Longboard          16
+       SMC             PC550Longboard          16
+       SMC             PC600                   16
+       SMC             PC710                   8
+       SMC?            LCS-8830-T              16?
+       Puredata        PDI507                  8
+       CNet Tech       CN120-Series            8
+       CNet Tech       CN160-Series            16
+       Lantech?        UM9065L chipset         8
+       Acer            5210-003                8
+       Datapoint?      LAN-ARC-8               8
+       Topware         TA-ARC/10               8
+       Thomas-Conrad   500-6242-0097 REV A     8
+       Waterloo?       (C)1985 Waterloo Micro. 8
+       No Name         --                      8/16
+       No Name         Taiwan R.O.C?           8
+       No Name         Model 9058              8
+       Tiara           Tiara Lancard?          8
        
 
 ** SMC = Standard Microsystems Corp.
@@ -289,7 +392,7 @@ Unclassified Stuff
 ------------------
   - Please send any other information you can find.
   
-  - And some unknowns (other info is welcome!):
+  - And some other stuff (more info is welcome!):
      From: root@ultraworld.xs4all.nl (Timo Hilbrink)
      To: apenwarr@foxnet.net (Avery Pennarun)
      Date: Wed, 26 Oct 1994 02:10:32 +0000 (GMT)
@@ -602,7 +705,7 @@ board activity:
 *****************************************************************************
 
 ** Standard Microsystems Corp (SMC) **
-PC500/PC550 Long Board (16-bit cards)
+PC500/PC550 Longboard (16-bit cards)
 -------------------------------------
   - from Juergen Seifert <seifert@htwm.de>
 
@@ -613,10 +716,15 @@ STANDARD MICROSYSTEMS CORPORATION (SMC) ARCNET-PC500/PC550 Long Board
 Note: There is another Version of the PC500 called Short Version, which 
       is different in hard- and software! The most important differences
       are:
-      - The long board has no Shared memory
+      - The long board has no Shared memory.
       - On the long board the selection of the interrupt is done by binary
         coded switch, on the short board directly by jumper.
-
+        
+[Avery's note: pay special attention to that: the long board HAS NO SHARED
+MEMORY.  This means the current Linux-ARCnet driver can't use these cards. 
+I have obtained a PC500Longboard and will be doing some experiments on it in
+the future, but don't hold your breath.  Thanks again to Juergen Seifert for
+his advice about this!]
 
 This description has been written by Juergen Seifert <seifert@htwm.de>
 using information from the following Original SMC Manual 
@@ -821,6 +929,48 @@ board activity:
         | node ID is zero               | I/O address
 
 
+*****************************************************************************
+
+** SMC **
+PC710 (8-bit card)
+------------------
+  - from J.S. van Oosten <jvoosten@compiler.tdcnet.nl>
+  
+Note: this data is gathered by experimenting and looking at info of other
+cards. However, I'm sure I got 99% of the settings right.
+
+The SMC710 card resembles the PC270 card, but is much more basic (i.e. no
+LEDs, RJ11 jacks, etc.) and 8 bit. Here's a little drawing:
+
+    _______________________________________   
+   | +---------+  +---------+              |____
+   | |   S2    |  |   S1    |              |
+   | +---------+  +---------+              |
+   |                                       |
+   |  +===+    __                          |
+   |  | R |   |  | X-tal                 ###___
+   |  | O |   |__|                      ####__'|
+   |  | M |    ||                        ###
+   |  +===+                                |
+   |                                       |
+   |   .. JP1   +----------+               |
+   |   ..       | big chip |               |   
+   |   ..       |  90C63   |               |
+   |   ..       |          |               |
+   |   ..       +----------+               |
+    -------                     -----------
+           |||||||||||||||||||||
+
+The row of jumpers at JP1 actually consists of 8 jumpers, (sometimes
+labelled) the same as on the PC270, from top to bottom: EXT2, EXT1, ROM,
+IRQ7, IRQ5, IRQ4, IRQ3, IRQ2 (gee, wonder what they would do? :-) )
+
+S1 and S2 perform the same function as on the PC270, only their numbers
+are swapped (S1 is the nodeaddress, S2 sets IO- and RAM-address).
+
+I know it works when connected to a PC110 type ARCnet board.
+
+       
 *****************************************************************************
 
 ** Possibly SMC **
@@ -936,27 +1086,17 @@ Switches        Ram           Rom
 PDI507 (8-bit card)
 --------------------
   - from Mark Rejhon <mdrejhon@magi.com> (slight modifications by Avery)
+  - Avery's note: I think PDI508 cards (but definitely NOT PDI508Plus cards)
+    are mostly the same as this.  PDI508Plus cards appear to be mainly
+    software-configured.
 
 Jumpers:
-
        There is a jumper array at the bottom of the card, near the edge
         connector.  This array is labelled J1.  They control the IRQs and
         something else.  Put only one jumper on the IRQ pins.
 
-       IRQ2    - Use IRQ 2 (same as IRQ 9 as far as software is concerned)
-       IRQ3    - Use IRQ 3 (used by COM2 or COM4 serial port if either exists)
-       IRQ4    - Use IRQ 4 (used by COM1 or COM3 serial port if either exists)
-       IRQ5    - Use IRQ 5 (used by LPT2 parallel port if one exists)
-       IRQ6    - Use IRQ 6 (used by Floppy Disk Controller if one exists)
-       IRQ7    - Use IRQ 7 (used by LPT1 parallel port if one exists)
-
-[Avery's note:  This "unknown" set of two jumpers appears to be on all
-ARCnet cards by SMC as well.  Putting jumpers on them seems to affect the
-status register, but only for the two "reserved" bits, ETS1 and ETS2.  Any
-further information is welcome.]
-
-       ET1     - What is this?  (Not tested, no jumper put on it)
-       ET2     - What is this?  (Not tested, no jumper put on it)
+       ETS1, ETS2 are for timing on very long distance networks.  See the
+       more general information near the top of this file.
 
        There is a J2 jumper on two pins.  A jumper should be put on them,
         since it was already there when I got the card.  I don't know what
@@ -973,9 +1113,32 @@ further information is welcome.]
         o | o   o |             in this direction ------->
           `-------'
 
-       There is also a J4 jumper on two pins.  A jumper should be put on
-        them, since it was already there when I got the card.  I don't know
-        what this jumper is for though.
+Carl de Billy <CARL@carainfo.com> explains J3 and J4:
+
+       J3 Diagram:
+
+           .-------.
+         o | o   o |
+           :-------:    TWIST Technology
+         o | o   o |
+           `-------'
+           .-------.
+           | o   o | o
+           :-------:    COAX Technology
+           | o   o | o
+           `-------'
+
+  - If using coax cable in a bus topology the J4 jumper must be removed;
+    place it on one pin.
+
+  - If using bus topology with twisted pair wiring move the J3 
+    jumpers so they connect the middle pin and the pins closest to the RJ11
+    Connectors.  Also the J4 jumper must be removed; place it on one pin of
+    J4 jumper for storage.
+
+  - If using  star topology with twisted pair wiring move the J3 
+    jumpers so they connect the middle pin and the pins closest to the RJ11
+    connectors.
 
 
 DIP Switches:
@@ -1465,6 +1628,724 @@ The jumpers labeled JP1 and JP2 are used to determine the timeout
 parameters. These two jumpers are normally left open.
 
 
+*****************************************************************************
+
+** Lantech **
+8-bit card, unknown model
+-------------------------
+  - from Vlad Lungu <vlungu@ugal.ro> - his e-mail address seemed broken at
+    the time I tried to reach him.  Sorry Vlad, if you didn't get my reply.
+
+   ________________________________________________________________
+   |   1         8                                                 |
+   |   ___________                                               __|
+   |   |   SW1    |                                         LED |__|
+   |   |__________|                                                |
+   |                                                            ___|
+   |                _____________________                       |S | 8
+   |                |                   |                       |W |
+   |                |                   |                       |2 |
+   |                |                   |                       |__| 1
+   |                |      UM9065L      |     |o|  JP4         ____|____
+   |                |                   |     |o|              |  CN    |
+   |                |                   |                      |________|
+   |                |                   |                          |
+   |                |___________________|                          |
+   |                                                               |
+   |                                                               |
+   |      _____________                                            |
+   |      |            |                                           |
+   |      |    PROM    |        |ooooo|  JP6                       |
+   |      |____________|        |ooooo|                            |
+   |_____________                                             _   _|
+                |____________________________________________| |__|
+
+
+UM9065L : Arcnet Controller
+
+SW 1    : Shared Memory Address and I/O Base
+
+        ON=0
+
+        12345|Memory Address
+        -----|--------------
+        00001|  D4000
+        00010|  CC000
+        00110|  D0000
+        01110|  D1000
+        01101|  D9000
+        10010|  CC800
+        10011|  DC800
+        11110|  D1800
+
+It seems that the bits are considered in reverse order.  Also, you must
+observe that some of those addresses are unusual and I didn't probe them; I
+used a memory dump in DOS to identify them.  For the 00000 configuration and
+some others that I didn't write here the card seems to conflict with the
+video card (an S3 GENDAC). I leave the full decoding of those addresses to
+you.
+
+        678| I/O Address
+        ---|------------
+        000|    260
+        001|    failed probe
+        010|    2E0
+        011|    380
+        100|    290
+        101|    350
+        110|    failed probe
+        111|    3E0
+
+SW 2  : Node ID (binary coded)
+
+JP 4  : Boot PROM enable   CLOSE - enabled
+                           OPEN  - disabled
+
+JP 6  : IRQ set (ONLY ONE jumper on 1-5 for IRQ 2-6)
+
+
+*****************************************************************************
+
+** Acer **
+8-bit card, Model 5210-003
+--------------------------
+  - from Vojtech Pavlik <vpav4328@diana.troja.mff.cuni.cz> using portions of
+    the existing arcnet-hardware file.
+
+This is a 90C26 based card.  Its configuration seems similar to 
+the SMC PC100, but has some additional jumpers I don't know.
+
+               __
+              |  |
+   ___________|__|_________________________
+  |         |      |                       |
+  |         | BNC  |                       |
+  |         |______|                    ___|
+  |  _____________________             |___  
+  | |                     |                |
+  | | Hybrid IC           |                |
+  | |                     |       o|o J1   |
+  | |_____________________|       8|8      |
+  |                               8|8 J5   |
+  |                               o|o      |
+  |                               8|8      |
+  |__                             8|8      |
+ (|__| LED                        o|o      |
+  |                               8|8      |
+  |                               8|8 J15  |
+  |                                        |
+  |                    _____               |
+  |                   |     |   _____      |
+  |                   |     |  |     |  ___|
+  |                   |     |  |     | |    
+  |  _____            | ROM |  | UFS | |    
+  | |     |           |     |  |     | |   
+  | |     |     ___   |     |  |     | |   
+  | |     |    |   |  |__.__|  |__.__| |   
+  | | NCR |    |XTL|   _____    _____  |   
+  | |     |    |___|  |     |  |     | |   
+  | |90C26|           |     |  |     | |   
+  | |     |           | RAM |  | UFS | |   
+  | |     | J17 o|o   |     |  |     | |   
+  | |     | J16 o|o   |     |  |     | |   
+  | |__.__|           |__.__|  |__.__| |   
+  |  ___                               |   
+  | |   |8                             |   
+  | |SW2|                              |   
+  | |   |                              |   
+  | |___|1                             |   
+  |  ___                               |   
+  | |   |10           J18 o|o          |   
+  | |   |                 o|o          |   
+  | |SW1|                 o|o          |   
+  | |   |             J21 o|o          |   
+  | |___|1                             |   
+  |                                    |   
+  |____________________________________|   
+
+
+Legend:
+
+90C26       ARCNET Chip
+XTL         20 MHz Crystal
+SW1 1-6     Base I/O Address Select
+    7-10    Memory Address Select
+SW2 1-8     Node ID Select (ID0-ID7)
+J1-J5       IRQ Select
+J6-J21      Unknown (Probably extra timeouts & ROM enable ...)
+LED1        Activity LED 
+BNC         Coax connector (STAR arcnet)
+RAM         2k of SRAM
+ROM         Boot ROM socket
+UFS         Unidentified Flying Sockets
+
+
+Setting the Node ID
+-------------------
+
+The eight switches in SW2 are used to set the node ID. Each node attached
+to the network must have an unique node ID which must not be 0.
+Switch 1 (ID0) serves as the least significant bit (LSB).
+
+Setting one of the switches to OFF means "1", ON means "0".
+
+The node ID is the sum of the values of all switches set to "1"
+These values are:
+
+   Switch | Value
+   -------|-------
+     1    |   1
+     2    |   2
+     3    |   4
+     4    |   8
+     5    |  16
+     6    |  32
+     7    |  64
+     8    | 128
+
+Don't set this to 0 or 255; these values are reserved.
+
+
+Setting the I/O Base Address
+----------------------------
+
+The switches 1 to 6 of switch block SW1 are used to select one
+of 32 possible I/O Base addresses using the followig tables
+   
+          | Hex
+   Switch | Value
+   -------|-------
+     1    | 200  
+     2    | 100  
+     3    |  80  
+     4    |  40  
+     5    |  20  
+     6    |  10 
+
+The I/O address is sum of all switches set to "1". Remember that
+the I/O address space bellow 0x200 is RESERVED for mainboard, so
+switch 1 should be ALWAYS SET TO OFF. 
+
+
+Setting the Base Memory (RAM) buffer Address
+--------------------------------------------
+
+The memory buffer (RAM) requires 2K. The base of this buffer can be
+located in any of sixteen positions. However, the addresses below
+A0000 are likely to cause system hang because there's main RAM.
+
+Jumpers 7-10 of switch block SW1 select the Memory Base address.
+
+   Switch          | Hex RAM
+    7   8   9  10  | Address
+   ----------------|---------
+   OFF OFF OFF OFF |  F0000 (conflicts with main BIOS)
+   OFF OFF OFF ON  |  E0000 
+   OFF OFF ON  OFF |  D0000
+   OFF OFF ON  ON  |  C0000 (conflicts with video BIOS)
+   OFF ON  OFF OFF |  B0000 (conflicts with mono video)
+   OFF ON  OFF ON  |  A0000 (conflicts with graphics)
+
+
+Setting the Interrupt Line
+--------------------------
+
+Jumpers 1-5 of the jumper block J1 controll the IRQ level. ON means 
+shorted, OFF means open.
+
+    Jumper              |  IRQ
+    1   2   3   4   5   |
+   ----------------------------
+    ON  OFF OFF OFF OFF |  7
+    OFF ON  OFF OFF OFF |  5
+    OFF OFF ON  OFF OFF |  4
+    OFF OFF OFF ON  OFF |  3
+    OFF OFF OFF OFF ON  |  2
+
+
+Unknown jumpers & sockets
+-------------------------
+
+I know nothing about these. I just guess that J16&J17 are timeout
+jumpers and maybe one of J18-J21 selects ROM. Also J6-J10 and
+J11-J15 are connecting IRQ2-7 to some pins on the UFSs. I can't
+guess the purpose.
+
+
+*****************************************************************************
+
+** Datapoint? **
+LAN-ARC-8, an 8-bit card
+------------------------
+  - from Vojtech Pavlik <vpav4328@diana.troja.mff.cuni.cz>
+
+This is another SMC 90C65 based arcnet card. I couldn't identify the
+manufacturer, but it might be DataPoint, becsuse the card has the
+original arcNet logo in its upper right corner.
+
+          _______________________________________________________
+         |                         _________                     |
+         |                        |   SW2   | ON      arcNet     |
+         |                        |_________| OFF             ___|
+         |  _____________         1 ______  8                |   | 8  
+         | |             | SW1     | XTAL | ____________     | S |    
+         | > RAM (2k)    |         |______||            |    | W |    
+         | |_____________|                 |      H     |    | 3 |    
+         |                        _________|_____ y     |    |___| 1  
+         |  _________            |         |     |b     |        |    
+         | |_________|           |         |     |r     |        |    
+         |                       |     SMC |     |i     |        |    
+         |                       |    90C65|     |d     |        |      
+         |  _________            |         |     |      |        |
+         | |   SW1   | ON        |         |     |I     |        |
+         | |_________| OFF       |_________|_____/C     |   _____|
+         |  1       8                      |            |  |     |___
+         |  ______________                 |            |  | BNC |___|
+         | |              |                |____________|  |_____|
+         | > EPROM SOCKET |              _____________           |
+         | |______________|             |_____________|          |
+         |                                         ______________|
+         |                                        | 
+         |________________________________________|
+
+Legend:
+
+90C65       ARCNET Chip 
+SW1 1-5:    Base Memory Address Select
+    6-8:    Base I/O Address Select
+SW2 1-8:    Node ID Select
+SW3 1-5:    IRQ Select   
+    6-7:    Extra Timeout
+    8  :    Rom Enable   
+BNC         Coax connector
+XTAL        20MHz Crystal
+
+
+Setting the Node ID
+-------------------
+
+The eight switches in SW3 are used to set the node ID. Each node attached
+to the network must have an unique node ID which must not be 0.
+Switch 1 serves as the least significant bit (LSB).
+
+Setting one of the switches to Off means "1", On means "0".
+
+The node ID is the sum of the values of all switches set to "1"  
+These values are:
+
+   Switch | Value
+   -------|-------
+     1    |   1
+     2    |   2
+     3    |   4
+     4    |   8
+     5    |  16
+     6    |  32
+     7    |  64
+     8    | 128
+
+
+Setting the I/O Base Address
+----------------------------
+
+The last three switches in switch block SW1 are used to select one
+of eight possible I/O Base addresses using the followig table
+
+
+   Switch      | Hex I/O
+    6   7   8  | Address
+   ------------|--------
+   ON  ON  ON  |  260
+   OFF ON  ON  |  290
+   ON  OFF ON  |  2E0  (Manufacturer's default)
+   OFF OFF ON  |  2F0
+   ON  ON  OFF |  300
+   OFF ON  OFF |  350
+   ON  OFF OFF |  380
+   OFF OFF OFF |  3E0
+
+
+Setting the Base Memory (RAM) buffer Address
+--------------------------------------------
+
+The memory buffer (RAM) requires 2K. The base of this buffer can be 
+located in any of eight positions. The address of the Boot Prom is
+memory base + 0x2000.
+Jumpers 3-5 of switch block SW1 select the Memory Base address.
+
+   Switch              | Hex RAM | Hex ROM
+    1   2   3   4   5  | Address | Address *)
+   --------------------|---------|-----------
+   ON  ON  ON  ON  ON  |  C0000  |  C2000
+   ON  ON  OFF ON  ON  |  C4000  |  C6000
+   ON  ON  ON  OFF ON  |  CC000  |  CE000
+   ON  ON  OFF OFF ON  |  D0000  |  D2000  (Manufacturerr's default)
+   ON  ON  ON  ON  OFF |  D4000  |  D6000
+   ON  ON  OFF ON  OFF |  D8000  |  DA000
+   ON  ON  ON  OFF OFF |  DC000  |  DE000
+   ON  ON  OFF OFF OFF |  E0000  |  E2000
+  
+*) To enable the Boot ROM set the switch 8 of switch block SW3 to position ON.
+
+The switches 1 and 2 probably add 0x0800 and 0x1000 to RAM base address.
+
+
+Setting the Interrupt Line
+--------------------------
+
+Switches 1-5 of the switch block SW3 control the IRQ level.
+
+    Jumper              |  IRQ
+    1   2   3   4   5   |
+   ----------------------------
+    ON  OFF OFF OFF OFF |  3
+    OFF ON  OFF OFF OFF |  4
+    OFF OFF ON  OFF OFF |  5
+    OFF OFF OFF ON  OFF |  7
+    OFF OFF OFF OFF ON  |  2
+
+
+Setting the Timeout Parameters
+------------------------------
+
+The switches 6-7 of the switch block SW3 are used to determine the timeout
+parameters.  These two switches are normally left in the OFF position.
+
+
+*****************************************************************************
+
+** Topware **
+8-bit card, TA-ARC/10
+-------------------------
+  - from Vojtech Pavlik <vpav4328@diana.troja.mff.cuni.cz>
+
+This is another very similar 90C65 card. Most of the switches and jumpers
+are the same as on other clones.
+
+ _____________________________________________________________________
+|  ___________   |                         |            ______        |
+| |SW2 NODE ID|  |                         |           | XTAL |       |
+| |___________|  |  Hybrid IC              |           |______|       |
+|  ___________   |                         |                        __|    
+| |SW1 MEM+I/O|  |_________________________|                   LED1|__|)   
+| |___________|           1 2                                         |     
+|                     J3 |o|o| TIMEOUT                          ______|    
+|     ______________     |o|o|                                 |      |    
+|    |              |  ___________________                     | RJ   |    
+|    > EPROM SOCKET | |                   \                    |------|     
+|J2  |______________| |                    |                   |      |    
+||o|                  |                    |                   |______|
+||o| ROM ENABLE       |        SMC         |    _________             |
+|     _____________   |       90C65        |   |_________|       _____|    
+|    |             |  |                    |                    |     |___ 
+|    > RAM (2k)    |  |                    |                    | BNC |___|
+|    |_____________|  |                    |                    |_____|    
+|                     |____________________|                          |    
+| ________ IRQ 2 3 4 5 7                  ___________                 |
+||________|   |o|o|o|o|o|                |___________|                |
+|________   J1|o|o|o|o|o|                               ______________|
+         |                                             |
+         |_____________________________________________|
+
+Legend:
+
+90C65       ARCNET Chip
+XTAL        20 MHz Crystal
+SW1 1-5     Base Memory Address Select
+    6-8     Base I/O Address Select
+SW2 1-8     Node ID Select (ID0-ID7)
+J1          IRQ Select
+J2          Rom Enable
+J3          Extra Timeout
+LED1        Activity LED 
+BNC         Coax connector (BUS arcnet)
+RJ          Twisted Pair Connector (daisychain)
+
+
+Setting the Node ID
+-------------------
+
+The eight switches in SW2 are used to set the node ID. Each node attached to
+the network must have an unique node ID which must not be 0.  Switch 1 (ID0)
+serves as the least significant bit (LSB).
+
+Setting one of the switches to Off means "1", On means "0".
+
+The node ID is the sum of the values of all switches set to "1"
+These values are:
+
+   Switch | Label | Value
+   -------|-------|-------
+     1    | ID0   |   1
+     2    | ID1   |   2
+     3    | ID2   |   4
+     4    | ID3   |   8
+     5    | ID4   |  16
+     6    | ID5   |  32
+     7    | ID6   |  64
+     8    | ID7   | 128
+
+Setting the I/O Base Address
+----------------------------
+
+The last three switches in switch block SW1 are used to select one
+of eight possible I/O Base addresses using the following table:
+
+
+   Switch      | Hex I/O
+    6   7   8  | Address
+   ------------|--------
+   ON  ON  ON  |  260  (Manufacturer's default)
+   OFF ON  ON  |  290
+   ON  OFF ON  |  2E0                         
+   OFF OFF ON  |  2F0
+   ON  ON  OFF |  300
+   OFF ON  OFF |  350
+   ON  OFF OFF |  380
+   OFF OFF OFF |  3E0
+
+
+Setting the Base Memory (RAM) buffer Address
+--------------------------------------------
+
+The memory buffer (RAM) requires 2K. The base of this buffer can be
+located in any of eight positions. The address of the Boot Prom is
+memory base + 0x2000.
+Jumpers 3-5 of switch block SW1 select the Memory Base address.
+
+   Switch              | Hex RAM | Hex ROM
+    1   2   3   4   5  | Address | Address *)
+   --------------------|---------|-----------
+   ON  ON  ON  ON  ON  |  C0000  |  C2000
+   ON  ON  OFF ON  ON  |  C4000  |  C6000  (Manufacturer's default) 
+   ON  ON  ON  OFF ON  |  CC000  |  CE000
+   ON  ON  OFF OFF ON  |  D0000  |  D2000  
+   ON  ON  ON  ON  OFF |  D4000  |  D6000
+   ON  ON  OFF ON  OFF |  D8000  |  DA000
+   ON  ON  ON  OFF OFF |  DC000  |  DE000
+   ON  ON  OFF OFF OFF |  E0000  |  E2000
+
+*) To enable the Boot ROM short the jumper J2.
+
+The jumpers 1 and 2 probably add 0x0800 and 0x1000 to RAM address.
+
+
+Setting the Interrupt Line
+--------------------------
+
+Jumpers 1-5 of the jumper block J1 control the IRQ level.  ON means
+shorted, OFF means open.
+
+    Jumper              |  IRQ
+    1   2   3   4   5   |
+   ----------------------------
+    ON  OFF OFF OFF OFF |  2
+    OFF ON  OFF OFF OFF |  3
+    OFF OFF ON  OFF OFF |  4
+    OFF OFF OFF ON  OFF |  5
+    OFF OFF OFF OFF ON  |  7
+
+
+Setting the Timeout Parameters
+------------------------------
+
+The jumpers J3 are used to set the timeout parameters. These two 
+jumpers are normally left open.
+
+  
+*****************************************************************************
+
+** Thomas-Conrad **
+Model #500-6242-0097 REV A (8-bit card)
+---------------------------------------
+  - from Lars Karlsson <100617.3473@compuserve.com>
+
+     ________________________________________________________
+   |          ________   ________                           |_____
+   |         |........| |........|                            |
+   |         |________| |________|                         ___|
+   |            SW 3       SW 1                           |   |
+   |         Base I/O   Base Addr.                Station |   |
+   |                                              address |   |
+   |    ______                                    switch  |   |
+   |   |      |                                           |   |
+   |   |      |                                           |___|    
+   |   |      |                                 ______        |___._
+   |   |______|                                |______|         ____| BNC
+   |                                            Jumper-        _____| Connector
+   |   Main chip                                block  _    __|   '  
+   |                                                  | |  |    RJ Connector
+   |                                                  |_|  |    with 110 Ohm
+   |                                                       |__  Terminator
+   |    ___________                                         __|
+   |   |...........|                                       |    RJ-jack
+   |   |...........|    _____                              |    (unused)
+   |   |___________|   |_____|                             |__
+   |  Boot PROM socket IRQ-jumpers                            |_  Diagnostic
+   |________                                       __          _| LED (red)
+            | | | | | | | | | | | | | | | | | | | |  |        |
+            | | | | | | | | | | | | | | | | | | | |  |________|
+                                                              |
+                                                              |
+
+And here are the settings for some of the switches and jumpers on the cards.
+
+
+          I/O
+
+         1 2 3 4 5 6 7 8
+
+2E0----- 0 0 0 1 0 0 0 1
+2F0----- 0 0 0 1 0 0 0 0
+300----- 0 0 0 0 1 1 1 1
+350----- 0 0 0 0 1 1 1 0
+
+"0" in the above example means switch is off "1" means that it is on.
+
+
+    ShMem address.
+
+      1 2 3 4 5 6 7 8
+
+CX00--0 0 1 1 | |   |
+DX00--0 0 1 0       |
+X000--------- 1 1   |
+X400--------- 1 0   |
+X800--------- 0 1   |
+XC00--------- 0 0   
+ENHANCED----------- 1
+COMPATIBLE--------- 0
+
+
+       IRQ
+
+
+   3 4 5 7 2
+   . . . . .
+   . . . . .
+
+
+There is a DIP-switch with 8 switches, used to set the shared memory address
+to be used. The first 6 switches set the address, the 7th doesn't have any
+function, and the 8th switch is used to select "compatible" or "enhanced".
+When I got my two cards, one of them had this switch set to "enhanced". That
+card didn't work at all, it wasn't even recognized by the driver. The other
+card had this switch set to "compatible" and it behaved absolutely normal. I
+guess that the switch on one of the cards, must have been changed accidently
+when the card was taken out of it's former host. The question remains
+unanswered, what is the purpose of the "enhanced" position?
+
+[Avery's note: "enhanced" probably either disables shared memory (use IO
+ports instead) or disables IO ports (use memory addresses instead).  This
+varies by the type of card involved.  I fail to see how either of these
+enhance anything.  Send me more detailed information about this mode, or
+just use "compatible" mode instead.]
+
+
+*****************************************************************************
+
+** Waterloo Microsystems Inc. ?? **
+8-bit card (C) 1985
+-------------------
+  - from Robert Michael Best <rmb117@cs.usask.ca>
+
+[Avery's note: these don't work with my driver for some reason.  These cards
+SEEM to have settings similar to the PDI508Plus, which is
+software-configured and doesn't work with my driver either.  The "Waterloo
+chip" is a boot PROM, probably designed specifically for the University of
+Waterloo.  If you have any further information about this card, please
+e-mail me.]
+
+The probe has not been able to detect the card on any of the J2 settings,
+and I tried them again with the "Waterloo" chip removed.
+ _____________________________________________________________________
+| \/  \/              ___  __ __                                      |
+| C4  C4     |^|     | M ||  ^  ||^|                                  |
+| --  --     |_|     | 5 ||     || | C3                               |
+| \/  \/      C10    |___||     ||_|                                  | 
+| C4  C4             _  _ |     |                 ??                  | 
+| --  --            | \/ ||     |                                     | 
+|                   |    ||     |                                     | 
+|                   |    ||  C1 |                                     | 
+|                   |    ||     |  \/                            _____|    
+|                   | C6 ||     |  C9                           |     |___ 
+|                   |    ||     |  --                           | BNC |___| 
+|                   |    ||     |          >C7|                 |_____|
+|                   |    ||     |                                     |
+| __ __             |____||_____|       1 2 3     6                   |
+||  ^  |     >C4|                      |o|o|o|o|o|o| J2    >C4|       |
+||     |                               |o|o|o|o|o|o|                  |
+|| C2  |     >C4|                                          >C4|       |
+||     |                                   >C8|                       |
+||     |       2 3 4 5 6 7  IRQ                            >C4|       |
+||_____|      |o|o|o|o|o|o| J3                                        |
+|_______      |o|o|o|o|o|o|                            _______________|
+        |                                             |
+        |_____________________________________________|
+
+C1 -- "COM9026
+       SMC 8638"
+      In a chip socket.
+
+C2 -- "@Copyright
+       Waterloo Microsystems Inc.
+       1985"
+      In a chip Socket with info printed on a label covering a round window
+      showing the circuit inside. (The window indicates it is an EPROM chip.)
+
+C3 -- "COM9032
+       SMC 8643"
+      In a chip socket.
+
+C4 -- "74LS"
+      9 total no sockets.
+
+M5 -- "50006-136
+       20.000000 MHZ
+       MTQ-T1-S3
+       0 M-TRON 86-40"
+      Metallic case with 4 pins, no socket.
+
+C6 -- "MOSTEK@TC8643
+       MK6116N-20
+       MALAYSIA"
+      No socket.
+
+C7 -- No stamp or label but in a 20 pin chip socket.
+
+C8 -- "PAL10L8CN
+       8623"
+      In a 20 pin socket.
+
+C9 -- "PAl16R4A-2CN
+       8641"
+      In a 20 pin socket.
+
+C10 -- "M8640
+          NMC
+        9306N"
+       In an 8 pin socket.
+
+?? -- Some components on a smaller board and attached with 20 pins all 
+      along the side closest to the BNC connector.  The are coated in a dark 
+      resin.
+
+On the board there are two jumper banks labeled J2 and J3. The 
+manufacturer didn't put a J1 on the board. The two boards I have both 
+came with a jumper box for each bank.
+
+J2 -- Numbered 1 2 3 4 5 6. 
+      4 and 5 are not stamped due to solder points.
+       
+J3 -- IRQ 2 3 4 5 6 7
+
+The board itself has a maple leaf stamped just above the irq jumpers 
+and "-2 46-86" beside C2. Between C1 and C6 "ASS 'Y 300163" and "@1986 
+CORMAN CUSTOM ELECTRONICS CORP." stamped just below the BNC connector.
+Below that "MADE IN CANADA"
+
+  
 *****************************************************************************
 
 ** No Name **
@@ -1477,7 +2358,7 @@ NONAME 8-BIT ARCNET
 
 I have named this ARCnet card "NONAME", since there is no name of any
 manufactor on the Installation manual nor on the shipping box. The only
-hint to the existence of a manufactor at all is written into cupper,
+hint to the existence of a manufacturer at all is written in copper,
 it is "Made in Taiwan"
 
 This description has been written by Juergen Seifert <seifert@htwm.de>
@@ -1851,10 +2732,6 @@ I have named this ARCnet card "NONAME", since I got only the card with
 no manual at all and the only text identifying the manufacturer is 
 "MADE IN TAIWAN R.O.C" printed on the card.
 
-This description was written by Vojtech Pavlik 
-(vpav4328@diana.troja.mff.cuni.cz) using parts of the ARCNET-jumpers 
-README file from Linux kernel 1.2.2. 
-
           ____________________________________________________________
          |                 1 2 3 4 5 6 7 8                            |
          | |o|o| JP1       o|o|o|o|o|o|o|o| ON                        |
@@ -1902,7 +2779,7 @@ Setting the Node ID
 -------------------
 
 The eight switches in SW2 are used to set the node ID. Each node attached
-to the network must have an unique node ID which must be diffrent from 0.
+to the network must have an unique node ID which must not be 0.
 Switch 1 (ID0) serves as the least significant bit (LSB).
 
 Setting one of the switches to Off means "1", On means "0".
@@ -2007,6 +2884,157 @@ parameters. These two jumpers are normally left in the OFF position.
 
 
 *****************************************************************************
+
+** No Name **
+(Generic Model 9058)
+--------------------
+  - from Andrew J. Kroll <ag784@freenet.buffalo.edu>
+  - Sorry this sat in my to-do box for so long, Andrew! (yikes - over a
+    year!)
+                                                                      _____
+                                                                     |    <
+                                                                     | .---'
+    ________________________________________________________________ | |
+   |                           |     SW2     |                      |  |
+   |   ___________             |_____________|                      |  |
+   |  |           |              1 2 3 4 5 6                     ___|  |
+   |  >  6116 RAM |         _________                         8 |   |  |
+   |  |___________|        |20MHzXtal|                        7 |   |  |
+   |                       |_________|       __________       6 | S |  |
+   |    74LS373                             |          |-     5 | W |  |
+   |   _________                            |      E   |-     4 |   |  |
+   |   >_______|              ______________|..... P   |-     3 | 3 |  |
+   |                         |              |    : O   |-     2 |   |  |
+   |                         |              |    : X   |-     1 |___|  |
+   |   ________________      |              |    : Y   |-           |  |
+   |  |      SW1       |     |      SL90C65 |    :     |-           |  |
+   |  |________________|     |              |    : B   |-           |  |
+   |    1 2 3 4 5 6 7 8      |              |    : O   |-           |  |
+   |                         |_________o____|..../ A   |-    _______|  |
+   |    ____________________                |      R   |-   |       |------,   
+   |   |                    |               |      D   |-   |  BNC  |   #  |
+   |   > 2764 PROM SOCKET   |               |__________|-   |_______|------'
+   |   |____________________|              _________                |  |
+   |                                       >________| <- 74LS245    |  |
+   |                                                                |  |
+   |___                                               ______________|  |
+       |H H H H H H H H H H H H H H H H H H H H H H H|               | |
+       |U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U|               | |
+                                                                      \|
+Legend:
+
+SL90C65        ARCNET Controller / Transceiver /Logic
+SW1    1-5:    IRQ Select
+         6:    ET1
+         7:    ET2
+         8:    ROM ENABLE 
+SW2    1-3:    Memory Buffer/PROM Address
+       3-6:    I/O Address Map
+SW3    1-8:    Node ID Select
+BNC            BNC RG62/U Connection 
+               *I* have had success using RG59B/U with *NO* terminators!
+               What gives?!
+
+SW1: Timeouts, Interrupt and ROM
+---------------------------------
+
+To select a hardware interrupt level set one (only one!) of the dip switches
+up (on) SW1...(switches 1-5)
+IRQ3, IRQ4, IRQ5, IRQ7, IRQ2. The Manufacturer's default is IRQ2.
+
+The switches on SW1 labeled EXT1 (switch 6) and EXT2 (switch 7)
+are used to determine the timeout parameters. These two dip switches
+are normally left off (down).
+
+   To enable the 8K Boot PROM position SW1 switch 8 on (UP) labeled ROM.
+   The default is jumper ROM not installed.
+
+
+Setting the I/O Base Address
+----------------------------
+
+The last three switches in switch group SW2 are used to select one
+of eight possible I/O Base addresses using the following table
+
+
+   Switch | Hex I/O
+   4 5 6  | Address
+   -------|--------
+   0 0 0  |  260
+   0 0 1  |  290
+   0 1 0  |  2E0  (Manufacturer's default)
+   0 1 1  |  2F0
+   1 0 0  |  300
+   1 0 1  |  350
+   1 1 0  |  380
+   1 1 1  |  3E0
+
+
+Setting the Base Memory Address (RAM & ROM)
+-------------------------------------------
+
+The memory buffer requires 2K of a 16K block of RAM. The base of this
+16K block can be located in any of eight positions.
+Switches 1-3 of switch group SW2 select the Base of the 16K block.
+(0 = DOWN, 1 = UP)
+I could, however, only verify two settings...
+
+   Switch| Hex RAM | Hex ROM
+   1 2 3 | Address | Address
+   ------|---------|-----------
+   0 0 0 |  E0000  |  E2000
+   0 0 1 |  D0000  |  D2000  (Manufacturer's default)
+   0 1 0 |  ?????  |  ?????
+   0 1 1 |  ?????  |  ?????  
+   1 0 0 |  ?????  |  ?????
+   1 0 1 |  ?????  |  ?????
+   1 1 0 |  ?????  |  ?????
+   1 1 1 |  ?????  |  ?????
+
+
+Setting the Node ID
+-------------------
+
+The eight switches in group SW3 are used to set the node ID.
+Each node attached to the network must have an unique node ID which
+must be diffrent from 0.
+Switch 1 serves as the least significant bit (LSB).
+switches in the DOWN position are OFF (0) and in the UP position are ON (1)
+
+The node ID is the sum of the values of all switches set to "1"  
+These values are:
+    Switch | Value
+    -------|-------
+      1    |   1
+      2    |   2
+      3    |   4
+      4    |   8
+      5    |  16
+      6    |  32
+      7    |  64
+      8    | 128
+
+Some Examples:
+
+    Switch#     |   Hex   | Decimal 
+8 7 6 5 4 3 2 1 | Node ID | Node ID
+----------------|---------|---------
+0 0 0 0 0 0 0 0 |    not allowed  <-.
+0 0 0 0 0 0 0 1 |    1    |    1    | 
+0 0 0 0 0 0 1 0 |    2    |    2    |
+0 0 0 0 0 0 1 1 |    3    |    3    |
+    . . .       |         |         |
+0 1 0 1 0 1 0 1 |   55    |   85    |
+    . . .       |         |         + Don't use 0 or 255!
+1 0 1 0 1 0 1 0 |   AA    |  170    |
+    . . .       |         |         |
+1 1 1 1 1 1 0 1 |   FD    |  253    |
+1 1 1 1 1 1 1 0 |   FE    |  254    |
+1 1 1 1 1 1 1 1 |   FF    |  255  <-'
+  
+
+*****************************************************************************
+
 ** Tiara **
 (model unknown)
 -------------------------
index 2ecf033233551163a684215cd6257b32f46a8995..a181dc3926706cf1f24f8c9b4c936edb9080d438 100644 (file)
@@ -1,6 +1,6 @@
 
 ----------------------------------------------------------------------------
-NOTE:  See also README.arcnet-hardware in this directory for jumper-setting
+NOTE:  See also arcnet-hardware.txt in this directory for jumper-setting
 and cabling information if you're like many of us and didn't happen to get a
 manual with your ARCnet card.
 ----------------------------------------------------------------------------
@@ -144,6 +144,9 @@ line.  For example:
        insmod arcnet.o io=0x300 irqnum=2 shmem=0xd0000
 You can also add a num=1, num=2 etc for additional arcnet cards that will
 use arc1, arc2 etc for their device names (instead of the default, arc0).
+
+** NEWS FLASH!  Starting with 2.30 ALPHA, the ARCnet driver can autoprobe
+   even as a module.  So "insmod arcnet.o" by itself should work.
        
 
 Using the Driver
index 15ec4c789e69a62fce67b5600976710207b43ca8..14476b8e8d0544582e6139dd0dd005a76071ff23 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 56
+SUBLEVEL = 57
 
 ARCH = i386
 
index 1e937e347247bec567e10603fac75e4b49f64787..e6ff1ce6a60cbad816350ba5fc9641841fc003a2 100644 (file)
@@ -166,7 +166,7 @@ $(MX_OBJS): $(TOPDIR)/include/linux/modversions.h
 $(LX_OBJS) $(OX_OBJS): $(TOPDIR)/include/linux/modversions.h
        $(CC) $(CFLAGS) -DMODVERSIONS -DEXPORT_SYMTAB -c $(@:.o=.c)
 
-dep fastdep: $(TOPDIR)/include/linux/modversions.h
+dep fastdep $(M_OBJS): $(TOPDIR)/include/linux/modversions.h
 
 endif
 endif
index 519f153b391191bd5db69842abbacfe1a4abd9cb..a18f99ef58bf48f2090f1dc8f2a41369e39e36f6 100644 (file)
@@ -52,7 +52,7 @@ define_bool CONFIG_ALPHA_NEED_ROUNDING_EMULATION y
 bool 'Echo console messages on /dev/ttyS1' CONFIG_SERIAL_ECHO
 if [ "$CONFIG_PCI" = "y" ]; then
   bool 'TGA Console Support' CONFIG_TGA_CONSOLE
-  bool 'PCI bridge optimisation (experimental)' CONFIG_PCI_OPTIMIZE
+  bool 'PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
 fi
 bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
index a2da90bcb5640511555ae56ba00e381d194c30dc..541fbef452d48f5a48e35aa4ae53f864c2fdb814 100644 (file)
@@ -207,7 +207,7 @@ static inline void unmask_irq(unsigned long irq)
        } else {
                cache_806 &= mask;
                outb(cache_806, 0x806);
-#elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB66P)
+#elif NR_IRQS == 32
        } else if (irq < 24) {
                cache_26 &= mask;
                outb(cache_26, 0x26);
index a98123aa7909238a9059d29e96934729e2e20fbc..2f6e6f12a7a84394eb38755acb233e59963e0832 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
+#include <linux/swap.h>
 
 #include <asm/system.h>
 #include <asm/segment.h>
index 6133622a4abdd313320dbf6672fbcedfe8db879a..1161ade4f91ed86eecde73b4b85945139c15b925 100644 (file)
@@ -316,7 +316,7 @@ void decompress_kernel()
        lines = SCREEN_INFO.orig_video_lines;
        cols = SCREEN_INFO.orig_video_cols;
 
-       if (EXT_MEM_K < 1024) error("<2M of mem\n");
+       if (EXT_MEM_K < 1024) error("Less than 2MB of memory.\n");
 
        output_data = (char *)0x100000; /* Points to 1M */
        makecrc();
index b118469680a98b839dbf393c104e7e090661f687..5110e2633f4924b672f6742ce644e8ebaadbf3a5 100644 (file)
@@ -10,6 +10,7 @@ bool 'Enable loadable module support' CONFIG_MODULES
 if [ "$CONFIG_MODULES" = "y" ]; then
   MODULES=y
   bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
+  bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD
 fi
 
 mainmenu_option next_comment
@@ -20,7 +21,7 @@ bool 'Networking support' CONFIG_NET
 bool 'Limit memory to low 16MB' CONFIG_MAX_16M
 bool 'PCI bios support' CONFIG_PCI
 if [ "$CONFIG_PCI" = "y" ]; then
-  bool '   PCI bridge optimisation (experimental)' CONFIG_PCI_OPTIMIZE
+  bool '   PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
 fi
 bool 'System V IPC' CONFIG_SYSVIPC
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
index efc82ea42d5ae5ab65e3838aa6a36da8422454cf..d0201388509cff97cf3c38840da9835f979dcc73 100644 (file)
@@ -7,6 +7,7 @@
 #
 CONFIG_MODULES=y
 # CONFIG_MODVERSIONS is not set
+# CONFIG_KERNELD is not set
 
 #
 # General setup
index 52975e98f0707000e2f1491ccb136c1d7cb2e0f8..9c3eedec6fa9e43d9ae16afac5bb65efdd1bfba8 100644 (file)
@@ -658,7 +658,7 @@ ENTRY(sys_call_table)
        .long SYMBOL_NAME(sys_writev)
        .long SYMBOL_NAME(sys_getsid)
        .long SYMBOL_NAME(sys_fdatasync)
-       .long 0
+       .long SYMBOL_NAME(sys_sysctl)
        .long SYMBOL_NAME(sys_mlock)            /* 150 */
        .long SYMBOL_NAME(sys_munlock)
        .long SYMBOL_NAME(sys_mlockall)
index 62a4df142c1b95f38cd579736bad0b557323ebee..865b2b99bf82118e8ddfdc6f4777e0fc96deb5bc 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
+#include <linux/swap.h>
 #include <linux/smp.h>
 
 #include <asm/system.h>
index cddafbdae8224eb2461281658c8abc7ed23954e1..19b2fbbdd0094723e70617a5eff67fc624dd506e 100644 (file)
@@ -44,7 +44,7 @@ bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN
 bool 'Networking support' CONFIG_NET
 #bool 'PCI bios support' CONFIG_PCI
 #if [ "$CONFIG_PCI" = "y" ]; then
-#  bool '   PCI bridge optimisation (experimental)' CONFIG_PCI_OPTIMIZE
+#  bool '   PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
 #fi
 bool 'System V IPC' CONFIG_SYSVIPC
 
index 668c81b2a543e2cb947902e58679e1e2aa2592cd..53bf958248bf28fe64aac51c7592703166d4470a 100644 (file)
@@ -29,7 +29,7 @@ bool 'Networking support' CONFIG_NET y
 #bool 'Limit memory to low 16MB' CONFIG_MAX_16M n
 bool 'PCI bios support' CONFIG_PCI y
 if [ "$CONFIG_PCI" = "y" ]; then
-  bool '   PCI bridge optimisation (experimental)' CONFIG_PCI_OPTIMIZE n
+  bool '   PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE n
   if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then
     bool '   PCI Triton IDE Bus Master DMA support' CONFIG_BLK_DEV_TRITON y
   fi
index c265b442e26f529637b811e6dfc4e8d9427d35b7..8a37d4a49ecf9114155a20fb5225bc507dee2dbb 100644 (file)
@@ -38,10 +38,13 @@ if [ "$CONFIG_APM" = "y" ]; then
 fi
 bool 'Watchdog Timer Support'  CONFIG_WATCHDOG
 if [ "$CONFIG_WATCHDOG" = "y" ]; then
-#  bool '   WDT501P Watchdog timer' CONFIG_WDT_501P
-#  if [ "$CONFIG_WDT_501P" = "y" ]; then
-#    bool '       Fan Tachomeeter' CONFIG_WDT_501P_TACHO
-#  fi
-#  bool '   WDT500P Watchdog timer' CONFIG_WDT_500P
-  bool '   Software Watchdog' CONFIG_SOFT_WATCHDOG
+  bool '   WDT Watchdog timer' CONFIG_WDT
+  if [ "$CONFIG_WDT" = "y" ]; then
+     bool '       WDT501 features' CONFIG_WDT_501
+     if [ "$CONFIG_WDT_501" = "y" ]; then
+         bool '       Fan Tachometer' CONFIG_WDT_501_FAN
+     fi
+  else
+     bool '   Software Watchdog' CONFIG_SOFT_WATCHDOG
+  fi
 fi
diff --git a/drivers/char/wd501p.h b/drivers/char/wd501p.h
new file mode 100644 (file)
index 0000000..9796609
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *     Industrial Computer Source WDT500/501 driver for Linux 1.3.x
+ *
+ *     (c) Copyright 1995      CymruNET Ltd
+ *                             Innovation Centre
+ *                             Singleton Park
+ *                             Swansea
+ *                             Wales
+ *                             UK
+ *                             SA2 8PP
+ *
+ *     http://www.cymru.net
+ *
+ *     This driver is provided under the GNU public license, incorporated
+ *     herein by reference. The driver is provided without warranty or 
+ *     support.
+ *
+ *     Release 0.04.
+ *
+ */
+#define WATCHDOG_MINOR         130     /* Watchdog timer     */
+#define TEMP_MINOR             131     /* Temperature Sensor */
+
+#define WDT_COUNT0             (io+0)
+#define WDT_COUNT1             (io+1)
+#define WDT_COUNT2             (io+2)
+#define WDT_CR                 (io+3)
+#define WDT_SR                 (io+4)
+#define WDT_RT                 (io+5)
+#define WDT_UNUSED             (io+6)
+#define WDT_DC                 (io+7)
+
+#define WDC_SR_WCCR            1       /* Active low */
+#define WDC_SR_TGOOD           2
+#define WDC_SR_ISOI0           4
+#define WDC_SR_ISII1           8
+#define WDC_SR_FANGOOD         16
+#define WDC_SR_PSUOVER         32      /* Active low */
+#define WDC_SR_PSUUNDR         64      /* Active low */
+#define WDC_SR_IRQ             128     /* Active low */
+
+/*
+ *     Feature Map 1 is the active high inputs not supported on your card.
+ *     Feature Map 2 is the active low inputs not supported on your card.
+ */
+#ifdef CONFIG_WDT_501          /* Full board */
+
+#ifdef CONFIG_WDT501_FAN       /* Full board, Fan has no tachometer */
+#define FEATUREMAP1            0
+#else
+#define FEATUREMAP1            WDC_SR_FANGOOD
+#endif
+
+#define FEATUREMAP2            0
+#endif
+
+
+#ifdef CONFIG_WDT500           /* Minimal board */
+#define FEATUREMAP1            (WDC_SR_TGOOD|WDC_SR_FANGOOD)
+#define FEATUREMAP2            (WDC_SR_PSUOVER|WDC_SR_PSUUNDR)
+#endif
+
+#ifndef FEATUREMAP1
+#error "Config option not set"
+#endif
diff --git a/drivers/char/wdt.c b/drivers/char/wdt.c
new file mode 100644 (file)
index 0000000..2bc23ab
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ *     Industrial Computer Source WDT500/501 driver for Linux 1.3.x
+ *
+ *     (c) Copyright 1995      CymruNET Ltd
+ *                             Innovation Centre
+ *                             Singleton Park
+ *                             Swansea
+ *                             Wales
+ *                             UK
+ *                             SA2 8PP
+ *
+ *     http://www.cymru.net
+ *
+ *     This driver is provided under the GNU public license, incorporated
+ *     herein by reference. The driver is provided without warranty or 
+ *     support.
+ *
+ *     Release 0.04.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mouse.h>
+#include "wd501p.h"
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+
+static int wdt_is_open=0;
+
+/*
+ *     You must set these - there is no sane way to probe for this board.
+ */
+int io=0x240;
+int irq=14;
+
+#define WD_TIMO (100*60)               /* 1 minute */
+
+/*
+ *     Programming suppoort
+ */
+static void wdt_ctr_mode(int ctr, int mode)
+{
+       ctr<<=6;
+       ctr|=0x30;
+       ctr|=(mode<<1);
+       outb_p(ctr, WDT_CR);
+}
+
+static void wdt_ctr_load(int ctr, int val)
+{
+       outb_p(val&0xFF, WDT_COUNT0+ctr);
+       outb_p(val>>8, WDT_COUNT0+ctr);
+}
+
+/*
+ *     Kernel methods.
+ */
+static void wdt_interrupt(int irq, struct pt_regs *regs)
+{
+       /*
+        *      Read the status register see what is up and
+        *      then printk it.
+        */
+        
+       unsigned char status=inb_p(WDT_SR);
+       
+       status|=FEATUREMAP1;
+       status&=~FEATUREMAP2;   
+       
+       printk(KERN_CRIT "WDT status %d\n", status);
+       
+       if(!(status&WDC_SR_TGOOD))
+               printk(KERN_CRIT "Overheat alarm.(%d)\n",inb_p(WDT_RT));
+       if(!(status&WDC_SR_PSUOVER))
+               printk(KERN_CRIT "PSU over voltage.\n");
+       if(!(status&WDC_SR_PSUUNDR))
+               printk(KERN_CRIT "PSU under voltage.\n");
+       if(!(status&WDC_SR_FANGOOD))
+               printk(KERN_CRIT "Possible fan fault.\n");
+       if(!(status&WDC_SR_WCCR))
+#ifdef SOFTWARE_REBOOT
+#ifdef ONLY_TESTING
+               printk(KERN_CRIT "Would Reboot.\n");
+#else          
+               printk(KERN_CRIT "Initiating system reboot.\n");
+               hard_reset_now();
+#endif         
+#else
+               printk(KERN_CRIT "Reset in 5ms.\n");
+#endif         
+}
+
+
+static int wdt_lseek(struct inode *inode, struct file *file, off_t offset, 
+       int origin)
+{
+       return -ESPIPE;
+}
+
+static int wdt_write(struct inode *inode, struct file *file, char *buf, int count)
+{
+       /* Write a watchdog value */
+       inb_p(WDT_DC);
+       wdt_ctr_mode(1,2);
+       wdt_ctr_load(1,WD_TIMO);                /* Timeout */
+       outb_p(0, WDT_DC);
+       return count;
+}
+
+/*
+ *     Read reports the temperature in farenheit
+ */
+static int wdt_read(struct inode *inode, struct file *file, char *buf, int count)
+{
+       unsigned short c=inb_p(WDT_RT);
+       unsigned char cp;
+       int err;
+       
+       switch(MINOR(inode->i_rdev))
+       {
+               case TEMP_MINOR:
+                       err=verify_area(VERIFY_WRITE, buf, 1);
+                       if(err)
+                               return err;
+                       c*=11;
+                       c/=15;
+                       cp=c;
+                       memcpy_tofs(buf,&cp,1);
+                       return 1;
+               default:
+                       return -EINVAL;
+       }
+}
+
+static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+       unsigned long arg)
+{
+       return -EINVAL;
+}
+
+static int wdt_open(struct inode *inode, struct file *file)
+{
+       switch(MINOR(inode->i_rdev))
+       {
+               case WATCHDOG_MINOR:
+                       if(wdt_is_open)
+                               return -EBUSY;
+                       MOD_INC_USE_COUNT;
+                       /*
+                        *      Activate 
+                        */
+        
+                       wdt_is_open=1;
+                       inb_p(WDT_DC);          /* Disable */
+                       wdt_ctr_mode(0,3);
+                       wdt_ctr_mode(1,2);
+                       wdt_ctr_mode(2,0);
+                       wdt_ctr_load(0, 8948);          /* count at 100Hz */
+                       wdt_ctr_load(1,WD_TIMO);        /* Timeout 120 seconds */
+                       wdt_ctr_load(2,65535);
+                       outb_p(0, WDT_DC);      /* Enable */
+                       return 0;
+               case TEMP_MINOR:
+                       MOD_INC_USE_COUNT;
+                       return 0;
+               default:
+                       return -ENODEV;
+       }
+}
+
+static void wdt_release(struct inode *inode, struct file *file)
+{
+       if(MINOR(inode->i_rdev)==WATCHDOG_MINOR)
+       {
+               inb_p(WDT_DC);          /* Disable counters */
+               wdt_ctr_load(2,0);      /* 0 length reset pulses now */
+               wdt_is_open=0;
+       }
+       MOD_DEC_USE_COUNT;
+}
+
+/*
+ *     Kernel Interfaces
+ */
+static struct file_operations wdt_fops = {
+       wdt_lseek,
+       wdt_read,
+       wdt_write,
+       NULL,           /* No Readdir */
+       NULL,           /* No Select */
+       wdt_ioctl,
+       NULL,           /* No mmap */
+       wdt_open,
+       wdt_release
+};
+
+static struct mouse wdt_mouse=
+{
+       WATCHDOG_MINOR,
+       "wdt",
+       &wdt_fops
+};
+
+static struct mouse temp_mouse=
+{
+       TEMP_MINOR,
+       "temperature",
+       &wdt_fops
+};
+
+#ifdef MODULE
+
+int init_module(void)
+{
+       printk("WDT501-P module at %X(Interrupt %d)\n", io,irq);
+       if(request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p"))
+       {
+               printk("IRQ %d is not free.\n", irq);
+               return -EIO;
+       }
+       mouse_register(&wdt_mouse);
+#ifdef CONFIG_WDT_501  
+       mouse_register(&temp_mouse);
+#endif 
+       request_region(io, 8, "wdt501");
+       return 0;
+}
+
+void cleanup_module(void)
+{
+       mouse_deregister(&wdt_mouse);
+#ifdef CONFIG_WDT_501  
+       mouse_deregister(&temp_mouse);
+#endif 
+       release_region(io,8);
+       free_irq(irq);
+}
+
+#else
+
+int wdt_init(void)
+{
+       printk("WDT500/501-P driver at %X(Interrupt %d)\n", io,irq);
+       if(request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p"))
+       {
+               printk("IRQ %d is not free.\n", irq);
+               return -EIO;
+       }
+       mouse_register(&wdt_mouse);
+       mouse_register(&temp_mouse);
+       request_region(io, 8, "wdt501");
+       return 0;
+}
+
+#endif
index b58d2d66ff41ff6d41907d06c9507e562f9e899a..37f5847c650cf52e9c4004c7bf7dc322fd2bbaec 100644 (file)
@@ -1,6 +1,6 @@
 /* arcnet.c
-       Written 1994-95 by Avery Pennarun, derived from skeleton.c by Donald
-       Becker.
+       Written 1994-1996 by Avery Pennarun,
+       derived from skeleton.c by Donald Becker.
 
        Contact Avery at: apenwarr@foxnet.net or
        RR #5 Pole Line Road, Thunder Bay, ON, Canada P7C 5M9
         modified by SRC, incorporated herein by reference.
          
        **********************
-
+       
+       This is ONLY A SUMMARY.  The complete ChangeLog is available in
+       the full Linux-ARCnet package.
+
+       v2.30 ALPHA (96/01/10)
+         - Abandoned support for Linux 1.2 to simplify coding and allow me
+           to take advantage of new features in 1.3.
+         - Updated cabling/jumpers documentation with MUCH information that
+           people have recently (and in some cases, not so recently) sent
+           me.  I don't mind writing documentation, but the jumpers
+           database is REALLY starting to get dull.
+         - Autoprobing works as a module now - but ONLY with my fix to
+           register_netdev and unregister_netdev.  It's also much faster,
+           and uses the "new-style" IRQ autoprobe routines.  Autoprobe is
+           still a horrible mess and will be cleaned up further as time
+           passes.
+           
        v2.22 (95/12/08)
-         - IRQ is always printed as a decimal, instead of a hex number.
-         - Replaced most remaining printk's with BUGMSG macros.
-         - Moved variables for VERIFY_ACK from the Outgoing struct into
-           the lp struct; Outgoing is really for packet-splitting info
-           only.
-         - Simplified INTMASK handling using a memory variable to keep a
-           "running total."
-         - Tracked down more (maybe the last?) "missed IRQ" messages caused
-           by TX-done IRQ's occurring WHILE arcnet??_send_packet was in
-           progress.  These were pretty obscure and mostly harmless.
-         - Made an actual non-ALPHA release of the thing.
-
-       v2.21 ALPHA (95/11/29)
-         - "Unknown protocol ID" messages now also indicate the station
-           which sent the unrecognized packet, to aid in debugging network
-           confusion.  Also, if anyone knows why Novell servers send packets
-           with protocol ID 0xEC, be sure to tell me.  For now they're
-           ignored.
-         - Rearranged ARC_P_* handling a bit, so it makes slightly more
-           sense.
-         - We were clearing irq2dev_map too soon, and causing spurious
-           "irq %d for unknown device" messages.  Moved all the set/clear
-           irq2dev_map operations to more intelligent places.
-         - 1.2.x kernels really didn't work with 2.20 ALPHA.  Maybe this
-           will fix it.
-         - Fixed the setting of set_multicast_list.  Since we don't have
-           multicast support, there's no point in using this at all.
-
-       v2.20 ALPHA (95/11/12)
-         - Added a bit of protocol confusion to the arc0 code to allow
-           trxnet-compatible IPX support - and the use of all that new
-           Linux-IPX stuff (including lwared).  Just tell the ipx_interface
-           command that arc0 uses 802.3 (other protocols will probably also
-           work).
-         - Fixed lp->stats to update tx_packets on all devices, not just
-           arc0.  Also, changed a lot of the error counting to make more
-           sense.
-         - rx_packets on arc0 was being updated for each completely received
-           packet.  It now updates for each segment received, which makes
-           more sense. 
-         - Removed unneeded extra check of dev->start in arcnet_inthandler.
-         - Included someone else's fixes from kernel 1.3.39.  Does it still
-           work with kernel 1.2?
-         - Added a new define to disable PRINTING (not checking) of RECON
-           messages.
-         - Separated the duplicated error checking code from the various
-           arcnet??_send_packet routines into a new function.
-         - Cleaned up lock variables and ping-pong buffers a bit.  This
-           should mean more stability, fewer missing packets, and less ugly
-           debug messages.  Assuming it works.
-         - Changed the format of debug messages to always include the actual
-           device name instead of just "arcnet:".  Used more macros to
-           shorten debugging code even more.
-         - Finally squashed the "startup NULL pointer" bug.  irq2dev_map
-           wasn't being cleared to NULL when the driver was closed.
-         - Improved RECON checking; if a certain number of RECON messages
-           are received within one minute, a warning message is printed
-           to the effect of "cabling problem."  One-log-message-per-recon
-           now defaults to OFF.
-
-       v2.12 ALPHA (95/10/27)
-         - Tried to improve skb handling and init code to fix problems with
-           the latest 1.3.x kernels. (We no longer use ether_setup except
-           in arc0e since they keep coming up with new and improved
-           incompatibilities for us.)
-
-       v2.11 ALPHA (95/10/25)
-         - Removed superfluous sti() from arcnet_inthandler.
-         - "Cleaned up" (?) handling of dev->interrupt for multiple
-           devices.
-         - Place includes BEFORE configuration settings (solves some
-           problems with insmod and undefined symbols)
-         - Removed race condition in arcnet_open that could cause
-           packet reception to be disabled until after the first TX.
-         
-       v2.10 ALPHA (95/09/10)
-         - Integrated Tomasz Motylewski's new RFC1051 compliant "arc0s"
-           ([S]imple [S]tandard?) device.  This should make Linux-ARCnet
-           work with the NetBSD/AmiTCP implementation of this older RFC,
-           via the arc0s device.
-         - Decided the current implementation of Multiprotocol ARCnet
-           involved way too much duplicated code, and tried to share things
-           a _bit_ more, at least.  This means, pretty much, that any
-           bugs in the arc0s module are now my fault :)
-         - Added a new ARCNET_DEBUG_MAX define that sets the highest
-           debug message level to be included in the driver.  This can
-           reduce the size of the object file, and probably increases
-           efficiency a bit.  I get a 0.1 ms speedup in my "ping" times if
-           I disable all debug messages.  Oh, wow.
-         - Fixed a long-standing annoyance with some of the power-up debug
-           messages.  ("IRQ for unknown device" was showing up too often)
+         - Major cleanups, speedups, and better code-sharing.
+         - Eliminated/changed many useless/meaningless/scary debug messages
+           (and, in most cases, the bugs that caused them).
+         - Better IPX support.
+         - lp->stats updated properly.
+         - RECON checking now by default only bugs you if there are an
+           excessive number (ie. your cable is probably broken).
+         - New RFC1051-compliant "arc0s" virtual device by Tomasz
+           Motylewski.
+         - Excess debug messages can be compiled out for maximum
+           efficiency.
 
        v2.00 (95/09/06)
-         - THIS IS ONLY A SUMMARY.  The complete changelog is available
-           from me upon request.
-
          - ARCnet RECON messages are now detected and logged.  These occur
            when a new computer is powered up on the network, or in a
            constant stream when the network cable is broken.  Thanks to
          - Initial non-alpha release.
        
          
-       TO DO:
+       TO DO: (it it just me, or does this list only get longer?)
        
          - Test in systems with NON-ARCnet network cards, just to see if
            autoprobe kills anything.  Currently, we do cause some NE2000's
            to die.  Autoprobe is also way too slow and verbose, particularly
-           if there aren't any ARCnet cards in the system.  And why shouldn't
-           it work as a module again?
-         - Rewrite autoprobe.
+           if there aren't any ARCnet cards in the system.
+         - Rewrite autoprobe.  Try the Linux-generic-autoirq function instead
+           of the net-specific one.
          - Make sure RESET flag is cleared during an IRQ even if dev->start==0;
            mainly a portability fix.  This will confuse autoprobe a bit, so
            test that too.
          - What about cards with shared memory that can be "turned off?"
            (or that have none at all, like the SMC PC500longboard)
-         - Some newer ARCnets support promiscuous mode, supposedly.  If
-           someone sends me information, I'll try to implement it.
-         - Dump Linux 1.2 support and its ugly #ifdefs.
+         - Autoconfigure PDI5xxPlus cards. (I now have a PDI508Plus to play
+           with temporarily)
+         - Try to implement promiscuous (receive-all-packets) mode available
+           on some newer cards with COM20020 and similar chips.  I don't have
+           one, but SMC sent me the specs.
          - Add support for the new 1.3.x IP header cache features.
          - Support printk's priority levels.
          - Make arcnetE_send_packet use arcnet_prepare_tx for loading the
            packet into ARCnet memory.
          - Move the SKB and memory dump code into separate functions.
          - ATA protocol support?? 
-         - Banyan VINES TCP/IP support??
+         - VINES TCP/IP encapsulation?? (info needed)
 
            
        Sources:
         - skeleton.c v0.05 dated 11/16/93 by Donald Becker
                (from Linux Kernel 1.1.45)
         - RFC's 1201 and 1051 - re: TCP/IP over ARCnet
-        - The official ARCnet data sheets (!) thanks to Ken Cornetet
-               <kcornete@nyx10.cs.du.edu>
+        - The official ARCnet COM9026 data sheets (!) thanks to Ken
+               Cornetet <kcornete@nyx10.cs.du.edu>
+        - Information on some more obscure ARCnet controller chips, thanks
+          to the nice people at SMC.
         - net/inet/eth.c (from kernel 1.1.50) for header-building info.
         - Alternate Linux ARCnet source by V.Shergin <vsher@sao.stavropol.su>
         - Textual information and more alternate source from Joachim Koenig
 */
 
 static const char *version =
- "arcnet.c: v2.22 95/12/08 Avery Pennarun <apenwarr@foxnet.net>\n";
+ "arcnet.c: v2.30 ALPHA 96/01/10 Avery Pennarun <apenwarr@foxnet.net>\n";
 
  
 
@@ -196,23 +133,6 @@ static const char *version =
 #include <linux/config.h>
 #include <linux/version.h>
 
-/* are we Linux 1.2.x? */
-#if LINUX_VERSION_CODE < 0x10300
-# define LINUX12
-#endif
-
-/* for older kernels with older module.h */
-#ifdef LINUX12 
-# ifdef MODULE
-   char kernel_version[] = UTS_RELEASE;
-# else
-#  undef  MOD_INC_USE_COUNT
-#  define MOD_INC_USE_COUNT
-#  undef  MOD_DEC_USE_COUNT
-#  define MOD_DEC_USE_COUNT
-# endif
-#endif
-
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/types.h>
@@ -231,18 +151,12 @@ static const char *version =
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
-/*#include <linux/config.h>*/          /* For CONFIG_INET */
-
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
-#ifdef LINUX12
-#include "arp.h"
-#else
 #include <net/arp.h>
-#endif
 
 /**************************************************************************/
 
@@ -252,7 +166,7 @@ static const char *version =
  * the cable is broken.
  *
  * Define DETECT_RECONFIGS if you want to detect network reconfigurations. 
- * They may be a real nuisance on a larger ARCnet network; if you are a
+ * Recons may be a real nuisance on a larger ARCnet network; if you are a
  * network administrator you probably would like to count them. 
  * Reconfigurations will be recorded in stats.tx_carrier_errors (the last
  * field of the /proc/net/dev file).
@@ -278,8 +192,9 @@ static const char *version =
 /* Define this if you want to make sure transmitted packets are "acknowledged"
  * by the destination host, as long as they're not to the broadcast address.
  *
- * That way, if one segment of a split packet doesn't get through, it can
- * be resent immediately rather than confusing the other end.
+ * That way, if one segment of a split packet doesn't get through, it can be
+ * resent immediately rather than confusing the other end.  We don't
+ * actually do that yet, though.
  *
  * Disable this to return to 1.02-style behaviour, if you have problems.
  */
@@ -339,20 +254,6 @@ int arcnet_debug = ARCNET_DEBUG;
 #define BUGLVL(x) if ((ARCNET_DEBUG_MAX)&arcnet_debug&(x))
 #define BUGMSG(x,msg,args...) BUGLVL(x) printk("%6s: " msg, dev->name , ## args);
 
-#ifndef HAVE_AUTOIRQ
-/* From auto_irq.c, in ioport.h for later versions. */
-extern void autoirq_setup(int waittime);
-extern int autoirq_report(int waittime);
-/* The map from IRQ number (as passed to the interrupt handler) to
-   'struct device'. */
-extern struct device *irq2dev_map[16];
-#endif
-
-#ifndef HAVE_PORTRESERVE
-#define check_region(ioaddr, size)             0
-#define        request_region(ioaddr, size)            do ; while (0)
-#endif
-
 /* Some useful multiprotocol macros */
 #define TBUSY lp->adev->tbusy \
                =lp->edev->tbusy \
@@ -388,9 +289,7 @@ extern struct device *irq2dev_map[16];
 
        /* Time needed for various things (in clock ticks, 1/100 sec) */
        /* We mostly don't bother with these - watch out. */
-#define RESETtime 40           /* reset */
-#define XMITtime 10            /* send (?) */
-#define ACKtime 10             /* acknowledge (?) */
+#define RESETtime 30           /* reset */
 
        /* these are the max/min lengths of packet data. (including
         * ClientData header)
@@ -582,10 +481,9 @@ struct arcnet_local {
 
 /* Index to functions, as function prototypes. */
 extern int arcnet_probe(struct device *dev);
-#ifndef MODULE
 static int arcnet_memprobe(struct device *dev,u_char *addr);
 static int arcnet_ioprobe(struct device *dev, short ioaddr);
-#endif
+
 static void arcnet_setup(struct device *dev);
 static int arcnetE_init(struct device *dev);
 static int arcnetS_init(struct device *dev);
@@ -619,19 +517,10 @@ static struct enet_statistics *arcnet_get_stats(struct device *dev);
 static void set_multicast_list(struct device *dev);
 */
        /* functions for header/arp/etc building */
-#ifdef LINUX12
-int arcnetA_header(unsigned char *buff,struct device *dev,
-               unsigned short type,void *daddr,void *saddr,unsigned len,
-               struct sk_buff *skb);
-int arcnetS_header(unsigned char *buff,struct device *dev,
-               unsigned short type,void *daddr,void *saddr,unsigned len,
-               struct sk_buff *skb);
-#else
 int arcnetA_header(struct sk_buff *skb,struct device *dev,
                unsigned short type,void *daddr,void *saddr,unsigned len);
 int arcnetS_header(struct sk_buff *skb,struct device *dev,
                unsigned short type,void *daddr,void *saddr,unsigned len);
-#endif
 int arcnetA_rebuild_header(void *eth,struct device *dev,unsigned long raddr,
                struct sk_buff *skb);
 int arcnetS_rebuild_header(void *eth,struct device *dev,unsigned long raddr,
@@ -665,7 +554,6 @@ void cleanup_module(void);
 int
 arcnet_probe(struct device *dev)
 {
-#ifndef MODULE
        /* I refuse to probe anything less than 0x200, because anyone using
         * an address like that should probably be shot.
         */
@@ -691,13 +579,12 @@ arcnet_probe(struct device *dev)
                                        /* terminator */
                                        0};
        int base_addr=dev->base_addr, status=0;
-#endif /* MODULE */
-       int delayval;
+       int delayval,ioaddr;
        struct arcnet_local *lp;
 
        printk(version);
        
-#if 0
+#if 1
        BUGLVL(D_NORMAL)
        {
                printk("arcnet: ***\n");
@@ -722,32 +609,34 @@ arcnet_probe(struct device *dev)
        BUGMSG(D_INIT,"given: base %lXh, IRQ %d, shmem %lXh\n",
                        dev->base_addr,dev->irq,dev->mem_start);
 
-#ifndef MODULE
        if (base_addr > 0x1ff)          /* Check a single specified location. */
                status=arcnet_ioprobe(dev, base_addr);
        else if (base_addr > 0)         /* Don't probe at all. */
-               return ENXIO;
+               return -ENXIO;
        else for (port = &ports[0]; *port; port++)
        {
-               int ioaddr = *port;
-               if (check_region(ioaddr, ARCNET_TOTAL_SIZE))
+               if (check_region(*port, ARCNET_TOTAL_SIZE))
                {
                        BUGMSG(D_INIT,"Skipping %Xh because of check_region...\n",
-                                       ioaddr);
+                                       *port);
                        continue;
                }
 
-               status=arcnet_ioprobe(dev, ioaddr);
+               status=arcnet_ioprobe(dev, *port);
                if (!status) break;
        }
        
        if (status) return status;
+       
+       /* arcnet_ioprobe set this */
+       ioaddr=dev->base_addr;
 
-       /* ioprobe turned out okay.  Now give it a couple seconds to finish
-        * initializing...
+       /* ioprobe turned out okay.  Now reset the card, so we have
+        * a test byte to look for in shared memory...
         */
        BUGMSG(D_INIT,"ioprobe okay!  Waiting for reset...\n");
-       JIFFER(100);
+       inb(RESET);
+       JIFFER(RESETtime);
 
        /* okay, now we have to find the shared memory area. */
        BUGMSG(D_INIT,"starting memory probe, given %lXh\n",
@@ -766,24 +655,16 @@ arcnet_probe(struct device *dev)
                
                if (status) return status;
        }
-#else /* MODULE */
-       if (!dev->base_addr || !dev->irq || !dev->mem_start 
-               || !dev->rmem_start)
-       {
-               BUGMSG(D_NORMAL,"loadable modules can't autoprobe!\n");
-               BUGMSG(D_NORMAL,"try using io=, irqnum=, and shmem= on the insmod line.\n");
-               BUGMSG(D_NORMAL,"you may also need num= to change the device name. (ie. num=1 for arc1)\n");
-               return ENODEV;
-       }
-#endif
+
        /* now reserve the irq... */
        {       
                int irqval = request_irq(dev->irq, &arcnet_interrupt, 0,
                        "arcnet");
-               if (irqval) {
+               if (irqval)
+               {
                        BUGMSG(D_NORMAL,"unable to get IRQ %d (irqval=%d).\n",
                                dev->irq, irqval);
-                       return EAGAIN;
+                       return -EIO;
                }
                
                irq2dev_map[dev->irq]=dev;
@@ -827,7 +708,6 @@ arcnet_probe(struct device *dev)
        
        BUGMSG(D_INIT,"arcnet_probe: resetting card.\n");
        arcnet_reset(dev);
-       JIFFER(50);
        BUGMSG(D_NORMAL,"We appear to be station %d (%02Xh)\n",
                        lp->stationid,lp->stationid);
        if (lp->stationid==0)
@@ -841,18 +721,14 @@ arcnet_probe(struct device *dev)
        dev->hard_header=arcnetA_header;
        dev->rebuild_header=arcnetA_rebuild_header;
        
-       #ifdef LINUX12
-       dev->type_trans=arcnetA_type_trans;
-       #endif
-
        return 0;
 }
 
-#ifndef MODULE
 
 int arcnet_ioprobe(struct device *dev, short ioaddr)
 {
-       int delayval,airq;
+       int airq;
+       unsigned long airqmask;
 
        BUGMSG(D_INIT,"probing address %Xh\n",ioaddr);
        BUGMSG(D_INIT," status1=%Xh\n",inb(STATUS));
@@ -861,17 +737,23 @@ int arcnet_ioprobe(struct device *dev, short ioaddr)
        /* very simple - all we have to do is reset the card, and if there's
         * no irq, it's not an ARCnet.  We can also kill two birds with
         * one stone because we detect the IRQ at the same time :)
+        *
+        * BUT: some newer cards don't seem to IRQ upon reset, or worse,
+        * don't reset when BASE+0x08 is read.  This code is no longer
+        * so simple, and in fact quite dangerous.  It should be redesigned.
         */
         
+#if 0
        /* reset the card by reading the reset port */
        inb(RESET);
        JIFFER(RESETtime);
+#endif
 
        /* if status port is FF, there's certainly no arcnet... give up. */
        if (inb(STATUS)==0xFF)
        {
                BUGMSG(D_INIT," probe failed.  Status port empty.\n");
-               return ENODEV;
+               return -ENODEV;
        }
 
 #if 0
@@ -892,7 +774,7 @@ int arcnet_ioprobe(struct device *dev, short ioaddr)
                {
                        BUGLVL(D_INIT," probe failed.  never-changing command port (%02Xh).\n",
                                initval);
-                       return ENODEV;
+                       return -ENODEV;
                }
        }
 #endif
@@ -905,27 +787,43 @@ int arcnet_ioprobe(struct device *dev, short ioaddr)
        {
                BUGMSG(D_INIT," probe failed.  eternal reset flag1...(status=%Xh)\n",
                                inb(STATUS));
-               return ENODEV;
+               return -ENODEV;
        }
 
+       outb(NORXcmd,COMMAND);
+       outb(0,INTMASK);
+       udelay(1);
+
        /* set up automatic IRQ detection */
-       autoirq_setup(0);
-       
+       airqmask = probe_irq_on();
+       BUGMSG(D_INIT," airqmask=%lXh\n",airqmask);
 
-       /* if we do this, we're sure to get an IRQ since the card has
-        * just reset and the NORXflag is on until we tell it to start
-        * receiving.
+       /* if we do this, we're sure to get an IRQ since the card
+        * has just reset and the NORXflag is on until we tell it to
+        * start receiving.
         */
        outb(NORXflag,INTMASK);
-       JIFFER(RESETtime);
+       udelay(1);
        outb(0,INTMASK);
 
-       /* and turn the reset flag back off */
+       /* and turn the reset flag back off.  On some systems, we NEED to do
+        * this before we re-enable the IRQ!
+        */
        outb(CFLAGScmd|RESETclear|CONFIGclear,COMMAND);
 
-       airq = autoirq_report(0);
-       if (airq)
+       /* get autoirq results */
+       airq = probe_irq_off(airqmask);
+
+       if (airq>0)
+       {
                BUGMSG(D_INIT," autoirq is %d\n", airq);
+       }
+       else if (airq<0)
+       {
+               BUGMSG(D_INIT," autoirq MAY be %d (please send mail to Avery)\n",
+                       -airq);
+               airq=0;
+       }
 
        /* if there was no autoirq AND the user hasn't set any defaults,
         * give up.
@@ -933,30 +831,34 @@ int arcnet_ioprobe(struct device *dev, short ioaddr)
        if (!airq && !(dev->base_addr && dev->irq))
        {
                BUGMSG(D_INIT," probe failed.  no autoirq...\n");
-               return ENODEV;
+               return -ENODEV;
        }
 
        /* otherwise we probably have a card.  Let's make sure. */
        
+#if 0
        if (inb(STATUS) & RESETflag) /* reset flag on */
        {
                /* now we turn the reset bit off */
                outb(CFLAGScmd|RESETclear|CONFIGclear,COMMAND);
        }
+#endif
        
        if (inb(STATUS) & RESETflag) /* reset flag STILL on */
        {
                BUGMSG(D_INIT," probe failed.  eternal reset flag...(status=%Xh)\n",
                                inb(STATUS));
-               return ENODEV;
+               return -ENODEV;
        }
        
-       /* okay, we've got a real, live ARCnet on our hands. */
+       /* okay, we've got a real, live ARCnet on our hands.
+        * I hope.
+        */
        if (!dev->base_addr) dev->base_addr=ioaddr;
        
        if (dev->irq < 2)               /* "Auto-IRQ" */
        {
-               /* we already did the autoirq above, so store the values */
+               /* we already did the autoirq above, so store the value */
                dev->irq=airq;
        }
        else if (dev->irq == 2)
@@ -986,7 +888,7 @@ int arcnet_memprobe(struct device *dev,u_char *addr)
        {
                BUGMSG(D_INIT," probe failed.  addr=%lXh, addr[0]=%Xh (not %Xh)\n",
                                (unsigned long)addr,addr[0],TESTvalue);
-               return ENODEV;
+               return -ENODEV;
        }
        
        /* now verify the shared memory writability */
@@ -995,7 +897,7 @@ int arcnet_memprobe(struct device *dev,u_char *addr)
        {
                BUGMSG(D_INIT," probe failed.  addr=%lXh, addr[0]=%Xh (not 42h)\n",
                                (unsigned long)addr,addr[0]);
-               return ENODEV;
+               return -ENODEV;
        }
 
        /* got it!  fill in dev */
@@ -1007,8 +909,6 @@ int arcnet_memprobe(struct device *dev,u_char *addr)
        return 0;
 }
 
-#endif /* MODULE */
-
 
 /* Do a hardware reset on the card.
  */
@@ -1133,9 +1033,6 @@ static int arcnetS_init(struct device *dev)
        dev->hard_start_xmit=arcnetS_send_packet;
        dev->hard_header=arcnetS_header;
        dev->rebuild_header=arcnetS_rebuild_header;
-#ifdef LINUX12
-       dev->type_trans=arcnetS_type_trans;
-#endif
        BUGMSG(D_EXTRA,"ARCnet RFC1051 (NetBSD, AmiTCP) protocol initialized.\n");
 
        return 0;
@@ -1160,7 +1057,7 @@ static int
 arcnet_open(struct device *dev)
 {
        struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-       int ioaddr=dev->base_addr,delayval;
+       int ioaddr=dev->base_addr;
        
        if (dev->metric>=1000)
        {
@@ -1214,10 +1111,14 @@ arcnet_open(struct device *dev)
        
        /* make sure we're ready to receive IRQ's.
         * arcnet_reset sets this for us, but if we receive one before
-        * START is set to 1, it could be ignored.
+        * START is set to 1, it could be ignored.  So, we turn IRQ's
+        * off, then on again to clean out the IRQ controller.
         */
        outb(0,INTMASK);
-       JIFFER(ACKtime);
+       udelay(1);      /* give it time to set the mask before
+                        * we reset it again. (may not even be
+                        * necessary)
+                        */
        SETMASK;
        
        MOD_INC_USE_COUNT;
@@ -1241,7 +1142,7 @@ arcnet_close(struct device *dev)
        SETMASK;        /* no IRQ's (except RESET, of course) */
        outb(NOTXcmd,COMMAND);  /* stop transmit */
        outb(NORXcmd,COMMAND);  /* disable receive */
-       
+
        /* reset more flags */
        INTERRUPT=0;
        
@@ -2394,9 +2295,7 @@ arcnetA_rx(struct device *dev,u_char *buf,
                                printk("\n");
                }
 
-               #ifndef LINUX12
                skb->protocol=arcnetA_type_trans(skb,dev);
-               #endif
 
                netif_rx(skb);
          }
@@ -2567,9 +2466,7 @@ arcnetA_rx(struct device *dev,u_char *buf,
                                }
 
                        
-                               #ifndef LINUX12
                                skb->protocol=arcnetA_type_trans(skb,dev);
-                               #endif
                                
                                netif_rx(skb);
                        }
@@ -2616,9 +2513,7 @@ arcnetE_rx(struct device *dev,u_char *arcsoft,
                 printk("\n");
         }
         
-       #ifndef LINUX12
        skb->protocol=eth_type_trans(skb,dev);
-       #endif
         
         netif_rx(skb);
 }
@@ -2673,9 +2568,7 @@ arcnetS_rx(struct device *dev,u_char *buf,
                                printk("\n");
                }
 
-               #ifndef LINUX12
                skb->protocol=arcnetS_type_trans(skb,dev);
-               #endif
 
                netif_rx(skb);
          }
@@ -2729,21 +2622,11 @@ set_multicast_list(struct device *dev)
  * saddr=NULL  means use device source address (always will anyway)
  * daddr=NULL  means leave destination address (eg unresolved arp)
  */
-#ifdef LINUX12
-int arcnetA_header(unsigned char *buff,struct device *dev,
-               unsigned short type,void *daddr,void *saddr,unsigned len,
-               struct sk_buff *skb)
-#else
 int arcnetA_header(struct sk_buff *skb,struct device *dev,
                unsigned short type,void *daddr,void *saddr,unsigned len)
-#endif
 {
        struct ClientData *head = (struct ClientData *)
-#ifdef LINUX12
-               buff;
-#else
                skb_push(skb,dev->hard_header_len);
-#endif
        struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
 
        BUGMSG(D_DURING,"create header from %d to %d; protocol %d (%Xh); size %u.\n",
@@ -2813,21 +2696,11 @@ int arcnetA_header(struct sk_buff *skb,struct device *dev,
  * saddr=NULL  means use device source address (always will anyway)
  * daddr=NULL  means leave destination address (eg unresolved arp)
  */
-#ifdef LINUX12
-int arcnetS_header(unsigned char *buff,struct device *dev,
-               unsigned short type,void *daddr,void *saddr,unsigned len,
-               struct sk_buff *skb)
-#else
 int arcnetS_header(struct sk_buff *skb,struct device *dev,
                unsigned short type,void *daddr,void *saddr,unsigned len)
-#endif
 {
        struct S_ClientData *head = (struct S_ClientData *)
-#ifdef LINUX12
-               buff;
-#else
                skb_push(skb,dev->hard_header_len);
-#endif
        struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
 
        /* set the protocol ID according to RFC1051 */
@@ -2959,14 +2832,10 @@ unsigned short arcnetA_type_trans(struct sk_buff *skb,struct device *dev)
        struct ClientData *head;
        struct arcnet_local *lp=(struct arcnet_local *) (dev->priv);
 
-#ifdef LINUX12
-       head=(struct ClientData *)skb->data;
-#else
        /* Pull off the arcnet header. */
        skb->mac.raw=skb->data;
        skb_pull(skb,dev->hard_header_len);
        head=(struct ClientData *)skb->mac.raw;
-#endif
        
        if (head->daddr==0)
                skb->pkt_type=PACKET_BROADCAST;
@@ -3004,14 +2873,10 @@ unsigned short arcnetS_type_trans(struct sk_buff *skb,struct device *dev)
        struct S_ClientData *head;
        struct arcnet_local *lp=(struct arcnet_local *) (dev->priv);
 
-#ifdef LINUX12
-       head=(struct S_ClientData *)skb->data;
-#else
        /* Pull off the arcnet header. */
        skb->mac.raw=skb->data;
        skb_pull(skb,dev->hard_header_len);
        head=(struct S_ClientData *)skb->mac.raw;
-#endif
        
        if (head->daddr==0)
                skb->pkt_type=PACKET_BROADCAST;
@@ -3089,8 +2954,18 @@ init_module(void)
 void
 cleanup_module(void)
 {
+       int ioaddr=thiscard.base_addr;
+
        if (thiscard.start) arcnet_close(&thiscard);
-       
+
+       /* Flush TX and disable RX */
+       if (ioaddr)
+       {
+               outb(0,INTMASK);        /* disable IRQ's */
+               outb(NOTXcmd,COMMAND);  /* stop transmit */
+               outb(NORXcmd,COMMAND);  /* disable receive */
+       }
+
        if (thiscard.irq)
        {
                free_irq(thiscard.irq);
index e29e095222d311bac5deb4532c74b21a4c37b65d..ca0f2308d92c11df6b622dbf7ecf7a009571ed40 100644 (file)
@@ -258,11 +258,13 @@ int register_netdev(struct device *dev)
                                }
                }
 
+               sti();  /* device probes assume interrupts enabled */
                if (dev->init(dev) != 0) {
                    if (i < MAX_ETH_CARDS) ethdev_index[i] = NULL;
                        restore_flags(flags);
                        return -EIO;
                }
+               cli();
 
                /* Add device to end of chain */
                if (dev_base) {
@@ -345,6 +347,9 @@ void unregister_netdev(struct device *dev)
                        break;
                }
        }
+
+       restore_flags(flags);
+
        /* You can i.e use a interfaces in a route though it is not up.
           We call close_dev (which is changed: it will down a device even if
           dev->flags==0 (but it will not call dev->stop if IFF_UP
@@ -353,8 +358,6 @@ void unregister_netdev(struct device *dev)
           dev_mc_discard(dev), ....
        */
        dev_close(dev);
-
-       restore_flags(flags);
 }
 
 \f
index c5ca97d01c28a7e49bbdd61d6da30ac10d50f62e..d2c8c3e288d00591a3f67c357eaa2c5dbd5ef1d5 100644 (file)
@@ -1753,8 +1753,6 @@ static void set_multicast_list(struct device *dev)
     }
 } /* End of set_multicast_list() */
 
-#endif     
-
 
 \f
 /*-
index 41d35bd80ee118bf1f95afd6370c2c99c44673cc..2dcb6050b203a9b7d43de94d41e471b3cf5cfa96 100644 (file)
  * General Public License for more details.
  *
  *
- * $Id: aha152x.c,v 1.12 1995/12/16 12:26:07 fischer Exp fischer $
+ * $Id: aha152x.c,v 1.13 1996/01/09 02:15:53 fischer Exp $
  *
  * $Log: aha152x.c,v $
+ * Revision 1.13  1996/01/09  02:15:53  fischer
+ * - some cleanups
+ * - moved request_irq behind controller initialization
+ *   (to avoid spurious interrupts)
+ *
  * Revision 1.12  1995/12/16  12:26:07  fischer
  * - barrier()'s added
  * - configurable RESET delay added
@@ -299,6 +304,8 @@ struct proc_dir_entry proc_scsi_aha152x = {
 
 extern long loops_per_sec;
 
+#define DELAY_DEFAULT 100
+
 /* some additional "phases" for getphase() */
 #define P_BUSFREE  1
 #define P_PARITY   2
@@ -322,7 +329,6 @@ enum {
 /* set by aha152x_setup according to the command line */
 static int  setup_count=0;
 static struct aha152x_setup {
-  char *conf;
   int io_port;
   int irq;
   int scsiid;
@@ -333,6 +339,7 @@ static struct aha152x_setup {
 #ifdef DEBUG_AHA152X
   int debug;
 #endif
+  char *conf;
 } setup[2];
 
 static struct Scsi_Host *aha152x_host[IRQS];
@@ -566,7 +573,7 @@ void aha152x_setup(char *str, int *ints)
   setup[setup_count].reconnect   = ints[0] >= 4 ? ints[4] : 1;
   setup[setup_count].parity      = ints[0] >= 5 ? ints[5] : 1;
   setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 0 /* FIXME: 1 */;
-  setup[setup_count].delay       = ints[0] >= 7 ? ints[7] : 100;
+  setup[setup_count].delay       = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT;
 #ifdef DEBUG_AHA152X
   setup[setup_count].debug       = ints[0] >= 8 ? ints[8] : DEBUG_DEFAULT;
   if(ints[0]>8)
@@ -745,7 +752,10 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
                   setup[setup_count].reconnect   = conf.cf_tardisc;
                   setup[setup_count].parity      = !conf.cf_parity;
                   setup[setup_count].synchronous = 0 /* FIXME: conf.cf_syncneg */;
+                  setup[setup_count].delay       = DELAY_DEFAULT;
+#ifdef DEBUG_AHA152X
                   setup[setup_count].debug       = DEBUG_DEFAULT;
+#endif
                   setup_count++;
                 }
        }
@@ -775,7 +785,9 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
       HOSTDATA(shpnt)->parity            = setup[i].parity;
       HOSTDATA(shpnt)->synchronous       = setup[i].synchronous;
       HOSTDATA(shpnt)->delay             = setup[i].delay;
+#ifdef DEBUG_AHA152X
       HOSTDATA(shpnt)->debug             = setup[i].debug;
+#endif
 
       HOSTDATA(shpnt)->aborting          = 0;
       HOSTDATA(shpnt)->abortion_complete = 0;
@@ -787,29 +799,6 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
       for(j=0; j<8; j++)
         HOSTDATA(shpnt)->syncrate[j] = 0;
  
-      ok = request_irq(setup[i].irq, aha152x_intr, SA_INTERRUPT, "aha152x");
-  
-  if(ok<0)
-    {
-      if(ok == -EINVAL)
-       {
-              printk("aha152x%d: bad IRQ %d.\n", i, setup[i].irq);
-          printk("         Contact author.\n");
-       }
-      else
-            if(ok == -EBUSY)
-              printk("aha152x%d: IRQ %d already in use. Configure another.\n",
-                    i, setup[i].irq);
-       else
-         {
-                printk("\naha152x%d: Unexpected error code on"
-                      " requesting IRQ %d.\n", i, setup[i].irq);
-           printk("         Contact author.\n");
-         }
-          printk("aha152x: driver needs an IRQ.\n");
-          continue;
-    }
-
       SETPORT(SCSIID, setup[i].scsiid << 4);
       shpnt->this_id=setup[i].scsiid;
   
@@ -842,6 +831,29 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
   SETPORT(SIMODE1, 0);
 
       SETBITS(DMACNTRL0, INTEN);
+
+      ok = request_irq(setup[i].irq, aha152x_intr, SA_INTERRUPT, "aha152x");
+      
+      if(ok<0)
+        {
+          if(ok == -EINVAL)
+            {
+              printk("aha152x%d: bad IRQ %d.\n", i, setup[i].irq);
+              printk("          Contact author.\n");
+            }
+          else
+            if(ok == -EBUSY)
+              printk("aha152x%d: IRQ %d already in use. Configure another.\n",
+                    i, setup[i].irq);
+            else
+              {
+                printk("\naha152x%d: Unexpected error code on"
+                      " requesting IRQ %d.\n", i, setup[i].irq);
+                printk("          Contact author.\n");
+              }
+          printk("aha152x: driver needs an IRQ.\n");
+          continue;
+        }
     }
   
   return (setup_count>0);
index 3d543080237ead76b8b016bdc5397f96298c77f7..13c241dc1d490614ea471b32200ccf5170b05414 100644 (file)
@@ -2,7 +2,7 @@
 #define _AHA152X_H
 
 /*
- * $Id: aha152x.h,v 1.12 1995/12/07 01:03:48 fischer Exp fischer $
+ * $Id: aha152x.h,v 1.13 1995/12/16 12:27:23 fischer Exp $
  */
 
 #if defined(__KERNEL__)
@@ -23,7 +23,7 @@ int aha152x_proc_info(char *buffer, char **start, off_t offset, int length, int
    (unless we support more than 1 cmd_per_lun this should do) */
 #define AHA152X_MAXQUEUE       7               
 
-#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.12 $"
+#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.13 $"
 
 extern struct proc_dir_entry proc_scsi_aha152x;
 
index 15581e50b99b61ed93f8d1d7f686f302022b78db..a55e30b2e6db119ad7dd0168c0dab6eda5c7bede 100644 (file)
@@ -5,9 +5,6 @@
  *  Development Sponsored by Killy Corp. NY NY
  *   
  *  Borrows code from st driver.
- *
- *  Version from 1.3.51 modified by Rick Richardson to fix problem in
- *  detecting whether its a send or a recieve style command (see sg_write)
  */
 #include <linux/module.h>
 
@@ -295,9 +292,6 @@ static void sg_command_done(Scsi_Cmnd * SCpnt)
     wake_up(&scsi_generics[dev].read_wait);
 }
 
-#define SG_SEND 0
-#define SG_REC  1
-
 static int sg_write(struct inode *inode,struct file *filp,const char *buf,int count)
 {
     int                          bsize,size,amt,i;
@@ -305,7 +299,7 @@ static int sg_write(struct inode *inode,struct file *filp,const char *buf,int co
     kdev_t               devt = inode->i_rdev;
     int                          dev = MINOR(devt);
     struct scsi_generic   * device=&scsi_generics[dev];
-    int                          direction;
+    int                          input_size;
     unsigned char        opcode;
     Scsi_Cmnd          * SCpnt;
     
@@ -342,33 +336,43 @@ static int sg_write(struct inode *inode,struct file *filp,const char *buf,int co
     device->complete=0;
     memcpy_fromfs(&device->header,buf,sizeof(struct sg_header));
 
-    /*
-     * fix input size, and see if we are sending data.
-     *
-     * Mod by Rick Richardson (rick@dgii.com):
-     * The original test to see if its a SEND/REC was:
-     *     if( device->header.pack_len > device->header.reply_len )
-     * I haven't a clue why the author thought this would work.  Instead,
-     * I've changed it to see if there is any additional data in this
-     * packet beyond the length of the SCSI command itself.
-     */
     device->header.pack_len=count;
     buf+=sizeof(struct sg_header);
-    size = COMMAND_SIZE(get_user(buf)) + sizeof(struct sg_header);
-    if( device->header.pack_len > size)
+
+    /*
+     * Now we need to grab the command itself from the user's buffer.
+     */
+    opcode = get_user(buf);
+    size=COMMAND_SIZE(opcode);
+    if (opcode >= 0xc0 && device->header.twelve_byte) size = 12;
+
+    /*
+     * Determine buffer size.
+     */
+    input_size = device->header.pack_len - size;
+    if( input_size > device->header.reply_len)
     {
-        bsize = device->header.pack_len;
-        direction = SG_SEND;
+        bsize = input_size;
     } else {
         bsize = device->header.reply_len;
-        direction = SG_REC;
     }
     
     /*
      * Don't include the command header itself in the size.
      */
     bsize-=sizeof(struct sg_header);
+    input_size-=sizeof(struct sg_header);
 
+    /*
+     * Verify that the user has actually passed enough bytes for this command.
+     */
+    if( input_size < 0 )
+    {
+       device->pending=0;
+        wake_up( &device->write_wait );
+       return -EIO;
+    }
+    
     /*
      * Allocate a buffer that is large enough to hold the data
      * that has been requested.  Round up to an even number of sectors,
@@ -409,37 +413,11 @@ static int sg_write(struct inode *inode,struct file *filp,const char *buf,int co
     printk("device allocated\n");
 #endif    
 
-    /*
-     * Now we need to grab the command itself from the user's buffer.
-     */
     SCpnt->request.rq_dev = devt;
     SCpnt->request.rq_status = RQ_ACTIVE;
     SCpnt->sense_buffer[0]=0;
-    opcode = get_user(buf);
-    size=COMMAND_SIZE(opcode);
-    if (opcode >= 0xc0 && device->header.twelve_byte) size = 12;
     SCpnt->cmd_len = size;
 
-    /*
-     * If we are writing data, subtract off the size
-     * of the command itself, to get the amount of actual data
-     * that we need to send to the device.
-     */
-    if( direction == SG_SEND )
-        amt -= size;
-    
-    /*
-     * Verify that the user has actually passed enough bytes for this command.
-     */
-    if( count < (sizeof(struct sg_header) + size) )
-    {
-       device->pending=0;
-        wake_up( &device->write_wait );
-        sg_free( device->buff, device->buff_len );
-       device->buff = NULL;
-       return -EIO;
-    }
-    
     /*
      * Now copy the SCSI command from the user's address space.
      */
@@ -451,7 +429,7 @@ static int sg_write(struct inode *inode,struct file *filp,const char *buf,int co
      * field also includes the length of the header and the command,
      * so we need to subtract these off.
      */
-    if( direction == SG_SEND )  memcpy_fromfs(device->buff,buf, amt);
+    if (input_size > 0) memcpy_fromfs(device->buff, buf, input_size);
     
     /*
      * Set the LUN field in the command structure.
index aafc116b3bc9d2b1a789190f2886ddd5a96092ba..c3f4faf545f5d2ff077f8836cdaa67fb84953546 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/errno.h>
 #include <linux/malloc.h>
 #include <linux/pagemap.h>
+#include <linux/swap.h>
 #include <linux/swapctl.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
@@ -1216,10 +1217,10 @@ static int grow_buffers(int pri, int size)
 /* =========== Reduce the buffer memory ============= */
 
 /*
- * try_to_free() checks if all the buffers on this particular page
+ * try_to_free_buffer() checks if all the buffers on this particular page
  * are unused, and free's the page if so.
  */
-static int try_to_free(struct buffer_head * bh, struct buffer_head ** bhp,
+int try_to_free_buffer(struct buffer_head * bh, struct buffer_head ** bhp,
                       int priority)
 {
        unsigned long page;
@@ -1286,9 +1287,9 @@ static inline void age_buffer(struct buffer_head *bh)
        clear_bit(BH_Has_aged, &bh->b_state);
 
        if (touched) 
-               touch_page((unsigned long) bh->b_data);
+               touch_page(mem_map + MAP_NR((unsigned long) bh->b_data));
        else
-               age_page((unsigned long) bh->b_data);
+               age_page(mem_map + MAP_NR((unsigned long) bh->b_data));
 }
 
 /*
@@ -1352,19 +1353,6 @@ static int maybe_shrink_lav_buffers(int size)
  * that are in the 0 - limit address range, for DMA re-allocations.
  * We ignore that right now.
  */
-int shrink_buffers(unsigned int priority, unsigned long limit)
-{
-       if (priority < 2) {
-               sync_buffers(0,0);
-       }
-
-       if(priority == 2) wakeup_bdflush(1);
-
-       if(maybe_shrink_lav_buffers(0)) return 1;
-
-       /* No good candidate size - take any size we can find */
-        return shrink_specific_buffers(priority, 0);
-}
 
 static int shrink_specific_buffers(unsigned int priority, int size)
 {
@@ -1388,7 +1376,7 @@ static int shrink_specific_buffers(unsigned int priority, int size)
                            !bh->b_this_page)
                                 continue;
                        if (!age_of((unsigned long) bh->b_data) &&
-                           try_to_free(bh, &bh, 6))
+                           try_to_free_buffer(bh, &bh, 6))
                                 return 1;
                        if(!bh) break;
                        /* Some interrupt must have used it after we
@@ -1436,7 +1424,7 @@ static int shrink_specific_buffers(unsigned int priority, int size)
                        if ((age_of((unsigned long) bh->b_data) >>
                             (6-priority)) > 0)
                                continue;                               
-                       if (try_to_free(bh, &bh, 0))
+                       if (try_to_free_buffer(bh, &bh, 0))
                                 return 1;
                        if(!bh) break;
                }
@@ -1855,7 +1843,7 @@ int bdflush(void * unused)
 
        current->session = 1;
        current->pgrp = 1;
-       sprintf(current->comm, "kernel bdflush");
+       sprintf(current->comm, "kflushd");
 
        /*
         *      As a kernel thread we want to tamper with system buffers
index ae016cd437da95bdd3c69b910374221c50d02e09..4ddbf046a4a3a6405c3f5587209726b68221be1e 100644 (file)
@@ -4,8 +4,11 @@
  * (C) 1993 Matthias Urlichs -- collected common code and tables.
  * 
  *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Added kerneld support: Jacques Gelinas and Bjorn Ekwall
  */
 
+#include <linux/config.h>
 #include <linux/fs.h>
 #include <linux/major.h>
 #include <linux/string.h>
@@ -14,6 +17,9 @@
 #include <linux/stat.h>
 #include <linux/fcntl.h>
 #include <linux/errno.h>
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
 
 struct device_struct {
        const char * name;
@@ -47,19 +53,53 @@ int get_device_list(char * page)
        }
        return len;
 }
+/*
+       Return the function table of a device.
+       Load the driver if needed.
+*/
+static struct file_operations * get_fops(
+       unsigned int major,
+       unsigned int maxdev,
+       const char *mangle,             /* String to use to build the module name */
+       struct device_struct tb[])
+{
+       struct file_operations *ret = NULL;
+       if (major < maxdev){
+#ifdef CONFIG_KERNELD
+               /*
+                * I do get request for device 0. I have no idea why. It happen
+                * at shutdown time for one. Without the following test, the
+                * kernel will happily trigger a request_module() which will
+                * trigger kerneld and modprobe for nothing (since there
+                * is no device with major number == 0. And furthermore
+                * it locks the reboot process :-(
+                *
+                * Jacques Gelinas (jacques@solucorp.qc.ca)
+                */
+               if (!tb[major].fops && major != 0) {
+                       char name[20];
+                       sprintf(name, mangle, major);
+                       request_module(name);
+               }
+#endif
+               ret = tb[major].fops;
+       }
+       return ret;
+}
 
+
+/*
+       Return the function table of a device.
+       Load the driver if needed.
+*/
 struct file_operations * get_blkfops(unsigned int major)
 {
-       if (major >= MAX_BLKDEV)
-               return NULL;
-       return blkdevs[major].fops;
+       return get_fops (major,MAX_BLKDEV,"block-major-%d",blkdevs);
 }
 
 struct file_operations * get_chrfops(unsigned int major)
 {
-       if (major >= MAX_CHRDEV)
-               return NULL;
-       return chrdevs[major].fops;
+       return get_fops (major,MAX_CHRDEV,"char-major-%d",chrdevs);
 }
 
 int register_chrdev(unsigned int major, const char * name, struct file_operations *fops)
@@ -170,17 +210,24 @@ int check_disk_change(kdev_t dev)
  */
 int blkdev_open(struct inode * inode, struct file * filp)
 {
-       int i;
-
-       i = MAJOR(inode->i_rdev);
-       if (i >= MAX_BLKDEV || !blkdevs[i].fops)
-               return -ENODEV;
-       filp->f_op = blkdevs[i].fops;
-       if (filp->f_op->open)
-               return filp->f_op->open(inode,filp);
-       return 0;
+       int ret = -ENODEV;
+       filp->f_op = get_blkfops(MAJOR(inode->i_rdev));
+       if (filp->f_op != NULL){
+               ret = 0;
+               if (filp->f_op->open != NULL)
+                       ret = filp->f_op->open(inode,filp);
+       }       
+       return ret;
 }      
 
+void blkdev_release(struct inode * inode)
+{
+       struct file_operations *fops = get_blkfops(MAJOR(inode->i_rdev));
+       if (fops && fops->release)
+               fops->release(inode,NULL);
+}
+
+
 /*
  * Dummy default file-operations: the only thing this does
  * is contain the open that then fills in the correct operations
@@ -223,15 +270,14 @@ struct inode_operations blkdev_inode_operations = {
  */
 int chrdev_open(struct inode * inode, struct file * filp)
 {
-       int i;
-
-       i = MAJOR(inode->i_rdev);
-       if (i >= MAX_CHRDEV || !chrdevs[i].fops)
-               return -ENODEV;
-       filp->f_op = chrdevs[i].fops;
-       if (filp->f_op->open)
-               return filp->f_op->open(inode,filp);
-       return 0;
+       int ret = -ENODEV;
+       filp->f_op = get_chrfops(MAJOR(inode->i_rdev));
+       if (filp->f_op != NULL){
+               ret = 0;
+               if (filp->f_op->open != NULL)
+                       ret = filp->f_op->open(inode,filp);
+       }
+       return ret;
 }
 
 /*
index 93b909806b693bbb578a8b5838dc96c4c45af82c..528a9394004ab311cbc95b3cc01f383799445b9a 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -44,6 +44,9 @@
 #include <asm/pgtable.h>
 
 #include <linux/config.h>
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
 
 asmlinkage int sys_exit(int exit_code);
 asmlinkage int sys_brk(unsigned long);
@@ -616,6 +619,7 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs
        int i;
        int retval;
        int sh_bang = 0;
+       int try;
 #ifdef __alpha__
        int loader = 0;
 #endif
@@ -781,18 +785,29 @@ restart_interp:
        }
 
        bprm.sh_bang = sh_bang;
-       for (fmt = formats ; fmt ; fmt = fmt->next) {
-               int (*fn)(struct linux_binprm *, struct pt_regs *) = fmt->load_binary;
-               if (!fn)
-                       break;
-               retval = fn(&bprm, regs);
-               if (retval >= 0) {
-                       iput(bprm.inode);
-                       current->did_exec = 1;
-                       return retval;
+       for (try=0; try<2; try++) {
+               for (fmt = formats ; fmt ; fmt = fmt->next) {
+                       int (*fn)(struct linux_binprm *, struct pt_regs *) = fmt->load_binary;
+                       if (!fn)
+                               break;
+                       retval = fn(&bprm, regs);
+                       if (retval >= 0) {
+                               iput(bprm.inode);
+                               current->did_exec = 1;
+                               return retval;
+                       }
+                       if (retval != -ENOEXEC)
+                               break;
                }
-               if (retval != -ENOEXEC)
+               if (retval != -ENOEXEC) {
                        break;
+#ifdef CONFIG_KERNELD
+               }else{
+                       char modname[20];
+                       sprintf(modname, "binfmt-%hd", *(short*)(&bprm.buf));
+                       request_module(modname);
+#endif
+               }
        }
 exec_error2:
        iput(bprm.inode);
index 5daecf04ee585dff4d81c524a0d28932c93d9658..67fa62dc2c94539e3f113cb1c068c40beb95f079 100644 (file)
@@ -16,6 +16,7 @@
  */
 struct file * first_file = NULL;
 int nr_files = 0;
+int max_files = NR_FILE;
 
 /*
  * Insert a new file structure at the head of the list of available ones.
@@ -116,7 +117,7 @@ struct file * get_empty_filp(void)
                                f->f_version = ++event;
                                return f;
                        }
-       } while (nr_files < NR_FILE && grow_files());
+       } while (nr_files < max_files && grow_files());
 
        return NULL;
 }
index 2407fc2977623816ff00d8819eec33185c4556e4..f6117d9fef8c69a90334725c9f9ef4bec2eb6c27 100644 (file)
@@ -19,7 +19,9 @@ static struct inode_hash_entry {
 
 static struct inode * first_inode;
 static struct wait_queue * inode_wait = NULL;
-static int nr_inodes = 0, nr_free_inodes = 0;
+/* Keep these next two contiguous in memory for sysctl.c */
+int nr_inodes = 0, nr_free_inodes = 0;
+int max_inodes = NR_INODE;
 
 static inline int const hashfn(kdev_t dev, unsigned int i)
 {
@@ -455,7 +457,7 @@ struct inode * get_empty_inode(void)
        unsigned long badness = 1000;
        int i;
 
-       if (nr_inodes < NR_INODE && nr_free_inodes < (nr_inodes >> 1))
+       if (nr_inodes < max_inodes && nr_free_inodes < (nr_inodes >> 1))
                grow_inodes();
 repeat:
        inode = first_inode;
@@ -471,7 +473,7 @@ repeat:
                }
        }
        if (badness)
-               if (nr_inodes < NR_INODE) {
+               if (nr_inodes < max_inodes) {
                        if (grow_inodes() == 0)
                                goto repeat;
                }
index 77d6a5c8163a58a85b0be4edbc8f7bd019a9fd03..afa784f2b88fc6dbc3611b17e5709c94abe11eda 100644 (file)
@@ -81,9 +81,7 @@ static int parse_options(char *options,char *check,char *conversion,uid_t *uid,
 
        *check = 'n';
        *conversion = 'b';
-       /* Please leave dotsOK as 1, and contact Albert Cahalan if */
-       /* it causes any problems for you. <albert@ccs.neu.edu>    */
-       *dotsOK =1;  /* see note above, and report problems */
+       *dotsOK = 0;
        *uid = current->uid;
        *gid = current->gid;
        *umask = current->fs->umask;
@@ -108,6 +106,12 @@ static int parse_options(char *options,char *check,char *conversion,uid_t *uid,
                        else if (!strcmp(value,"auto")) *conversion = 'a';
                        else return 0;
                }
+               else if (!strcmp(this_char,"dots")) {
+                 *dotsOK = 1;
+               }
+               else if (!strcmp(this_char,"nodots")) {
+                 *dotsOK = 0;
+               }
                else if (!strcmp(this_char,"dotsOK") && value) {
                        if (!strcmp(value,"yes")) *dotsOK = 1;
                        else if (!strcmp(value,"no")) *dotsOK = 0;
index fcfa38731f6aeded7da4d8969d783b48245ffc94..e5d5d6f60246799ebafefedbcd4538d093ae4a2b 100644 (file)
@@ -675,7 +675,7 @@ static struct file nfs_file;                /* File descriptor containing socket */
 static struct inode nfs_inode;         /* Inode containing socket */
 static int *rpc_packet = NULL;         /* RPC packet */
 
-extern asmlinkage int sys_socketcall(int call, unsigned long *args);
+extern asmlinkage int sys_socket(int family, int type, int protocol);
 
 
 /*
@@ -684,10 +684,9 @@ extern asmlinkage int sys_socketcall(int call, unsigned long *args);
 static int root_nfs_open(void)
 {
        struct file *filp;
-       unsigned long opt[] = { AF_INET, SOCK_DGRAM, IPPROTO_UDP };
 
        /* Open the socket */
-       if ((nfs_data.fd = sys_socketcall(SYS_SOCKET, opt)) < 0) {
+       if ((nfs_data.fd = sys_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
                printk(KERN_ERR "NFS: Cannot open UDP socket\n");
                return -1;
        }
index 11fc4490740daab85a39c69d238aefd6ba5c84d9..f61dd922ee34fed3fd49eaedc5816011d92eb2ab 100644 (file)
@@ -81,13 +81,13 @@ nfs_rpc_call(struct nfs_server *server, int *start, int *end, int size)
                if (result == -ETIMEDOUT) {
                        if (server->flags & NFS_MOUNT_SOFT) {
                                printk("NFS server %s not responding, "
-                                       "still trying.\n", server->hostname);
+                                       "timed out.\n", server->hostname);
                                result = -EIO;
                                break;
                        }
                        if (!major_timeout_seen) {
                                printk("NFS server %s not responding, "
-                                       "timed out.\n", server->hostname);
+                                       "still trying.\n", server->hostname);
                                major_timeout_seen = 1;
                        }
                        if ((timeout.init_timeout <<= 1) >= maxtimeo)
index 858dc19c7f2db2d2c75d040b6e9d4a25c3f9d9bd..8a137ddedade0cd75a9374cf94819637b3da40a5 100644 (file)
@@ -45,6 +45,7 @@
 #ifdef CONFIG_APM
 #include <linux/apm_bios.h>
 #endif
+#include <linux/swap.h>
 
 #include <asm/segment.h>
 #include <asm/pgtable.h>
index e4872deb9724e23863d4cbe972636d340465abd8..0c1d7f788966bd187c58d032b31f7343a96303ef 100644 (file)
@@ -16,6 +16,7 @@
 #ifdef CONFIG_APM
 #include <linux/apm_bios.h>
 #endif
+#include <asm/bitops.h>
 
 /*
  * Offset of the first process in the /proc root directory..
@@ -25,6 +26,8 @@
 static int proc_root_readdir(struct inode *, struct file *, void *, filldir_t);
 static int proc_root_lookup(struct inode *,const char *,int,struct inode **);
 
+static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8] = {0};
+
 /*
  * These are the generic /proc directory operations. They
  * use the in-memory "struct proc_dir_entry" tree to parse
@@ -49,7 +52,7 @@ static struct file_operations proc_dir_operations = {
 /*
  * proc directories can do almost nothing..
  */
-static struct inode_operations proc_dir_inode_operations = {
+struct inode_operations proc_dir_inode_operations = {
        &proc_dir_operations,   /* default net directory file-ops */
        NULL,                   /* create */
        proc_lookup,            /* lookup */
@@ -139,6 +142,15 @@ struct proc_dir_entry proc_scsi = {
        NULL, &proc_root, NULL
 };
 
+struct proc_dir_entry proc_sys_root = {
+       PROC_SYS, 3, "sys",                     /* inode, name */
+       S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,   /* mode, nlink, uid, gid */
+       0, &proc_dir_inode_operations,          /* size, ops */
+       NULL, NULL,                             /* get_info, fill_inode */
+       NULL,                                   /* next */
+       NULL, NULL                              /* parent, subdir */
+};
+
 int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
 {
        dp->next = dir->subdir;
@@ -159,6 +171,10 @@ int proc_unregister(struct proc_dir_entry * dir, int ino)
                        dp->next = NULL;
                        if (S_ISDIR(dp->mode))
                                dir->nlink--;
+                       if (ino >= PROC_DYNAMIC_FIRST &&
+                           ino < PROC_DYNAMIC_FIRST+PROC_NDYNAMIC)
+                               clear_bit(ino-PROC_DYNAMIC_FIRST, 
+                                         (void *) proc_alloc_map);
                        return 0;
                }
                p = &dp->next;
@@ -166,6 +182,30 @@ int proc_unregister(struct proc_dir_entry * dir, int ino)
        return -EINVAL;
 }      
 
+static int make_inode_number(void)
+{
+       int i = find_first_zero_bit((void *) proc_alloc_map, PROC_NDYNAMIC);
+       if (i<0 || i>=PROC_NDYNAMIC) 
+               return -1;
+       set_bit(i, (void *) proc_alloc_map);
+       return PROC_DYNAMIC_FIRST + i;
+}
+
+int proc_register_dynamic(struct proc_dir_entry * dir,
+                         struct proc_dir_entry * dp)
+{
+       int i = make_inode_number();
+       if (i < 0)
+               return -EAGAIN;
+       dp->low_ino = i;
+       dp->next = dir->subdir;
+       dp->parent = dir;
+       dir->subdir = dp;
+       if (S_ISDIR(dp->mode))
+               dir->nlink++;
+       return 0;
+}
+
 /*
  * /proc/self:
  */
@@ -262,6 +302,8 @@ void proc_root_init(void)
        proc_register(&proc_root, &proc_scsi);
 #endif
 
+       proc_register(&proc_root, &proc_sys_root);
+
 #ifdef CONFIG_DEBUG_MALLOC
        proc_register(&proc_root, &(struct proc_dir_entry) {
                PROC_MALLOC, 6, "malloc",
index 301adc5819197deb9d9c8d43bca6b4eac1e536e4..15c584e97219c84ef873c01ba57bd973f263123e 100644 (file)
@@ -9,6 +9,8 @@
  *                                   - umount systemcall
  *
  * GK 2/5/95  -  Changed to support mounting the root fs via NFS
+ *
+ *  Added kerneld support: Jacques Gelinas and Bjorn Ekwall
  */
 
 #include <stdarg.h>
 #include <asm/system.h>
 #include <asm/segment.h>
 #include <asm/bitops.h>
-extern struct file_operations * get_blkfops(unsigned int);
-extern struct file_operations * get_chrfops(unsigned int);
 
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
 extern void wait_for_keypress(void);
+extern struct file_operations * get_blkfops(unsigned int major);
+extern void blkdev_release (struct inode *);
 
 extern int root_mountflags;
 
@@ -278,11 +283,15 @@ struct file_system_type *get_fs_type(const char *name)
        
        if (!name)
                return fs;
-       while (fs) {
-               if (!strcmp(name,fs->name))
-                       break;
-               fs = fs->next;
+       for (fs = file_systems; fs && strcmp(fs->name, name); fs = fs->next)
+               ;
+#ifdef CONFIG_KERNELD
+       if (!fs && (request_module(name) == 0)) {
+               for (fs = file_systems; fs && strcmp(fs->name, name); fs = fs->next)
+                       ;
        }
+#endif
+
        return fs;
 }
 
@@ -525,7 +534,6 @@ asmlinkage int sys_umount(char * name)
        kdev_t dev;
        int retval;
        struct inode dummy_inode;
-       struct file_operations * fops;
 
        if (!suser())
                return -EPERM;
@@ -557,9 +565,7 @@ asmlinkage int sys_umount(char * name)
                return -ENXIO;
        }
        if (!(retval = do_umount(dev)) && dev != ROOT_DEV) {
-               fops = get_blkfops(MAJOR(dev));
-               if (fops && fops->release)
-                       fops->release(inode,NULL);
+               blkdev_release (inode);
                if (MAJOR(dev) == UNNAMED_MAJOR)
                        put_unnamed_dev(dev);
        }
index 4c6b96097e1df03b4384e7207bd89db70952feda..27b2e7925a9b85d1fdc98bac3a5cc0c6877e3ed1 100644 (file)
@@ -36,26 +36,28 @@ __ntohl(unsigned long int x)
 {
        unsigned long int res, t1, t2;
 
-       __asm__
-           ("bis       %3,%3,%0        # %0 is result; %0=aabbccdd
-             extlh     %0,5,%1         # %1 = dd000000
-             zap       %0,0xfd,%2      # %2 = 0000cc00
-             sll       %2,5,%2         # %2 = 00198000
-             s8addl    %2,%1,%1        # %1 = ddcc0000
-             zap       %0,0xfb,%2      # %2 = 00bb0000
-             srl       %2,8,%2         # %2 = 0000bb00
-             extbl     %0,3,%0         # %0 = 000000aa
-             or        %1,%0,%0        # %0 = ddcc00aa
-             or        %2,%0,%0        # %0 = ddccbbaa"
-            : "r="(res), "r="(t1), "r="(t2) : "r"(x));
+       __asm__(
+       "# bswap input: %0 (aabbccdd)
+       # output: %0, used %1 %2
+       extlh   %0,5,%1         # %1 = dd000000
+       zap     %0,0xfd,%2      # %2 = 0000cc00
+       sll     %2,5,%2         # %2 = 00198000
+       s8addq  %2,%1,%1        # %1 = ddcc0000
+       zap     %0,0xfb,%2      # %2 = 00bb0000
+       srl     %2,8,%2         # %2 = 0000bb00
+       extbl   %0,3,%0         # %0 = 000000aa
+       or      %1,%0,%0        # %0 = ddcc00aa
+       or      %2,%0,%0        # %0 = ddccbbaa"
+       : "r="(res), "r="(t1), "r="(t2)
+       : "0" (x & 0xffffffffUL));
        return res;
 }
 
 #define __constant_ntohl(x) \
-((unsigned int)((((unsigned int)(x) & 0x000000ffU) << 24) | \
-               (((unsigned int)(x) & 0x0000ff00U) <<  8) | \
-               (((unsigned int)(x) & 0x00ff0000U) >>  8) | \
-               (((unsigned int)(x) & 0xff000000U) >> 24)))
+   ((unsigned long int)((((x) & 0x000000ffUL) << 24) | \
+                       (((x) & 0x0000ff00UL) <<  8) | \
+                       (((x) & 0x00ff0000UL) >>  8) | \
+                       (((x) & 0xff000000UL) >> 24)))
 
 extern __inline__ unsigned short int
 __ntohs(unsigned short int x)
index 2c5a0d41d44bb8c28c38ac521b9ac15577d2c031..e2c230a425a16643c91de96184f3a8bc6e2369a3 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef __LINUX_SMPLOCK_H
-#define __LINUX_SMPLOCK_H
+#ifndef __I386_SMPLOCK_H
+#define __I386_SMPLOCK_H
 
 #ifdef __SMP__
 
index ca21fb0affee1df63f391258af069b9abe2a8aa7..b8fe58ddaade5d4fb484bea86d15bf3f14022454 100644 (file)
 #define __NR_writev            146
 #define __NR_getsid            147
 #define __NR_fdatasync         148
+#define __NR__sysctl           149
 
 #define __NR_mlock             150
 #define __NR_munlock           151
index 4adab0456140d16da33e367e6166873bd4ec15e5..5a7a04442b0873d7895469f83f4744e3a1c71546 100644 (file)
  * Some programs (notably those using select()) may have to be 
  * recompiled to take full advantage of the new limits..
  */
+
+/* Fixed constants first: */
 #undef NR_OPEN
 #define NR_OPEN 256
 
-#define NR_INODE 2048  /* this should be bigger than NR_FILE */
-#define NR_FILE 1024   /* this can well be larger on a larger system */
-#define NR_SUPER 32
+#define NR_SUPER 64
 #define NR_IHASH 131
 #define BLOCK_SIZE 1024
 #define BLOCK_SIZE_BITS 10
 
+/* And dynamically-tunable limits and defaults: */
+extern int max_inodes, nr_inodes;
+extern int max_files, nr_files;
+#define NR_INODE 2048  /* this should be bigger than NR_FILE */
+#define NR_FILE 1024   /* this can well be larger on a larger system */
+
 #define MAY_EXEC 1
 #define MAY_WRITE 2
 #define MAY_READ 4
@@ -483,10 +489,10 @@ extern struct file *first_file;
 extern int nr_files;
 extern struct super_block super_blocks[NR_SUPER];
 
-extern int shrink_buffers(unsigned int priority, unsigned long limit);
 extern void refile_buffer(struct buffer_head * buf);
 extern void set_writetime(struct buffer_head * buf, int flag);
 extern void refill_freelist(int size);
+extern int try_to_free_buffer(struct buffer_head*, struct buffer_head**, int);
 
 extern struct buffer_head ** buffer_pages;
 extern int nr_buffers;
diff --git a/include/linux/kerneld.h b/include/linux/kerneld.h
new file mode 100644 (file)
index 0000000..c6769c1
--- /dev/null
@@ -0,0 +1,110 @@
+#ifndef _LINUX_KERNELD_H
+#define _LINUX_KERNELD_H
+
+#define KERNELD_SYSTEM 1
+#define KERNELD_REQUEST_MODULE 2 /* "insmod" */
+#define KERNELD_RELEASE_MODULE 3 /* "rmmod" */
+#define KERNELD_DELAYED_RELEASE_MODULE 4 /* "rmmod" */
+#define KERNELD_CANCEL_RELEASE_MODULE 5 /* "rmmod" */
+#define KERNELD_REQUEST_ROUTE 6 /* from net/ipv4/route.c */
+#define KERNELD_BLANKER 7 /* from drivers/char/console.c */
+
+#define IPC_KERNELD 00040000   /* use the kerneld message channel */
+#define KERNELD_MAXCMD 0x7ffeffff
+#define KERNELD_MINSEQ 0x7fff0000 /* "commands" legal up to 0x7ffeffff */
+#define KERNELD_WAIT 0x80000000
+#define KERNELD_NOWAIT 0
+
+struct kerneld_msg {
+       long mtype;
+       long id;
+#ifdef __KERNEL__
+       char *text;
+#else
+       char text[1];
+#endif /* __KERNEL__ */
+};
+
+#ifdef __KERNEL__
+extern int kerneld_send(int msgtype, int ret_size, int msgsz,
+               const char *text, const char *ret_val);
+
+/*
+ * Request that a module should be loaded.
+ * Wait for the exit status from insmod/modprobe.
+ * If it fails, it fails... at least we tried...
+ */
+static inline int request_module(const char *name)
+{
+       return kerneld_send(KERNELD_REQUEST_MODULE,
+                       0 | KERNELD_WAIT,
+                       strlen(name), name, NULL);
+}
+
+/*
+ * Request the removal of a module, maybe don't wait for it.
+ * It doesn't matter if the removal fails, now does it?
+ */
+static inline int release_module(const char *name, int waitflag)
+{
+       return kerneld_send(KERNELD_RELEASE_MODULE,
+                       0 | (waitflag?KERNELD_WAIT:KERNELD_NOWAIT),
+                       strlen(name), name, NULL);
+}
+
+/*
+ * Request a delayed removal of a module, but don't wait for it.
+ * The delay is done by kerneld (default: 60 seconds)
+ */
+static inline int delayed_release_module(const char *name)
+{
+       return kerneld_send(KERNELD_DELAYED_RELEASE_MODULE,
+                       0 | KERNELD_NOWAIT,
+                       strlen(name), name, NULL);
+}
+
+/*
+ * Attempt to cancel a previous request for removal of a module,
+ * but don't wait for it.
+ * This call can be made if the kernel wants to prevent a delayed
+ * unloading of a module.
+ */
+static inline int cancel_release_module(const char *name)
+{
+       return kerneld_send(KERNELD_CANCEL_RELEASE_MODULE,
+                       0 | KERNELD_NOWAIT,
+                       strlen(name), name, NULL);
+}
+
+/*
+ * Perform an "inverted" system call, maybe return the exit status
+ */
+static inline int ksystem(const char *cmd, int waitflag)
+{
+       return kerneld_send(KERNELD_SYSTEM,
+                       0 | (waitflag?KERNELD_WAIT:KERNELD_NOWAIT),
+                       strlen(cmd), cmd, NULL);
+}
+
+/*
+ * Try to create a route, possibly by opening a ppp-connection
+ */
+static inline int kerneld_route(const char *ip_route)
+{
+       return kerneld_send(KERNELD_REQUEST_ROUTE,
+                       0 | KERNELD_WAIT,
+                       strlen(ip_route), ip_route, NULL);
+}
+
+/*
+ * Handle an external screen blanker
+ */
+static inline int kerneld_blanker(int on_off) /* 0 => "off", else "on" */
+{
+       return kerneld_send(KERNELD_BLANKER,
+                       0 | (on_off?KERNELD_NOWAIT:KERNELD_WAIT),
+                       strlen(on_off?"on":"off"), on_off?"on":"off", NULL);
+}
+
+#endif /* __KERNEL__ */
+#endif
diff --git a/include/linux/lists.h b/include/linux/lists.h
new file mode 100644 (file)
index 0000000..04f905a
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * lists.h:  Simple list macros for Linux
+ */
+
+#define DLNODE(ptype)                                          \
+       struct {                                                \
+               ptype * dl_prev;                                \
+               ptype * dl_next;                                \
+       }
+
+#define DNODE_SINGLE(node) {(node),(node)}
+#define DNODE_NULL {0,0}
+
+#define DLIST_INIT(listnam)                                    \
+       (listnam).dl_prev = &(listnam);                         \
+       (listnam).dl_last = &(listnam);
+
+#define DLIST_NEXT(listnam)    listnam.dl_next
+#define DLIST_PREV(listnam)    listnam.dl_prev
+
+#define DLIST_INSERT_AFTER(node, new, listnam) do {            \
+       (new)->listnam.dl_prev = (node);                        \
+       (new)->listnam.dl_next = (node)->listnam.dl_next;       \
+       (node)->listnam.dl_next->listnam.dl_prev = (new);       \
+       (node)->listnam.dl_next = (new);                        \
+       } while (0)
+
+#define DLIST_INSERT_BEFORE(node, new, listnam)        do {            \
+       (new)->listnam.dl_next = (node);                        \
+       (new)->listnam.dl_prev = (node)->listnam.dl_prev;       \
+       (node)->listnam.dl_prev->listnam.dl_next = (new);       \
+       (node)->listnam.dl_prev = (new);                        \
+       } while (0)
+
+#define DLIST_DELETE(node, listnam)    do {            \
+       node->listnam.dl_prev->listnam.dl_next =                \
+               node->listnam.dl_next;                          \
+       node->listnam.dl_next->listnam.dl_prev =                \
+               node->listnam.dl_prev;                          \
+       } while (0)
index eda8916896761195e8093c10499c87908accb63d..919dc83db4da9652275856bbfd172eb611bcb76a 100644 (file)
@@ -111,7 +111,8 @@ typedef struct page {
                 age:8,
                 uptodate:1,
                 error:1,
-                unused:5,
+                referenced:1,
+                unused:4,
                 reserved:1;
        unsigned long offset;
        struct inode *inode;
@@ -127,10 +128,6 @@ extern mem_map_t * mem_map;
  * Free area management
  */
 
-extern int nr_swap_pages;
-extern int nr_free_pages;
-extern int min_free_pages;
-
 #define NR_MEM_LISTS 6
 
 struct mem_list {
@@ -197,15 +194,6 @@ extern void * vremap(unsigned long offset, unsigned long size);
 extern void vfree(void * addr);
 extern int vread(char *buf, char *addr, int count);
 
-/* swap.c */
-
-extern void swap_free(unsigned long);
-extern void swap_duplicate(unsigned long);
-extern void swap_in(struct task_struct *, struct vm_area_struct *, pte_t *, unsigned long id, int write_access);
-
-extern void si_swapinfo(struct sysinfo * val);
-extern void rw_swap_page(int rw, unsigned long nr, char * buf);
-
 /* mmap.c */
 extern unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
        unsigned long prot, unsigned long flags, unsigned long off);
@@ -221,11 +209,6 @@ extern unsigned long get_unmapped_area(unsigned long, unsigned long);
 extern unsigned long page_unuse(unsigned long);
 extern int shrink_mmap(int, unsigned long);
 
-#define read_swap_page(nr,buf) \
-       rw_swap_page(READ,(nr),(buf))
-#define write_swap_page(nr,buf) \
-       rw_swap_page(WRITE,(nr),(buf))
-
 #define GFP_BUFFER     0x00
 #define GFP_ATOMIC     0x01
 #define GFP_USER       0x02
@@ -291,69 +274,6 @@ static inline struct vm_area_struct * find_vma_intersection (struct task_struct
        return vma;
 }
 
-/*
- * vm_ops not present page codes for shared memory.
- *
- * Will go away eventually..
- */
-#define SHM_SWP_TYPE 0x40
-
-extern void shm_no_page (ulong *);
-
-/*
- * swap cache stuff (in swap.c)
- */
-#define SWAP_CACHE_INFO
-
-extern unsigned long * swap_cache;
-
-#ifdef SWAP_CACHE_INFO
-extern unsigned long swap_cache_add_total;
-extern unsigned long swap_cache_add_success;
-extern unsigned long swap_cache_del_total;
-extern unsigned long swap_cache_del_success;
-extern unsigned long swap_cache_find_total;
-extern unsigned long swap_cache_find_success;
-#endif
-
-extern inline unsigned long in_swap_cache(unsigned long addr)
-{
-       return swap_cache[MAP_NR(addr)]; 
-}
-
-extern inline long find_in_swap_cache (unsigned long addr)
-{
-       unsigned long entry;
-
-#ifdef SWAP_CACHE_INFO
-       swap_cache_find_total++;
-#endif
-       entry = xchg(swap_cache + MAP_NR(addr), 0);
-#ifdef SWAP_CACHE_INFO
-       if (entry)
-               swap_cache_find_success++;
-#endif 
-       return entry;
-}
-
-extern inline int delete_from_swap_cache(unsigned long addr)
-{
-       unsigned long entry;
-       
-#ifdef SWAP_CACHE_INFO
-       swap_cache_del_total++;
-#endif 
-       entry= xchg(swap_cache + MAP_NR(addr), 0);
-       if (entry)  {
-#ifdef SWAP_CACHE_INFO
-               swap_cache_del_success++;
-#endif
-               swap_free(entry);
-               return 1;
-       }
-       return 0;
-}
-
 #endif /* __KERNEL__ */
 
 #endif
index 0bc253c74ed3c4e7f9e2e9de5a5c64122204f11f..a91ad19b3cdfae1224aecb4958204b897e4a911c 100644 (file)
@@ -26,6 +26,9 @@
 /* maximum length of module name */
 #define MOD_MAX_NAME 64
 
+/* magic marker for modules inserted from kerneld, to be auto-reaped */
+#define MOD_AUTOCLEAN 0x40000000 /* big enough, but no sign problems... */
+
 /* maximum length of symbol name */
 #define SYM_MAX_NAME 60
 
@@ -90,7 +93,7 @@ extern int register_symtab(struct symbol_table *);
 extern long mod_use_count_;
 #define MOD_INC_USE_COUNT      mod_use_count_++
 #define MOD_DEC_USE_COUNT      mod_use_count_--
-#define MOD_IN_USE            (mod_use_count_ != 0)
+#define MOD_IN_USE            ((mod_use_count_ & ~MOD_AUTOCLEAN) != 0)
 
 #ifndef __NO_VERSION__
 #include <linux/version.h>
index ee416dd2c954953d36dbc50cef7915639eb9baaf..e70875f23540fd3e4a8f04e0ee1d069bd99573f3 100644 (file)
@@ -39,16 +39,6 @@ static inline unsigned long _page_hashfn(struct inode * inode, unsigned long off
 
 #define page_hash(inode,offset) page_hash_table[_page_hashfn(inode,offset)]
 
-static inline int page_age_update(struct page * page, int accessed)
-{
-       unsigned int age = page->age;
-       if (accessed)
-               age |= PAGE_AGE_VALUE << 1;
-       age >>= 1;
-       page->age = age;
-       return age > (PAGE_AGE_VALUE >> 1);
-}
-
 static inline struct page * find_page(struct inode * inode, unsigned long offset)
 {
        struct page *page;
@@ -58,7 +48,7 @@ static inline struct page * find_page(struct inode * inode, unsigned long offset
                        continue;
                if (page->offset != offset)
                        continue;
-               page->age = PAGE_AGE_VALUE | (page->age >> 1);
+               page->referenced = 1;
                page->count++;
                break;
        }
@@ -84,6 +74,7 @@ static inline void add_page_to_hash_queue(struct inode * inode, struct page * pa
        struct page **p = &page_hash(inode,page->offset);
 
        page_cache_size++;
+       page->referenced = 1;
        page->age = PAGE_AGE_VALUE;
        page->prev_hash = NULL;
        if ((page->next_hash = *p) != NULL)
index 9483b206d307968711f66ff00cba459b3d101c39..58cf6ea5a6b254ffa9ae81a3d34f18d337fe7c84 100644 (file)
@@ -36,7 +36,8 @@ enum root_directory_inos {
        PROC_IOPORTS,
        PROC_APM,
        PROC_PROFILE, /* whether enabled or not */
-       PROC_CMDLINE
+       PROC_CMDLINE,
+       PROC_SYS
 };
 
 enum pid_directory_inos {
@@ -123,6 +124,11 @@ enum scsi_directory_inos {
        PROC_SCSI_LAST = (PROC_SCSI_FILE + 16) /* won't ever see more than */
 };                                             /* 16 HBAs in one machine   */
 
+/* Finally, the dynamically allocatable proc entries are reserved: */
+
+#define PROC_DYNAMIC_FIRST 4096
+#define PROC_NDYNAMIC      4096
+
 #define PROC_SUPER_MAGIC 0x9fa0
 
 /*
@@ -153,11 +159,13 @@ struct proc_dir_entry {
        int (*get_info)(char *, char **, off_t, int, int);
        void (*fill_inode)(struct inode *);
        struct proc_dir_entry *next, *parent, *subdir;
+       void *data;
 };
 
 extern struct proc_dir_entry proc_root;
 extern struct proc_dir_entry proc_net;
 extern struct proc_dir_entry proc_scsi;
+extern struct proc_dir_entry proc_sys;
 extern struct proc_dir_entry proc_pid;
 extern struct proc_dir_entry proc_pid_fd;
 
@@ -168,6 +176,8 @@ extern void proc_base_init(void);
 extern void proc_net_init(void);
 
 extern int proc_register(struct proc_dir_entry *, struct proc_dir_entry *);
+extern int proc_register_dynamic(struct proc_dir_entry *, 
+                                struct proc_dir_entry *);
 extern int proc_unregister(struct proc_dir_entry *, int);
 
 static inline int proc_net_register(struct proc_dir_entry * x)
@@ -229,10 +239,12 @@ extern int proc_match(int, const char *, struct proc_dir_entry *);
 extern int proc_readdir(struct inode *, struct file *, void *, filldir_t);
 extern int proc_lookup(struct inode *, const char *, int, struct inode **);
 
+extern struct inode_operations proc_dir_inode_operations;
 extern struct inode_operations proc_net_inode_operations;
 extern struct inode_operations proc_netdir_inode_operations;
 extern struct inode_operations proc_scsi_inode_operations;
 extern struct inode_operations proc_mem_inode_operations;
+extern struct inode_operations proc_sys_inode_operations;
 extern struct inode_operations proc_array_inode_operations;
 extern struct inode_operations proc_arraylong_inode_operations;
 extern struct inode_operations proc_kcore_inode_operations;
index 0a40f91588c3c8e43e5090aa01fe7d38988c207d..aa8db50d70d4e399a949be56fa9c9f1e312feb7a 100644 (file)
@@ -5,4 +5,134 @@
 #define SWAP_FLAG_PRIO_MASK    0x7fff
 #define SWAP_FLAG_PRIO_SHIFT   0
 
+#define MAX_SWAPFILES 8
+
+#ifdef __KERNEL__
+
+#define SWP_USED       1
+#define SWP_WRITEOK    3
+
+struct swap_info_struct {
+       unsigned int flags;
+       kdev_t swap_device;
+       struct inode * swap_file;
+       unsigned char * swap_map;
+       unsigned char * swap_lockmap;
+       int lowest_bit;
+       int highest_bit;
+       int prio;                       /* swap priority */
+       int pages;
+       unsigned long max;
+       int next;                       /* next entry on swap list */
+};
+
+extern int nr_swap_pages;
+extern int nr_free_pages;
+extern int min_free_pages;
+extern int free_pages_low;
+extern int free_pages_high;
+
+/* Incomplete types for prototype declarations: */
+struct task_struct;
+struct vm_area_struct;
+struct sysinfo;
+
+/* linux/ipc/shm.c */
+extern int shm_swap (int, unsigned long);
+
+/* linux/mm/swap_clock.c */
+extern int try_to_free_page(int, unsigned long);
+
+/* linux/mm/swap_io.c */
+extern void rw_swap_page(int, unsigned long, char *);
+#define read_swap_page(nr,buf) \
+       rw_swap_page(READ,(nr),(buf))
+#define write_swap_page(nr,buf) \
+       rw_swap_page(WRITE,(nr),(buf))
+
+/* linux/mm/swap_mman.c */
+extern void swap_in(struct task_struct *, struct vm_area_struct *,
+                   pte_t *, unsigned long, int);
+
+
+/* linux/mm/swap_state.c */
+extern void show_swap_cache_info(void);
+extern int add_to_swap_cache(unsigned long, unsigned long);
+extern unsigned long init_swap_cache(unsigned long, unsigned long);
+extern void swap_duplicate(unsigned long);
+
+/* linux/mm/swapfile.c */
+extern int nr_swapfiles;
+extern struct swap_info_struct swap_info[];
+void si_swapinfo(struct sysinfo *);
+unsigned long get_swap_page(void);
+extern void swap_free(unsigned long);
+
+/*
+ * vm_ops not present page codes for shared memory.
+ *
+ * Will go away eventually..
+ */
+#define SHM_SWP_TYPE 0x40
+
+extern void shm_no_page (ulong *);
+
+/*
+ * swap cache stuff (in linux/mm/swap_state.c)
+ */
+
+#define SWAP_CACHE_INFO
+
+extern unsigned long * swap_cache;
+
+#ifdef SWAP_CACHE_INFO
+extern unsigned long swap_cache_add_total;
+extern unsigned long swap_cache_add_success;
+extern unsigned long swap_cache_del_total;
+extern unsigned long swap_cache_del_success;
+extern unsigned long swap_cache_find_total;
+extern unsigned long swap_cache_find_success;
+#endif
+
+extern inline unsigned long in_swap_cache(unsigned long addr)
+{
+       return swap_cache[MAP_NR(addr)]; 
+}
+
+extern inline long find_in_swap_cache (unsigned long addr)
+{
+       unsigned long entry;
+
+#ifdef SWAP_CACHE_INFO
+       swap_cache_find_total++;
+#endif
+       entry = xchg(swap_cache + MAP_NR(addr), 0);
+#ifdef SWAP_CACHE_INFO
+       if (entry)
+               swap_cache_find_success++;
+#endif 
+       return entry;
+}
+
+extern inline int delete_from_swap_cache(unsigned long addr)
+{
+       unsigned long entry;
+       
+#ifdef SWAP_CACHE_INFO
+       swap_cache_del_total++;
+#endif 
+       entry= xchg(swap_cache + MAP_NR(addr), 0);
+       if (entry)  {
+#ifdef SWAP_CACHE_INFO
+               swap_cache_del_success++;
+#endif
+               swap_free(entry);
+               return 1;
+       }
+       return 0;
+}
+
+
+#endif /* __KERNEL__*/
+
 #endif /* _LINUX_SWAP_H */
index 8d6f51bc5c3c3f9cdf4e69da8c05de016b8ed5b7..9dd64cec9e851928fa0d8bb42dae23bb8e61a3ea 100644 (file)
@@ -28,11 +28,20 @@ typedef struct swap_control_v5
        int     sc_nr_pages_to_free;
        enum RCL_POLICY sc_policy;
 } swap_control_v5;
-
 typedef struct swap_control_v5 swap_control_t;
-
 extern swap_control_t swap_control;
 
+typedef struct kswapd_control_v1
+{
+       int     maxpages;
+       int     pages_buff;
+       int     pages_shm;
+       int     pages_mmap;
+       int     pages_swap;
+} kswapd_control_v1;
+typedef kswapd_control_v1 kswapd_control_t;
+extern kswapd_control_t kswapd_ctl;
+
 #define SC_VERSION     1
 #define SC_MAX_VERSION 1
 
@@ -79,24 +88,20 @@ static inline int AGE_CLUSTER_SIZE(int resources)
                return n;
 }
 
-static inline void touch_page(unsigned long addr)
+static inline void touch_page(struct page *page)
 {
-       unsigned char age = mem_map[MAP_NR(addr)].age;
-       if (age < (MAX_PAGE_AGE - PAGE_ADVANCE))
-               age += PAGE_ADVANCE;
+       if (page->age < (MAX_PAGE_AGE - PAGE_ADVANCE))
+               page->age += PAGE_ADVANCE;
        else
-               age = MAX_PAGE_AGE;
-       mem_map[MAP_NR(addr)].age = age;
+               page->age = MAX_PAGE_AGE;
 }
 
-static inline void age_page(unsigned long addr)
+static inline void age_page(struct page *page)
 {
-       unsigned char age = mem_map[MAP_NR(addr)].age;
-       if (age > PAGE_DECLINE)
-               age -= PAGE_DECLINE;
+       if (page->age > PAGE_DECLINE)
+               page->age -= PAGE_DECLINE;
        else
-               age = 0;
-       mem_map[MAP_NR(addr)].age = age;
+               page->age = 0;
 }
 
 static inline int age_of(unsigned long addr)
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
new file mode 100644 (file)
index 0000000..b4c23df
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * sysctl.h: General linux system control interface
+ *
+ * Begun 24 March 1995, Stephen Tweedie
+ */
+
+#include <linux/lists.h>
+
+#ifndef _LINUX_SYSCTL_H
+#define _LINUX_SYSCTL_H
+
+#define CTL_MAXNAME 10
+
+struct __sysctl_args {
+       int *name;
+       int nlen;
+       void *oldval;
+       size_t *oldlenp;
+       void *newval;
+       size_t newlen;
+       unsigned long __unused[4];
+};
+
+/* Define sysctl names first */
+
+/* Top-level names: */
+
+/* For internal pattern-matching use only: */
+#ifdef __KERNEL__
+#define CTL_ANY                -1      /* Matches any name */
+#define CTL_NONE               0
+#endif
+
+#define CTL_KERN       1       /* General kernel info and control */
+#define CTL_VM         2       /* VM management */
+#define CTL_NET                3       /* Networking */
+#define CTL_PROC       4       /* Process info */
+#define CTL_FS         5       /* Filesystems */
+#define CTL_DEBUG      6       /* Debugging */
+#define CTL_DEV                7       /* Devices */
+#define CTL_MAXID      8
+
+/* CTL_KERN names: */
+#define KERN_OSTYPE    1       /* string: system version */
+#define KERN_OSRELEASE 2       /* string: system release */
+#define KERN_OSREV     3       /* int: system revision */
+#define KERN_VERSION   4       /* string: compile time info */
+#define KERN_SECUREMASK 5      /* struct: maximum rights mask */
+#define KERN_PROF      6       /* table: profiling information */
+#define KERN_NODENAME   7
+#define KERN_DOMAINNAME 8
+#define KERN_NRINODE   9
+#define KERN_MAXINODE  10
+#define KERN_NRFILE    11
+#define KERN_MAXFILE   12
+#define KERN_MAXID     13
+
+/* CTL_VM names: */
+#define VM_SWAPCTL     1       /* struct: Set vm swapping control */
+#define VM_KSWAPD      2       /* struct: control background pagout */
+#define VM_MAXID       3
+
+/* CTL_NET names: */
+
+/* CTL_PROC names: */
+
+/* CTL_FS names: */
+
+/* CTL_DEBUG names: */
+
+/* CTL_DEV names: */
+
+#ifdef __KERNEL__
+
+extern asmlinkage int sys_sysctl(struct __sysctl_args *);
+extern void init_sysctl(void);
+
+typedef struct ctl_table ctl_table;
+
+typedef int ctl_handler (ctl_table *table, int *name, int nlen,
+                        void *oldval, size_t *oldlenp,
+                        void *newval, size_t newlen, 
+                        void **context);
+
+typedef int proc_handler (ctl_table *ctl, int write, struct file * filp,
+                         void *buffer, size_t *lenp);
+
+extern int proc_dostring(ctl_table *, int, struct file *,
+                        void *, size_t *);
+extern int proc_dointvec(ctl_table *, int, struct file *,
+                        void *, size_t *);
+
+extern int do_sysctl (int *name, int nlen,
+                     void *oldval, size_t *oldlenp,
+                     void *newval, size_t newlen);
+
+extern int do_sysctl_strategy (ctl_table *table, 
+                              int *name, int nlen,
+                              void *oldval, size_t *oldlenp,
+                              void *newval, size_t newlen, void ** context);
+
+extern ctl_handler sysctl_string;
+
+extern int do_string (
+       void *oldval, size_t *oldlenp, void *newval, size_t newlen,
+       int rdwr, char *data, size_t max);
+extern int do_int (
+       void *oldval, size_t *oldlenp, void *newval, size_t newlen,
+       int rdwr, int *data);
+extern int do_struct (
+       void *oldval, size_t *oldlenp, void *newval, size_t newlen,
+       int rdwr, void *data, size_t len);
+
+
+/*
+ * Register a set of sysctl names by calling register_sysctl_table
+ * with an initialised array of ctl_table's.  An entry with zero
+ * ctl_name terminates the table.  table->de will be set up by the
+ * registration and need not be initialised in advance.
+ *
+ * sysctl names can be mirrored automatically under /proc/sys.  The
+ * procname supplied controls /proc naming.
+ *
+ * The table's mode will be honoured both for sys_sysctl(2) and
+ * proc-fs access.
+ *
+ * Leaf nodes in the sysctl tree will be represented by a single file
+ * under /proc; non-leaf nodes will be represented by directories.  A
+ * null procname disables /proc mirroring at this node.
+ * 
+ * sysctl(2) can automatically manage read and write requests through
+ * the sysctl table.  The data and maxlen fields of the ctl_table
+ * struct enable minimal validation of the values being written to be
+ * performed, and the mode field allows minimal authentication.
+ * 
+ * More sophisticated management can be enabled by the provision of a
+ * strategy routine with the table entry.  This will be called before
+ * any automatic read or write of the data is performed.
+ * 
+ * The strategy routine may return:
+ * <0: Error occurred (error is passed to user process)
+ * 0:  OK - proceed with automatic read or write.
+ * >0: OK - read or write has been done by the strategy routine, so 
+ *     return immediately.
+ * 
+ * There must be a proc_handler routine for any terminal nodes
+ * mirrored under /proc/sys (non-terminals are handled by a built-in
+ * directory handler).  Several default handlers are available to
+ * cover common cases.
+ */
+
+/* A sysctl table is an array of struct ctl_table: */
+struct ctl_table 
+{
+       int ctl_name;                   /* Binary ID */
+       const char *procname;           /* Text ID for /proc/sys, or zero */
+       void *data;
+       int maxlen;
+       mode_t mode;
+       ctl_table *child;
+       proc_handler *proc_handler;     /* Callback for text formatting */
+       ctl_handler *strategy;          /* Callback function for all r/w */
+       struct proc_dir_entry *de;      /* /proc control block */
+};
+
+/* struct ctl_table_header is used to maintain dynamic lists of
+   ctl_table trees. */
+struct ctl_table_header
+{
+       ctl_table *ctl_table;
+       DLNODE(struct ctl_table_header) ctl_entry;      
+};
+
+struct ctl_table_header * register_sysctl_table(ctl_table * table, 
+                                               int insert_at_head);
+void unregister_sysctl_table(struct ctl_table_header * table);
+
+#else /* __KERNEL__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_SYSCTL_H */
index f15cb68e260f709cebb3d007c5e982d232d35785..c54e8c5e675af285126d24015152a96d88110f7c 100644 (file)
@@ -14,6 +14,8 @@
  * BEEP_TIMER          console beep timer
  *
  * RS_TIMER            timer for the RS-232 ports
+ *
+ * SWAP_TIMER          timer for the background pageout daemon
  * 
  * HD_TIMER            harddisk timer
  *
@@ -40,6 +42,7 @@
 #define BLANK_TIMER    0
 #define BEEP_TIMER     1
 #define RS_TIMER       2
+#define SWAP_TIMER     3
 
 #define HD_TIMER       16
 #define FLOPPY_TIMER   17
index 48001b0dc8d7b8efe4fdd33e5d8da7df8f77baaa..637cc7c18006dc198ff432d83bbaf7a74d3fda51 100644 (file)
@@ -185,6 +185,9 @@ extern __inline__ void ip_rt_put(struct rtable * rt)
 ;
 #endif
 
+#ifdef CONFIG_KERNELD
+extern struct rtable * ip_rt_route(__u32 daddr, int local);
+#else
 extern __inline__ struct rtable * ip_rt_route(__u32 daddr, int local)
 #ifndef MODULE
 {
@@ -208,6 +211,7 @@ extern __inline__ struct rtable * ip_rt_route(__u32 daddr, int local)
 #else
 ;
 #endif
+#endif
 
 extern __inline__ struct rtable * ip_check_route(struct rtable ** rp,
                                                       __u32 daddr, int local)
index 8eba77f7fafa4d3c4e162202ea6bb00455aed3ac..5e483f7d3ff037b18ac6411e0eb275c3b22d8262 100644 (file)
@@ -44,6 +44,7 @@ extern int console_loglevel;
 
 static int init(void *);
 extern int bdflush(void *);
+extern int kswapd(void *);
 
 extern void init_IRQ(void);
 extern void init_modules(void);
@@ -51,6 +52,7 @@ extern long console_init(long, long);
 extern long kmalloc_init(long,long);
 extern void sock_init(void);
 extern long pci_init(long, long);
+extern void sysctl_init(void);
 
 extern void swap_setup(char *str, int *ints);
 extern void buff_setup(char *str, int *ints);
@@ -108,7 +110,7 @@ static void load_ramdisk(char *str, int *ints);
 static void prompt_ramdisk(char *str, int *ints);
 #endif CONFIG_BLK_DEV_RAM
 
-#ifdef CONFIG_SYSVIPC
+#if defined(CONFIG_SYSVIPC) || defined(CONFIG_KERNELD)
 extern void ipc_init(void);
 #endif
 
@@ -626,7 +628,7 @@ asmlinkage void start_kernel(void)
        mem_init(memory_start,memory_end);
        buffer_init();
        sock_init();
-#ifdef CONFIG_SYSVIPC
+#if defined(CONFIG_SYSVIPC) || defined(CONFIG_KERNELD)
        ipc_init();
 #endif
 #ifdef CONFIG_APM
@@ -640,6 +642,7 @@ asmlinkage void start_kernel(void)
 #ifdef __SMP__
        smp_init();
 #endif
+       sysctl_init();
        /* 
         *      We count on the initial thread going ok 
         *      Like idlers init is an unlocked kernel thread, which will
@@ -693,6 +696,8 @@ static int init(void * unused)
 
        /* Launch bdflush from here, instead of the old syscall way. */
        kernel_thread(bdflush, NULL, 0);
+       /* Start the background pageout daemon. */
+       kernel_thread(kswapd, NULL, 0);
 
        setup();
 
index 4e947582b4b2ce8b2c040687d7ff5d1face131df..4240520177d10861f64ecefba1de5850ac5fdfda 100644 (file)
 O_TARGET := ipc.o
 O_OBJS   := util.o
 
+ifdef CONFIG_KERNELD
+CONFIG_SYSVIPC=1
+endif
+
 ifdef CONFIG_SYSVIPC
 O_OBJS += msg.o sem.o shm.o
 endif
index 1ad5c612bc89864c2c6565d0e927260f288baac7..aad0973ecf45a59c9d4614aebcd576735a0e1b7a 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -1,13 +1,18 @@
 /*
  * linux/ipc/msg.c
  * Copyright (C) 1992 Krishna Balasubramanian 
+ *
+ * Kerneld extensions by Bjorn Ekwall <bj0rn@blox.se> in May 1995
+ *
  */
 
+#include <linux/autoconf.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/msg.h>
 #include <linux/stat.h>
 #include <linux/malloc.h>
+#include <linux/kerneld.h>
 
 #include <asm/segment.h>
 
@@ -24,6 +29,8 @@ static unsigned short msg_seq = 0;
 static int used_queues = 0;
 static int max_msqid = 0;
 static struct wait_queue *msg_lock = NULL;
+static int kerneld_msqid = -1;
+static int kerneld_pid;
 
 void msg_init (void)
 {
@@ -36,7 +43,7 @@ void msg_init (void)
        return;
 }
 
-asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
+static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
 {
        int id, err;
        struct msqid_ds *msq;
@@ -48,11 +55,19 @@ asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msg
                return -EINVAL;
        if (!msgp) 
                return -EFAULT;
-       err = verify_area (VERIFY_READ, msgp->mtext, msgsz);
-       if (err) 
-               return err;
-       if ((mtype = get_user (&msgp->mtype)) < 1)
-               return -EINVAL;
+       /*
+        * Calls from kernel level (IPC_KERNELD set)
+        * have the message somewhere in kernel space already!
+        */
+       if ((msgflg & IPC_KERNELD))
+               mtype = msgp->mtype;
+       else {
+               err = verify_area (VERIFY_READ, msgp->mtext, msgsz);
+               if (err) 
+                       return err;
+               if ((mtype = get_user (&msgp->mtype)) < 1)
+                       return -EINVAL;
+       }
        id = (unsigned int) msqid % MSGMNI;
        msq = msgque [id];
        if (msq == IPC_UNUSED || msq == IPC_NOID)
@@ -62,8 +77,14 @@ asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msg
  slept:
        if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) 
                return -EIDRM;
-       if (ipcperms(ipcp, S_IWUGO)) 
-               return -EACCES;
+       /*
+        * Non-root processes may send to kerneld! 
+        * i.e. no permission check if called from the kernel
+        * otoh we don't want user level non-root snoopers...
+        */
+       if ((msgflg & IPC_KERNELD) == 0)
+               if (ipcperms(ipcp, S_IWUGO)) 
+                       return -EACCES;
        
        if (msgsz + msq->msg_cbytes > msq->msg_qbytes) { 
                /* no space in queue */
@@ -71,6 +92,11 @@ asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msg
                        return -EAGAIN;
                if (current->signal & ~current->blocked)
                        return -EINTR;
+               if (intr_count) {
+                       /* Very unlikely, but better safe than sorry... */
+                       printk("Ouch, kerneld:msgsnd wants to sleep at interrupt!\n");
+                       return -EINTR;
+               }
                interruptible_sleep_on (&msq->wwait);
                goto slept;
        }
@@ -80,7 +106,24 @@ asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msg
        if (!msgh)
                return -ENOMEM;
        msgh->msg_spot = (char *) (msgh + 1);
-       memcpy_fromfs (msgh->msg_spot, msgp->mtext, msgsz); 
+
+       /*
+        * Calls from kernel level (IPC_KERNELD set)
+        * have the message somewhere in kernel space already!
+        */
+       if (msgflg & IPC_KERNELD) {
+               struct kerneld_msg *kdmp = (struct kerneld_msg *)msgp;
+
+               /*
+                * Note that the kernel supplies a pointer
+                * but the user-level kerneld uses a char array...
+                */
+               memcpy(msgh->msg_spot, (char *)(&(kdmp->id)), sizeof(long)); 
+               memcpy(msgh->msg_spot + sizeof(long), kdmp->text,
+                       msgsz - sizeof(long)); 
+       }
+       else
+               memcpy_fromfs (msgh->msg_spot, msgp->mtext, msgsz); 
        
        if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID
                || msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) {
@@ -108,8 +151,7 @@ asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msg
        return 0;
 }
 
-asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, 
-               int msgflg)
+static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg)
 {
        struct msqid_ds *msq;
        struct ipc_perm *ipcp;
@@ -121,9 +163,15 @@ asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long ms
                return -EINVAL;
        if (!msgp || !msgp->mtext)
            return -EFAULT;
-       err = verify_area (VERIFY_WRITE, msgp->mtext, msgsz);
-       if (err)
-               return err;
+       /*
+        * Calls from kernel level (IPC_KERNELD set)
+        * wants the message put in kernel space!
+        */
+       if ((msgflg & IPC_KERNELD) == 0) {
+               err = verify_area (VERIFY_WRITE, msgp->mtext, msgsz);
+               if (err)
+                       return err;
+       }
 
        id = (unsigned int) msqid % MSGMNI;
        msq = msgque [id];
@@ -140,6 +188,12 @@ asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long ms
        while (!nmsg) {
                if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
                        return -EIDRM;
+               if ((msgflg & IPC_KERNELD) == 0)
+                       /*
+                        * Non-root processes may recieve from kerneld! 
+                        * i.e. no permission check if called from the kernel
+                        * otoh we don't want user level non-root snoopers...
+                        */
                if (ipcperms (ipcp, S_IRUGO))
                        return -EACCES;
                if (msgtyp == 0) 
@@ -192,8 +246,29 @@ asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long ms
                        msq->msg_cbytes -= nmsg->msg_ts;
                        if (msq->wwait)
                                wake_up (&msq->wwait);
-                       put_user (nmsg->msg_type, &msgp->mtype);
-                       memcpy_tofs (msgp->mtext, nmsg->msg_spot, msgsz);
+                       /*
+                        * Calls from kernel level (IPC_KERNELD set)
+                        * wants the message copied to kernel space!
+                        */
+                       if (msgflg & IPC_KERNELD) {
+                               struct kerneld_msg *kdmp = (struct kerneld_msg *) msgp;
+
+                               memcpy((char *)(&(kdmp->id)),
+                                       nmsg->msg_spot,
+                                       sizeof(long)); 
+                               /*
+                                * Note that kdmp->text is a pointer
+                                * when called from kernel space!
+                                */
+                               if ((msgsz > sizeof(long)) && kdmp->text)
+                                       memcpy(kdmp->text,
+                                               nmsg->msg_spot + sizeof(long),
+                                               msgsz - sizeof(long)); 
+                       }
+                       else {
+                               put_user (nmsg->msg_type, &msgp->mtype);
+                               memcpy_tofs (msgp->mtext, nmsg->msg_spot, msgsz);
+                       }
                        kfree(nmsg);
                        return msgsz;
                } else {  /* did not find a message */
@@ -201,12 +276,29 @@ asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long ms
                                return -ENOMSG;
                        if (current->signal & ~current->blocked)
                                return -EINTR; 
+                       if (intr_count) {
+                               /* Won't happen... */
+                               printk("Ouch, kerneld:msgrcv wants to sleep at interrupt!\n");
+                               return -EINTR;
+                       }
                        interruptible_sleep_on (&msq->rwait);
                }
        } /* end while */
        return -1;
 }
 
+asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
+{
+       /* IPC_KERNELD is used as a marker for kernel calls */
+       return real_msgsnd(msqid, msgp, msgsz, msgflg & ~IPC_KERNELD);
+}
+
+asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz,
+       long msgtyp, int msgflg)
+{
+       /* IPC_KERNELD is used as a marker for kernel calls */
+       return real_msgrcv (msqid, msgp, msgsz, msgtyp, msgflg & ~IPC_KERNELD);
+}
 
 static int findkey (key_t key)
 {
@@ -272,6 +364,19 @@ asmlinkage int sys_msgget (key_t key, int msgflg)
        int id;
        struct msqid_ds *msq;
        
+       /*
+        * If the IPC_KERNELD flag is set, the key is forced to IPC_PRIVATE,
+        * and a designated kerneld message queue is created/refered to
+        */
+       if ((msgflg & IPC_KERNELD)) {
+               if (!suser())
+                       return -EPERM;
+               if ((kerneld_msqid == -1) && (kerneld_msqid =
+                               newque(IPC_PRIVATE, msgflg & S_IRWXU)) >= 0)
+                       kerneld_pid = current->pid;
+               return kerneld_msqid;
+       }
+       /* else it is a "normal" request */
        if (key == IPC_PRIVATE) 
                return newque(key, msgflg);
        if ((id = findkey (key)) == -1) { /* key not used */
@@ -433,9 +538,104 @@ asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
                if (!suser() && current->euid != ipcp->cuid && 
                    current->euid != ipcp->uid)
                        return -EPERM;
+               /*
+                * There is only one kerneld message queue,
+                * mark it as non-existant
+                */
+               if ((kerneld_msqid >= 0) && (msqid == kerneld_msqid))
+                       kerneld_pid = kerneld_msqid = -1;
                freeque (id); 
                return 0;
        default:
                return -EINVAL;
        }
 }
+
+/*
+ * We do perhaps need a "flush" for waiting processes,
+ * so that if they are terminated, a call from do_exit
+ * will minimize the possibility of orphaned recieved
+ * messages in the queue.  For now we just make sure
+ * that the queue is shut down whenever kerneld dies.
+ */
+void kerneld_exit(void)
+{
+        if ((current->pid == kerneld_pid) && (kerneld_msqid != -1))
+                sys_msgctl(kerneld_msqid, IPC_RMID, NULL);
+}
+
+/*
+ * Kerneld internal message format/syntax:
+ *
+ * The message type from the kernel to kerneld is used to specify _what_
+ * function we want kerneld to perform. 
+ *
+ * The "normal" message area is divided into a long, followed by a char array.
+ * The long is used to hold the sequence number of the request, which will
+ * be used as the return message type from kerneld back to the kernel.
+ * In the return message, the long will be used to store the exit status
+ * of the kerneld "job", or task.
+ * The character array is used to pass parameters to kerneld and (optional)
+ * return information from kerneld back to the kernel.
+ * It is the responsibility of kerneld and the kernel level caller
+ * to set usable sizes on the parameter/return value array, since
+ * that information is _not_ included in the message format
+ */
+
+/*
+ * The basic kernel level entry point to kerneld.
+ *     msgtype should correspond to a task type for (a) kerneld
+ *     ret_size is the size of the (optional) return _value,
+ *             OR-ed with KERNELD_WAIT if we want an answer
+ *     msgsize is the size (in bytes) of the message, not including
+ *             the long that is always sent first in a kerneld message
+ *     text is the parameter for the kerneld specific task
+ *     ret_val is NULL or the kernel address where an expected answer
+ *             from kerneld should be placed.
+ *
+ * See <linux/kerneld.h> for usage (inline convenience functions)
+ *
+ */
+int kerneld_send(int msgtype, int ret_size, int msgsz,
+               const char *text, const char *ret_val)
+{
+       int status = -ENOSYS;
+#ifdef CONFIG_KERNELD
+       static int id = KERNELD_MINSEQ;
+       struct kerneld_msg kmsp = { msgtype, 0, (char *)text };
+       int msgflg = S_IRUSR | S_IWUSR | IPC_KERNELD | MSG_NOERROR;
+
+       msgsz += sizeof(long);
+       if (ret_size & KERNELD_WAIT) {
+               if (++id <= 0)
+                       id = KERNELD_MINSEQ;
+               kmsp.id = id;
+       }
+
+       if (kerneld_msqid == -1)
+               return -ENODEV;
+
+       status = real_msgsnd(kerneld_msqid, (struct msgbuf *)&kmsp, msgsz, msgflg);
+       if ((status >= 0) && (ret_size & KERNELD_WAIT)) {
+               ret_size &= ~KERNELD_WAIT;
+               if (intr_count) {
+                       /*
+                        * Do not wait for an answer at interrupt-time!
+                        * OK, so fake it...
+                        * If the kerneld request failed in user-space
+                        * we will find out eventually, and retry again!
+                        */
+                       return 0; /* i.e. say that it worked... */
+               }
+               /* else */
+               kmsp.text = (char *)ret_val;
+               status = real_msgrcv(kerneld_msqid, (struct msgbuf *)&kmsp,
+                               sizeof(long) + ((ret_val)?ret_size:0),
+                               kmsp.id, msgflg);
+               if (status > 0) /* a valid answer contains at least a long */
+                       status = kmsp.id;
+       }
+
+#endif /* CONFIG_KERNELD */
+       return status;
+}
index 19af4736d05242a1bb2f73052554055b8dd95e3b..4da405a07cbfb59edada244f1bb212d65ec1f9cb 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -12,6 +12,7 @@
 #include <linux/shm.h>
 #include <linux/stat.h>
 #include <linux/malloc.h>
+#include <linux/swap.h>
 
 #include <asm/segment.h>
 #include <asm/pgtable.h>
index 5f5f98a8473a85aa905ebde7de4194963fab026b..c2d3dc883a786f1b52af9ff8521ccb047f646c72 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/shm.h>
 #include <linux/stat.h>
 
-#ifdef CONFIG_SYSVIPC
+#if defined(CONFIG_SYSVIPC) || defined(CONFIG_KERNELD)
 
 extern void sem_init (void), msg_init (void), shm_init (void);
 
index 4e80ba70ab5696d9794efb87d665ff90918741e8..9586d067fbdb18cfcbcd9dc4343796bc58d29d23 100644 (file)
@@ -13,7 +13,7 @@
 O_TARGET := kernel.o
 O_OBJS    = sched.o dma.o fork.o exec_domain.o panic.o printk.o sys.o \
        module.o exit.o signal.o itimer.o info.o time.o softirq.o \
-       resource.o
+       resource.o sysctl.o
 
 ifeq ($(CONFIG_MODULES),y)
 OX_OBJS = ksyms.o
index 2a801ace84dc50ecefc6f22c8bd370864b7b81fd..60ab9d259b8d5700c687e5c52c60b6938cae0615 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <asm/segment.h>
 extern void sem_exit (void);
+extern void kerneld_exit(void);
 
 int getrusage(struct task_struct *, int, struct rusage *);
 
@@ -511,6 +512,7 @@ fake_volatile:
        current->flags |= PF_EXITING;
        del_timer(&current->real_timer);
        sem_exit();
+       kerneld_exit();
        exit_mm();
        __exit_files(current);
        __exit_fs(current);
index 929f1e20f73cbb78c48c4e388cc3fe8521b59e12..ab69ff67763252328bb43a16a478abc4220e20b6 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/unistd.h>
 #include <linux/types.h>
 #include <linux/mm.h>
+#include <linux/swap.h>
 
 asmlinkage int sys_sysinfo(struct sysinfo *info)
 {
index dd578118987430b049b4c7914e70adbe6e6b96bc..e16721d0e7a3cec76155d04dde200607b96e6fce 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/random.h>
 #include <linux/mount.h>
 #include <linux/pagemap.h>
+#include <linux/sysctl.h>
 
 extern unsigned char aux_device_present, kbd_read_mask;
 
@@ -102,7 +103,9 @@ extern void __remqu (void);
 #if defined(CONFIG_PROC_FS)
 #include <linux/proc_fs.h>
 #endif
-
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
 #include <asm/irq.h>
 #ifdef __SMP__
 #include <linux/smp.h>
@@ -178,6 +181,9 @@ struct symbol_table symbol_table = {
        /* stackable module support */
        X(rename_module_symbol),
        X(register_symtab),
+#ifdef CONFIG_KERNELD
+       X(kerneld_send),
+#endif
        X(get_options),
 
        /* system info variables */
@@ -307,6 +313,10 @@ struct symbol_table symbol_table = {
        X(register_exec_domain),
        X(unregister_exec_domain),
 
+       /* sysctl table registration */
+       X(register_sysctl_table),
+       X(unregister_sysctl_table),
+
        /* interrupt handling */
        X(request_irq),
        X(free_irq),
index 2b3668a5fcc52f4f4a015a78e68a0ad32eac3ea1..2eb13911ce81cca4701a6164c8e55896426a6cda 100644 (file)
@@ -228,6 +228,14 @@ sys_init_module(char *module_name, char *code, unsigned codesize,
        memcpy_fromfs(&rt, routines, sizeof rt);
        if ((mp = find_module(name)) == NULL)
                return -ENOENT;
+       if (codesize & MOD_AUTOCLEAN) {
+               /*
+                * set autoclean marker from codesize...
+                * set useage count to "zero"
+                */
+               codesize &= ~MOD_AUTOCLEAN;
+               GET_USE_COUNT(mp) = MOD_AUTOCLEAN;
+       }
        if ((codesize + sizeof (long) + PAGE_SIZE - 1) / PAGE_SIZE > mp->size)
                return -EINVAL;
        memcpy_fromfs((char *)mp->addr + sizeof (long), code, codesize);
@@ -336,13 +344,26 @@ sys_delete_module(char *module_name)
                        return error;
                if ((mp = find_module(name)) == NULL)
                        return -ENOENT;
-               if ((mp->ref != NULL) || (GET_USE_COUNT(mp) != 0))
+               if ((mp->ref != NULL) || ((GET_USE_COUNT(mp) & ~MOD_AUTOCLEAN) != 0))
                        return -EBUSY;
+               GET_USE_COUNT(mp) &= ~MOD_AUTOCLEAN;
                if (mp->state == MOD_RUNNING)
                        (*mp->cleanup)();
                mp->state = MOD_DELETED;
+               free_modules();
+       }
+       /* for automatic reaping */
+       else {
+               for (mp = module_list; mp != &kernel_module; mp = mp->next) {
+                       if ((mp->ref == NULL) && (GET_USE_COUNT(mp) == MOD_AUTOCLEAN) &&
+                           (mp->state == MOD_RUNNING)) {
+                               GET_USE_COUNT(mp) &= ~MOD_AUTOCLEAN;
+                               (*mp->cleanup)();
+                               mp->state = MOD_DELETED;
+                               free_modules();
+                       }
+               }
        }
-       free_modules();
        return 0;
 }
 
@@ -495,7 +516,7 @@ free_modules( void)
                if (mp->state != MOD_DELETED) {
                        mpp = &mp->next;
                } else {
-                       if (GET_USE_COUNT(mp) != 0) {
+                       if ((GET_USE_COUNT(mp) != 0) || (mp->ref != NULL)) {
                                freeing_modules = 1;
                                mpp = &mp->next;
                        } else {        /* delete it */
@@ -552,10 +573,8 @@ int get_module_list(char *buf)
                        *p++ = *q++;
                if (mp->state == MOD_UNINITIALIZED)
                        q = "  (uninitialized)";
-               else if (mp->state == MOD_RUNNING) {
-                       sprintf(size,"\t%ld",GET_USE_COUNT(mp));
-                       q=size;
-               }
+               else if (mp->state == MOD_RUNNING)
+                       q = "";
                else if (mp->state == MOD_DELETED)
                        q = "  (deleted)";
                else
@@ -575,6 +594,15 @@ int get_module_list(char *buf)
                        }
                        *p++ = ']';
                }
+               if (mp->state == MOD_RUNNING) {
+                       sprintf(size,"\t%ld%s",
+                               GET_USE_COUNT(mp) & ~MOD_AUTOCLEAN,
+                               ((GET_USE_COUNT(mp) & MOD_AUTOCLEAN)?
+                                       " (autoclean)":""));
+                       q = size;
+                       while (*q)
+                               *p++ = *q++;
+               }
                *p++ = '\n';
        }
        return p - buf;
index 1a7dd3c5f39ee567d673cf63184c1a63cac64734..bb1893daf185f917e1b8adc827041c855cea5830 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
+#include <linux/swap.h>
 
 #include <asm/segment.h>
 #include <asm/io.h>
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
new file mode 100644 (file)
index 0000000..105a89c
--- /dev/null
@@ -0,0 +1,669 @@
+/*
+ * sysctl.c: General linux system control interface
+ *
+ * Begun 24 March 1995, Stephen Tweedie
+ * Added /proc support, Dec 1995
+ */
+
+#include <linux/autoconf.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/sysctl.h>
+#include <linux/swapctl.h>
+#include <linux/proc_fs.h>
+#include <linux/malloc.h>
+#include <linux/stat.h>
+#include <linux/ctype.h>
+#include <asm/bitops.h>
+#include <asm/segment.h>
+
+#include <linux/utsname.h>
+#include <linux/swapctl.h>
+
+static ctl_table root_table[];
+static struct ctl_table_header root_table_header = 
+       {root_table, DNODE_SINGLE(&root_table_header)};
+
+static int parse_table(int *, int, void *, size_t *, void *, size_t,
+                      ctl_table *, void **);
+
+static ctl_table kern_table[];
+static ctl_table vm_table[];
+
+/* /proc declarations: */
+
+#ifdef CONFIG_PROC_FS
+
+static int proc_readsys(struct inode * inode, struct file * file,
+                       char * buf, int count);
+static int proc_writesys(struct inode * inode, struct file * file,
+                        const char * buf, int count);
+static int proc_sys_permission(struct inode *, int);
+
+struct file_operations proc_sys_file_operations =
+{
+       NULL,           /* lseek   */
+       proc_readsys,   /* read    */
+       proc_writesys,  /* write   */
+       NULL,           /* readdir */
+       NULL,           /* select  */
+       NULL,           /* ioctl   */
+       NULL,           /* mmap    */
+       NULL,           /* no special open code    */
+       NULL,           /* no special release code */
+       NULL            /* can't fsync */
+};
+
+struct inode_operations proc_sys_inode_operations =
+{
+       &proc_sys_file_operations,
+       NULL,           /* create */
+       NULL,           /* lookup */
+       NULL,           /* link */
+       NULL,           /* unlink */
+       NULL,           /* symlink */
+       NULL,           /* mkdir */
+       NULL,           /* rmdir */
+       NULL,           /* mknod */
+       NULL,           /* rename */
+       NULL,           /* readlink */
+       NULL,           /* follow_link */
+       NULL,           /* readpage */
+       NULL,           /* writepage */
+       NULL,           /* bmap */
+       NULL,           /* truncate */
+       proc_sys_permission
+};
+
+extern struct proc_dir_entry proc_sys_root;
+
+static void register_proc_table(ctl_table *, struct proc_dir_entry *);
+static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
+#endif
+
+/* The default sysctl tables: */
+
+static ctl_table root_table[] = {
+       {CTL_KERN, "kernel", NULL, 0, 0555, kern_table},
+       {CTL_VM, "vm", NULL, 0, 0555, vm_table},
+       {0}
+};
+
+static ctl_table kern_table[] = {
+       {KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
+        0444, NULL, &proc_dostring, &sysctl_string},
+       {KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
+        0444, NULL, &proc_dostring, &sysctl_string},
+       {KERN_VERSION, "version", system_utsname.version, 64,
+        0444, NULL, &proc_dostring, &sysctl_string},
+       {KERN_NODENAME, "hostname", system_utsname.nodename, 64,
+        0644, NULL, &proc_dostring, &sysctl_string},
+       {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
+        0644, NULL, &proc_dostring, &sysctl_string},
+       {KERN_NRINODE, "inode-nr", &nr_inodes, 2*sizeof(int),
+        0444, NULL, &proc_dointvec},
+       {KERN_MAXINODE, "inode-max", &max_inodes, sizeof(int),
+        0644, NULL, &proc_dointvec},
+       {KERN_NRFILE, "file-nr", &nr_files, sizeof(int),
+        0444, NULL, &proc_dointvec},
+       {KERN_MAXFILE, "file-max", &max_files, sizeof(int),
+        0644, NULL, &proc_dointvec},
+       {0}
+};
+
+static ctl_table vm_table[] = {
+       {VM_SWAPCTL, "swapctl", 
+        &swap_control, sizeof(swap_control_t), 0600, NULL, &proc_dointvec},
+       {VM_KSWAPD, "kswapd", 
+        &kswapd_ctl, sizeof(kswapd_ctl), 0600, NULL, &proc_dointvec},
+       {0}
+};
+
+void sysctl_init(void)
+{
+#ifdef CONFIG_PROC_FS
+       register_proc_table(root_table, &proc_sys_root);
+#endif
+}
+
+
+int do_sysctl (int *name, int nlen,
+              void *oldval, size_t *oldlenp,
+              void *newval, size_t newlen)
+{
+       int error;
+       struct ctl_table_header *tmp;
+       void *context;
+       
+       if (nlen == 0 || nlen >= CTL_MAXNAME)
+               return -ENOTDIR;
+       
+       error = verify_area(VERIFY_READ,name,nlen*sizeof(int));
+       if (error) return error;
+       if (oldval) {
+               if (!oldlenp)
+                       return -EFAULT;
+               error = verify_area(VERIFY_WRITE,oldlenp,sizeof(size_t));
+               if (error) return error;
+               error = verify_area(VERIFY_WRITE,oldval,get_user(oldlenp));
+               if (error) return error;
+       }
+       if (newval) {
+               error = verify_area(VERIFY_READ,newval,newlen);
+               if (error) return error;
+       }
+       tmp = &root_table_header;
+       do {
+               context = 0;
+               error = parse_table(name, nlen, oldval, oldlenp, 
+                                   newval, newlen, root_table, &context);
+               if (context)
+                       kfree(context);
+               if (error != ENOTDIR)
+                       return error;
+               tmp = tmp->DLIST_NEXT(ctl_entry);
+       } while (tmp != &root_table_header);
+       return -ENOTDIR;
+}
+
+extern asmlinkage int sys_sysctl(struct __sysctl_args *args)
+{
+       struct __sysctl_args tmp;
+       int error;
+       error = verify_area(VERIFY_READ, args, sizeof(*args));
+       if (error)
+               return error;
+       memcpy_fromfs(&tmp, args, sizeof(tmp));
+       return do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp, 
+                        tmp.newval, tmp.newlen);
+}
+
+/* Like in_group_p, but testing against egid, not fsgid */
+static int in_egroup_p(gid_t grp)
+{
+       int     i;
+
+       if (grp == current->euid)
+               return 1;
+
+       for (i = 0; i < NGROUPS; i++) {
+               if (current->groups[i] == NOGROUP)
+                       break;
+               if (current->groups[i] == grp)
+                       return 1;
+       }
+       return 0;
+}
+/* ctl_perm does NOT grant the superuser all rights automatically, because
+   some sysctl variables are readonly even to root. */
+static int test_perm(int mode, int op)
+{
+       if (!current->euid)
+               mode >>= 6;
+       else if (in_egroup_p(0))
+               mode >>= 3;
+       if ((mode & op & 0007) == op)
+               return 0;
+       return -EACCES;
+}
+static inline int ctl_perm(ctl_table *table, int op)
+{
+       return test_perm(table->mode, op);
+}
+
+static int parse_table(int *name, int nlen,
+                      void *oldval, size_t *oldlenp,
+                      void *newval, size_t newlen,
+                      ctl_table *table, void **context)
+{
+       int error;
+repeat:
+       if (!nlen)
+               return -ENOTDIR;
+
+       for ( ; table->ctl_name; table++) {
+               if (get_user(name) == table->ctl_name ||
+                   table->ctl_name == CTL_ANY) {
+                       if (table->child) {
+                               if (ctl_perm(table, 001))
+                                       return -EPERM;
+                               if (table->strategy) {
+                                       error = table->strategy(
+                                               table, name, nlen,
+                                               oldval, oldlenp,
+                                               newval, newlen, context);
+                               if (error)
+                                       return error;
+                               }
+                               name++;
+                               nlen--;
+                               table = table->child;
+                               goto repeat;
+                       }
+                       error = do_sysctl_strategy(table, name, nlen,
+                                                  oldval, oldlenp,
+                                                  newval, newlen, context);
+                       return error;
+               }
+       };
+       return -ENOTDIR;
+}
+
+/* Perform the actual read/write of a sysctl table entry. */
+int do_sysctl_strategy (ctl_table *table, 
+                       int *name, int nlen,
+                       void *oldval, size_t *oldlenp,
+                       void *newval, size_t newlen, void **context)
+{
+       int op = 0, rc, len;
+
+       if (oldval)
+               op |= 004;
+       if (newval) 
+               op |= 002;
+       if (ctl_perm(table, op))
+               return -EPERM;
+
+       if (table->strategy) {
+               rc = table->strategy(table, name, nlen, oldval, oldlenp,
+                                    newval, newlen, context);
+               if (rc < 0)
+                       return rc;
+               if (rc > 0)
+                       return 0;
+       }
+
+       /* If there is no strategy routine, or if the strategy returns
+        * zero, proceed with automatic r/w */
+       if (table->data && table->maxlen) {
+               if (oldval && oldlenp && get_user(oldlenp)) {
+                       len = get_user(oldlenp);
+                       if (len > table->maxlen)
+                               len = table->maxlen;
+                       memcpy_tofs(oldval, table->data, len);
+                       put_user(len, oldlenp);
+               }
+               if (newval && newlen) {
+                       len = newlen;
+                       if (len > table->maxlen)
+                               len = table->maxlen;
+                       memcpy_fromfs(table->data, newval, len);
+               }
+       }
+       return 0;
+}
+
+
+struct ctl_table_header *register_sysctl_table(ctl_table * table, 
+                                              int insert_at_head)
+{
+       struct ctl_table_header *tmp;
+       tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+       if (!tmp)
+               return 0;
+       *tmp = ((struct ctl_table_header) {table, DNODE_NULL});
+       if (insert_at_head)
+               DLIST_INSERT_AFTER(&root_table_header, tmp, ctl_entry);
+       else
+               DLIST_INSERT_BEFORE(&root_table_header, tmp, ctl_entry);
+#ifdef CONFIG_PROC_FS
+       register_proc_table(table, &proc_sys_root);
+#endif
+       return tmp;
+}
+
+void unregister_sysctl_table(struct ctl_table_header * table)
+{
+       DLIST_DELETE(table, ctl_entry);
+#ifdef CONFIG_PROC_FS
+       unregister_proc_table(table->ctl_table, &proc_sys_root);
+#endif
+}
+
+/*
+ * /proc/sys support
+ */
+
+#ifdef CONFIG_PROC_FS
+
+/* Scan the sysctl entries in table and add them all into /proc */
+static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
+{
+       struct proc_dir_entry *de;
+       
+       for (; table->ctl_name; table++) {
+               /* Can't do anything without a proc name. */
+               if (!table->procname)
+                       continue;
+               /* Maybe we can't do anything with it... */
+               if (!table->proc_handler &&
+                   !table->child)
+                       continue;
+               
+               de = kmalloc(sizeof(*de), GFP_KERNEL);
+               if (!de) continue;
+               de->namelen = strlen(table->procname);
+               de->name = table->procname;
+               de->mode = table->mode;
+               de->nlink = 1;
+               de->uid = 0;
+               de->gid = 0;
+               de->size = 0;
+               de->get_info = 0;       /* For internal use if we want it */
+               de->fill_inode = 0;     /* To override struct inode fields */
+               de->next = de->subdir = 0;
+               de->data = (void *) table;
+               /* Is it a file? */
+               if (table->proc_handler) {
+                       de->ops = &proc_sys_inode_operations;
+                       de->mode |= S_IFREG;
+               }
+               /* Otherwise it's a subdir */
+               else  {
+                       de->ops = &proc_dir_inode_operations;
+                       de->nlink++;
+                       de->mode |= S_IFDIR;
+               }
+               table->de = de;
+               proc_register_dynamic(root, de);
+               if (de->mode & S_IFDIR )
+                       register_proc_table(table->child, de);
+       }
+}
+
+static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root)
+{
+       struct proc_dir_entry *de;
+       for (; table->ctl_name; table++) {
+               if (!(de = table->de))
+                       continue;
+               if (de->mode & S_IFDIR) {
+                       if (!table->child) {
+                               printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
+                               continue;
+                       }
+                       unregister_proc_table(table->child, de);
+               }
+               proc_unregister(root, de->low_ino);
+               kfree(de);                      
+       }
+}
+
+
+static int do_rw_proc(int write, struct inode * inode, struct file * file,
+                     char * buf, int count)
+{
+       int error, op;
+       struct proc_dir_entry *de;
+       struct ctl_table *table;
+       size_t res;
+       
+       error = verify_area(write ? VERIFY_READ : VERIFY_WRITE, buf, count);
+       if (error)
+               return error;
+
+       de = (struct proc_dir_entry*) inode->u.generic_ip;
+       if (!de || !de->data)
+               return -ENOTDIR;
+       table = (struct ctl_table *) de->data;
+       if (!table || !table->proc_handler)
+               return -ENOTDIR;
+       op = (write ? 002 : 004);
+       if (ctl_perm(table, op))
+               return -EPERM;
+       
+       res = count;
+       error = (*table->proc_handler) (table, write, file, buf, &res);
+       if (error)
+               return error;
+       return res;
+}
+
+static int proc_readsys(struct inode * inode, struct file * file,
+                       char * buf, int count)
+{
+       return do_rw_proc(0, inode, file, buf, count);
+}
+
+static int proc_writesys(struct inode * inode, struct file * file,
+                        const char * buf, int count)
+{
+       return do_rw_proc(1, inode, file, (char *) buf, count);
+}
+
+static int proc_sys_permission(struct inode *inode, int op)
+{
+       return test_perm(inode->i_mode, op);
+}
+
+int proc_dostring(ctl_table *table, int write, struct file *filp,
+                 void *buffer, size_t *lenp)
+{
+       int len;
+       char *p, c;
+       
+       if (!table->data || !table->maxlen || !*lenp ||
+           (filp->f_pos && !write)) {
+               *lenp = 0;
+               return 0;
+       }
+       
+       if (write) {
+               len = 0;
+               p = buffer;
+               while (len < *lenp && 
+                      (c = get_user(p++)) != 0 && c != '\n')
+                       len++;
+               if (len >= table->maxlen)
+                       len = table->maxlen-1;
+               memcpy_fromfs(table->data, buffer, len);
+               ((char *) table->data)[len] = 0;
+               filp->f_pos += *lenp;
+       } else {
+               len = strlen(table->data) + 1;
+               if (len > table->maxlen)
+                       len = table->maxlen;
+               if (len > *lenp)
+                       len = *lenp;
+               if (len) {                      
+                       memcpy_tofs(buffer, table->data, len-1);
+                       put_user(0, ((char *) buffer) + len - 1);
+               }
+               if (len < *lenp) {
+                       put_user('\n', ((char *) buffer) + len);
+                       len++;
+               }
+               *lenp = len;
+               filp->f_pos += len;
+       }
+       return 0;
+}
+
+int proc_dointvec(ctl_table *table, int write, struct file *filp,
+                 void *buffer, size_t *lenp)
+{
+       int *i, vleft, first=1, len, left, neg, val;
+       #define TMPBUFLEN 20
+       char buf[TMPBUFLEN], *p;
+       
+       if (!table->data || !table->maxlen || !*lenp ||
+           (filp->f_pos && !write)) {
+               *lenp = 0;
+               return 0;
+       }
+       
+       i = (int *) table->data;
+       vleft = table->maxlen / sizeof(int);
+       left = *lenp;
+       
+       for (; left && vleft--; i++, first=0) {
+               if (write) {
+                       while (left && isspace(get_user((char *) buffer)))
+                               left--, ((char *) buffer)++;
+                       if (!left)
+                               break;
+                       neg = 0;
+                       len = left;
+                       if (len > TMPBUFLEN-1)
+                               len = TMPBUFLEN-1;
+                       memcpy_fromfs(buf, buffer, len);
+                       buf[len] = 0;
+                       p = buf;
+                       if (*p == '-' && left > 1) {
+                               neg = 1;
+                               left--, p++;
+                       }
+                       if (*p < '0' || *p > '9')
+                               break;
+                       val = simple_strtoul(p, &p, 0);
+                       len = p-buf;
+                       if ((len < left) && *p && !isspace(*p))
+                               break;
+                       if (neg)
+                               val = -val;
+                       buffer += len;
+                       left -= len;
+                       *i = val;
+               } else {
+                       p = buf;
+                       if (!first)
+                               *p++ = '\t';
+                       sprintf(p, "%d", *i);
+                       len = strlen(buf);
+                       if (len > left)
+                               len = left;
+                       memcpy_tofs(buffer, buf, len);
+                       left -= len;
+                       buffer += len;
+               }
+       }
+
+       if (!write && !first && left) {
+               put_user('\n', (char *) buffer);
+               left--, buffer++;
+       }
+       if (write) {
+               p = (char *) buffer;
+               while (left && isspace(get_user(p++)))
+                       left--;
+       }
+       if (write && first)
+               return -EINVAL;
+       *lenp -= left;
+       filp->f_pos += *lenp;
+       return 0;
+}
+
+#else /* CONFIG_PROC_FS */
+
+int proc_dostring(ctl_table *table, int write, struct file *filp,
+                 void *buffer, size_t *lenp)
+{
+       return -ENOSYS;
+}
+
+int proc_dointvec(ctl_table *table, int write, struct file *filp,
+                 void *buffer, size_t *lenp)
+{
+       return -ENOSYS;
+}
+
+#endif /* CONFIG_PROC_FS */
+
+
+/*
+ * General sysctl support routines 
+ */
+
+/* The generic string strategy routine: */
+int sysctl_string(ctl_table *table, int *name, int nlen,
+                 void *oldval, size_t *oldlenp,
+                 void *newval, size_t newlen, void **context)
+{
+       int l, len;
+       
+       if (!table->data || !table->maxlen) 
+               return -ENOTDIR;
+       
+       if (oldval && oldlenp && get_user(oldlenp)) {
+               len = get_user(oldlenp);
+               l = strlen(table->data);
+               if (len > l) len = l;
+               if (len >= table->maxlen)
+                       len = table->maxlen;
+               memcpy_tofs(oldval, table->data, len);
+               put_user(0, ((char *) oldval) + len);
+               put_user(len, oldlenp);
+       }
+       if (newval && newlen) {
+               len = newlen;
+               if (len > table->maxlen)
+                       len = table->maxlen;
+               memcpy_fromfs(table->data, newval, len);
+               if (len == table->maxlen)
+                       len--;
+               ((char *) table->data)[len] = 0;
+       }
+       return 0;
+}
+
+int do_string (
+       void *oldval, size_t *oldlenp, void *newval, size_t newlen,
+       int rdwr, char *data, size_t max)
+{
+       int l = strlen(data) + 1;
+       if (newval && !rdwr)
+               return -EPERM;
+       if (newval && newlen >= max)
+               return -EINVAL;
+       if (oldval) {
+               if (l > get_user(oldlenp))
+                       return -ENOMEM;
+               put_user(l, oldlenp);
+               memcpy_tofs(oldval, data, l);
+       }
+       if (newval) {
+               memcpy_fromfs(data, newval, newlen);
+               data[newlen] = 0;
+       }
+       return 0;
+}
+
+int do_int (
+       void *oldval, size_t *oldlenp, void *newval, size_t newlen,
+       int rdwr, int *data)
+{
+       if (newval && !rdwr)
+               return -EPERM;
+       if (newval && newlen != sizeof(int))
+               return -EINVAL;
+       if (oldval) {
+               if (get_user(oldlenp) < sizeof(int))
+                       return -ENOMEM;
+               put_user(sizeof(int), oldlenp);
+               memcpy_tofs(oldval, data, sizeof(int));
+       }
+       if (newval)
+               memcpy_fromfs(data, newval, sizeof(int));
+       return 0;
+}
+
+int do_struct (
+       void *oldval, size_t *oldlenp, void *newval, size_t newlen,
+       int rdwr, void *data, size_t len)
+{
+       if (newval && !rdwr)
+               return -EPERM;
+       if (newval && newlen != len)
+               return -EINVAL;
+       if (oldval) {
+               if (get_user(oldlenp) < len)
+                       return -ENOMEM;
+               put_user(len, oldlenp);
+               memcpy_tofs(oldval, data, len);
+       }
+       if (newval)
+               memcpy_fromfs(data, newval, len);
+       return 0;
+}
+
index 5c305d81b00301599c5dc955b894880b5646628f..60c2659d17019ab3cba6d09a5bafa235b90071fb 100644 (file)
@@ -8,7 +8,8 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := mm.o
-O_OBJS  := memory.o swap.o mmap.o filemap.o mprotect.o mlock.o \
-           kmalloc.o vmalloc.o
+O_OBJS  := memory.o mmap.o filemap.o mprotect.o mlock.o \
+           kmalloc.o vmalloc.o \
+           swap.o vmscan.o page_io.o page_alloc.o swap_state.o swapfile.o
 
 include $(TOPDIR)/Rules.make
index 17a41eb389d15dcf41002fa3d021eed606f05fe8..d1323e9aab1b2c4c1acca1343662fb305f3dee6f 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/fs.h>
 #include <linux/locks.h>
 #include <linux/pagemap.h>
+#include <linux/swap.h>
 
 #include <asm/segment.h>
 #include <asm/system.h>
@@ -73,6 +74,7 @@ int shrink_mmap(int priority, unsigned long limit)
 {
        static int clock = 0;
        struct page * page;
+       struct buffer_head *tmp, *bh;
 
        if (limit > high_memory)
                limit = high_memory;
@@ -82,18 +84,40 @@ int shrink_mmap(int priority, unsigned long limit)
        priority = (limit<<2) >> priority;
        page = mem_map + clock;
        while (priority-- > 0) {
-               if (page->inode) {
-                       unsigned age = page->age;
-                       /* if the page is shared, we juvenate it */
-                       if (page->count != 1)
-                               age |= PAGE_AGE_VALUE << 1;
-                       page->age = age >> 1;
-                       if (age < PAGE_AGE_VALUE) {
+               /* First of all, regenerate the page's referenced bit
+                   from any buffers in the page */
+               bh = buffer_pages[MAP_NR(page_address(page))];
+               if (bh) {
+                       tmp = bh;
+                       do {
+                               if (buffer_touched(tmp)) {
+                                       clear_bit(BH_Touched, &tmp->b_state);
+                                       page->referenced = 1;
+                               }
+                               tmp = tmp->b_this_page;
+                       } while (tmp != bh);
+               }
+
+               /* We can't throw away shared pages, but we do mark
+                  them as referenced.  This relies on the fact that
+                  no page is currently in both the page cache and the
+                  buffer cache; we'd have to modify the following
+                  test to allow for that case. */
+               if (page->count > 1)
+                       page->referenced = 1;
+               else if (page->referenced)
+                       page->referenced = 0;
+               else if (page->count) {
+                       /* The page is an old, unshared page --- try
+                           to discard it. */
+                       if (page->inode) {
                                remove_page_from_hash_queue(page);
                                remove_page_from_inode_queue(page);
                                free_page(page_address(page));
                                return 1;
                        }
+                       if (bh && try_to_free_buffer(bh, &bh, 6))
+                               return 1;
                }
                page++;
                clock++;
index 694eefaab3b032de488d339c4bffd89851483857..e025d5404a70d32d9008e9cd7c8d9e577ba3d480 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
+#include <linux/swap.h>
 
 #include <asm/system.h>
 #include <asm/segment.h>
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
new file mode 100644 (file)
index 0000000..4fbad0e
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ *  linux/mm/page_alloc.c
+ *
+ *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *  Swap reorganised 29.12.95, Stephen Tweedie
+ */
+
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/head.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/swap.h>
+#include <linux/fs.h>
+#include <linux/swapctl.h>
+
+#include <asm/dma.h>
+#include <asm/system.h> /* for cli()/sti() */
+#include <asm/segment.h> /* for memcpy_to/fromfs */
+#include <asm/bitops.h>
+#include <asm/pgtable.h>
+
+static inline void add_mem_queue(struct mem_list * head, struct mem_list * entry)
+{
+       entry->prev = head;
+       (entry->next = head->next)->prev = entry;
+       head->next = entry;
+}
+
+static inline void remove_mem_queue(struct mem_list * head, struct mem_list * entry)
+{
+       struct mem_list * next = entry->next;
+       (next->prev = entry->prev)->next = next;
+}
+
+/*
+ * Free_page() adds the page to the free lists. This is optimized for
+ * fast normal cases (no error jumps taken normally).
+ *
+ * The way to optimize jumps for gcc-2.2.2 is to:
+ *  - select the "normal" case and put it inside the if () { XXX }
+ *  - no else-statements if you can avoid them
+ *
+ * With the above two rules, you get a straight-line execution path
+ * for the normal case, giving better asm-code.
+ *
+ * free_page() may sleep since the page being freed may be a buffer
+ * page or present in the swap cache. It will not sleep, however,
+ * for a freshly allocated page (get_free_page()).
+ */
+
+/*
+ * Buddy system. Hairy. You really aren't expected to understand this
+ */
+static inline void free_pages_ok(unsigned long addr, unsigned long order)
+{
+       unsigned long index = MAP_NR(addr) >> (1 + order);
+       unsigned long mask = PAGE_MASK << order;
+
+       addr &= mask;
+       nr_free_pages += 1 << order;
+       while (order < NR_MEM_LISTS-1) {
+               if (!change_bit(index, free_area_map[order]))
+                       break;
+               remove_mem_queue(free_area_list+order, (struct mem_list *) (addr ^ (1+~mask)));
+               order++;
+               index >>= 1;
+               mask <<= 1;
+               addr &= mask;
+       }
+       add_mem_queue(free_area_list+order, (struct mem_list *) addr);
+}
+
+static inline void check_free_buffers(unsigned long addr)
+{
+       struct buffer_head * bh;
+
+       bh = buffer_pages[MAP_NR(addr)];
+       if (bh) {
+               struct buffer_head *tmp = bh;
+               do {
+                       if (tmp->b_list == BUF_SHARED
+                           && tmp->b_dev != B_FREE)
+                               refile_buffer(tmp);
+                       tmp = tmp->b_this_page;
+               } while (tmp != bh);
+       }
+}
+
+void free_pages(unsigned long addr, unsigned long order)
+{
+       if (MAP_NR(addr) < MAP_NR(high_memory)) {
+               unsigned long flag;
+               mem_map_t * map = mem_map + MAP_NR(addr);
+               if (map->reserved)
+                       return;
+               if (map->count) {
+                       save_flags(flag);
+                       cli();
+                       if (!--map->count) {
+                               free_pages_ok(addr, order);
+                               delete_from_swap_cache(addr);
+                       }
+                       restore_flags(flag);
+                       if (map->count == 1)
+                               check_free_buffers(addr);
+                       return;
+               }
+               printk("Trying to free free memory (%08lx): memory probably corrupted\n",addr);
+               printk("PC = %p\n", __builtin_return_address(0));
+               return;
+       }
+}
+
+/*
+ * Some ugly macros to speed up __get_free_pages()..
+ */
+#define RMQUEUE(order, limit) \
+do { struct mem_list * queue = free_area_list+order; \
+     unsigned long new_order = order; \
+       do { struct mem_list *prev = queue, *ret; \
+               while (queue != (ret = prev->next)) { \
+                       if ((unsigned long) ret < (limit)) { \
+                               (prev->next = ret->next)->prev = prev; \
+                               mark_used((unsigned long) ret, new_order); \
+                               nr_free_pages -= 1 << order; \
+                               restore_flags(flags); \
+                               EXPAND(ret, order, new_order); \
+                               return (unsigned long) ret; \
+                       } \
+                       prev = ret; \
+               } \
+               new_order++; queue++; \
+       } while (new_order < NR_MEM_LISTS); \
+} while (0)
+
+static inline int mark_used(unsigned long addr, unsigned long order)
+{
+       return change_bit(MAP_NR(addr) >> (1+order), free_area_map[order]);
+}
+
+#define EXPAND(addr,low,high) \
+do { unsigned long size = PAGE_SIZE << high; \
+       while (high > low) { \
+               high--; size >>= 1; cli(); \
+               add_mem_queue(free_area_list+high, addr); \
+               mark_used((unsigned long) addr, high); \
+               restore_flags(flags); \
+               addr = (struct mem_list *) (size + (unsigned long) addr); \
+       } mem_map[MAP_NR((unsigned long) addr)].count = 1; \
+       mem_map[MAP_NR((unsigned long) addr)].age = PAGE_INITIAL_AGE; \
+} while (0)
+
+unsigned long __get_free_pages(int priority, unsigned long order, unsigned long limit)
+{
+       unsigned long flags;
+       int reserved_pages;
+
+       if (order >= NR_MEM_LISTS)
+               return 0;
+       if (intr_count && priority != GFP_ATOMIC) {
+               static int count = 0;
+               if (++count < 5) {
+                       printk("gfp called nonatomically from interrupt %p\n",
+                               __builtin_return_address(0));
+                       priority = GFP_ATOMIC;
+               }
+       }
+       reserved_pages = 5;
+       if (priority != GFP_NFS)
+               reserved_pages = min_free_pages;
+       save_flags(flags);
+repeat:
+       cli();
+       if ((priority==GFP_ATOMIC) || nr_free_pages > reserved_pages) {
+               RMQUEUE(order, limit);
+               restore_flags(flags);
+               return 0;
+       }
+       restore_flags(flags);
+       if (priority != GFP_BUFFER && try_to_free_page(priority, limit))
+               goto repeat;
+       return 0;
+}
+
+/*
+ * Show free area list (used inside shift_scroll-lock stuff)
+ * We also calculate the percentage fragmentation. We do this by counting the
+ * memory on each free list with the exception of the first item on the list.
+ */
+void show_free_areas(void)
+{
+       unsigned long order, flags;
+       unsigned long total = 0;
+
+       printk("Free pages:      %6dkB\n ( ",nr_free_pages<<(PAGE_SHIFT-10));
+       save_flags(flags);
+       cli();
+       for (order=0 ; order < NR_MEM_LISTS; order++) {
+               struct mem_list * tmp;
+               unsigned long nr = 0;
+               for (tmp = free_area_list[order].next ; tmp != free_area_list + order ; tmp = tmp->next) {
+                       nr ++;
+               }
+               total += nr * ((PAGE_SIZE>>10) << order);
+               printk("%lu*%lukB ", nr, (PAGE_SIZE>>10) << order);
+       }
+       restore_flags(flags);
+       printk("= %lukB)\n", total);
+#ifdef SWAP_CACHE_INFO
+       show_swap_cache_info();
+#endif 
+}
+
+#define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
+
+/*
+ * set up the free-area data structures:
+ *   - mark all pages reserved
+ *   - mark all memory queues empty
+ *   - clear the memory bitmaps
+ */
+unsigned long free_area_init(unsigned long start_mem, unsigned long end_mem)
+{
+       mem_map_t * p;
+       unsigned long mask = PAGE_MASK;
+       int i;
+
+       /*
+        * select nr of pages we try to keep free for important stuff
+        * with a minimum of 16 pages. This is totally arbitrary
+        */
+       i = (end_mem - PAGE_OFFSET) >> (PAGE_SHIFT+7);
+       if (i < 16)
+               i = 16;
+       min_free_pages = i;
+       free_pages_low = i + (i>>1);
+       free_pages_high = i + i;
+       start_mem = init_swap_cache(start_mem, end_mem);
+       mem_map = (mem_map_t *) start_mem;
+       p = mem_map + MAP_NR(end_mem);
+       start_mem = LONG_ALIGN((unsigned long) p);
+       memset(mem_map, 0, start_mem - (unsigned long) mem_map);
+       do {
+               --p;
+               p->reserved = 1;
+       } while (p > mem_map);
+
+       for (i = 0 ; i < NR_MEM_LISTS ; i++) {
+               unsigned long bitmap_size;
+               free_area_list[i].prev = free_area_list[i].next = &free_area_list[i];
+               mask += mask;
+               end_mem = (end_mem + ~mask) & mask;
+               bitmap_size = (end_mem - PAGE_OFFSET) >> (PAGE_SHIFT + i);
+               bitmap_size = (bitmap_size + 7) >> 3;
+               bitmap_size = LONG_ALIGN(bitmap_size);
+               free_area_map[i] = (unsigned int *) start_mem;
+               memset((void *) start_mem, 0, bitmap_size);
+               start_mem += bitmap_size;
+       }
+       return start_mem;
+}
+
+/*
+ * The tests may look silly, but it essentially makes sure that
+ * no other process did a swap-in on us just as we were waiting.
+ *
+ * Also, don't bother to add to the swap cache if this page-in
+ * was due to a write access.
+ */
+void swap_in(struct task_struct * tsk, struct vm_area_struct * vma,
+       pte_t * page_table, unsigned long entry, int write_access)
+{
+       unsigned long page = __get_free_page(GFP_KERNEL);
+
+       if (pte_val(*page_table) != entry) {
+               free_page(page);
+               return;
+       }
+       if (!page) {
+               set_pte(page_table, BAD_PAGE);
+               swap_free(entry);
+               oom(tsk);
+               return;
+       }
+       read_swap_page(entry, (char *) page);
+       if (pte_val(*page_table) != entry) {
+               free_page(page);
+               return;
+       }
+       vma->vm_mm->rss++;
+       tsk->maj_flt++;
+       if (!write_access && add_to_swap_cache(page, entry)) {
+               set_pte(page_table, mk_pte(page, vma->vm_page_prot));
+               return;
+       }
+       set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))));
+       swap_free(entry);
+       return;
+}
+
diff --git a/mm/page_io.c b/mm/page_io.c
new file mode 100644 (file)
index 0000000..bf609ad
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ *  linux/mm/page_io.c
+ *
+ *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  Swap reorganised 29.12.95, 
+ *  Asynchronous swapping added 30.12.95. Stephen Tweedie
+ */
+
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/head.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/swap.h>
+#include <linux/fs.h>
+#include <linux/locks.h>
+#include <linux/swapctl.h>
+
+#include <asm/dma.h>
+#include <asm/system.h> /* for cli()/sti() */
+#include <asm/segment.h> /* for memcpy_to/fromfs */
+#include <asm/bitops.h>
+#include <asm/pgtable.h>
+
+static struct wait_queue * lock_queue = NULL;
+
+void rw_swap_page(int rw, unsigned long entry, char * buf)
+{
+       unsigned long type, offset;
+       struct swap_info_struct * p;
+
+       type = SWP_TYPE(entry);
+       if (type >= nr_swapfiles) {
+               printk("Internal error: bad swap-device\n");
+               return;
+       }
+       p = &swap_info[type];
+       offset = SWP_OFFSET(entry);
+       if (offset >= p->max) {
+               printk("rw_swap_page: weirdness\n");
+               return;
+       }
+       if (p->swap_map && !p->swap_map[offset]) {
+               printk("Hmm.. Trying to use unallocated swap (%08lx)\n", entry);
+               return;
+       }
+       if (!(p->flags & SWP_USED)) {
+               printk("Trying to swap to unused swap-device\n");
+               return;
+       }
+       while (set_bit(offset,p->swap_lockmap))
+               sleep_on(&lock_queue);
+       if (rw == READ)
+               kstat.pswpin++;
+       else
+               kstat.pswpout++;
+       if (p->swap_device) {
+               ll_rw_page(rw,p->swap_device,offset,buf);
+       } else if (p->swap_file) {
+               struct inode *swapf = p->swap_file;
+               unsigned int zones[PAGE_SIZE/512];
+               int i;
+               if (swapf->i_op->bmap == NULL
+                       && swapf->i_op->smap != NULL){
+                       /*
+                               With MsDOS, we use msdos_smap which return
+                               a sector number (not a cluster or block number).
+                               It is a patch to enable the UMSDOS project.
+                               Other people are working on better solution.
+
+                               It sounds like ll_rw_swap_file defined
+                               it operation size (sector size) based on
+                               PAGE_SIZE and the number of block to read.
+                               So using bmap or smap should work even if
+                               smap will require more blocks.
+                       */
+                       int j;
+                       unsigned int block = offset << 3;
+
+                       for (i=0, j=0; j< PAGE_SIZE ; i++, j += 512){
+                               if (!(zones[i] = swapf->i_op->smap(swapf,block++))) {
+                                       printk("rw_swap_page: bad swap file\n");
+                                       return;
+                               }
+                       }
+               }else{
+                       int j;
+                       unsigned int block = offset
+                               << (PAGE_SHIFT - swapf->i_sb->s_blocksize_bits);
+
+                       for (i=0, j=0; j< PAGE_SIZE ; i++, j +=swapf->i_sb->s_blocksize)
+                               if (!(zones[i] = bmap(swapf,block++))) {
+                                       printk("rw_swap_page: bad swap file\n");
+                                       return;
+                               }
+               }
+               ll_rw_swap_file(rw,swapf->i_dev, zones, i,buf);
+       } else
+               printk("re_swap_page: no swap file or device\n");
+       if (offset && !clear_bit(offset,p->swap_lockmap))
+               printk("rw_swap_page: lock already cleared\n");
+       wake_up(&lock_queue);
+}
+
index b777cc5c5fafb0c1679b4a76fa4b3608b09c3925..1e10b326af82b3ecfeaa12ce712e33b5ca3845bd 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
 #include <asm/bitops.h>
 #include <asm/pgtable.h>
 
-#define MAX_SWAPFILES 8
-
-#define SWP_USED       1
-#define SWP_WRITEOK    3
-
+/*
+ * We identify three levels of free memory.  We never let free mem
+ * fall below the min_free_pages except for atomic allocations.  We
+ * start background swapping if we fall below free_pages_high free
+ * pages, and we begin intensive swapping below free_pages_low.
+ *
+ * Keep these three variables contiguous for sysctl(2).  
+ */
 int min_free_pages = 20;
+int free_pages_low = 30;
+int free_pages_high = 40;
 
 /*
  * Constants for the page aging mechanism: the maximum age (actually,
@@ -53,87 +58,6 @@ swap_control_t swap_control = {
        RCL_ROUND_ROBIN         /* Balancing policy */
 };
 
-static int nr_swapfiles = 0;
-static struct wait_queue * lock_queue = NULL;
-static struct {
-       int head;       /* head of priority-ordered swapfile list */
-       int next;       /* swapfile to be used next */
-} swap_list = {-1, -1};
-
-static struct swap_info_struct {
-       unsigned int flags;
-       kdev_t swap_device;
-       struct inode * swap_file;
-       unsigned char * swap_map;
-       unsigned char * swap_lockmap;
-       int lowest_bit;
-       int highest_bit;
-       int prio;                       /* swap priority */
-       int pages;
-       unsigned long max;
-       int next;                       /* next entry on swap list */
-} swap_info[MAX_SWAPFILES];
-
-extern int shm_swap (int, unsigned long);
-
-/*
- * To save us from swapping out pages which have just been swapped in and
- * have not been modified since then, we keep in swap_cache[page>>PAGE_SHIFT]
- * the swap entry which was last used to fill the page, or zero if the
- * page does not currently correspond to a page in swap. PAGE_DIRTY makes
- * this info useless.
- */
-unsigned long *swap_cache;
-
-#ifdef SWAP_CACHE_INFO
-unsigned long swap_cache_add_total = 0;
-unsigned long swap_cache_add_success = 0;
-unsigned long swap_cache_del_total = 0;
-unsigned long swap_cache_del_success = 0;
-unsigned long swap_cache_find_total = 0;
-unsigned long swap_cache_find_success = 0;
-
-extern inline void show_swap_cache_info(void)
-{
-       printk("Swap cache: add %ld/%ld, delete %ld/%ld, find %ld/%ld\n",
-               swap_cache_add_total, swap_cache_add_success, 
-               swap_cache_del_total, swap_cache_del_success,
-               swap_cache_find_total, swap_cache_find_success);
-}
-#endif
-
-static int add_to_swap_cache(unsigned long addr, unsigned long entry)
-{
-       struct swap_info_struct * p = &swap_info[SWP_TYPE(entry)];
-
-#ifdef SWAP_CACHE_INFO
-       swap_cache_add_total++;
-#endif
-       if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
-               entry = xchg(swap_cache + MAP_NR(addr), entry);
-               if (entry)  {
-                       printk("swap_cache: replacing non-NULL entry\n");
-               }
-#ifdef SWAP_CACHE_INFO
-               swap_cache_add_success++;
-#endif
-               return 1;
-       }
-       return 0;
-}
-
-static unsigned long init_swap_cache(unsigned long mem_start,
-       unsigned long mem_end)
-{
-       unsigned long swap_cache_size;
-
-       mem_start = (mem_start + 15) & ~15;
-       swap_cache = (unsigned long *) mem_start;
-       swap_cache_size = MAP_NR(mem_end);
-       memset(swap_cache, 0, swap_cache_size * sizeof (unsigned long));
-       return (unsigned long) (swap_cache + swap_cache_size);
-}
-
 /* General swap control */
 
 /* Parse the kernel command line "swap=" option at load time: */
@@ -174,1174 +98,3 @@ void buff_setup(char *str, int *ints)
        }
 }
 
-/* Page aging */
-
-void rw_swap_page(int rw, unsigned long entry, char * buf)
-{
-       unsigned long type, offset;
-       struct swap_info_struct * p;
-
-       type = SWP_TYPE(entry);
-       if (type >= nr_swapfiles) {
-               printk("Internal error: bad swap-device\n");
-               return;
-       }
-       p = &swap_info[type];
-       offset = SWP_OFFSET(entry);
-       if (offset >= p->max) {
-               printk("rw_swap_page: weirdness\n");
-               return;
-       }
-       if (p->swap_map && !p->swap_map[offset]) {
-               printk("Hmm.. Trying to use unallocated swap (%08lx)\n", entry);
-               return;
-       }
-       if (!(p->flags & SWP_USED)) {
-               printk("Trying to swap to unused swap-device\n");
-               return;
-       }
-       while (set_bit(offset,p->swap_lockmap))
-               sleep_on(&lock_queue);
-       if (rw == READ)
-               kstat.pswpin++;
-       else
-               kstat.pswpout++;
-       if (p->swap_device) {
-               ll_rw_page(rw,p->swap_device,offset,buf);
-       } else if (p->swap_file) {
-               struct inode *swapf = p->swap_file;
-               unsigned int zones[PAGE_SIZE/512];
-               int i;
-               if (swapf->i_op->bmap == NULL
-                       && swapf->i_op->smap != NULL){
-                       /*
-                               With MsDOS, we use msdos_smap which return
-                               a sector number (not a cluster or block number).
-                               It is a patch to enable the UMSDOS project.
-                               Other people are working on better solution.
-
-                               It sounds like ll_rw_swap_file defined
-                               it operation size (sector size) based on
-                               PAGE_SIZE and the number of block to read.
-                               So using bmap or smap should work even if
-                               smap will require more blocks.
-                       */
-                       int j;
-                       unsigned int block = offset << 3;
-
-                       for (i=0, j=0; j< PAGE_SIZE ; i++, j += 512){
-                               if (!(zones[i] = swapf->i_op->smap(swapf,block++))) {
-                                       printk("rw_swap_page: bad swap file\n");
-                                       return;
-                               }
-                       }
-               }else{
-                       int j;
-                       unsigned int block = offset
-                               << (PAGE_SHIFT - swapf->i_sb->s_blocksize_bits);
-
-                       for (i=0, j=0; j< PAGE_SIZE ; i++, j +=swapf->i_sb->s_blocksize)
-                               if (!(zones[i] = bmap(swapf,block++))) {
-                                       printk("rw_swap_page: bad swap file\n");
-                                       return;
-                               }
-               }
-               ll_rw_swap_file(rw,swapf->i_dev, zones, i,buf);
-       } else
-               printk("re_swap_page: no swap file or device\n");
-       if (offset && !clear_bit(offset,p->swap_lockmap))
-               printk("rw_swap_page: lock already cleared\n");
-       wake_up(&lock_queue);
-}
-
-unsigned long get_swap_page(void)
-{
-       struct swap_info_struct * p;
-       unsigned long offset, entry;
-       int type, wrapped = 0;
-
-       type = swap_list.next;
-       if (type < 0)
-         return 0;
-
-       while (1) {
-               p = &swap_info[type];
-               if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
-                       for (offset = p->lowest_bit; offset <= p->highest_bit ; offset++) {
-                               if (p->swap_map[offset])
-                                 continue;
-                               if (test_bit(offset, p->swap_lockmap))
-                                 continue;
-                               p->swap_map[offset] = 1;
-                               nr_swap_pages--;
-                               if (offset == p->highest_bit)
-                                 p->highest_bit--;
-                               p->lowest_bit = offset;
-                               entry = SWP_ENTRY(type,offset);
-
-                               type = swap_info[type].next;
-                               if (type < 0 || p->prio != swap_info[type].prio) {
-                                   swap_list.next = swap_list.head;
-                               } else {
-                                   swap_list.next = type;
-                               }
-                               return entry;
-                       }
-               }
-               type = p->next;
-               if (!wrapped) {
-                       if (type < 0 || p->prio != swap_info[type].prio) {
-                               type = swap_list.head;
-                               wrapped = 1;
-                       }
-               } else if (type < 0) {
-                       return 0;       /* out of swap space */
-               }
-       }
-}
-
-void swap_duplicate(unsigned long entry)
-{
-       struct swap_info_struct * p;
-       unsigned long offset, type;
-
-       if (!entry)
-               return;
-       offset = SWP_OFFSET(entry);
-       type = SWP_TYPE(entry);
-       if (type & SHM_SWP_TYPE)
-               return;
-       if (type >= nr_swapfiles) {
-               printk("Trying to duplicate nonexistent swap-page\n");
-               return;
-       }
-       p = type + swap_info;
-       if (offset >= p->max) {
-               printk("swap_duplicate: weirdness\n");
-               return;
-       }
-       if (!p->swap_map[offset]) {
-               printk("swap_duplicate: trying to duplicate unused page\n");
-               return;
-       }
-       p->swap_map[offset]++;
-       return;
-}
-
-void swap_free(unsigned long entry)
-{
-       struct swap_info_struct * p;
-       unsigned long offset, type;
-
-       if (!entry)
-               return;
-       type = SWP_TYPE(entry);
-       if (type & SHM_SWP_TYPE)
-               return;
-       if (type >= nr_swapfiles) {
-               printk("Trying to free nonexistent swap-page\n");
-               return;
-       }
-       p = & swap_info[type];
-       offset = SWP_OFFSET(entry);
-       if (offset >= p->max) {
-               printk("swap_free: weirdness\n");
-               return;
-       }
-       if (!(p->flags & SWP_USED)) {
-               printk("Trying to free swap from unused swap-device\n");
-               return;
-       }
-       if (offset < p->lowest_bit)
-               p->lowest_bit = offset;
-       if (offset > p->highest_bit)
-               p->highest_bit = offset;
-       if (!p->swap_map[offset])
-               printk("swap_free: swap-space map bad (entry %08lx)\n",entry);
-       else
-               if (!--p->swap_map[offset])
-                       nr_swap_pages++;
-       if (p->prio > swap_info[swap_list.next].prio) {
-           swap_list.next = swap_list.head;
-       }
-}
-
-/*
- * The tests may look silly, but it essentially makes sure that
- * no other process did a swap-in on us just as we were waiting.
- *
- * Also, don't bother to add to the swap cache if this page-in
- * was due to a write access.
- */
-void swap_in(struct task_struct * tsk, struct vm_area_struct * vma,
-       pte_t * page_table, unsigned long entry, int write_access)
-{
-       unsigned long page = __get_free_page(GFP_KERNEL);
-
-       if (pte_val(*page_table) != entry) {
-               free_page(page);
-               return;
-       }
-       if (!page) {
-               set_pte(page_table, BAD_PAGE);
-               swap_free(entry);
-               oom(tsk);
-               return;
-       }
-       read_swap_page(entry, (char *) page);
-       if (pte_val(*page_table) != entry) {
-               free_page(page);
-               return;
-       }
-       vma->vm_mm->rss++;
-       tsk->maj_flt++;
-       if (!write_access && add_to_swap_cache(page, entry)) {
-               set_pte(page_table, mk_pte(page, vma->vm_page_prot));
-               return;
-       }
-       set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))));
-       swap_free(entry);
-       return;
-}
-
-/*
- * The swap-out functions return 1 if they successfully
- * threw something out, and we got a free page. It returns
- * zero if it couldn't do anything, and any other value
- * indicates it decreased rss, but the page was shared.
- *
- * NOTE! If it sleeps, it *must* return 1 to make sure we
- * don't continue with the swap-out. Otherwise we may be
- * using a process that no longer actually exists (it might
- * have died while we slept).
- */
-static inline int try_to_swap_out(struct task_struct * tsk, struct vm_area_struct* vma,
-       unsigned long address, pte_t * page_table, unsigned long limit)
-{
-       pte_t pte;
-       unsigned long entry;
-       unsigned long page;
-       struct page * page_map;
-
-       pte = *page_table;
-       if (!pte_present(pte))
-               return 0;
-       page = pte_page(pte);
-       if (MAP_NR(page) >= MAP_NR(high_memory))
-               return 0;
-       if (page >= limit)
-               return 0;
-
-       page_map = mem_map + MAP_NR(page);
-       if (page_map->reserved)
-               return 0;
-       /* Deal with page aging.  Pages age from being unused; they
-        * rejuvinate on being accessed.  Only swap old pages (age==0
-        * is oldest). */
-       if ((pte_dirty(pte) && delete_from_swap_cache(page)) 
-           || pte_young(pte))  {
-               set_pte(page_table, pte_mkold(pte));
-               page_age_update(page_map, 1);
-               return 0;
-       }       
-       if (page_age_update(page_map, pte_young(pte)))
-               return 0;
-       if (pte_dirty(pte)) {
-               if (vma->vm_ops && vma->vm_ops->swapout) {
-                       pid_t pid = tsk->pid;
-                       vma->vm_mm->rss--;
-                       if (vma->vm_ops->swapout(vma, address - vma->vm_start + vma->vm_offset, page_table))
-                               kill_proc(pid, SIGBUS, 1);
-               } else {
-                       if (page_map->count != 1)
-                               return 0;
-                       if (!(entry = get_swap_page()))
-                               return 0;
-                       vma->vm_mm->rss--;
-                       set_pte(page_table, __pte(entry));
-                       invalidate_page(vma, address);
-                       tsk->nswap++;
-                       write_swap_page(entry, (char *) page);
-               }
-               free_page(page);
-               return 1;       /* we slept: the process may not exist any more */
-       }
-        if ((entry = find_in_swap_cache(page)))  {
-               if (page_map->count != 1) {
-                       set_pte(page_table, pte_mkdirty(pte));
-                       printk("Aiee.. duplicated cached swap-cache entry\n");
-                       return 0;
-               }
-               vma->vm_mm->rss--;
-               set_pte(page_table, __pte(entry));
-               invalidate_page(vma, address);
-               free_page(page);
-               return 1;
-       } 
-       vma->vm_mm->rss--;
-       pte_clear(page_table);
-       invalidate_page(vma, address);
-       entry = page_unuse(page);
-       free_page(page);
-       return entry;
-}
-
-/*
- * A new implementation of swap_out().  We do not swap complete processes,
- * but only a small number of blocks, before we continue with the next
- * process.  The number of blocks actually swapped is determined on the
- * number of page faults, that this process actually had in the last time,
- * so we won't swap heavily used processes all the time ...
- *
- * Note: the priority argument is a hint on much CPU to waste with the
- *       swap block search, not a hint, of how much blocks to swap with
- *       each process.
- *
- * (C) 1993 Kai Petzke, wpp@marie.physik.tu-berlin.de
- */
-
-static inline int swap_out_pmd(struct task_struct * tsk, struct vm_area_struct * vma,
-       pmd_t *dir, unsigned long address, unsigned long end, unsigned long limit)
-{
-       pte_t * pte;
-       unsigned long pmd_end;
-
-       if (pmd_none(*dir))
-               return 0;
-       if (pmd_bad(*dir)) {
-               printk("swap_out_pmd: bad pmd (%08lx)\n", pmd_val(*dir));
-               pmd_clear(dir);
-               return 0;
-       }
-       
-       pte = pte_offset(dir, address);
-       
-       pmd_end = (address + PMD_SIZE) & PMD_MASK;
-       if (end > pmd_end)
-               end = pmd_end;
-
-       do {
-               int result;
-               tsk->swap_address = address + PAGE_SIZE;
-               result = try_to_swap_out(tsk, vma, address, pte, limit);
-               if (result)
-                       return result;
-               address += PAGE_SIZE;
-               pte++;
-       } while (address < end);
-       return 0;
-}
-
-static inline int swap_out_pgd(struct task_struct * tsk, struct vm_area_struct * vma,
-       pgd_t *dir, unsigned long address, unsigned long end, unsigned long limit)
-{
-       pmd_t * pmd;
-       unsigned long pgd_end;
-
-       if (pgd_none(*dir))
-               return 0;
-       if (pgd_bad(*dir)) {
-               printk("swap_out_pgd: bad pgd (%08lx)\n", pgd_val(*dir));
-               pgd_clear(dir);
-               return 0;
-       }
-
-       pmd = pmd_offset(dir, address);
-
-       pgd_end = (address + PGDIR_SIZE) & PGDIR_MASK;  
-       if (end > pgd_end)
-               end = pgd_end;
-       
-       do {
-               int result = swap_out_pmd(tsk, vma, pmd, address, end, limit);
-               if (result)
-                       return result;
-               address = (address + PMD_SIZE) & PMD_MASK;
-               pmd++;
-       } while (address < end);
-       return 0;
-}
-
-static int swap_out_vma(struct task_struct * tsk, struct vm_area_struct * vma,
-       pgd_t *pgdir, unsigned long start, unsigned long limit)
-{
-       unsigned long end;
-
-       /* Don't swap out areas like shared memory which have their
-           own separate swapping mechanism or areas which are locked down */
-       if (vma->vm_flags & (VM_SHM | VM_LOCKED))
-               return 0;
-
-       end = vma->vm_end;
-       while (start < end) {
-               int result = swap_out_pgd(tsk, vma, pgdir, start, end, limit);
-               if (result)
-                       return result;
-               start = (start + PGDIR_SIZE) & PGDIR_MASK;
-               pgdir++;
-       }
-       return 0;
-}
-
-static int swap_out_process(struct task_struct * p, unsigned long limit)
-{
-       unsigned long address;
-       struct vm_area_struct* vma;
-
-       /*
-        * Go through process' page directory.
-        */
-       address = p->swap_address;
-       p->swap_address = 0;
-
-       /*
-        * Find the proper vm-area
-        */
-       vma = find_vma(p, address);
-       if (!vma)
-               return 0;
-       if (address < vma->vm_start)
-               address = vma->vm_start;
-
-       for (;;) {
-               int result = swap_out_vma(p, vma, pgd_offset(p->mm, address), address, limit);
-               if (result)
-                       return result;
-               vma = vma->vm_next;
-               if (!vma)
-                       break;
-               address = vma->vm_start;
-       }
-       p->swap_address = 0;
-       return 0;
-}
-
-static int swap_out(unsigned int priority, unsigned long limit)
-{
-       static int swap_task;
-       int loop, counter;
-       struct task_struct *p;
-
-       counter = ((PAGEOUT_WEIGHT * nr_tasks) >> 10) >> priority;
-       for(; counter >= 0; counter--) {
-               /*
-                * Check that swap_task is suitable for swapping.  If not, look for
-                * the next suitable process.
-                */
-               loop = 0;
-               while(1) {
-                       if (swap_task >= NR_TASKS) {
-                               swap_task = 1;
-                               if (loop)
-                                       /* all processes are unswappable or already swapped out */
-                                       return 0;
-                               loop = 1;
-                       }
-
-                       p = task[swap_task];
-                       if (p && p->swappable && p->mm->rss)
-                               break;
-
-                       swap_task++;
-               }
-
-               /*
-                * Determine the number of pages to swap from this process.
-                */
-               if (!p->swap_cnt) {
-                       /* Normalise the number of pages swapped by
-                          multiplying by (RSS / 1MB) */
-                       p->swap_cnt = AGE_CLUSTER_SIZE(p->mm->rss);
-               }
-               if (!--p->swap_cnt)
-                       swap_task++;
-               switch (swap_out_process(p, limit)) {
-                       case 0:
-                               if (p->swap_cnt)
-                                       swap_task++;
-                               break;
-                       case 1:
-                               return 1;
-                       default:
-                               break;
-               }
-       }
-       return 0;
-}
-
-/*
- * We are much more aggressive about trying to swap out than we used
- * to be.  This works out OK, because we now do proper aging on page
- * contents. 
- */
-static int try_to_free_page(int priority, unsigned long limit)
-{
-       static int state = 0;
-       int i=6;
-
-       switch (state) {
-               do {
-               case 0:
-                       if (priority != GFP_NOBUFFER && shrink_buffers(i, limit))
-                               return 1;
-                       state = 1;
-               case 1:
-                       if (shm_swap(i, limit))
-                               return 1;
-                       state = 2;
-               case 2:
-                       if (shrink_mmap(i, limit))
-                               return 1;
-                       state = 3;
-               default:
-                       if (swap_out(i, limit))
-                               return 1;
-                       state = 0;
-               } while(i--);
-       }
-       return 0;
-}
-
-static inline void add_mem_queue(struct mem_list * head, struct mem_list * entry)
-{
-       entry->prev = head;
-       (entry->next = head->next)->prev = entry;
-       head->next = entry;
-}
-
-static inline void remove_mem_queue(struct mem_list * head, struct mem_list * entry)
-{
-       struct mem_list * next = entry->next;
-       (next->prev = entry->prev)->next = next;
-}
-
-/*
- * Free_page() adds the page to the free lists. This is optimized for
- * fast normal cases (no error jumps taken normally).
- *
- * The way to optimize jumps for gcc-2.2.2 is to:
- *  - select the "normal" case and put it inside the if () { XXX }
- *  - no else-statements if you can avoid them
- *
- * With the above two rules, you get a straight-line execution path
- * for the normal case, giving better asm-code.
- *
- * free_page() may sleep since the page being freed may be a buffer
- * page or present in the swap cache. It will not sleep, however,
- * for a freshly allocated page (get_free_page()).
- */
-
-/*
- * Buddy system. Hairy. You really aren't expected to understand this
- */
-static inline void free_pages_ok(unsigned long addr, unsigned long order)
-{
-       unsigned long index = MAP_NR(addr) >> (1 + order);
-       unsigned long mask = PAGE_MASK << order;
-
-       addr &= mask;
-       nr_free_pages += 1 << order;
-       while (order < NR_MEM_LISTS-1) {
-               if (!change_bit(index, free_area_map[order]))
-                       break;
-               remove_mem_queue(free_area_list+order, (struct mem_list *) (addr ^ (1+~mask)));
-               order++;
-               index >>= 1;
-               mask <<= 1;
-               addr &= mask;
-       }
-       add_mem_queue(free_area_list+order, (struct mem_list *) addr);
-}
-
-static inline void check_free_buffers(unsigned long addr)
-{
-       struct buffer_head * bh;
-
-       bh = buffer_pages[MAP_NR(addr)];
-       if (bh) {
-               struct buffer_head *tmp = bh;
-               do {
-                       if (tmp->b_list == BUF_SHARED
-                           && tmp->b_dev != B_FREE)
-                               refile_buffer(tmp);
-                       tmp = tmp->b_this_page;
-               } while (tmp != bh);
-       }
-}
-
-void free_pages(unsigned long addr, unsigned long order)
-{
-       if (MAP_NR(addr) < MAP_NR(high_memory)) {
-               unsigned long flag;
-               mem_map_t * map = mem_map + MAP_NR(addr);
-               if (map->reserved)
-                       return;
-               if (map->count) {
-                       save_flags(flag);
-                       cli();
-                       if (!--map->count) {
-                               free_pages_ok(addr, order);
-                               delete_from_swap_cache(addr);
-                       }
-                       restore_flags(flag);
-                       if (map->count == 1)
-                               check_free_buffers(addr);
-                       return;
-               }
-               printk("Trying to free free memory (%08lx): memory probably corrupted\n",addr);
-               printk("PC = %p\n", __builtin_return_address(0));
-               return;
-       }
-}
-
-/*
- * Some ugly macros to speed up __get_free_pages()..
- */
-#define RMQUEUE(order, limit) \
-do { struct mem_list * queue = free_area_list+order; \
-     unsigned long new_order = order; \
-       do { struct mem_list *prev = queue, *ret; \
-               while (queue != (ret = prev->next)) { \
-                       if ((unsigned long) ret < (limit)) { \
-                               (prev->next = ret->next)->prev = prev; \
-                               mark_used((unsigned long) ret, new_order); \
-                               nr_free_pages -= 1 << order; \
-                               restore_flags(flags); \
-                               EXPAND(ret, order, new_order); \
-                               return (unsigned long) ret; \
-                       } \
-                       prev = ret; \
-               } \
-               new_order++; queue++; \
-       } while (new_order < NR_MEM_LISTS); \
-} while (0)
-
-static inline int mark_used(unsigned long addr, unsigned long order)
-{
-       return change_bit(MAP_NR(addr) >> (1+order), free_area_map[order]);
-}
-
-#define EXPAND(addr,low,high) \
-do { unsigned long size = PAGE_SIZE << high; \
-       while (high > low) { \
-               high--; size >>= 1; cli(); \
-               add_mem_queue(free_area_list+high, addr); \
-               mark_used((unsigned long) addr, high); \
-               restore_flags(flags); \
-               addr = (struct mem_list *) (size + (unsigned long) addr); \
-       } mem_map[MAP_NR((unsigned long) addr)].count = 1; \
-       mem_map[MAP_NR((unsigned long) addr)].age = PAGE_INITIAL_AGE; \
-} while (0)
-
-unsigned long __get_free_pages(int priority, unsigned long order, unsigned long limit)
-{
-       unsigned long flags;
-       int reserved_pages;
-
-       if (order >= NR_MEM_LISTS)
-               return 0;
-       if (intr_count && priority != GFP_ATOMIC) {
-               static int count = 0;
-               if (++count < 5) {
-                       printk("gfp called nonatomically from interrupt %p\n",
-                               __builtin_return_address(0));
-                       priority = GFP_ATOMIC;
-               }
-       }
-       reserved_pages = 5;
-       if (priority != GFP_NFS)
-               reserved_pages = min_free_pages;
-       save_flags(flags);
-repeat:
-       cli();
-       if ((priority==GFP_ATOMIC) || nr_free_pages > reserved_pages) {
-               RMQUEUE(order, limit);
-               restore_flags(flags);
-               return 0;
-       }
-       restore_flags(flags);
-       if (priority != GFP_BUFFER && try_to_free_page(priority, limit))
-               goto repeat;
-       return 0;
-}
-
-/*
- * Show free area list (used inside shift_scroll-lock stuff)
- * We also calculate the percentage fragmentation. We do this by counting the
- * memory on each free list with the exception of the first item on the list.
- */
-void show_free_areas(void)
-{
-       unsigned long order, flags;
-       unsigned long total = 0;
-
-       printk("Free pages:      %6dkB\n ( ",nr_free_pages<<(PAGE_SHIFT-10));
-       save_flags(flags);
-       cli();
-       for (order=0 ; order < NR_MEM_LISTS; order++) {
-               struct mem_list * tmp;
-               unsigned long nr = 0;
-               for (tmp = free_area_list[order].next ; tmp != free_area_list + order ; tmp = tmp->next) {
-                       nr ++;
-               }
-               total += nr * ((PAGE_SIZE>>10) << order);
-               printk("%lu*%lukB ", nr, (PAGE_SIZE>>10) << order);
-       }
-       restore_flags(flags);
-       printk("= %lukB)\n", total);
-#ifdef SWAP_CACHE_INFO
-       show_swap_cache_info();
-#endif 
-}
-
-/*
- * Trying to stop swapping from a file is fraught with races, so
- * we repeat quite a bit here when we have to pause. swapoff()
- * isn't exactly timing-critical, so who cares (but this is /really/
- * inefficient, ugh).
- *
- * We return 1 after having slept, which makes the process start over
- * from the beginning for this process..
- */
-static inline int unuse_pte(struct vm_area_struct * vma, unsigned long address,
-       pte_t *dir, unsigned int type, unsigned long page)
-{
-       pte_t pte = *dir;
-
-       if (pte_none(pte))
-               return 0;
-       if (pte_present(pte)) {
-               unsigned long page = pte_page(pte);
-               if (page >= high_memory)
-                       return 0;
-               if (!in_swap_cache(page))
-                       return 0;
-               if (SWP_TYPE(in_swap_cache(page)) != type)
-                       return 0;
-               delete_from_swap_cache(page);
-               set_pte(dir, pte_mkdirty(pte));
-               return 0;
-       }
-       if (SWP_TYPE(pte_val(pte)) != type)
-               return 0;
-       read_swap_page(pte_val(pte), (char *) page);
-       if (pte_val(*dir) != pte_val(pte)) {
-               free_page(page);
-               return 1;
-       }
-       set_pte(dir, pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))));
-       ++vma->vm_mm->rss;
-       swap_free(pte_val(pte));
-       return 1;
-}
-
-static inline int unuse_pmd(struct vm_area_struct * vma, pmd_t *dir,
-       unsigned long address, unsigned long size, unsigned long offset,
-       unsigned int type, unsigned long page)
-{
-       pte_t * pte;
-       unsigned long end;
-
-       if (pmd_none(*dir))
-               return 0;
-       if (pmd_bad(*dir)) {
-               printk("unuse_pmd: bad pmd (%08lx)\n", pmd_val(*dir));
-               pmd_clear(dir);
-               return 0;
-       }
-       pte = pte_offset(dir, address);
-       offset += address & PMD_MASK;
-       address &= ~PMD_MASK;
-       end = address + size;
-       if (end > PMD_SIZE)
-               end = PMD_SIZE;
-       do {
-               if (unuse_pte(vma, offset+address-vma->vm_start, pte, type, page))
-                       return 1;
-               address += PAGE_SIZE;
-               pte++;
-       } while (address < end);
-       return 0;
-}
-
-static inline int unuse_pgd(struct vm_area_struct * vma, pgd_t *dir,
-       unsigned long address, unsigned long size,
-       unsigned int type, unsigned long page)
-{
-       pmd_t * pmd;
-       unsigned long offset, end;
-
-       if (pgd_none(*dir))
-               return 0;
-       if (pgd_bad(*dir)) {
-               printk("unuse_pgd: bad pgd (%08lx)\n", pgd_val(*dir));
-               pgd_clear(dir);
-               return 0;
-       }
-       pmd = pmd_offset(dir, address);
-       offset = address & PGDIR_MASK;
-       address &= ~PGDIR_MASK;
-       end = address + size;
-       if (end > PGDIR_SIZE)
-               end = PGDIR_SIZE;
-       do {
-               if (unuse_pmd(vma, pmd, address, end - address, offset, type, page))
-                       return 1;
-               address = (address + PMD_SIZE) & PMD_MASK;
-               pmd++;
-       } while (address < end);
-       return 0;
-}
-
-static int unuse_vma(struct vm_area_struct * vma, pgd_t *pgdir,
-       unsigned long start, unsigned long end,
-       unsigned int type, unsigned long page)
-{
-       while (start < end) {
-               if (unuse_pgd(vma, pgdir, start, end - start, type, page))
-                       return 1;
-               start = (start + PGDIR_SIZE) & PGDIR_MASK;
-               pgdir++;
-       }
-       return 0;
-}
-
-static int unuse_process(struct task_struct * p, unsigned int type, unsigned long page)
-{
-       struct vm_area_struct* vma;
-
-       /*
-        * Go through process' page directory.
-        */
-       if (!p->mm || pgd_inuse(p->mm->pgd))
-               return 0;
-       vma = p->mm->mmap;
-       while (vma) {
-               pgd_t * pgd = pgd_offset(p->mm, vma->vm_start);
-               if (unuse_vma(vma, pgd, vma->vm_start, vma->vm_end, type, page))
-                       return 1;
-               vma = vma->vm_next;
-       }
-       return 0;
-}
-
-/*
- * To avoid races, we repeat for each process after having
- * swapped something in. That gets rid of a few pesky races,
- * and "swapoff" isn't exactly timing critical.
- */
-static int try_to_unuse(unsigned int type)
-{
-       int nr;
-       unsigned long page = get_free_page(GFP_KERNEL);
-
-       if (!page)
-               return -ENOMEM;
-       nr = 0;
-       while (nr < NR_TASKS) {
-               if (task[nr]) {
-                       if (unuse_process(task[nr], type, page)) {
-                               page = get_free_page(GFP_KERNEL);
-                               if (!page)
-                                       return -ENOMEM;
-                               continue;
-                       }
-               }
-               nr++;
-       }
-       free_page(page);
-       return 0;
-}
-
-asmlinkage int sys_swapoff(const char * specialfile)
-{
-       struct swap_info_struct * p;
-       struct inode * inode;
-       struct file filp;
-       int i, type, prev;
-
-       if (!suser())
-               return -EPERM;
-       i = namei(specialfile,&inode);
-       if (i)
-               return i;
-       prev = -1;
-       for (type = swap_list.head; type >= 0; type = swap_info[type].next) {
-               p = swap_info + type;
-               if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
-                       if (p->swap_file) {
-                               if (p->swap_file == inode)
-                                 break;
-                       } else {
-                               if (S_ISBLK(inode->i_mode)
-                                   && (p->swap_device == inode->i_rdev))
-                                 break;
-                       }
-               }
-               prev = type;
-       }
-       if (type < 0){
-               iput(inode);
-               return -EINVAL;
-       }
-       if (prev < 0) {
-               swap_list.head = p->next;
-       } else {
-               swap_info[prev].next = p->next;
-       }
-       if (type == swap_list.next) {
-               /* just pick something that's safe... */
-               swap_list.next = swap_list.head;
-       }
-       p->flags = SWP_USED;
-       i = try_to_unuse(type);
-       if (i) {
-               iput(inode);
-               p->flags = SWP_WRITEOK;
-               return i;
-       }
-
-       if(p->swap_device){
-               memset(&filp, 0, sizeof(filp));         
-               filp.f_inode = inode;
-               filp.f_mode = 3; /* read write */
-               /* open it again to get fops */
-               if( !blkdev_open(inode, &filp) &&
-                  filp.f_op && filp.f_op->release){
-                       filp.f_op->release(inode,&filp);
-                       filp.f_op->release(inode,&filp);
-               }
-       }
-       iput(inode);
-
-       nr_swap_pages -= p->pages;
-       iput(p->swap_file);
-       p->swap_file = NULL;
-       p->swap_device = 0;
-       vfree(p->swap_map);
-       p->swap_map = NULL;
-       free_page((long) p->swap_lockmap);
-       p->swap_lockmap = NULL;
-       p->flags = 0;
-       return 0;
-}
-
-/*
- * Written 01/25/92 by Simmule Turner, heavily changed by Linus.
- *
- * The swapon system call
- */
-asmlinkage int sys_swapon(const char * specialfile, int swap_flags)
-{
-       struct swap_info_struct * p;
-       struct inode * swap_inode;
-       unsigned int type;
-       int i, j, prev;
-       int error;
-       struct file filp;
-       static int least_priority = 0;
-
-       memset(&filp, 0, sizeof(filp));
-       if (!suser())
-               return -EPERM;
-       p = swap_info;
-       for (type = 0 ; type < nr_swapfiles ; type++,p++)
-               if (!(p->flags & SWP_USED))
-                       break;
-       if (type >= MAX_SWAPFILES)
-               return -EPERM;
-       if (type >= nr_swapfiles)
-               nr_swapfiles = type+1;
-       p->flags = SWP_USED;
-       p->swap_file = NULL;
-       p->swap_device = 0;
-       p->swap_map = NULL;
-       p->swap_lockmap = NULL;
-       p->lowest_bit = 0;
-       p->highest_bit = 0;
-       p->max = 1;
-       p->next = -1;
-       if (swap_flags & SWAP_FLAG_PREFER) {
-               p->prio =
-                 (swap_flags & SWAP_FLAG_PRIO_MASK)>>SWAP_FLAG_PRIO_SHIFT;
-       } else {
-               p->prio = --least_priority;
-       }
-       error = namei(specialfile,&swap_inode);
-       if (error)
-               goto bad_swap_2;
-       p->swap_file = swap_inode;
-       error = -EBUSY;
-       if (swap_inode->i_count != 1)
-               goto bad_swap_2;
-       error = -EINVAL;
-
-       if (S_ISBLK(swap_inode->i_mode)) {
-               p->swap_device = swap_inode->i_rdev;
-
-               filp.f_inode = swap_inode;
-               filp.f_mode = 3; /* read write */
-               error = blkdev_open(swap_inode, &filp);
-               p->swap_file = NULL;
-               iput(swap_inode);
-               if(error)
-                       goto bad_swap_2;
-               error = -ENODEV;
-               if (!p->swap_device)
-                       goto bad_swap;
-               error = -EBUSY;
-               for (i = 0 ; i < nr_swapfiles ; i++) {
-                       if (i == type)
-                               continue;
-                       if (p->swap_device == swap_info[i].swap_device)
-                               goto bad_swap;
-               }
-       } else if (!S_ISREG(swap_inode->i_mode))
-               goto bad_swap;
-       p->swap_lockmap = (unsigned char *) get_free_page(GFP_USER);
-       if (!p->swap_lockmap) {
-               printk("Unable to start swapping: out of memory :-)\n");
-               error = -ENOMEM;
-               goto bad_swap;
-       }
-       read_swap_page(SWP_ENTRY(type,0), (char *) p->swap_lockmap);
-       if (memcmp("SWAP-SPACE",p->swap_lockmap+PAGE_SIZE-10,10)) {
-               printk("Unable to find swap-space signature\n");
-               error = -EINVAL;
-               goto bad_swap;
-       }
-       memset(p->swap_lockmap+PAGE_SIZE-10,0,10);
-       j = 0;
-       p->lowest_bit = 0;
-       p->highest_bit = 0;
-       for (i = 1 ; i < 8*PAGE_SIZE ; i++) {
-               if (test_bit(i,p->swap_lockmap)) {
-                       if (!p->lowest_bit)
-                               p->lowest_bit = i;
-                       p->highest_bit = i;
-                       p->max = i+1;
-                       j++;
-               }
-       }
-       if (!j) {
-               printk("Empty swap-file\n");
-               error = -EINVAL;
-               goto bad_swap;
-       }
-       p->swap_map = (unsigned char *) vmalloc(p->max);
-       if (!p->swap_map) {
-               error = -ENOMEM;
-               goto bad_swap;
-       }
-       for (i = 1 ; i < p->max ; i++) {
-               if (test_bit(i,p->swap_lockmap))
-                       p->swap_map[i] = 0;
-               else
-                       p->swap_map[i] = 0x80;
-       }
-       p->swap_map[0] = 0x80;
-       memset(p->swap_lockmap,0,PAGE_SIZE);
-       p->flags = SWP_WRITEOK;
-       p->pages = j;
-       nr_swap_pages += j;
-       printk("Adding Swap: %dk swap-space\n",j<<(PAGE_SHIFT-10));
-
-       /* insert swap space into swap_list: */
-       prev = -1;
-       for (i = swap_list.head; i >= 0; i = swap_info[i].next) {
-               if (p->prio >= swap_info[i].prio) {
-                       break;
-               }
-               prev = i;
-       }
-       p->next = i;
-       if (prev < 0) {
-               swap_list.head = swap_list.next = p - swap_info;
-       } else {
-               swap_info[prev].next = p - swap_info;
-       }
-       return 0;
-bad_swap:
-       if(filp.f_op && filp.f_op->release)
-               filp.f_op->release(filp.f_inode,&filp);
-bad_swap_2:
-       free_page((long) p->swap_lockmap);
-       vfree(p->swap_map);
-       iput(p->swap_file);
-       p->swap_device = 0;
-       p->swap_file = NULL;
-       p->swap_map = NULL;
-       p->swap_lockmap = NULL;
-       p->flags = 0;
-       return error;
-}
-
-void si_swapinfo(struct sysinfo *val)
-{
-       unsigned int i, j;
-
-       val->freeswap = val->totalswap = 0;
-       for (i = 0; i < nr_swapfiles; i++) {
-               if ((swap_info[i].flags & SWP_WRITEOK) != SWP_WRITEOK)
-                       continue;
-               for (j = 0; j < swap_info[i].max; ++j)
-                       switch (swap_info[i].swap_map[j]) {
-                               case 128:
-                                       continue;
-                               case 0:
-                                       ++val->freeswap;
-                               default:
-                                       ++val->totalswap;
-                       }
-       }
-       val->freeswap <<= PAGE_SHIFT;
-       val->totalswap <<= PAGE_SHIFT;
-       return;
-}
-
-#define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
-
-/*
- * set up the free-area data structures:
- *   - mark all pages reserved
- *   - mark all memory queues empty
- *   - clear the memory bitmaps
- */
-unsigned long free_area_init(unsigned long start_mem, unsigned long end_mem)
-{
-       mem_map_t * p;
-       unsigned long mask = PAGE_MASK;
-       int i;
-
-       /*
-        * select nr of pages we try to keep free for important stuff
-        * with a minimum of 16 pages. This is totally arbitrary
-        */
-       i = (end_mem - PAGE_OFFSET) >> (PAGE_SHIFT+6);
-       if (i < 16)
-               i = 16;
-       min_free_pages = i;
-       start_mem = init_swap_cache(start_mem, end_mem);
-       mem_map = (mem_map_t *) start_mem;
-       p = mem_map + MAP_NR(end_mem);
-       start_mem = LONG_ALIGN((unsigned long) p);
-       memset(mem_map, 0, start_mem - (unsigned long) mem_map);
-       do {
-               --p;
-               p->reserved = 1;
-       } while (p > mem_map);
-
-       for (i = 0 ; i < NR_MEM_LISTS ; i++) {
-               unsigned long bitmap_size;
-               free_area_list[i].prev = free_area_list[i].next = &free_area_list[i];
-               mask += mask;
-               end_mem = (end_mem + ~mask) & mask;
-               bitmap_size = (end_mem - PAGE_OFFSET) >> (PAGE_SHIFT + i);
-               bitmap_size = (bitmap_size + 7) >> 3;
-               bitmap_size = LONG_ALIGN(bitmap_size);
-               free_area_map[i] = (unsigned int *) start_mem;
-               memset((void *) start_mem, 0, bitmap_size);
-               start_mem += bitmap_size;
-       }
-       return start_mem;
-}
diff --git a/mm/swap_state.c b/mm/swap_state.c
new file mode 100644 (file)
index 0000000..c4b1210
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ *  linux/mm/swap_state.c
+ *
+ *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *  Swap reorganised 29.12.95, Stephen Tweedie
+ */
+
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/head.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/swap.h>
+#include <linux/fs.h>
+#include <linux/swapctl.h>
+
+#include <asm/dma.h>
+#include <asm/system.h> /* for cli()/sti() */
+#include <asm/segment.h> /* for memcpy_to/fromfs */
+#include <asm/bitops.h>
+#include <asm/pgtable.h>
+
+/*
+ * To save us from swapping out pages which have just been swapped in and
+ * have not been modified since then, we keep in swap_cache[page>>PAGE_SHIFT]
+ * the swap entry which was last used to fill the page, or zero if the
+ * page does not currently correspond to a page in swap. PAGE_DIRTY makes
+ * this info useless.
+ */
+unsigned long *swap_cache;
+
+#ifdef SWAP_CACHE_INFO
+unsigned long swap_cache_add_total = 0;
+unsigned long swap_cache_add_success = 0;
+unsigned long swap_cache_del_total = 0;
+unsigned long swap_cache_del_success = 0;
+unsigned long swap_cache_find_total = 0;
+unsigned long swap_cache_find_success = 0;
+
+void show_swap_cache_info(void)
+{
+       printk("Swap cache: add %ld/%ld, delete %ld/%ld, find %ld/%ld\n",
+               swap_cache_add_total, swap_cache_add_success, 
+               swap_cache_del_total, swap_cache_del_success,
+               swap_cache_find_total, swap_cache_find_success);
+}
+#endif
+
+int add_to_swap_cache(unsigned long addr, unsigned long entry)
+{
+       struct swap_info_struct * p = &swap_info[SWP_TYPE(entry)];
+
+#ifdef SWAP_CACHE_INFO
+       swap_cache_add_total++;
+#endif
+       if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
+               entry = xchg(swap_cache + MAP_NR(addr), entry);
+               if (entry)  {
+                       printk("swap_cache: replacing non-NULL entry\n");
+               }
+#ifdef SWAP_CACHE_INFO
+               swap_cache_add_success++;
+#endif
+               return 1;
+       }
+       return 0;
+}
+
+unsigned long init_swap_cache(unsigned long mem_start,
+       unsigned long mem_end)
+{
+       unsigned long swap_cache_size;
+
+       mem_start = (mem_start + 15) & ~15;
+       swap_cache = (unsigned long *) mem_start;
+       swap_cache_size = MAP_NR(mem_end);
+       memset(swap_cache, 0, swap_cache_size * sizeof (unsigned long));
+       return (unsigned long) (swap_cache + swap_cache_size);
+}
+
+void swap_duplicate(unsigned long entry)
+{
+       struct swap_info_struct * p;
+       unsigned long offset, type;
+
+       if (!entry)
+               return;
+       offset = SWP_OFFSET(entry);
+       type = SWP_TYPE(entry);
+       if (type & SHM_SWP_TYPE)
+               return;
+       if (type >= nr_swapfiles) {
+               printk("Trying to duplicate nonexistent swap-page\n");
+               return;
+       }
+       p = type + swap_info;
+       if (offset >= p->max) {
+               printk("swap_duplicate: weirdness\n");
+               return;
+       }
+       if (!p->swap_map[offset]) {
+               printk("swap_duplicate: trying to duplicate unused page\n");
+               return;
+       }
+       p->swap_map[offset]++;
+       return;
+}
+
diff --git a/mm/swapfile.c b/mm/swapfile.c
new file mode 100644 (file)
index 0000000..c2ad850
--- /dev/null
@@ -0,0 +1,522 @@
+/*
+ *  linux/mm/swapfile.c
+ *
+ *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *  Swap reorganised 29.12.95, Stephen Tweedie
+ */
+
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/head.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/swap.h>
+#include <linux/fs.h>
+#include <linux/swapctl.h>
+
+#include <asm/dma.h>
+#include <asm/system.h> /* for cli()/sti() */
+#include <asm/segment.h> /* for memcpy_to/fromfs */
+#include <asm/bitops.h>
+#include <asm/pgtable.h>
+
+int nr_swapfiles = 0;
+static struct {
+       int head;       /* head of priority-ordered swapfile list */
+       int next;       /* swapfile to be used next */
+} swap_list = {-1, -1};
+
+struct swap_info_struct swap_info[MAX_SWAPFILES];
+
+unsigned long get_swap_page(void)
+{
+       struct swap_info_struct * p;
+       unsigned long offset, entry;
+       int type, wrapped = 0;
+
+       type = swap_list.next;
+       if (type < 0)
+         return 0;
+
+       while (1) {
+               p = &swap_info[type];
+               if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
+                       for (offset = p->lowest_bit; offset <= p->highest_bit ; offset++) {
+                               if (p->swap_map[offset])
+                                 continue;
+                               if (test_bit(offset, p->swap_lockmap))
+                                 continue;
+                               p->swap_map[offset] = 1;
+                               nr_swap_pages--;
+                               if (offset == p->highest_bit)
+                                 p->highest_bit--;
+                               p->lowest_bit = offset;
+                               entry = SWP_ENTRY(type,offset);
+
+                               type = swap_info[type].next;
+                               if (type < 0 || p->prio != swap_info[type].prio) {
+                                   swap_list.next = swap_list.head;
+                               } else {
+                                   swap_list.next = type;
+                               }
+                               return entry;
+                       }
+               }
+               type = p->next;
+               if (!wrapped) {
+                       if (type < 0 || p->prio != swap_info[type].prio) {
+                               type = swap_list.head;
+                               wrapped = 1;
+                       }
+               } else if (type < 0) {
+                       return 0;       /* out of swap space */
+               }
+       }
+}
+
+void swap_free(unsigned long entry)
+{
+       struct swap_info_struct * p;
+       unsigned long offset, type;
+
+       if (!entry)
+               return;
+       type = SWP_TYPE(entry);
+       if (type & SHM_SWP_TYPE)
+               return;
+       if (type >= nr_swapfiles) {
+               printk("Trying to free nonexistent swap-page\n");
+               return;
+       }
+       p = & swap_info[type];
+       offset = SWP_OFFSET(entry);
+       if (offset >= p->max) {
+               printk("swap_free: weirdness\n");
+               return;
+       }
+       if (!(p->flags & SWP_USED)) {
+               printk("Trying to free swap from unused swap-device\n");
+               return;
+       }
+       if (offset < p->lowest_bit)
+               p->lowest_bit = offset;
+       if (offset > p->highest_bit)
+               p->highest_bit = offset;
+       if (!p->swap_map[offset])
+               printk("swap_free: swap-space map bad (entry %08lx)\n",entry);
+       else
+               if (!--p->swap_map[offset])
+                       nr_swap_pages++;
+       if (p->prio > swap_info[swap_list.next].prio) {
+           swap_list.next = swap_list.head;
+       }
+}
+
+/*
+ * Trying to stop swapping from a file is fraught with races, so
+ * we repeat quite a bit here when we have to pause. swapoff()
+ * isn't exactly timing-critical, so who cares (but this is /really/
+ * inefficient, ugh).
+ *
+ * We return 1 after having slept, which makes the process start over
+ * from the beginning for this process..
+ */
+static inline int unuse_pte(struct vm_area_struct * vma, unsigned long address,
+       pte_t *dir, unsigned int type, unsigned long page)
+{
+       pte_t pte = *dir;
+
+       if (pte_none(pte))
+               return 0;
+       if (pte_present(pte)) {
+               unsigned long page = pte_page(pte);
+               if (page >= high_memory)
+                       return 0;
+               if (!in_swap_cache(page))
+                       return 0;
+               if (SWP_TYPE(in_swap_cache(page)) != type)
+                       return 0;
+               delete_from_swap_cache(page);
+               set_pte(dir, pte_mkdirty(pte));
+               return 0;
+       }
+       if (SWP_TYPE(pte_val(pte)) != type)
+               return 0;
+       read_swap_page(pte_val(pte), (char *) page);
+       if (pte_val(*dir) != pte_val(pte)) {
+               free_page(page);
+               return 1;
+       }
+       set_pte(dir, pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))));
+       ++vma->vm_mm->rss;
+       swap_free(pte_val(pte));
+       return 1;
+}
+
+static inline int unuse_pmd(struct vm_area_struct * vma, pmd_t *dir,
+       unsigned long address, unsigned long size, unsigned long offset,
+       unsigned int type, unsigned long page)
+{
+       pte_t * pte;
+       unsigned long end;
+
+       if (pmd_none(*dir))
+               return 0;
+       if (pmd_bad(*dir)) {
+               printk("unuse_pmd: bad pmd (%08lx)\n", pmd_val(*dir));
+               pmd_clear(dir);
+               return 0;
+       }
+       pte = pte_offset(dir, address);
+       offset += address & PMD_MASK;
+       address &= ~PMD_MASK;
+       end = address + size;
+       if (end > PMD_SIZE)
+               end = PMD_SIZE;
+       do {
+               if (unuse_pte(vma, offset+address-vma->vm_start, pte, type, page))
+                       return 1;
+               address += PAGE_SIZE;
+               pte++;
+       } while (address < end);
+       return 0;
+}
+
+static inline int unuse_pgd(struct vm_area_struct * vma, pgd_t *dir,
+       unsigned long address, unsigned long size,
+       unsigned int type, unsigned long page)
+{
+       pmd_t * pmd;
+       unsigned long offset, end;
+
+       if (pgd_none(*dir))
+               return 0;
+       if (pgd_bad(*dir)) {
+               printk("unuse_pgd: bad pgd (%08lx)\n", pgd_val(*dir));
+               pgd_clear(dir);
+               return 0;
+       }
+       pmd = pmd_offset(dir, address);
+       offset = address & PGDIR_MASK;
+       address &= ~PGDIR_MASK;
+       end = address + size;
+       if (end > PGDIR_SIZE)
+               end = PGDIR_SIZE;
+       do {
+               if (unuse_pmd(vma, pmd, address, end - address, offset, type, page))
+                       return 1;
+               address = (address + PMD_SIZE) & PMD_MASK;
+               pmd++;
+       } while (address < end);
+       return 0;
+}
+
+static int unuse_vma(struct vm_area_struct * vma, pgd_t *pgdir,
+       unsigned long start, unsigned long end,
+       unsigned int type, unsigned long page)
+{
+       while (start < end) {
+               if (unuse_pgd(vma, pgdir, start, end - start, type, page))
+                       return 1;
+               start = (start + PGDIR_SIZE) & PGDIR_MASK;
+               pgdir++;
+       }
+       return 0;
+}
+
+static int unuse_process(struct task_struct * p, unsigned int type, unsigned long page)
+{
+       struct vm_area_struct* vma;
+
+       /*
+        * Go through process' page directory.
+        */
+       if (!p->mm || pgd_inuse(p->mm->pgd))
+               return 0;
+       vma = p->mm->mmap;
+       while (vma) {
+               pgd_t * pgd = pgd_offset(p->mm, vma->vm_start);
+               if (unuse_vma(vma, pgd, vma->vm_start, vma->vm_end, type, page))
+                       return 1;
+               vma = vma->vm_next;
+       }
+       return 0;
+}
+
+/*
+ * To avoid races, we repeat for each process after having
+ * swapped something in. That gets rid of a few pesky races,
+ * and "swapoff" isn't exactly timing critical.
+ */
+static int try_to_unuse(unsigned int type)
+{
+       int nr;
+       unsigned long page = get_free_page(GFP_KERNEL);
+
+       if (!page)
+               return -ENOMEM;
+       nr = 0;
+       while (nr < NR_TASKS) {
+               if (task[nr]) {
+                       if (unuse_process(task[nr], type, page)) {
+                               page = get_free_page(GFP_KERNEL);
+                               if (!page)
+                                       return -ENOMEM;
+                               continue;
+                       }
+               }
+               nr++;
+       }
+       free_page(page);
+       return 0;
+}
+
+asmlinkage int sys_swapoff(const char * specialfile)
+{
+       struct swap_info_struct * p;
+       struct inode * inode;
+       struct file filp;
+       int i, type, prev;
+
+       if (!suser())
+               return -EPERM;
+       i = namei(specialfile,&inode);
+       if (i)
+               return i;
+       prev = -1;
+       for (type = swap_list.head; type >= 0; type = swap_info[type].next) {
+               p = swap_info + type;
+               if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
+                       if (p->swap_file) {
+                               if (p->swap_file == inode)
+                                 break;
+                       } else {
+                               if (S_ISBLK(inode->i_mode)
+                                   && (p->swap_device == inode->i_rdev))
+                                 break;
+                       }
+               }
+               prev = type;
+       }
+       if (type < 0){
+               iput(inode);
+               return -EINVAL;
+       }
+       if (prev < 0) {
+               swap_list.head = p->next;
+       } else {
+               swap_info[prev].next = p->next;
+       }
+       if (type == swap_list.next) {
+               /* just pick something that's safe... */
+               swap_list.next = swap_list.head;
+       }
+       p->flags = SWP_USED;
+       i = try_to_unuse(type);
+       if (i) {
+               iput(inode);
+               p->flags = SWP_WRITEOK;
+               return i;
+       }
+
+       if(p->swap_device){
+               memset(&filp, 0, sizeof(filp));         
+               filp.f_inode = inode;
+               filp.f_mode = 3; /* read write */
+               /* open it again to get fops */
+               if( !blkdev_open(inode, &filp) &&
+                  filp.f_op && filp.f_op->release){
+                       filp.f_op->release(inode,&filp);
+                       filp.f_op->release(inode,&filp);
+               }
+       }
+       iput(inode);
+
+       nr_swap_pages -= p->pages;
+       iput(p->swap_file);
+       p->swap_file = NULL;
+       p->swap_device = 0;
+       vfree(p->swap_map);
+       p->swap_map = NULL;
+       free_page((long) p->swap_lockmap);
+       p->swap_lockmap = NULL;
+       p->flags = 0;
+       return 0;
+}
+
+/*
+ * Written 01/25/92 by Simmule Turner, heavily changed by Linus.
+ *
+ * The swapon system call
+ */
+asmlinkage int sys_swapon(const char * specialfile, int swap_flags)
+{
+       struct swap_info_struct * p;
+       struct inode * swap_inode;
+       unsigned int type;
+       int i, j, prev;
+       int error;
+       struct file filp;
+       static int least_priority = 0;
+
+       memset(&filp, 0, sizeof(filp));
+       if (!suser())
+               return -EPERM;
+       p = swap_info;
+       for (type = 0 ; type < nr_swapfiles ; type++,p++)
+               if (!(p->flags & SWP_USED))
+                       break;
+       if (type >= MAX_SWAPFILES)
+               return -EPERM;
+       if (type >= nr_swapfiles)
+               nr_swapfiles = type+1;
+       p->flags = SWP_USED;
+       p->swap_file = NULL;
+       p->swap_device = 0;
+       p->swap_map = NULL;
+       p->swap_lockmap = NULL;
+       p->lowest_bit = 0;
+       p->highest_bit = 0;
+       p->max = 1;
+       p->next = -1;
+       if (swap_flags & SWAP_FLAG_PREFER) {
+               p->prio =
+                 (swap_flags & SWAP_FLAG_PRIO_MASK)>>SWAP_FLAG_PRIO_SHIFT;
+       } else {
+               p->prio = --least_priority;
+       }
+       error = namei(specialfile,&swap_inode);
+       if (error)
+               goto bad_swap_2;
+       p->swap_file = swap_inode;
+       error = -EBUSY;
+       if (swap_inode->i_count != 1)
+               goto bad_swap_2;
+       error = -EINVAL;
+
+       if (S_ISBLK(swap_inode->i_mode)) {
+               p->swap_device = swap_inode->i_rdev;
+
+               filp.f_inode = swap_inode;
+               filp.f_mode = 3; /* read write */
+               error = blkdev_open(swap_inode, &filp);
+               p->swap_file = NULL;
+               iput(swap_inode);
+               if(error)
+                       goto bad_swap_2;
+               error = -ENODEV;
+               if (!p->swap_device)
+                       goto bad_swap;
+               error = -EBUSY;
+               for (i = 0 ; i < nr_swapfiles ; i++) {
+                       if (i == type)
+                               continue;
+                       if (p->swap_device == swap_info[i].swap_device)
+                               goto bad_swap;
+               }
+       } else if (!S_ISREG(swap_inode->i_mode))
+               goto bad_swap;
+       p->swap_lockmap = (unsigned char *) get_free_page(GFP_USER);
+       if (!p->swap_lockmap) {
+               printk("Unable to start swapping: out of memory :-)\n");
+               error = -ENOMEM;
+               goto bad_swap;
+       }
+       read_swap_page(SWP_ENTRY(type,0), (char *) p->swap_lockmap);
+       if (memcmp("SWAP-SPACE",p->swap_lockmap+PAGE_SIZE-10,10)) {
+               printk("Unable to find swap-space signature\n");
+               error = -EINVAL;
+               goto bad_swap;
+       }
+       memset(p->swap_lockmap+PAGE_SIZE-10,0,10);
+       j = 0;
+       p->lowest_bit = 0;
+       p->highest_bit = 0;
+       for (i = 1 ; i < 8*PAGE_SIZE ; i++) {
+               if (test_bit(i,p->swap_lockmap)) {
+                       if (!p->lowest_bit)
+                               p->lowest_bit = i;
+                       p->highest_bit = i;
+                       p->max = i+1;
+                       j++;
+               }
+       }
+       if (!j) {
+               printk("Empty swap-file\n");
+               error = -EINVAL;
+               goto bad_swap;
+       }
+       p->swap_map = (unsigned char *) vmalloc(p->max);
+       if (!p->swap_map) {
+               error = -ENOMEM;
+               goto bad_swap;
+       }
+       for (i = 1 ; i < p->max ; i++) {
+               if (test_bit(i,p->swap_lockmap))
+                       p->swap_map[i] = 0;
+               else
+                       p->swap_map[i] = 0x80;
+       }
+       p->swap_map[0] = 0x80;
+       memset(p->swap_lockmap,0,PAGE_SIZE);
+       p->flags = SWP_WRITEOK;
+       p->pages = j;
+       nr_swap_pages += j;
+       printk("Adding Swap: %dk swap-space\n",j<<(PAGE_SHIFT-10));
+
+       /* insert swap space into swap_list: */
+       prev = -1;
+       for (i = swap_list.head; i >= 0; i = swap_info[i].next) {
+               if (p->prio >= swap_info[i].prio) {
+                       break;
+               }
+               prev = i;
+       }
+       p->next = i;
+       if (prev < 0) {
+               swap_list.head = swap_list.next = p - swap_info;
+       } else {
+               swap_info[prev].next = p - swap_info;
+       }
+       return 0;
+bad_swap:
+       if(filp.f_op && filp.f_op->release)
+               filp.f_op->release(filp.f_inode,&filp);
+bad_swap_2:
+       free_page((long) p->swap_lockmap);
+       vfree(p->swap_map);
+       iput(p->swap_file);
+       p->swap_device = 0;
+       p->swap_file = NULL;
+       p->swap_map = NULL;
+       p->swap_lockmap = NULL;
+       p->flags = 0;
+       return error;
+}
+
+void si_swapinfo(struct sysinfo *val)
+{
+       unsigned int i, j;
+
+       val->freeswap = val->totalswap = 0;
+       for (i = 0; i < nr_swapfiles; i++) {
+               if ((swap_info[i].flags & SWP_WRITEOK) != SWP_WRITEOK)
+                       continue;
+               for (j = 0; j < swap_info[i].max; ++j)
+                       switch (swap_info[i].swap_map[j]) {
+                               case 128:
+                                       continue;
+                               case 0:
+                                       ++val->freeswap;
+                               default:
+                                       ++val->totalswap;
+                       }
+       }
+       val->freeswap <<= PAGE_SHIFT;
+       val->totalswap <<= PAGE_SHIFT;
+       return;
+}
+
diff --git a/mm/vmscan.c b/mm/vmscan.c
new file mode 100644 (file)
index 0000000..016d988
--- /dev/null
@@ -0,0 +1,427 @@
+/*
+ *  linux/mm/vmscan.c
+ *
+ *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  Swap reorganised 29.12.95, 
+ */
+
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/head.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/swap.h>
+#include <linux/fs.h>
+#include <linux/swapctl.h>
+#include <linux/smp_lock.h>
+
+#include <asm/dma.h>
+#include <asm/system.h> /* for cli()/sti() */
+#include <asm/segment.h> /* for memcpy_to/fromfs */
+#include <asm/bitops.h>
+#include <asm/pgtable.h>
+
+/* 
+ * When are we next due for a page scan? 
+ */
+static int next_swap_jiffies = 0;
+
+/* 
+ * How often do we do a pageout scan during normal conditions?
+ * Default is four times a second.
+ */
+int swapout_interval = HZ / 4;
+
+/* 
+ * The wait queue for waking up the pageout daemon:
+ */
+static struct wait_queue * kswapd_wait = NULL;
+
+/* 
+ * We avoid doing a reschedule if the pageout daemon is already awake;
+ */
+static int kswapd_awake = 0;
+
+/*
+ * sysctl-modifiable parameters to control the aggressiveness of the
+ * page-searching within the kswapd page recovery daemon.
+ */
+kswapd_control_t kswapd_ctl = {4, -1, -1, -1, -1};
+
+static void init_swap_timer(void);
+
+/*
+ * The swap-out functions return 1 if they successfully
+ * threw something out, and we got a free page. It returns
+ * zero if it couldn't do anything, and any other value
+ * indicates it decreased rss, but the page was shared.
+ *
+ * NOTE! If it sleeps, it *must* return 1 to make sure we
+ * don't continue with the swap-out. Otherwise we may be
+ * using a process that no longer actually exists (it might
+ * have died while we slept).
+ */
+static inline int try_to_swap_out(struct task_struct * tsk, struct vm_area_struct* vma,
+       unsigned long address, pte_t * page_table, unsigned long limit)
+{
+       pte_t pte;
+       unsigned long entry;
+       unsigned long page;
+       struct page * page_map;
+
+       pte = *page_table;
+       if (!pte_present(pte))
+               return 0;
+       page = pte_page(pte);
+       if (MAP_NR(page) >= MAP_NR(high_memory))
+               return 0;
+       if (page >= limit)
+               return 0;
+
+       page_map = mem_map + MAP_NR(page);
+       if (page_map->reserved)
+               return 0;
+       /* Deal with page aging.  Pages age from being unused; they
+        * rejuvinate on being accessed.  Only swap old pages (age==0
+        * is oldest). */
+       if ((pte_dirty(pte) && delete_from_swap_cache(page)) 
+           || pte_young(pte))  {
+               set_pte(page_table, pte_mkold(pte));
+               touch_page(page_map);
+               return 0;
+       }
+       age_page(page_map);
+       if (page_map->age)
+               return 0;
+       if (pte_dirty(pte)) {
+               if (vma->vm_ops && vma->vm_ops->swapout) {
+                       pid_t pid = tsk->pid;
+                       vma->vm_mm->rss--;
+                       if (vma->vm_ops->swapout(vma, address - vma->vm_start + vma->vm_offset, page_table))
+                               kill_proc(pid, SIGBUS, 1);
+               } else {
+                       if (page_map->count != 1)
+                               return 0;
+                       if (!(entry = get_swap_page()))
+                               return 0;
+                       vma->vm_mm->rss--;
+                       set_pte(page_table, __pte(entry));
+                       invalidate_page(vma, address);
+                       tsk->nswap++;
+                       write_swap_page(entry, (char *) page);
+               }
+               free_page(page);
+               return 1;       /* we slept: the process may not exist any more */
+       }
+        if ((entry = find_in_swap_cache(page)))  {
+               if (page_map->count != 1) {
+                       set_pte(page_table, pte_mkdirty(pte));
+                       printk("Aiee.. duplicated cached swap-cache entry\n");
+                       return 0;
+               }
+               vma->vm_mm->rss--;
+               set_pte(page_table, __pte(entry));
+               invalidate_page(vma, address);
+               free_page(page);
+               return 1;
+       } 
+       vma->vm_mm->rss--;
+       pte_clear(page_table);
+       invalidate_page(vma, address);
+       entry = page_unuse(page);
+       free_page(page);
+       return entry;
+}
+
+/*
+ * A new implementation of swap_out().  We do not swap complete processes,
+ * but only a small number of blocks, before we continue with the next
+ * process.  The number of blocks actually swapped is determined on the
+ * number of page faults, that this process actually had in the last time,
+ * so we won't swap heavily used processes all the time ...
+ *
+ * Note: the priority argument is a hint on much CPU to waste with the
+ *       swap block search, not a hint, of how much blocks to swap with
+ *       each process.
+ *
+ * (C) 1993 Kai Petzke, wpp@marie.physik.tu-berlin.de
+ */
+
+static inline int swap_out_pmd(struct task_struct * tsk, struct vm_area_struct * vma,
+       pmd_t *dir, unsigned long address, unsigned long end, unsigned long limit)
+{
+       pte_t * pte;
+       unsigned long pmd_end;
+
+       if (pmd_none(*dir))
+               return 0;
+       if (pmd_bad(*dir)) {
+               printk("swap_out_pmd: bad pmd (%08lx)\n", pmd_val(*dir));
+               pmd_clear(dir);
+               return 0;
+       }
+       
+       pte = pte_offset(dir, address);
+       
+       pmd_end = (address + PMD_SIZE) & PMD_MASK;
+       if (end > pmd_end)
+               end = pmd_end;
+
+       do {
+               int result;
+               tsk->swap_address = address + PAGE_SIZE;
+               result = try_to_swap_out(tsk, vma, address, pte, limit);
+               if (result)
+                       return result;
+               address += PAGE_SIZE;
+               pte++;
+       } while (address < end);
+       return 0;
+}
+
+static inline int swap_out_pgd(struct task_struct * tsk, struct vm_area_struct * vma,
+       pgd_t *dir, unsigned long address, unsigned long end, unsigned long limit)
+{
+       pmd_t * pmd;
+       unsigned long pgd_end;
+
+       if (pgd_none(*dir))
+               return 0;
+       if (pgd_bad(*dir)) {
+               printk("swap_out_pgd: bad pgd (%08lx)\n", pgd_val(*dir));
+               pgd_clear(dir);
+               return 0;
+       }
+
+       pmd = pmd_offset(dir, address);
+
+       pgd_end = (address + PGDIR_SIZE) & PGDIR_MASK;  
+       if (end > pgd_end)
+               end = pgd_end;
+       
+       do {
+               int result = swap_out_pmd(tsk, vma, pmd, address, end, limit);
+               if (result)
+                       return result;
+               address = (address + PMD_SIZE) & PMD_MASK;
+               pmd++;
+       } while (address < end);
+       return 0;
+}
+
+static int swap_out_vma(struct task_struct * tsk, struct vm_area_struct * vma,
+       pgd_t *pgdir, unsigned long start, unsigned long limit)
+{
+       unsigned long end;
+
+       /* Don't swap out areas like shared memory which have their
+           own separate swapping mechanism or areas which are locked down */
+       if (vma->vm_flags & (VM_SHM | VM_LOCKED))
+               return 0;
+
+       end = vma->vm_end;
+       while (start < end) {
+               int result = swap_out_pgd(tsk, vma, pgdir, start, end, limit);
+               if (result)
+                       return result;
+               start = (start + PGDIR_SIZE) & PGDIR_MASK;
+               pgdir++;
+       }
+       return 0;
+}
+
+static int swap_out_process(struct task_struct * p, unsigned long limit)
+{
+       unsigned long address;
+       struct vm_area_struct* vma;
+
+       /*
+        * Go through process' page directory.
+        */
+       address = p->swap_address;
+       p->swap_address = 0;
+
+       /*
+        * Find the proper vm-area
+        */
+       vma = find_vma(p, address);
+       if (!vma)
+               return 0;
+       if (address < vma->vm_start)
+               address = vma->vm_start;
+
+       for (;;) {
+               int result = swap_out_vma(p, vma, pgd_offset(p->mm, address), address, limit);
+               if (result)
+                       return result;
+               vma = vma->vm_next;
+               if (!vma)
+                       break;
+               address = vma->vm_start;
+       }
+       p->swap_address = 0;
+       return 0;
+}
+
+static int swap_out(unsigned int priority, unsigned long limit)
+{
+       static int swap_task;
+       int loop, counter;
+       struct task_struct *p;
+
+       counter = ((PAGEOUT_WEIGHT * nr_tasks) >> 10) >> priority;
+       for(; counter >= 0; counter--) {
+               /*
+                * Check that swap_task is suitable for swapping.  If not, look for
+                * the next suitable process.
+                */
+               loop = 0;
+               while(1) {
+                       if (swap_task >= NR_TASKS) {
+                               swap_task = 1;
+                               if (loop)
+                                       /* all processes are unswappable or already swapped out */
+                                       return 0;
+                               loop = 1;
+                       }
+
+                       p = task[swap_task];
+                       if (p && p->swappable && p->mm->rss)
+                               break;
+
+                       swap_task++;
+               }
+
+               /*
+                * Determine the number of pages to swap from this process.
+                */
+               if (!p->swap_cnt) {
+                       /* Normalise the number of pages swapped by
+                          multiplying by (RSS / 1MB) */
+                       p->swap_cnt = AGE_CLUSTER_SIZE(p->mm->rss);
+               }
+               if (!--p->swap_cnt)
+                       swap_task++;
+               switch (swap_out_process(p, limit)) {
+                       case 0:
+                               if (p->swap_cnt)
+                                       swap_task++;
+                               break;
+                       case 1:
+                               return 1;
+                       default:
+                               break;
+               }
+       }
+       return 0;
+}
+
+/*
+ * We are much more aggressive about trying to swap out than we used
+ * to be.  This works out OK, because we now do proper aging on page
+ * contents. 
+ */
+int try_to_free_page(int priority, unsigned long limit)
+{
+       static int state = 0;
+       int i=6;
+
+       switch (state) {
+               do {
+               case 0:
+                       if (shrink_mmap(i, limit))
+                               return 1;
+                       state = 1;
+               case 1:
+                       if (shm_swap(i, limit))
+                               return 1;
+                       state = 2;
+               default:
+                       if (swap_out(i, limit))
+                               return 1;
+                       state = 0;
+               } while(i--);
+       }
+       return 0;
+}
+
+
+/*
+ * The background pageout daemon.
+ * Started as a kernel thread from the init process.
+ */
+int kswapd(void *unused)
+{
+       int i;
+       
+       current->session = 1;
+       current->pgrp = 1;
+       sprintf(current->comm, "kswapd");
+       current->blocked = ~0UL;
+       
+       /*
+        *      As a kernel thread we want to tamper with system buffers
+        *      and other internals and thus be subject to the SMP locking
+        *      rules. (On a uniprocessor box this does nothing).
+        */
+        
+#ifdef __SMP__
+       lock_kernel();
+       syscall_count++;
+#endif
+
+       /* Give kswapd a realtime priority. */
+       current->policy = SCHED_FIFO;
+       current->priority = 32;  /* Fixme --- we need to standardise our
+                                   namings for POSIX.4 realtime scheduling
+                                   priorities.  */
+
+       printk ("Started kswapd v$Revision: 1.1.2.3 $\n");
+       init_swap_timer();
+       
+       while (1) {
+               kswapd_awake = 0;
+               current->signal = 0;
+               interruptible_sleep_on(&kswapd_wait);
+               kswapd_awake = 1;
+               
+               /* Do the background pageout: */
+               for (i=0; i < kswapd_ctl.maxpages; i++)
+                       try_to_free_page(GFP_KERNEL, ~0UL);
+       }
+}
+
+/* 
+ * The swap_tick function gets called on every clock tick.
+ */
+
+void swap_tick(void)
+{
+       if (nr_free_pages < free_pages_low ||
+           (nr_free_pages < free_pages_high && 
+            jiffies >= next_swap_jiffies)) {
+               if (!kswapd_awake && kswapd_ctl.maxpages > 0) {
+                       wake_up(&kswapd_wait);
+                       need_resched = 1;
+                       kswapd_awake = 1;
+               }
+               next_swap_jiffies = jiffies + swapout_interval;
+       }
+       timer_active |= (1<<SWAP_TIMER);
+}
+
+
+/* 
+ * Initialise the swap timer
+ */
+
+void init_swap_timer(void)
+{
+       timer_table[SWAP_TIMER].expires = 0;
+       timer_table[SWAP_TIMER].fn = swap_tick;
+       timer_active |= (1<<SWAP_TIMER);
+}
index 271b00201f17e7907fda2628c5155c48dbd48401..cce9c8009cb71e434d878bce5618339c48b03c3c 100644 (file)
@@ -41,6 +41,7 @@
  *             Rudi Cilibrasi  :       Pass the right thing to set_mac_address()
  *             Dave Miller     :       32bit quantity for the device lock to make it work out
  *                                     on a Sparc.
+ *             Bjorn Ekwall    :       Added KERNELD hack
  *
  */
 
@@ -73,6 +74,9 @@
 #ifdef CONFIG_NET_ALIAS
 #include <linux/net_alias.h>
 #endif
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
 
 /*
  *     The list of packet types we will receive (as opposed to discard)
@@ -203,6 +207,13 @@ struct device *dev_get(const char *name)
                if (strcmp(dev->name, name) == 0)
                        return(dev);
        }
+#ifdef CONFIG_KERNELD
+       if (request_module(name) == 0)
+               for (dev = dev_base; dev != NULL; dev = dev->next) {
+                       if (strcmp(dev->name, name) == 0)
+                               return(dev);
+               }
+#endif
        return(NULL);
 }
 
index 3e0f38ef1405259d9745bc328fe1213434ecbf3f..f418f9d6f8db1df2dff86af139e497adf0e806b4 100644 (file)
@@ -204,6 +204,8 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
        int brd=IS_MYADDR;
        struct options * opt = NULL;
        int is_frag=0;
+       __u32 daddr;
+
 #ifdef CONFIG_FIREWALL
        int err;
 #endif 
@@ -326,10 +328,10 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
         *      and don't go via ip_chk_addr. Note: brd is set to IS_MYADDR at
         *      function entry.
         */
-
+       daddr = iph->daddr;
        if ( iph->daddr == skb->dev->pa_addr || (brd = ip_chk_addr(iph->daddr)) != 0)
        {
-               if (opt && opt->srr) 
+               if (opt && opt->srr) 
                {
                        int srrspace, srrptr;
                        __u32 nexthop;
@@ -368,6 +370,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
                                        kfree_skb(skb, FREE_WRITE);
                                        return -EINVAL;
                                }
+                               memcpy(&daddr, &optptr[srrptr-1], 4);
                        }
                        if (srrptr <= srrspace) 
                        {
@@ -485,7 +488,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
                                        else
                                                break;  /* One pending raw socket left */
                                        if(skb1)
-                                               raw_rcv(raw_sk, skb1, dev, iph->saddr,iph->daddr);
+                                               raw_rcv(raw_sk, skb1, dev, iph->saddr,daddr);
                                        raw_sk=sknext;
                                }
                                while(raw_sk!=NULL);
@@ -540,7 +543,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
                        *       check the protocol handler's return values here...
                        */
 
-                       ipprot->handler(skb2, dev, opt, iph->daddr,
+                       ipprot->handler(skb2, dev, opt, daddr,
                                (ntohs(iph->tot_len) - (iph->ihl * 4)),
                                iph->saddr, 0, ipprot);
                }
@@ -577,7 +580,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
 #endif         
 
                if(raw_sk!=NULL)        /* Shift to last raw user */
-                       raw_rcv(raw_sk, skb, dev, iph->saddr, iph->daddr);
+                       raw_rcv(raw_sk, skb, dev, iph->saddr, daddr);
                else if (!flag)         /* Free and report errors */
                {
                        if (brd != IS_BROADCAST && brd!=IS_MULTICAST)
index 818b7269d7c42db41622d7209803ffd79771a604..82d057be86f77aeec6b85fe787463791210df096 100644 (file)
@@ -462,7 +462,7 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *op
                                if (opt->srr) 
                                {
                                        unsigned  char * optptr = opt->__data+opt->srr-sizeof(struct  iphdr);
-                                       memmove(optptr+7, optptr+4, optptr[1]-7);
+                                       memmove(optptr+7, optptr+3, optptr[1]-7);
                                        memcpy(optptr+3, &opt->faddr, 4);
                                }
                                if (opt->rr_needaddr) 
index bff29053b14f04892da3338a1bb98e6713252ff4..3c8b69b40457275c3182e346cf6f0d0ad097f6ac 100644 (file)
@@ -39,6 +39,7 @@
  *                                     routing caches and better behaviour.
  *             
  *             Olaf Erb        :       irtt wasnt being copied right.
+ *             Bjorn Ekwall    :       Added KERNELD hack for autodialling
  *
  *             This program is free software; you can redistribute it and/or
  *             modify it under the terms of the GNU General Public License
@@ -69,6 +70,9 @@
 #include <net/sock.h>
 #include <net/icmp.h>
 #include <net/netlink.h>
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
 
 /*
  * Forwarding Information Base definitions.
@@ -1561,7 +1565,12 @@ void ip_rt_put(struct rtable * rt)
                ATOMIC_DECR(&rt->rt_refcnt);
 }
 
-struct rtable * ip_rt_route(__u32 daddr, int local)
+#ifdef CONFIG_KERNELD
+static struct rtable * real_ip_rt_route
+#else
+struct rtable * ip_rt_route
+#endif
+       (__u32 daddr, int local)
 {
        struct rtable * rth;
 
@@ -1581,6 +1590,27 @@ struct rtable * ip_rt_route(__u32 daddr, int local)
        return ip_rt_slow_route (daddr, local);
 }
 
+#ifdef CONFIG_KERNELD
+struct rtable * ip_rt_route(__u32 daddr, int local)
+{
+       struct rtable *rt;
+       char wanted_route[20];
+       long ipaddr = ntohl(daddr);
+
+       if ((rt = real_ip_rt_route(daddr, local)) == NULL) {
+               sprintf(wanted_route, "%d.%d.%d.%d",
+                       (int)(ipaddr >> 24) & 0xff, (int)(ipaddr >> 16) & 0xff,
+                       (int)(ipaddr >> 8) & 0xff, (int)ipaddr & 0xff);
+               /* Not good while forwarding a packet... see ipc/msg.c */
+               kerneld_route(wanted_route); /* perhaps a ppp-connection? */
+               /* Try again */
+               rt = real_ip_rt_route(daddr, local);
+       }
+
+       return rt;
+}
+#endif
+
 
 /*
  *     Process a route add request from the user, or from a kernel
index 4381309232aea6eed145bc2c1a34f46e08fd6dbb..f1f48e7ef973bb64e46a6556ed17ca9568f5300b 100644 (file)
@@ -216,10 +216,10 @@ static unsigned short udp_check(struct udphdr *uh, int len, unsigned long saddr,
 struct udpfakehdr 
 {
        struct udphdr uh;
-       int daddr;
-       int other;
+       __u32 daddr;
+       __u32 other;
        const char *from;
-       int wcheck;
+       __u32 wcheck;
 };
 
 /*