diff -u --recursive --new-file v2.1.42/linux/CREDITS linux/CREDITS --- v2.1.42/linux/CREDITS Mon May 19 12:57:38 1997 +++ linux/CREDITS Sun Jun 15 11:00:19 1997 @@ -508,6 +508,13 @@ S: Toronto, Ontario, M5S 3A6 S: Canada +N: Richard Günther +E: richard.guenther@student.uni-tuebingen.de +D: binfmt_misc +S: Fichtenweg 3/511 +S: 72076 Tübingen +S: Germany + N: Danny ter Haar E: dth@cistron.nl D: /proc/procinfo, reboot on panic , kernel pre-patch tester ;) @@ -1387,7 +1394,7 @@ S: Spain N: Linus Torvalds -E: Linus.Torvalds@Helsinki.FI +E: torvalds@transmeta.com W: http://www.cs.helsinki.fi/~torvalds/ P: 1024/A86B35C5 96 54 50 29 EC 11 44 7A BE 67 3C 24 03 13 62 C8 D: Original kernel hacker @@ -1556,6 +1563,11 @@ S: 820 4th St. N. S: Fargo, North Dakota 58122 S: USA + +N: Steven Whitehouse +E: SteveW@ACM.org +D: Linux DECnet project: http://eeshack3.swan.ac.uk/~gw7rrm/DECnet/index.html +D: Minor debugging of other networking protocols. N: Hans-Joachim Widmaier E: hjw@zvw.de diff -u --recursive --new-file v2.1.42/linux/Documentation/00-INDEX linux/Documentation/00-INDEX --- v2.1.42/linux/Documentation/00-INDEX Tue May 13 22:40:59 1997 +++ linux/Documentation/00-INDEX Thu Jun 12 16:22:04 1997 @@ -18,6 +18,8 @@ - how to access I/O mapped memory from within device drivers. SMP.txt - notes, and "To Fix" list for multi-processor Linux. (see smp.tex) +binfmt_misc.txt + - info on the kernel support for extra binary formats. cdrom/ - directory with information on the CD-ROM drivers that Linux has. devices.tex diff -u --recursive --new-file v2.1.42/linux/Documentation/Changes linux/Documentation/Changes --- v2.1.42/linux/Documentation/Changes Tue May 13 22:40:59 1997 +++ linux/Documentation/Changes Thu Jun 12 16:22:04 1997 @@ -29,28 +29,30 @@ Also, don't forget http://www.linuxhq.com/ for all your Linux kernel needs. -Last updated: May 12, 1997. +Last updated: May 31, 1997. Current Author: Chris Ricker (gt1355b@prism.gatech.edu). Current Minimal Requirements **************************** Upgrade to at *least* these software revisions before thinking you've -encountered a bug! +encountered a bug! If you're unsure what version you're currently +running, the suggested command should tell you. -- Kernel modules modutils-2.1.34 -- Gnu C 2.7.2.1 -- Binutils 2.8.0.3 -- Linux C Library 5.4.23 -- Dynamic Linker (ld.so) 1.8.5 -- Linux C++ Library 2.7.2.1 -- Procps 1.01 -- Mount 2.6g -- Net-tools 1.41 +- Kernel modules modutils-2.1.34 ; insmod -v +- Gnu C 2.7.2.1 ; gcc --version +- Binutils 2.8.1.0.1 ; ld -v +- Linux C Library 5.4.23 ; ls -l /lib/libc.so.* +- Dynamic Linker (ld.so) 1.8.5 ; ldd -v +- Linux C++ Library 2.7.2.1 ; ls -l /usr/lib/libg++.so.* +- Procps 1.01 ; ps --version +- Procinfo 0.11 ; procinfo -v +- Mount 2.6g ; mount --version +- Net-tools 1.41 ; hostname -V - Loadlin 1.6a -- Sh-utils 1.16 -- Autofs 0.3.0 -- NFS 0.4.21 +- Sh-utils 1.16 ; expr --v +- Autofs 0.3.3 ; automount --version +- NFS 0.4.21 ; showmount --version Upgrade notes ************* @@ -86,6 +88,9 @@ later than 1.8.5, avoid 1.8.10 as it introduces a few bugs that are fixed in later releases. + If you upgrade to libc-5.4.x, you may also need to upgrade ypbind if +you're using NIS. + Modules ======= @@ -134,6 +139,15 @@ For support for new features like IPv6, upgrade to the latest net-tools. +Memory +====== + + As of 2.1.41, the format of /proc/meminfo has changed. This broke +many memory utils, which have to be upgraded. Get the new procinfo and +procps (which, AFAIK, is not yet available) to fix this. Until you +upgrade, programs which read /proc/meminfo will seg-fault or give an +error. + Mount and network file systems ============================== @@ -178,37 +192,18 @@ /dev/lp0 with the new Plug-and-Play driver. If printing breaks with the new driver, try checking your lpd configuration. -How to know the version of the installed programs -************************************************* - - There are some simple methods useful to know the version of the -installed programs and libraries. - -Binutils: ld -v -Gnu C: gcc -v or gcc --version -Kbd: dumpkeys -h -Ld.so: ldd -v -Libc: ls -l /lib/libc.so.* -Libc++: ls -l /usr/lib/libg++.so.* -Modutils: insmod -V -Mount: mount --version -Net-tools: hostname -V -Procps: ps --version -RPM: rpm --version -Sh-utils: expr --v - Where to get the files ********************** Binutils ======== -The 2.8.0.3 release: -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.8.0.3.bin.tar.gz -ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.8.0.3.bin.tar.gz +The 2.8.1.0.1 release: +ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.8.1.0.1.bin.tar.gz +ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.8.1.0.1.bin.tar.gz Installation notes: -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.8.0.3 -ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.8.0.3 +ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.8.1.0.1 +ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.8.1.0.1 Gnu C ===== @@ -258,9 +253,15 @@ ================ The 1.01 release: -ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.01.tgz +ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.01.tar.gz ftp://sunsite.unc.edu/pub/Linux/system/status/ps/procps-1.01.tgz +Procinfo utilities +================== + +The 0.11 release: +ftp://ftp.cistron.nl/pub/people/svm/procinfo-0.11.tar.gz + RPM utilities ============= @@ -304,8 +305,8 @@ Autofs ====== -The 0.3.0 release: -ftp://ftp.kernel.org/pub/linux/daemons/autofs/autofs-0.3.0.tar.gz +The 0.3.3 release: +ftp://ftp.kernel.org/pub/linux/daemons/autofs/autofs-0.3.3.tar.gz NFS === @@ -320,6 +321,12 @@ The 0.41 release: ftp://ftp.london.uk.eu.org/pub/ipv6/net-tools-1.41.tar.gz ftp://ftp.cs-ipv6.lancs.ac.uk/pub/Code/Linux/Net_Tools/net-tools-1.41.tar.gz + +Ypbind +====== + +The 3.2 release: +ftp://ftp.uni-paderborn.de/pub/linux/local/yp/ypbind-3.2.tar.gz Other Info ========== diff -u --recursive --new-file v2.1.42/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.42/linux/Documentation/Configure.help Thu May 29 21:53:03 1997 +++ linux/Documentation/Configure.help Sun Jun 15 14:05:27 1997 @@ -795,6 +795,20 @@ will be called binfmt_java.o. If you don't know what to answer at this point then answer Y. +Kernel support for MISC binaries +CONFIG_BINFMT_MISC + This enables the possibility to plug wrapper-driven binary formats + into the kernel. You will like this especially when you use programs + that need an interpreter to run like Java, Python or Emacs-Lisp. And + you don't need CONFIG_BINFMT_JAVA or CONFIG_BINFMT_EM86, as this is + a more general feature. + You can do other nice things, too. Read Documentation/binfmt_misc.txt + to learn how to use this feature. + You must enable CONFIG_PROC_FS to use this part of the kernel. + You may answer M for module support and later load the module when + you have use for it. + If you don't know what to answer at this point, say Y. + Processor type CONFIG_M386 This is the processor type of your CPU. This information is used for @@ -2371,7 +2385,8 @@ compatible cards. If you have a dual mode card (i.e. a WSS cards with a SoundBlaster emulation) you should say N here and Y to "Soundcard modem support for WSS and Crystal cards", below, because - this usually results in better performance. + this usually results in better performance. This option also supports + SB16/32/64 in full duplex mode. Soundcard modem support for WSS and Crystal cards CONFIG_SOUNDMODEM_WSS @@ -2389,26 +2404,27 @@ compatible to popular modems using TCM3105 or AM7911. The demodulator requires about 12% of the CPU power of a Pentium 75 CPU per channel. -Soundmodem 1200 baud AFSK using floating point -CONFIG_SOUNDMODEM_AFSK1200_FP - This option enables floating point calculations to be used for the - AFSK1200 baud modem. The Intel Pentium is a perverted chip because - integer multiplications are, although easier to implement in silicon, - an order of magnitude slower than floating point calculations. - Enabling this option uses a highly optimized assembler routine for - correlations, modeled after the one published by Phil Karn, KA9Q. - This reduces the computing power needed on Intel Pentium chips to - about 50%. On the other hand, Pentium clones with faster integer - multiply and slower floating point multiply will probably take - longer with this option turned on. As a rule of thumb, enable it for - Intel Pentium and Pentium Pro processors, and disable it for - anything else. - I (sailer@ife.ee.ethz.ch) am very interested in figures. If you are - willing to give me a feedback, please compile the driver once with - this option enabled and once with it disabled, and send me the cycle - counter numbers obtained with both compilations, and your exact - chip. The cycle counter numbers can be obtained with a recent - sethdlc utility. +Soundcard modem support for 2400 baud AFSK modulation (7.3728MHz crystal) +CONFIG_SOUNDMODEM_AFSK2400_7 + This option enables the soundmodem driver 2400 baud AFSK modem, + compatible to TCM3105 modems (over-)clocked with a 7.3728MHz crystal. + Note that the availability of this driver does _not_ imply that I + recommend building such links. It is only here since users especially + in eastern europe have asked me to do so. In fact this modulation scheme + has many disadvantages, mainly its incompatibility with many transceiver + designs and the fact that the TCM3105 (if used) is operated widely outside + its specifications. + +Soundcard modem support for 2400 baud AFSK modulation (8MHz crystal) +CONFIG_SOUNDMODEM_AFSK2400_8 + This option enables the soundmodem driver 2400 baud AFSK modem, + compatible to TCM3105 modems (over-)clocked with an 8MHz crystal. + Note that the availability of this driver does _not_ imply that I + recommend building such links. It is only here since users especially + in eastern europe have asked me to do so. In fact this modulation scheme + has many disadvantages, mainly its incompatibility with many transceiver + designs and the fact that the TCM3105 (if used) is operated widely outside + its specifications. Soundcard modem support for 4800 baud HAPN-1 modulation CONFIG_SOUNDMODEM_HAPN4800 @@ -2426,27 +2442,6 @@ can only use one protocol at a time, depending on what the other end can understand). -Soundcard modem support using floating point arithmetic -CONFIG_SOUNDMODEM_FLOAT - This option enables floating point calculations to be used for the - AFSK1200 baud modem. The Intel Pentium is a perverted chip because - integer multiplications are, although easier to implement in silicon, - an order of a magnitude slower than floating point calculations. - Enabling this option uses a highly optimized assembler routine for - correlations, modeled after the one published by Phil Karn, KA9Q. - This reduces the computing power needed on Intel Pentium chips to - about 50%. On the other hand, Pentium clones with faster integer - multiply and slower floating point multiply will probably take - longer with this option turned on. As a rule of thumb, enable it for - Intel Pentium and Pentium Pro processors, and disable it for - anything else. - I (sailer@ife.ee.ethz.ch) am very interested in figures. If you are - willing to give me a feedback, please compile the driver once with - this option enabled and once with it disabled, and send me the cycle - counter numbers obtained with both compilations, and your exact - chip. The cycle counter numbers can be obtained by a recent sethdlc - utility. - Serial port KISS driver for AX.25 CONFIG_MKISS KISS is the protocol used to send IP traffic over AX.25 radio @@ -3617,6 +3612,14 @@ be called isp16.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Preload dcache +CONFIG_DCACHE_PRELOAD + Preloading will create dcache entries when a directory is scanned + (e.g. with ls) the *first* time. This should speed up successive + inode lookups, but also can consume large amounts of memory. + Please report speedups (or slowdowns due to the memory usage if they + occur) to schoebel@informatik.uni-stuttgart.de . + Quota support CONFIG_QUOTA If you say Y here, you will be able to set per user limits for disk @@ -3627,6 +3630,138 @@ quota support is only useful for multi user systems. If unsure, say N. +Online mirror support +CONFIG_OMIRR + omirr is a package for _symmetric_ mirroring of files over the + internet. In contrast to rdist, the online mirror daemon (omirrd) + is running all the time and transfers any changes on the file system + as soon as possible to all other servers. Symmetric means that all + servers have equal rights in changing a file: the last changer of a + file will win. This is the same behaviour as multiple processes + operating on a global file system. In effect, omirr can do the same + as nfs mounts, but will have better performance since the data is + stored on local disks. In contrast to a cache filesystem which has a + dedicated master copy, broken connections and/or servers are no problem + for continuing work on the remaining ones, because there is no master + copy. You must say Y if you want to use omirrd, but you should (but + need not) say N if you don't (for performance reasons). + +Filename translation support +CONFIG_TRANS_NAMES + Normally used only when you want diskless clients to mount the root + filesystem of the server. If unsure, or if you don't have clients, select N. + When selected, filenames, directory names etc become context-sensitive. + If you have a file named "/etc/config#host=banana#", it will appear + (by default) as hardlinked to "/etc/config" on host "banana", while on host + "mango" another file "/etc/config#host=mango#" will appear as been + hardlinked to "/etc/config". The default behaviour can be changed + by setting the _first_ environment variable NAMETRANS to a colon-separated + list of suffixes which are tried in the specified order. For example, + in 'env - NAMETRANS=#host=mango#:#ktype=diskless# "`env`" command ...' the + command will see the same files as if it had been executed on host "mango" + with a diskless kernel. Using NAMETRANS supersedes _all_ default + translations. Thus translations can be generally switched off by an + empty list, e.g. 'env - NAMETRANS= "`env`" command ...'. + Note that some system utililies like tar, dump, restore should + be used with translation switched off, in order to avoid doubled + space in archive files and when extracting from them. Also, make sure + that nfsd, mountd (and similar ones like samba daemons) run without + translation, in order to avoid doubled (or even wrong) translation + at the server and at the client. You can automatically force the creation + of context-dependent filenames if there exists a template filename like + "/etc/mtab#host=CREATE#". As soon as a process running on "mango" tries + to create a file "/etc/mtab", the version "/etc/mtab#host=mango#" is + created instead (which appears in turn as hardlinked to "/etc/mtab"). + Note that if you want to make "/etc/fstab" context-dependend, you should + execute "touch /etc/mtab#host=CREATE#" and + "touch /etc/mtab.tmp#host=CREATE#", because mount, umount and others + running on different hosts would otherwise try to create one shared + /etc/mtab which would result in a clash. Also one should execute + "touch /etc/nologin#host=CREATE#" to prevent global side effects from + shutdown resp. runlevel. + +Restrict translation to gid +CONFIG_TRANS_RESTRICT + When selected, default translations are carried out only if the parent + directory of the context-sensitive file belongs to a specific group id + (gid). Trying to translate names everywhere will decrease performance of + file openings. Normally translations are used only in system configuration + files but not in ordinary user filespace. So you should change the gid of + directories containing context-dependent files to some special group like + "adm" (group id 4) and enable this option. As a result, users will not + notice any performance degradation resulting from filename translation. + Note that translations resulting from the first environment variable + "NAMETRANS=..." are always carried out regardless of the gid of directories. + Beware, before turning on this option make sure all directories containing + context-dependent files belong to the special group, or system + initialization may fail. In unsure, select N. + +Group id (gid) for translation restriction +CONFIG_TRANS_GID + Default name translations will be carried out only inside directories + belonging to the group id (gid) you can specify here. + Default is 4 (group "adm"). + +Nodename (hostname) translation +CONFIG_TR_NODENAME + Enables translation of name suffixes like in "/etc/config#host=banana#". + The syntax is #host=#. The hostname can be queried + with the command "uname -n". Normally this option is used heavily when + translation is enabled. If unsure, say Y. + +Kernelname translation +CONFIG_TR_KERNNAME + Enables translation of name suffixes like in "/etc/config#kname=default#". + The string is hard compiled into the kernel by the following option. + Useful if your kernel does not know the hostname at boot time, and there + is no way to tell the hostname by lilo or bootp. Please avoid using this + option and prefer CONFIG_TR_NODENAME wherever possible. When mounting + the root over nfs, the own hostname must be known at boot time anyway; + this option is just for special use. + Note that the default translations are tried in the order as occuring + in the configuration, that is 1) host 2) kname 3) ktype 4) machine + 5) system. If unsure, say Y. + +String for kernelname translation +CONFIG_KERNNAME + Enter the string you want to compile into the kernel. The string + will be used as context in context-depenant file like + "/etc/config#kname=#". + +Kerneltype translation +CONFIG_TR_KERNTYPE + Enables translation of name suffixes like in "/etc/config#ktype=default#". + The syntax is #ktype=#. The string is hard compiled + in the kernel by the following option. Use if you want to create + different kernels with different behaviour. For example, use the string + "default" on your server, and use "diskless" on all your diskless clients + (and perhaps "dataless" on dataless clients). This way you can avoid + dozens of "config#host=# with same contents and you have no + effort when new machines are added. If unsure, say Y. + +String for kerneltype translation +CONFIG_KERNTYPE + Enter the string you want to compile into the kernel. The string + will be used as context in context-depenant file like + "/etc/config#ktype=default#". If your kernel is to be used on a server, + you probably can use "default" here. If your kernel is intended for + a diskless client, you probably should enter "diskless" here. + +Machine type translation +CONFIG_TR_MACHINE + Enables translation of name suffixes like in "/etc/config#machine=i486#". + The syntax is #machine=#. The machine types can be queried + with the command "uname -m". Normally used only on multi-architecture + installations. If unsure, say Y. + +System name translation +CONFIG_TR_SYSNAME + Enables translation of name suffixes like in "/etc/config#system=Linux#". + The syntax is #system=#. The system name can be queried + with the command "uname -s". Currently only supportet by Linux, but + hopefully other operating systems will pick up the idea of context-dependent + translations. If unsure, say Y. + Minix fs support CONFIG_MINIX_FS Minix is a simple operating system used in many classes about @@ -4702,6 +4837,17 @@ said Y to "Kernel profiling support", you must be a kernel hacker and hence you know what this is about :-) +Magic System Request Key support +CONFIG_MAGIC_SYSRQ + This is for kernel hackers who want to have some control over the + system even if the system crashes during kernel debugging (e.g., to + flush the disks, reboot the system immediately or dump some status + information). This is accomplished by pressing various keys while + holding SysRq (Alt+PrintScreen). As you are expected to be a kernel + hacker to use this, the simple rule about learning what do the keys + mean is "Use the source, Luke!" -- read drivers/char/sysrq.c. + Don't say Y unless you really know what does this hack do. + ISDN subsystem CONFIG_ISDN ISDN ("Integrated Services Digital Networks", called RNIS in France) diff -u --recursive --new-file v2.1.42/linux/Documentation/binfmt_misc.txt linux/Documentation/binfmt_misc.txt --- v2.1.42/linux/Documentation/binfmt_misc.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/binfmt_misc.txt Thu Jun 12 16:22:04 1997 @@ -0,0 +1,83 @@ + Kernel Support for miscellaneous (your favourite) Binary Formats v1.1 + ==================================================================== + +This Kernel feature allows to invoke almost (for restrictions see below) every +program by simply typing it's name in the shell. +This includes for example compiled Java(TM), Python or Emacs programs. + +To achieve this you must tell binfmt_misc which interpreter has to be invoked with +which binary. Binfmt_misc recognises the binary-type by matching some bytes at the +beginning of the file with a magic byte sequence (masking out specified bits) you +have supplied. Binfmt_misc can also recognise a filename extension (aka .com) and +optionally strip it off. + +To actually register a new binary type, you have to set up a string looking like +:name:type:offset:magic:mask:interpreter: (where you can choose the ':' upon your +needs) and echo it to /proc/sys/fs/binfmt_misc/register. +Here is what the fields mean: + - 'name' is an identifier string. A new /proc file will be created with this + this name below /proc/sys/fs/binfmt_misc + - 'type' is the type of recognition. Give 'M' for magic and 'E' for extension. + Give the corresponding lowercase letter to let binfmt_misc strip of the + filename extension. + - 'offset' is the offset of the magic/mask in the file counted in bytes. This + defaults to 0 if you omit it (i.e. you write ':name:type::magic...') + - 'magic' is the byte sequence binfmt_misc is matching for. The magic string + may contain hex-encoded characters like \x0a or \xA4. In a shell environment + you will have to write \\x0a to prevent the shell from eating your \. + If you chose filename extension matching, this is the extension to be + recognised (the \x0a specials are not allowed). Extension matching is case + sensitive! + - 'mask' is an (optional, defaults to all 0xff) mask. You can mask out some bits + from matching by supplying a string like magic and as long as magic. The + mask is anded with the byte sequence of the file. + - 'interpreter' is the program that should be invoked with the binary as first + argument (specify the full path) +There are some restrictions: + - the whole register string may not exceed 255 characters + - the magic must resist in the first 128 bytes of the file, i.e. offset+size(magic) + has to be less than 128 + - the interpreter string may not exceed 127 characters +You may want to add the binary formats in one of your /etc/rc scripts during boot-up. +Read the manual of your init program to figure out how to do this right. + + +A few examples (assumed you are in /proc/sys/fs/binfmt_misc): + +- enable Java(TM)-support (like binfmt_java): + echo ":Java:M::\xca\xfe\xba\xbe::/usr/local/bin/java:" > register + echo :Applet:M::\<\!--applet::/usr/local/bin/appletviewer: > register +- enable support for em86 (like binfmt_em86, for Alpha AXP only): + echo ":i386:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:" > register + echo ":i486:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:" > register +- enable support for packed DOS applications (pre-configured dosemu hdimages): + echo ":DEXE:M::\x0eDEX::/usr/bin/dosexec:" > register +- enable support for DOS/Windows executables (using mzloader and dosemu/wine): + echo ":DOSWin:M::MZ::/usr/sbin/mzloader:" > register + echo ":DOS:E::com::/usr/sbin/mzloader:" > register + + +You can enable/disable binfmt_misc or one binary type by echoing 0 (to disable) +or 1 (to enable) to /proc/sys/fs/binfmt_misc/status or /proc/.../the_name. +Catting the file tells you the current status of binfmt_misc/the entry. + +You can remove one entry or all entries by echoing -1 to /proc/.../the_name +or /proc/sys/fs/binfmt_misc/status. + + +HINTS: +====== + +If your interpreter does not look at the PATH to determine the full name of the +program, you need to invoke a wrapper-script (like the following for java) first: + +#!/bin/sh +FOO=`which $1` || exit 1 +shift +/usr/local/bin/java $FOO ${1+$@} + + +There is a web page about binfmt_misc at +http://www.anatom.uni-tuebingen.de/~richi/linux/binfmt_misc.html + +Richard Günther, richard.guenther@student.uni-tuebingen.de diff -u --recursive --new-file v2.1.42/linux/Documentation/transname.txt linux/Documentation/transname.txt --- v2.1.42/linux/Documentation/transname.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/transname.txt Thu Jun 12 16:22:04 1997 @@ -0,0 +1,264 @@ +Transname version 1.9 (C) 1997 Thomas Schoebel-Theuer + +transname enables diskless clients, X-terminals etc to mount the +*root filesystem* of the server. This make administration of +large pools a lot easier. + +Wherefore is linux-2.0.21-transname.patch? + +Currently different diskless clients must have their root / on different +directories on the server, beause each client has _some_ different +configuration files. However, most files (typically about 99%) have the same +contents on the clients and on the server, but have to be replicated +(and maintained separately) just because of the 1% differences. +This duplication causes very large efforts in practise, since at least +the /etc directory has to be duplicated for every client. Even in /etc +many files are identical, for example sendmail.cf, initrc scripts and +others. Maintaining a large pool means to ensure coherence amoung the +duplicates. Classical methods like symlinks are unconvenient +for this task because they have to be valid in the view of mounted +filesystems at all clients, not at the server. + +Linux transname overcomes this problem by allowing filenames +to be context-dependend. For example, if you have a file /etc/config +that should differ on the hosts "myserver" and "myclient", you just +create two different files named /etc/config#host=myserver# and +/etc/config#host=myclient# . On host "myserver", the file +/etc/config#host=myserver# will appear as if it were hardlinked to +file /etc/config (without the #...=...# suffix). On host "myclient", +the corresponding other file will appear as /etc/config. So you +can access the right file contents under the _same_ name, depending +on which host you are working. + +A similar concept can be found in elder HP-UX versions, but with +so-called "hidden directories" which don't allow contemporary viewing +all versions by default. In contrast, transname shows all context-dependent +files in the dir listing and they can be edited using the +fully qualified name. + +Transname was developped for and is used at our Linux pool at the +University of Stuttgart with good results. Maintainance of the pool is +at a minimum, and adding new clients is a child's play. No worry with +keeping up mail configurations, newly installed tools, changed /etc/services, +/etc/shells, /etc/resolv.conf and many, many others. In contrast to a +sophisticated symlink solution, adding a new file to the /etc directory +is seen immediately by all clients. + +An example for the use of linux-2.0-transname.patch: + +For example, you can make your /etc/fstab context-dependend. If you want +to do that, you should create an /etc/fstab#ktype=default# for the +server and an /etc/fstab#ktype=diskless# for all clients. This is because +your clients may not yet know their own hostname when they attempt to mount +the root filesystem. You can compile in the kerneltypes "default" and +"diskless" into different kernels for servers and clients. Of course, +if your clients boot via bootp and know their names when mounting the root, +you can use /etc/fstab#host=myclient# instead. But at least servers +booting from disk normally dont know their hostname at root mount time, +so you can mix methods and use /etc/fstab#ktype=default# for the server, +/etc/fstab#ktype=diskless# for the majority of the clients and +/etc/fstab#host=myclient# for some specific client, because translation +of #host=...# is given precedence over #ktype=...# by default. + +This sort of name translation works with any underlying file system +and with any inode type (i.e. with directories, symlinks, devices etc), +because it is implemented in the VFS layer of the kernel. Currently, +five types of default translations are supported: + + * #host=# depends on the hostname, see "uname -n" + * #kname=# works with a hard compiled-in string + * #ktype=# works with a hard compiled-in string + * #machine=# depends on architecture, see "uname -m" + * #system=# currently only supported by Linux, see "uname -s" + +Others may be added in future. + +The current translation are displayed at boot time in the kernel messages +for easier debugging, and can be retrieved by reading +/proc/sys/kernel/nametrans which is a special file containing the currently +valid translations. + +The default translations change whenever the hostname(1) is set or changed. +Thus, the hostname is not set (or set to the name "(none)") at boot time +before init(8) sets it. So, if you want to use the hostname before that +moment, there are three ways: + + a) set the hostname before via bootp or similar. + b) use the compiled-in translations kname and ktype solely. + c) set all translations by lilo (or on the boot command line) with + kernel parameter nametrans=#host=banana#:#ktype=diskless# , + thus overriding and hiding the default (built-in) translations. + +Note that by supplying the colon-separated list of at most 16 suffixes, you +can also use other translation types that are not defined in the default +translations. However, you must ensure that the syntax #...=...# is correct. +The specified contexts will be tried in the specified order *instead* of the +default translations. + +You can override the default (or parameter-supplied) translations at runtime +by executing +echo "#host=$HOST#:#ktype=diskless#:#myconfig=something#" > /proc/sys/kernel/nametrans +However, after doing this (or setting as kernel parameter) the built-in +default translations have no effect any more, thus changing the hostname +will not be reflected in the overridden translations. You can switch +back to the default translations by executing +echo "" > /proc/sys/kernel/nametrans + +Another drawback is that administration tools currently are not aware of +context-dependend files, so you cannot switch between contexts inside +one tool session. However, you can simulate administration sessions +on the server as if they were running on some client. To do this, +you have to set an environment variable NAMETRANS which has to be the +*first* environment variable in the list. For example, you can execute +'env - NAMETRANS=#host=mango#:#ktype=diskless# "`env`" command ...' +where the command will see the same files as if it had been executed on host +"mango" with a "diskless" kernel. To switch off translations entirely, use +an empty list, e.g. 'env - NAMETRANS= "`env`" command ...'. + +Hopefully the creators of administration tools and maintainers of Linux +distributions will support changing environments in future, so that +maintaining different views will be very easy. + +Some hints: + +Archivers like tar, dump, restore should be used with translation +switched off, in order to avoid doubled space in archive files and when +extracting from them. Also, make sure that nfsd, mountd (and similar ones +like samba daemons) run without translation, in order to avoid doubled +(or even wrong) translation at the server and at the client. You can +automatically force the creation of context-dependent filenames if there +exists a template filename like /etc/mtab#host=CREATE#. As soon as a +process running on "mango" tries to create a file /etc/mtab, the version +/etc/mtab#host=mango# is created instead (which appears in turn as +hardlinked to /etc/mtab). Note that if you want to make /etc/fstab +context-dependend, you should execute "touch /etc/mtab#host=CREATE#" and +"touch /etc/mtab.tmp#host=CREATE#", because mount, umount and others +running on different hosts would otherwise try to create one shared +/etc/mtab which would result in a clash. Also one should execute +"touch /etc/nologin#host=CREATE#" to prevent global side effects from +shutdown resp. runlevel. + +Which files you have to make context-dependent will differ for different +needs and different applications. Hopefully some day a standard will +cover the most common cases and the mist common Linux distributions. +A HOWTO on this subject is in preparation. + +How to install linux-2.0.21-transname.patch? + +First of all, keep a backup of your kernel on your disk. Second, keep a +floppy with a miniroot handy, so you can boot from the floppy, mount +your harddisk root filesystem and change the names of your configuration +files back to their old names in case of emergency. + +Then, make a kernel with transname support enabled. With "make config" +or "make xconfig", just go to the section "filesystems". Take a look at +the help texts that are associated with the transname options, they tell +you further hints not mentioned in this README. Then build your kernel as +usual, install it with a *new* kernel-filename, add a *new* entry to +/etc/lilo.conf and run lilo. **DONT CHANGE** any configuration files for the +first reboot! + +Just reboot the new kernel and play a little bit around with +creating context-dependend filenames in your home directory. +Try all modes including setting NAMETRANS to different values. + +As an example for the changes necessary on our LST-1.8-based Linux pool, +here is the output of the command +find / /tmp -xdev -name "*#*#" -print | sort -u | xargs ls -ld + +-r--r--r-- 1 root root 1725 Dec 21 1995 /etc/X11R6/xdm/xdm-config#host=eiche# +-r--r--r-- 3 root root 9509 Feb 15 17:35 /etc/XF86Config#host=balsa# +-r--r--r-- 1 root root 9401 Feb 15 17:34 /etc/XF86Config#host=eiche# +-rw-r--r-- 1 root root 9820 Feb 21 17:00 /etc/XF86Config#host=fichte# +-rw-r--r-- 1 root root 9822 Feb 14 15:45 /etc/XF86Config#host=laerche# +-r--r--r-- 3 root root 9509 Feb 15 17:35 /etc/XF86Config#host=mahagoni# +-r--r--r-- 3 root root 9509 Feb 15 17:35 /etc/XF86Config#host=palisander# +-r--r--r-- 2 root root 9509 Feb 15 17:41 /etc/XF86Config#host=pcbs10# +-r--r--r-- 2 root root 9509 Feb 15 17:41 /etc/XF86Config#host=pcbs11# +-rw-r--r-- 1 root root 586 Jun 11 23:13 /etc/fstab#ktype=default# +-rw-r--r-- 1 root root 242 May 29 17:35 /etc/fstab#ktype=diskless# +-rw------- 1 root root 338 Jun 14 16:37 /etc/lilo.conf#host=eiche# +-rw------- 1 root root 5236 Dec 16 1995 /etc/lst.cnf#host=balsa# +-rw------- 1 root root 5254 Dec 16 1995 /etc/lst.cnf#host=eiche# +-rw------- 1 root root 5236 Dec 19 1995 /etc/lst.cnf#host=fichte# +-rw------- 1 root root 5236 Jan 11 13:47 /etc/lst.cnf#host=laerche# +-rw------- 1 root root 5236 Feb 14 16:57 /etc/lst.cnf#host=mahagoni# +-rw------- 1 root root 5236 Jan 4 1996 /etc/lst.cnf#host=palisander# +-rw------- 1 root root 5236 Feb 15 13:57 /etc/lst.cnf#host=pcbs10# +-rw------- 1 root root 5236 Feb 14 17:06 /etc/lst.cnf#host=pcbs11# +-rw-r--r-- 1 root root 0 Dec 18 1995 /etc/mtab#host=CREATE# +-rw-r--r-- 1 root root 157 Jun 23 21:16 /etc/mtab#host=balsa# +-rw-r--r-- 1 root root 466 Jul 1 16:15 /etc/mtab#host=eiche# +-rw-r--r-- 1 root root 239 Jul 4 11:10 /etc/mtab#host=fichte# +-rw-r--r-- 1 root root 239 Jun 18 14:17 /etc/mtab#host=laerche# +-rw-r--r-- 1 root root 239 May 23 10:50 /etc/mtab#host=mahagoni# +-rw-r--r-- 1 root root 239 Jul 3 10:36 /etc/mtab#host=palisander# +-rw-r--r-- 1 root root 47 Feb 15 14:57 /etc/mtab#host=pcbs10# +-rw-r--r-- 1 root root 47 Feb 14 20:04 /etc/mtab#host=pcbs11# +-rw-r--r-- 1 root root 0 Dec 18 1995 /etc/mtab.tmp#host=CREATE# +-rw-r--r-- 1 root root 0 Dec 19 1995 /etc/nologin#host=CREATE# +---------- 1 root root 115 Feb 15 14:57 /etc/nologin#host=pcbs10# +---------- 1 root root 115 Feb 14 20:04 /etc/nologin#host=pcbs11# +-rw-r--r-- 1 root root 4818 Dec 16 1995 /etc/system.cnf#host=balsa# +lrwxrwxrwx 1 root root 25 Dec 22 1995 /etc/system.cnf#host=eiche# -> system.cnf#ktype=default# +-rw-r--r-- 1 root root 4821 Dec 19 1995 /etc/system.cnf#host=fichte# +-rw-r--r-- 1 root root 4824 Jan 11 13:47 /etc/system.cnf#host=laerche# +-rw-r--r-- 1 root root 4827 Feb 14 16:57 /etc/system.cnf#host=mahagoni# +-rw-r--r-- 1 root root 4833 Jan 4 1996 /etc/system.cnf#host=palisander# +-rw-r--r-- 1 root root 4840 Feb 15 14:10 /etc/system.cnf#host=pcbs10# +-rw-r--r-- 1 root root 4846 Feb 14 18:23 /etc/system.cnf#host=pcbs11# +-rw-r--r-- 1 root root 4818 Dec 13 1995 /etc/system.cnf#ktype=default# +drwxrwxrwt 16 root root 3072 Jul 4 14:29 /tmp#ktype=default# +lrwxrwxrwx 1 root root 26 Jul 4 14:22 /tmp#ktype=diskless# -> /tmp#ktype=default#/client +-rw-rw-rw- 1 root root 0 Feb 15 14:57 /tmp/client#host=CREATE# +drwxrwxrwx 4 root root 1024 Jun 28 12:15 /tmp/client#host=balsa# +drwxrwxrwx 3 root root 1024 Jul 4 11:10 /tmp/client#host=fichte# +drwxrwxrwx 3 root root 1024 Jun 18 14:18 /tmp/client#host=laerche# +drwxrwxrwx 3 root root 1024 May 24 13:06 /tmp/client#host=mahagoni# +drwxrwxrwx 3 root root 1024 Jul 3 10:37 /tmp/client#host=palisander# +drwxrwxrwx 4 root root 1024 Feb 15 14:57 /tmp/client#host=pcbs10# +drwxrwxrwx 3 root root 1024 Feb 20 06:43 /tmp/client#host=pcbs11# +lrwxrwxrwx 1 root root 9 Feb 15 13:58 /usr/X11R6/bin/X#host=pcbs10# -> XF86_SVGA +lrwxrwxrwx 1 root root 9 Feb 14 17:37 /usr/X11R6/bin/X#host=pcbs11# -> XF86_SVGA +lrwxrwxrwx 1 root root 7 Feb 14 17:15 /usr/X11R6/bin/X#ktype=diskless# -> XF86_S3 +drwxr-xr-x 22 root root 1024 Dec 13 1995 /var#host=balsa# +drwxr-xr-x 23 root root 1024 Jan 12 14:22 /var#host=eiche# +drwxr-xr-x 22 root root 1024 Dec 13 1995 /var#host=fichte# +drwxr-xr-x 22 root root 1024 Dec 13 1995 /var#host=laerche# +drwxr-xr-x 22 root root 1024 Dec 13 1995 /var#host=mahagoni# +drwxr-xr-x 22 root root 1024 Dec 13 1995 /var#host=palisander# +drwxr-xr-x 22 root root 1024 Dec 13 1995 /var#host=pcbs10# +drwxr-xr-x 22 root root 1024 Dec 13 1995 /var#host=pcbs11# + +Notes: The /tmp directory has an own filesystem on server "eiche", +in order to prevent users from filling the whole filestore (we dont use +quotas). Each client needs a different /tmp because of possible name clashes. +Also, the whole /var hierarchy is kept differently to prevent any risk, but +that could be optimized perhaps. Note that nfsd and mountd have been +replaced by a script which switches off translations, in the style + +-rwxr-xr-x 2 root root 70 Mar 22 12:54 /usr/sbin/rpc.mountd +-rwxr-xr-x 1 root root 32772 Jun 11 1995 /usr/sbin/rpc.mountd.notrans +-rwxr-xr-x 2 root root 70 Mar 22 12:54 /usr/sbin/rpc.nfsd +-rwxr-xr-x 1 root root 45060 Jun 11 1995 /usr/sbin/rpc.nfsd.notrans + +where /usr/sbin/rpc.mountd has the contents + +#!/bin/sh +exec /usr/bin/env - NAMETRANS= "`/usr/bin/env`" $0.notrans $* + +Of course, that could be improved, but is a quick hack to get things work. + +Enjoy, + +-- Thomas + + +The author can be contacted under + schoebel@informatik.uni-stuttgart.de +or snailmail + Thomas Schoebel-Theuer + Institut fuer Informatik + Breitwiesenstr. 20-22 + D-70565 Stuttgart + diff -u --recursive --new-file v2.1.42/linux/MAINTAINERS linux/MAINTAINERS --- v2.1.42/linux/MAINTAINERS Sat May 24 09:10:22 1997 +++ linux/MAINTAINERS Thu Jun 12 16:22:05 1997 @@ -125,6 +125,12 @@ L: netatalk@umich.edu S: Maintained +DECnet NETWORK LAYER +P: Steven Whitehouse +M: SteveW@ACM.org +L: netdev@roxanne.nuclecu.unam.mx +S: Maintained + AX.25 NETWORK LAYER P: Jon Naylor M: jsn@cs.nott.ac.uk diff -u --recursive --new-file v2.1.42/linux/Makefile linux/Makefile --- v2.1.42/linux/Makefile Thu May 29 21:53:03 1997 +++ linux/Makefile Thu Jun 12 16:22:05 1997 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 42 +SUBLEVEL = 43 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/) diff -u --recursive --new-file v2.1.42/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.1.42/linux/arch/alpha/config.in Wed Apr 16 14:14:59 1997 +++ linux/arch/alpha/config.in Thu Jun 12 16:22:05 1997 @@ -94,10 +94,11 @@ bool 'Sysctl support' CONFIG_SYSCTL tristate 'Kernel support for a.out (ECOFF) binaries' CONFIG_BINFMT_AOUT tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF -tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA fi +tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86 tristate 'Parallel port support' CONFIG_PNP_PARPORT endmenu @@ -172,4 +173,5 @@ if [ "$CONFIG_PROFILE" = "y" ]; then int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi +bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu diff -u --recursive --new-file v2.1.42/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c --- v2.1.42/linux/arch/alpha/kernel/osf_sys.c Wed Apr 23 19:01:14 1997 +++ linux/arch/alpha/kernel/osf_sys.c Thu Jun 12 16:22:05 1997 @@ -295,7 +295,7 @@ retval = verify_area(VERIFY_WRITE, buffer, bufsiz); if (retval) goto out; - retval = namei(path, &inode); + retval = namei(NAM_FOLLOW_LINK, path, &inode); if (retval) goto out; retval = -ENOSYS; @@ -376,7 +376,7 @@ struct file_operations *fops; int retval; - retval = namei(name, &inode); + retval = namei(NAM_FOLLOW_LINK, name, &inode); if (retval) return retval; if (!S_ISBLK(inode->i_mode)) { @@ -845,14 +845,12 @@ unsigned long nbytes, int *start, void *arg) { - extern unsigned long rdfpcr(void); unsigned long w; switch (op) { case GSI_IEEE_FP_CONTROL: - /* build and return current fp control word: */ - w = current->tss.flags & IEEE_TRAP_ENABLE_MASK; - w |= ((rdfpcr() >> 52) << 17) & IEEE_STATUS_MASK; + /* Return current software fp control & status bits. */ + w = current->tss.flags & IEEE_SW_MASK; if (put_user(w, (unsigned long *) buffer)) return -EFAULT; return 0; @@ -883,16 +881,32 @@ unsigned long nbytes, int *start, void *arg) { - unsigned long v, w, i; - switch (op) { - case SSI_IEEE_FP_CONTROL: - /* update trap enable bits: */ - if (get_user(w, (unsigned long *) buffer)) + case SSI_IEEE_FP_CONTROL: { + unsigned long swcr, fpcr; + + /* + * Alpha Architecture Handbook 4.7.7.3: + * To be fully IEEE compiant, we must track the current IEEE + * exception state in software, because spurrious bits can be + * set in the trap shadow of a software-complete insn. + */ + + /* Update softare trap enable bits. */ + if (get_user(swcr, (unsigned long *)buffer)) return -EFAULT; - current->tss.flags &= ~IEEE_TRAP_ENABLE_MASK; - current->tss.flags |= (w & IEEE_TRAP_ENABLE_MASK); + current->tss.flags &= ~IEEE_SW_MASK; + current->tss.flags |= swcr & IEEE_SW_MASK; + + /* Update the real fpcr. For exceptions that are disabled in + software but have not been seen, enable the exception in + hardware so that we can update our software status mask. */ + fpcr = rdfpcr() & (~FPCR_MASK | FPCR_DYN_MASK); + fpcr = ieee_swcr_to_fpcr(swcr | (~swcr & IEEE_STATUS_MASK)>>16); + wrfpcr(fpcr); + return 0; + } case SSI_IEEE_STATE_AT_SIGNAL: case SSI_IEEE_IGNORE_STATE_AT_SIGNAL: @@ -903,7 +917,9 @@ */ break; - case SSI_NVPAIRS: + case SSI_NVPAIRS: { + unsigned long v, w, i; + for (i = 0; i < nbytes; ++i) { if (get_user(v, 2*i + (unsigned int *)buffer)) return -EFAULT; @@ -922,6 +938,7 @@ } } return 0; + } default: break; diff -u --recursive --new-file v2.1.42/linux/arch/alpha/math-emu/fp-emul.c linux/arch/alpha/math-emu/fp-emul.c --- v2.1.42/linux/arch/alpha/math-emu/fp-emul.c Tue Oct 29 04:02:04 1996 +++ linux/arch/alpha/math-emu/fp-emul.c Thu Jun 12 16:22:05 1997 @@ -13,9 +13,9 @@ #define OPC_INTL 0x11 #define OPC_INTS 0x12 #define OPC_INTM 0x13 -#define OPC_FLTV 0x14 -#define OPC_FLTI 0x15 -#define OPC_FLTL 0x16 +#define OPC_FLTV 0x15 +#define OPC_FLTI 0x16 +#define OPC_FLTL 0x17 #define OPC_MISC 0x18 @@ -298,19 +298,26 @@ * * - Set the appropriate bits in the FPCR * - If the specified exception is enabled in the FPCR, - * return. The caller (mxr_signal_handler) will dispatch + * return. The caller (entArith) will dispatch * the appropriate signal to the translated program. + * + * In addition, properly track the exception state in software + * as described in the Alpha Architectre Handbook section 4.7.7.3. */ if (res) { - fpcr |= FPCR_SUM | res; + /* Record exceptions in software control word. */ + current->tss.flags = fpcw |= res >> 35; + + /* Update hardware control register */ + fpcr &= (~FPCR_MASK | FPCR_DYN_MASK); + fpcr |= ieee_swcr_to_fpcr(fpcw | (~fpcw&IEEE_STATUS_MASK)>>16); wrfpcr(fpcr); - if (((res & FPCR_INV) && (fpcw & IEEE_TRAP_ENABLE_INV)) || - ((res & FPCR_DZE) && (fpcw & IEEE_TRAP_ENABLE_DZE)) || - ((res & FPCR_OVF) && (fpcw & IEEE_TRAP_ENABLE_OVF)) || - ((res & FPCR_UNF) && (fpcw & IEEE_TRAP_ENABLE_UNF)) || - ((res & FPCR_INE) && (fpcw & IEEE_TRAP_ENABLE_INE))) + + /* Do we generate a signal? */ + if (res >> 51 & fpcw & IEEE_TRAP_ENABLE_MASK) return 0; } + /* * Whoo-kay... we got this far, and we're not generating a signal * to the translated program. All that remains is to write the @@ -326,6 +333,7 @@ { unsigned long trigger_pc = regs->pc - 4; unsigned long insn, opcode, rc; + /* * Turn off the bits corresponding to registers that are the * target of instructions that set bits in the exception diff -u --recursive --new-file v2.1.42/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.1.42/linux/arch/i386/config.in Sun Apr 13 10:18:20 1997 +++ linux/arch/i386/config.in Thu Jun 12 16:22:05 1997 @@ -34,6 +34,7 @@ bool 'Sysctl support' CONFIG_SYSCTL tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA fi @@ -117,4 +118,5 @@ if [ "$CONFIG_PROFILE" = "y" ]; then int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi +bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu diff -u --recursive --new-file v2.1.42/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.1.42/linux/arch/i386/defconfig Tue May 13 22:41:00 1997 +++ linux/arch/i386/defconfig Thu Jun 12 16:22:05 1997 @@ -25,6 +25,7 @@ CONFIG_SYSCTL=y CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=y # CONFIG_M386 is not set # CONFIG_M486 is not set # CONFIG_M586 is not set @@ -190,6 +191,9 @@ # Filesystems # # CONFIG_QUOTA is not set +# CONFIG_DCACHE_PRELOAD is not set +# CONFIG_OMIRR is not set +# CONFIG_TRANS_NAMES is not set CONFIG_MINIX_FS=y CONFIG_EXT2_FS=y CONFIG_FAT_FS=y @@ -241,3 +245,4 @@ # Kernel hacking # # CONFIG_PROFILE is not set +# CONFIG_MAGIC_SYSRQ is not set diff -u --recursive --new-file v2.1.42/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S --- v2.1.42/linux/arch/i386/kernel/head.S Tue May 13 22:41:00 1997 +++ linux/arch/i386/kernel/head.S Thu Jun 12 16:22:05 1997 @@ -532,8 +532,8 @@ .quad 0x0000000000000000 /* not used */ .quad 0x00cf9a000000ffff /* 0x10 kernel 4GB code at 0x00000000 */ .quad 0x00cf92000000ffff /* 0x18 kernel 4GB data at 0x00000000 */ - .quad 0x00cbfa000000ffff /* 0x23 user 3GB code at 0x00000000 */ - .quad 0x00cbf2000000ffff /* 0x2b user 3GB data at 0x00000000 */ + .quad 0x00cffa000000ffff /* 0x23 user 4GB code at 0x00000000 */ + .quad 0x00cff2000000ffff /* 0x2b user 4GB data at 0x00000000 */ .quad 0x0000000000000000 /* not used */ .quad 0x0000000000000000 /* not used */ .fill 2*NR_TASKS,8,0 /* space for LDT's and TSS's etc */ diff -u --recursive --new-file v2.1.42/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- v2.1.42/linux/arch/i386/kernel/irq.c Tue May 13 22:41:01 1997 +++ linux/arch/i386/kernel/irq.c Thu Jun 12 16:22:05 1997 @@ -142,21 +142,6 @@ * the operations that are needed to keep the AT interrupt-controller * happy. They are also written to be fast - and to disable interrupts * as little as humanly possible. - * - * NOTE! These macros expand to three different handlers for each line: one - * complete handler that does all the fancy stuff (including signal handling), - * and one fast handler that is meant for simple IRQ's that want to be - * atomic. The specific handler is chosen depending on the SA_INTERRUPT - * flag when installing a handler. Finally, one "bad interrupt" handler, that - * is used when no handler is present. - * - * The timer interrupt is handled specially to insure that the jiffies - * variable is updated at all times. Specifically, the timer interrupt is - * just like the complete handlers except that it is invoked with interrupts - * disabled and should never re-enable them. If other interrupts were - * allowed to be processed while the timer interrupt is active, then the - * other interrupts would have to avoid using the jiffies variable for delay - * and interval timing operations to avoid hanging the system. */ #if NR_IRQS != 16 @@ -539,6 +524,9 @@ status = 0; action = *(irq + irq_action); if (action) { + if (!(action->flags & SA_INTERRUPT)) + __sti(); + do { status |= action->flags; action->handler(irq, action->dev_id, ®s); @@ -546,7 +534,6 @@ } while (action); if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - __cli(); spin_lock(&irq_controller_lock); unmask_irq(irq); diff -u --recursive --new-file v2.1.42/linux/arch/i386/kernel/irq.h linux/arch/i386/kernel/irq.h --- v2.1.42/linux/arch/i386/kernel/irq.h Mon May 19 12:57:38 1997 +++ linux/arch/i386/kernel/irq.h Thu Jun 12 16:22:05 1997 @@ -9,24 +9,10 @@ #ifdef __SMP__ -#undef INIT_STUCK -#define INIT_STUCK 200000000 - -#undef STUCK -#define STUCK \ -if (!--stuck) {printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",irq,cpu,global_irq_holder); stuck = INIT_STUCK;} - static inline void irq_enter(int cpu, int irq) { - int stuck = INIT_STUCK; - hardirq_enter(cpu); while (test_bit(0,&global_irq_lock)) { - if ((unsigned char) cpu == global_irq_holder) { - printk("BAD! Local interrupts enabled, global disabled\n"); - break; - } - STUCK; /* nothing */; } } diff -u --recursive --new-file v2.1.42/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c --- v2.1.42/linux/arch/i386/kernel/smp.c Tue May 13 22:41:01 1997 +++ linux/arch/i386/kernel/smp.c Thu Jun 12 16:22:05 1997 @@ -870,6 +870,8 @@ *((volatile unsigned long *)phys_to_virt(8192)) = 0; } +unsigned int prof_multiplier[NR_CPUS]; +unsigned int prof_counter[NR_CPUS]; /* * Cycle through the processors sending APIC IPI's to boot each. @@ -912,8 +914,15 @@ * of here now! */ - if (!smp_found_config) + if (!smp_found_config) { + /* + * For SMP-simulation on one CPU to work, we must initialize these + * values for the single CPU here: + */ + prof_counter[0] = prof_multiplier[0] = 1; + return; + } /* * Map the local APIC into kernel space @@ -1301,9 +1310,6 @@ * multiplier is 1 and it can be changed by writing the new multiplier * value into /proc/profile. */ - -unsigned int prof_multiplier[NR_CPUS]; -unsigned int prof_counter[NR_CPUS]; void smp_local_timer_interrupt(struct pt_regs * regs) { diff -u --recursive --new-file v2.1.42/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c --- v2.1.42/linux/arch/i386/kernel/time.c Tue May 13 22:41:01 1997 +++ linux/arch/i386/kernel/time.c Thu Jun 12 16:22:05 1997 @@ -515,7 +515,7 @@ return mktime(year, mon, day, hour, min, sec); } -static struct irqaction irq0 = { timer_interrupt, 0, 0, "timer", NULL, NULL}; +static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL}; __initfunc(void time_init(void)) diff -u --recursive --new-file v2.1.42/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- v2.1.42/linux/arch/i386/kernel/traps.c Tue May 13 22:41:01 1997 +++ linux/arch/i386/kernel/traps.c Thu Jun 12 16:22:05 1997 @@ -191,8 +191,6 @@ spin_lock_irq(&die_lock); printk("%s: %04lx\n", str, err & 0xffff); show_registers(regs); -do { int i=2000000000; while (i) i--; } while (0); -do { int i=2000000000; while (i) i--; } while (0); spin_unlock_irq(&die_lock); do_exit(SIGSEGV); } diff -u --recursive --new-file v2.1.42/linux/arch/m68k/amiga/amifb.c linux/arch/m68k/amiga/amifb.c --- v2.1.42/linux/arch/m68k/amiga/amifb.c Tue May 13 22:41:01 1997 +++ linux/arch/m68k/amiga/amifb.c Thu Jun 12 16:22:05 1997 @@ -1307,6 +1307,7 @@ */ extern unsigned short ami_intena_vals[]; +extern void amiga_init_sound(void); /* * Support for Graphics Boards @@ -1808,6 +1809,11 @@ { int err, tag, i; u_long chipptr; + + /* + * Our beloved beeper + */ + amiga_init_sound(); /* * Check for a Graphics Board diff -u --recursive --new-file v2.1.42/linux/arch/m68k/amiga/amikeyb.c linux/arch/m68k/amiga/amikeyb.c --- v2.1.42/linux/arch/m68k/amiga/amikeyb.c Tue May 13 22:41:01 1997 +++ linux/arch/m68k/amiga/amikeyb.c Thu Jun 12 16:22:05 1997 @@ -23,18 +23,17 @@ #include #include #include +#include #include #include #include -extern void handle_scancode(unsigned char); - #define AMIKEY_CAPS (0x62) #define BREAK_MASK (0x80) #define RESET_WARNING (0xf0) /* before rotation */ -static u_short amiplain_map[NR_KEYS] = { +static u_short amiplain_map[NR_KEYS] __initdata = { 0xf060, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf05c, 0xf200, 0xf300, 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, @@ -178,15 +177,13 @@ static void amikeyb_rep(unsigned long ignore); static struct timer_list amikeyb_rep_timer = {NULL, NULL, 0, 0, amikeyb_rep}; -extern struct pt_regs *pt_regs; - static void amikeyb_rep(unsigned long ignore) { unsigned long flags; save_flags(flags); cli(); - pt_regs = NULL; + kbd_pt_regs = NULL; amikeyb_rep_timer.expires = jiffies + key_repeat_rate; amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL; @@ -202,7 +199,7 @@ static int reset_warning = 0; /* save frame for register dump */ - pt_regs = (struct pt_regs *)fp; + kbd_pt_regs = fp; /* get and invert scancode (keyboard is active low) */ scancode = ~ciaa.sdr; @@ -302,14 +299,13 @@ return -EIO; /* setup key map */ - key_maps[0] = amiplain_map; + memcpy(plain_map, amiplain_map, sizeof(plain_map)); key_maps[1] = amishift_map; key_maps[2] = amialtgr_map; key_maps[4] = amictrl_map; key_maps[5] = amishift_ctrl_map; key_maps[8] = amialt_map; key_maps[12] = amictrl_alt_map; - memcpy(plain_map, amiplain_map, sizeof(plain_map)); /* * Initialize serial data direction. diff -u --recursive --new-file v2.1.42/linux/arch/m68k/amiga/amisound.c linux/arch/m68k/amiga/amisound.c --- v2.1.42/linux/arch/m68k/amiga/amisound.c Tue May 13 22:41:01 1997 +++ linux/arch/m68k/amiga/amisound.c Thu Jun 12 16:22:05 1997 @@ -40,7 +40,7 @@ static u_long clock_constant; -__initfunc(static void init_sound(void)) +__initfunc(void amiga_init_sound(void)) { snd_data = amiga_chip_alloc(sizeof(sine_data)); if (!snd_data) { @@ -58,13 +58,7 @@ void amiga_mksound( unsigned int hz, unsigned int ticks ) { - static int inited = 0; unsigned long flags; - - if (!inited) { - init_sound(); - inited = 1; - } if (!snd_data) return; diff -u --recursive --new-file v2.1.42/linux/arch/m68k/amiga/config.c linux/arch/m68k/amiga/config.c --- v2.1.42/linux/arch/m68k/amiga/config.c Thu May 29 21:53:04 1997 +++ linux/arch/m68k/amiga/config.c Thu Jun 12 16:22:05 1997 @@ -78,6 +78,7 @@ extern struct consw fb_con; extern struct fb_info *amiga_fb_init(long *); extern void zorro_init(void); +extern void amiga_init_sound(void); static void amiga_savekmsg_init(void); static void amiga_mem_console_write(const char *b, unsigned int count); static void amiga_serial_console_write(const char *s, unsigned int count); diff -u --recursive --new-file v2.1.42/linux/arch/m68k/atari/ataints.c linux/arch/m68k/atari/ataints.c --- v2.1.42/linux/arch/m68k/atari/ataints.c Sat May 24 09:10:22 1997 +++ linux/arch/m68k/atari/ataints.c Thu Jun 12 16:22:05 1997 @@ -48,6 +48,7 @@ #include #include #include +#include /* @@ -161,22 +162,6 @@ #define IRQ_NAME(nr) atari_slow_irq_##nr##_handler(void) -#define MFP_MK_BASE "0xfa13" - -/* This must agree with entry.S. */ -#define ORIG_DO "0x24" -#define FORMATVEC "0x32" -#define SR "0x2C" -#define SAVE_ALL \ - "clrl %%sp@-;" /* stk_adj */ \ - "pea -1:w;" /* orig d0 = -1 */ \ - "movel %%d0,%%sp@-;" /* d0 */ \ - "moveml %%d1-%%d5/%%a0-%%a2,%%sp@-" -#define GET_CURRENT(tmp) \ - "movel %%sp,"#tmp";" \ - "andw #-8192,"#tmp";" \ - "movel "#tmp",%%a2" - #define BUILD_SLOW_IRQ(n) \ asmlinkage void IRQ_NAME(n); \ /* Dummy function to allow asm with operands. */ \ @@ -184,29 +169,31 @@ __asm__ (ALIGN_STR "\n" \ SYMBOL_NAME_STR(atari_slow_irq_) #n "_handler:\t" \ " addql #1,"SYMBOL_NAME_STR(local_irq_count)"\n" \ - SAVE_ALL "\n" \ + SAVE_ALL_INT "\n" \ GET_CURRENT(%%d0) "\n" \ -" andb #~(1<<(" #n "&7))," /* mask this interrupt */ \ - "("MFP_MK_BASE"+(((" #n "&8)^8)>>2)+((" #n "&16)<<3)):w\n" \ -" bfextu %%sp@("SR"){#5,#3},%%d0\n" /* get old IPL from stack frame */ \ +" andb #~(1<<(%c3&7)),%a4:w\n" /* mask this interrupt */ \ + /* get old IPL from stack frame */ \ +" bfextu %%sp@(%c2){#5,#3},%%d0\n" \ " movew %%sr,%%d1\n" \ " bfins %%d0,%%d1{#21,#3}\n" \ " movew %%d1,%%sr\n" /* set IPL = previous value */ \ " addql #1,%a0\n" \ -" lea "SYMBOL_NAME_STR(irq_handler)"+("#n"+8)*8,%%a0\n" \ +" lea %a1,%%a0\n" \ " pea %%sp@\n" /* push addr of frame */ \ " movel %%a0@(4),%%sp@-\n" /* push handler data */ \ -" pea (" #n "+8)\n" /* push int number */ \ +" pea (%c3+8)\n" /* push int number */ \ " movel %%a0@,%%a0\n" \ " jbsr %%a0@\n" /* call the handler */ \ " addql #8,%%sp\n" \ " addql #4,%%sp\n" \ " orw #0x0600,%%sr\n" \ " andw #0xfeff,%%sr\n" /* set IPL = 6 again */ \ -" orb #(1<<(" #n "&7))," /* now unmask the int again */ \ - "("MFP_MK_BASE"+(((" #n "&8)^8)>>2)+((" #n "&16)<<3)):w\n" \ +" orb #(1<<(%c3&7)),%a4:w\n" /* now unmask the int again */ \ " jbra "SYMBOL_NAME_STR(ret_from_interrupt)"\n" \ - : : "i" (&kstat.interrupts[n+8]) \ + : : "i" (&kstat.interrupts[n+8]), "i" (&irq_handler[n+8]), \ + "n" (PT_OFF_SR), "n" (n), \ + "i" (n & 8 ? (n & 16 ? &tt_mfp.int_mk_a : &mfp.int_mk_a) \ + : (n & 16 ? &tt_mfp.int_mk_b : &mfp.int_mk_b)) \ ); \ } @@ -288,10 +275,10 @@ orw #0x700,%%sr /* disable all interrupts */ "SYMBOL_NAME_STR(atari_prio_irq_handler) ":\t addql #1,"SYMBOL_NAME_STR(local_irq_count)"\n" - SAVE_ALL "\n" + SAVE_ALL_INT "\n" GET_CURRENT(%%d0) " /* get vector number from stack frame and convert to source */ - bfextu %%sp@(" FORMATVEC "){#4,#10},%%d0 + bfextu %%sp@(%c1){#4,#10},%%d0 subw #(0x40-8),%%d0 jpl 1f addw #(0x40-8-0x18),%%d0 @@ -307,7 +294,7 @@ addql #8,%%sp addql #4,%%sp jbra "SYMBOL_NAME_STR(ret_from_interrupt) - : : "i" (&kstat.interrupts) + : : "i" (&kstat.interrupts), "n" (PT_OFF_FORMATVEC) ); } diff -u --recursive --new-file v2.1.42/linux/arch/m68k/atari/atakeyb.c linux/arch/m68k/atari/atakeyb.c --- v2.1.42/linux/arch/m68k/atari/atakeyb.c Tue May 13 22:41:02 1997 +++ linux/arch/m68k/atari/atakeyb.c Thu Jun 12 16:22:05 1997 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -31,7 +32,6 @@ #include #include -extern void handle_scancode(unsigned char); extern int ovsc_switchmode; extern unsigned char mach_keyboard_type; static void atakeyb_rep( unsigned long ignore ); @@ -99,7 +99,7 @@ * - Keypad Left/Right Parenthesis mapped to new K_PPAREN[LR] */ -static u_short ataplain_map[NR_KEYS] = { +static u_short ataplain_map[NR_KEYS] __initdata = { 0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf009, 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, @@ -139,7 +139,7 @@ static u_short atactrl_map[NR_KEYS] = { 0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e, - 0xf01f, 0xf07f, 0xf200, 0xf200, 0xf07f, 0xf200, 0xf008, 0xf200, + 0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200, 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, 0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf201, 0xf702, 0xf001, 0xf013, 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200, @@ -158,18 +158,18 @@ static u_short atashift_ctrl_map[NR_KEYS] = { 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf008, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf201, 0xf702, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf700, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf700, 0xf200, - 0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf117, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200, + 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, + 0xf00f, 0xf010, 0xf200, 0xf200, 0xf201, 0xf702, 0xf001, 0xf013, + 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200, + 0xf200, 0xf200, 0xf700, 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016, + 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf07f, 0xf700, 0xf200, + 0xf703, 0xf200, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, + 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf117, 0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200, - 0xf600, 0xf200, 0xf115, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307, + 0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307, 0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303, 0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200 @@ -207,7 +207,7 @@ 0xf118, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200, 0xf119, 0xf200, 0xf115, 0xf87f, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307, + 0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307, 0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303, 0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200 @@ -215,7 +215,7 @@ static u_short atactrl_alt_map[NR_KEYS] = { 0xf200, 0xf200, 0xf200, 0xf800, 0xf81b, 0xf81c, 0xf81d, 0xf81e, - 0xf81f, 0xf87f, 0xf200, 0xf200, 0xf87f, 0xf200, 0xf808, 0xf200, + 0xf81f, 0xf87f, 0xf200, 0xf200, 0xf81f, 0xf200, 0xf808, 0xf200, 0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809, 0xf80f, 0xf810, 0xf81b, 0xf81d, 0xf201, 0xf702, 0xf801, 0xf813, 0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200, @@ -224,7 +224,7 @@ 0xf703, 0xf800, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114, 0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200, - 0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf600, 0xf200, 0xf115, 0xf87f, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf1ff, 0xf202, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307, 0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303, @@ -234,18 +234,18 @@ static u_short atashift_ctrl_alt_map[NR_KEYS] = { 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf808, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf201, 0xf702, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf700, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf700, 0xf200, - 0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf117, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf81f, 0xf200, 0xf808, 0xf200, + 0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809, + 0xf80f, 0xf810, 0xf200, 0xf200, 0xf201, 0xf702, 0xf801, 0xf813, + 0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200, + 0xf200, 0xf200, 0xf700, 0xf200, 0xf81a, 0xf818, 0xf803, 0xf816, + 0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf87f, 0xf700, 0xf200, + 0xf703, 0xf200, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, + 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf117, 0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200, - 0xf600, 0xf200, 0xf115, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf600, 0xf200, 0xf115, 0xf87f, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307, + 0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307, 0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303, 0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200 @@ -277,12 +277,10 @@ static unsigned char rep_scancode; static struct timer_list atakeyb_rep_timer = { NULL, NULL, 0, 0, atakeyb_rep }; -extern struct pt_regs *pt_regs; - static void atakeyb_rep( unsigned long ignore ) { - pt_regs = NULL; + kbd_pt_regs = NULL; /* Disable keyboard for the time we call handle_scancode(), else a race * in the keyboard tty queue may happen */ @@ -327,7 +325,7 @@ int break_flag; /* save frame for register dump */ - pt_regs = (struct pt_regs *)fp; + kbd_pt_regs = fp; repeat: if (acia.mid_ctrl & ACIA_IRQ) @@ -420,14 +418,14 @@ * make codes instead. Therefore, simply ignore * break_flag... * */ - int keyval = ataplain_map[scancode], keytyp; - + int keyval = plain_map[scancode], keytyp; + set_bit( scancode, broken_keys ); self_test_last_rcv = jiffies; - keyval = ataplain_map[scancode]; + keyval = plain_map[scancode]; keytyp = KTYP(keyval) - 0xf0; keyval = KVAL(keyval); - + printk( KERN_WARNING "Key with scancode %d ", scancode ); if (keytyp == KT_LATIN || keytyp == KT_LETTER) { if (keyval < ' ') @@ -440,7 +438,7 @@ } else if (test_bit( scancode, broken_keys )) break; - + if (break_flag) { del_timer( &atakeyb_rep_timer ); rep_scancode = 0; @@ -808,7 +806,7 @@ __initfunc(int atari_keyb_init(void)) { /* setup key map */ - key_maps[0] = ataplain_map; + memcpy (plain_map, ataplain_map, sizeof(plain_map)); key_maps[1] = atashift_map; key_maps[2] = 0; /* ataaltgr_map */ key_maps[4] = atactrl_map; @@ -817,7 +815,6 @@ key_maps[9] = atashift_alt_map; key_maps[12] = atactrl_alt_map; key_maps[13] = atashift_ctrl_alt_map; - memcpy (plain_map, ataplain_map, sizeof(plain_map)); keymap_count = 8; /* say that we don't have an AltGr key */ diff -u --recursive --new-file v2.1.42/linux/arch/m68k/console/fbcon.c linux/arch/m68k/console/fbcon.c --- v2.1.42/linux/arch/m68k/console/fbcon.c Wed Apr 23 19:01:15 1997 +++ linux/arch/m68k/console/fbcon.c Thu Jun 12 16:22:05 1997 @@ -69,8 +69,8 @@ #include #include -#include "../../../drivers/char/vt_kern.h" /* vt_cons and vc_resize_con() */ -#include "../../../drivers/char/console_struct.h" +#include +#include /* Import console_blanked from console.c */ diff -u --recursive --new-file v2.1.42/linux/arch/m68k/fpsp040/skeleton.S linux/arch/m68k/fpsp040/skeleton.S --- v2.1.42/linux/arch/m68k/fpsp040/skeleton.S Sat May 24 09:10:22 1997 +++ linux/arch/m68k/fpsp040/skeleton.S Thu Jun 12 16:22:05 1997 @@ -39,6 +39,7 @@ | #include +#include |SKELETON idnt 2,1 | Motorola 040 Floating Point Software Package @@ -51,24 +52,6 @@ .include "fpsp.h" -/* - * This has to match entry.S - */ -LOFF_ORIG_D0 = 0x24 - -#define curptr a2 - -#define SAVE_ALL \ - clrl %sp@-; /* stk_adj */ \ - movel %d0,%sp@-; /* orig d0 */ \ - movel %d0,%sp@-; /* d0 */ \ - moveml %d1-%d5/%a0-%a1/%curptr,%sp@-; - -#define GET_CURRENT(tmp) \ - movel %sp,tmp; \ - andw &-8192,tmp; \ - movel tmp,%curptr; - |xref b1238_fix | @@ -86,11 +69,7 @@ frestore (%sp)+ unlk %a6 - SAVE_ALL - moveq #-1,%d0 - movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field - | signifies that the stack frame - | is NOT for syscall + SAVE_ALL_INT GET_CURRENT(%d0) movel %sp,%sp@- | stack frame pointer argument bsrl SYMBOL_NAME(trap_c) @@ -181,11 +160,7 @@ frestore (%sp)+ unlk %a6 - SAVE_ALL - moveq #-1,%d0 - movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field - | signifies that the stack frame - | is NOT for syscall + SAVE_ALL_INT GET_CURRENT(%d0) movel %sp,%sp@- | stack frame pointer argument bsrl SYMBOL_NAME(trap_c) @@ -211,11 +186,7 @@ frestore (%sp)+ unlk %a6 - SAVE_ALL - moveq #-1,%d0 - movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field - | signifies that the stack frame - | is NOT for syscall + SAVE_ALL_INT GET_CURRENT(%d0) movel %sp,%sp@- | stack frame pointer argument bsrl SYMBOL_NAME(trap_c) @@ -241,11 +212,7 @@ frestore (%sp)+ unlk %a6 - SAVE_ALL - moveq #-1,%d0 - movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field - | signifies that the stack frame - | is NOT for syscall + SAVE_ALL_INT GET_CURRENT(%d0) movel %sp,%sp@- | stack frame pointer argument bsrl SYMBOL_NAME(trap_c) @@ -267,11 +234,7 @@ frestore (%sp)+ unlk %a6 - SAVE_ALL - moveq #-1,%d0 - movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field - | signifies that the stack frame - | is NOT for syscall + SAVE_ALL_INT GET_CURRENT(%d0) movel %sp,%sp@- | stack frame pointer argument bsrl SYMBOL_NAME(trap_c) @@ -293,11 +256,7 @@ frestore (%sp)+ unlk %a6 - SAVE_ALL - moveq #-1,%d0 - movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field - | signifies that the stack frame - | is NOT for syscall + SAVE_ALL_INT GET_CURRENT(%d0) movel %sp,%sp@- | stack frame pointer argument bsrl SYMBOL_NAME(trap_c) @@ -325,11 +284,7 @@ frestore (%sp)+ unlk %a6 - SAVE_ALL - moveq #-1,%d0 - movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field - | signifies that the stack frame - | is NOT for syscall + SAVE_ALL_INT GET_CURRENT(%d0) movel %sp,%sp@- | stack frame pointer argument bsrl SYMBOL_NAME(trap_c) @@ -350,11 +305,7 @@ jmp fpsp_fline real_fline: - SAVE_ALL - moveq #-1,%d0 - movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field - | signifies that the stack frame - | is NOT for syscall + SAVE_ALL_INT GET_CURRENT(%d0) movel %sp,%sp@- | stack frame pointer argument bsrl SYMBOL_NAME(trap_c) @@ -376,11 +327,7 @@ frestore (%sp)+ unlk %a6 - SAVE_ALL - moveq #-1,%d0 - movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field - | signifies that the stack frame - | is NOT for syscall + SAVE_ALL_INT GET_CURRENT(%d0) movel %sp,%sp@- | stack frame pointer argument bsrl SYMBOL_NAME(trap_c) @@ -435,9 +382,7 @@ bne Lmustsched rte Lmustsched: - SAVE_ALL - moveq #-1,%d0 - movel %d0,%sp@(LOFF_ORIG_D0) | indicate stack frame not for syscall + SAVE_ALL_INT GET_CURRENT(%d0) bral SYMBOL_NAME(ret_from_exception) | deliver signals, reschedule etc.. diff -u --recursive --new-file v2.1.42/linux/arch/m68k/kernel/console.c linux/arch/m68k/kernel/console.c --- v2.1.42/linux/arch/m68k/kernel/console.c Wed Apr 23 19:01:15 1997 +++ linux/arch/m68k/kernel/console.c Thu Jun 12 16:22:05 1997 @@ -109,7 +109,6 @@ #include #include #include -#include #include #include #include @@ -119,17 +118,18 @@ #include #include #include +#include #include #include #include #include -#include "../../../drivers/char/kbd_kern.h" -#include "../../../drivers/char/vt_kern.h" -#include "../../../drivers/char/consolemap.h" -#include "../../../drivers/char/selection.h" -#include "../../../drivers/char/console_struct.h" +#include +#include +#include +#include +#include #ifndef MIN @@ -159,6 +159,8 @@ extern void vesa_blank(void); extern void vesa_unblank(void); extern void compute_shiftstate(void); +extern void reset_palette(int currcons); +extern void set_palette(void); void poke_blanked_console(void); void do_blank_screen(int); @@ -257,6 +259,7 @@ #define ulcolor (vc_cons[currcons].d->vc_ulcolor) #define halfcolor (vc_cons[currcons].d->vc_halfcolor) #define tab_stop (vc_cons[currcons].d->vc_tab_stop) +#define palette (vc_cons[currcons].d->vc_palette) #define bell_pitch (vc_cons[currcons].d->vc_bell_pitch) #define bell_duration (vc_cons[currcons].d->vc_bell_duration) #define sw (vc_cons[currcons].d->vc_sw) @@ -539,6 +542,14 @@ static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, 8,12,10,14, 9,13,11,15 }; +/* the default colour table, for VGA+ colour systems */ +int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa, + 0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff}; +int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa, + 0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff}; +int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa, + 0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff}; + /* * gotoxy() must verify all boundaries, because the arguments * might also be negative. If the given position is out of @@ -1655,7 +1666,7 @@ if (nextx == cols) { sw->con_putc(vc_cons[currcons].d, *putcs_buf, y, x); - ((unsigned short *)pos)--; + pos--; need_wrap = decawm; continue; } @@ -1837,9 +1848,7 @@ vc_state = ESpalette; continue; } else if (c=='R') { /* reset palette */ -#if 0 reset_palette (currcons); -#endif vc_state = ESnormal; } else vc_state = ESnormal; @@ -1848,7 +1857,6 @@ if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) { par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ; if (npar==7) { -#if 0 int i = par[0]*3, j = 1; palette[i] = 16*par[j++]; palette[i++] += par[j++]; @@ -1857,7 +1865,6 @@ palette[i] = 16*par[j++]; palette[i] += par[j]; set_palette() ; -#endif vc_state = ESnormal; } } else @@ -2283,7 +2290,7 @@ * Reads the information preserved by setup.s to determine the current display * type and sets everything accordingly. */ -unsigned long con_init(unsigned long kmem_start) +__initfunc(unsigned long con_init(unsigned long kmem_start)) { const char *display_desc = "????"; unsigned int currcons = 0; @@ -2617,22 +2624,61 @@ * map, 3 bytes per colour, 16 colours, range from 0 to 255. */ +static int set_get_cmap(unsigned char *arg, int set) +{ + int i, j, k; + + for (i = 0; i < 16; i++) + if (set) { + get_user(default_red[i], arg++); + get_user(default_grn[i], arg++); + get_user(default_blu[i], arg++); + } else { + put_user(default_red[i], arg++); + put_user(default_grn[i], arg++); + put_user(default_blu[i], arg++); + } + if (set) { + for (i = 0; i < MAX_NR_CONSOLES; i++) + if (vc_cons_allocated(i)) + for (j = k = 0; j < 16; j++) { + vc_cons[i].d->vc_palette[k++] = + default_red[j]; + vc_cons[i].d->vc_palette[k++] = + default_grn[j]; + vc_cons[i].d->vc_palette[k++] = + default_blu[j]; + } + set_palette(); + } + return 0; +} + int con_set_cmap (unsigned char *arg) { - return -EINVAL; + return set_get_cmap (arg, 1); } int con_get_cmap (unsigned char *arg) { - return -EINVAL; + return set_get_cmap (arg, 0); } void reset_palette(int currcons) { + int j, k; + for (j = k = 0; j < 16; j++) { + palette[k++] = default_red[j]; + palette[k++] = default_grn[j]; + palette[k++] = default_blu[j]; + } + set_palette() ; } void set_palette(void) { + if (vt_cons[fg_console]->vc_mode != KD_GRAPHICS) + conswitchp->con_set_palette(vc_cons[fg_console].d, color_table); } /* diff -u --recursive --new-file v2.1.42/linux/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S --- v2.1.42/linux/arch/m68k/kernel/entry.S Sat May 24 09:10:22 1997 +++ linux/arch/m68k/kernel/entry.S Thu Jun 12 16:22:05 1997 @@ -22,24 +22,6 @@ * NOTE: This code handles signal-recognition, which happens every time * after a timer-interrupt and after each system call. * - * Stack layout in 'ret_from_exception': - * - * This allows access to the syscall arguments in registers d1-d5 - * - * 0(sp) - d1 - * 4(sp) - d2 - * 8(sp) - d3 - * C(sp) - d4 - * 10(sp) - d5 - * 14(sp) - a0 - * 18(sp) - a1 - * 1C(sp) - a2 - * 20(sp) - d0 - * 24(sp) - orig_d0 - * 28(sp) - stack adjustment - * 2C(sp) - sr - * 2E(sp) - pc - * 32(sp) - format & vector */ /* @@ -48,94 +30,12 @@ * number 0 in the 'current_set' list. */ -/* - * 97/05/14 Andreas: Register %a2 is now set to the current task throughout - * the whole kernel. - */ - #include #include #include +#include #include #include -#ifdef CONFIG_KGDB -#include -.globl SYMBOL_NAME(kgdb_registers) -#endif - -#define curptr a2 - -LENOSYS = 38 - -/* - * these are offsets into the task-struct - */ -LTASK_STATE = 0 -LTASK_COUNTER = 4 -LTASK_PRIORITY = 8 -LTASK_SIGNAL = 12 -LTASK_BLOCKED = 16 -LTASK_FLAGS = 20 - -/* the following macro is used when enabling interrupts */ -#if defined(MACH_ATARI_ONLY) - /* block out HSYNC on the atari */ -#define ALLOWINT 0xfbff -#define MAX_NOINT_IPL 3 -#else - /* portable version */ -#define ALLOWINT 0xf8ff -#define MAX_NOINT_IPL 0 -#endif /* machine compilation types */ - -LD0 = 0x20 -LORIG_D0 = 0x24 -LSR = 0x2C -LFORMATVEC = 0x32 - -/* - * This defines the normal kernel pt-regs layout. - * - * regs a3-a6 and d6-d7 are preserved by C code - * the kernel doesn't mess with usp unless it needs to - */ -#ifndef CONFIG_KGDB -#define SAVE_ALL \ - clrl %sp@-; /* stk_adj */ \ - movel %d0,%sp@-; /* orig d0 */ \ - movel %d0,%sp@-; /* d0 */ \ - moveml %d1-%d5/%a0-%a1/%curptr,%sp@-; -#else -/* Need to save the "missing" registers for kgdb... - */ -#define SAVE_ALL \ - clrl %sp@-; /* stk_adj */ \ - movel %d0,%sp@-; /* orig d0 */ \ - movel %d0,%sp@-; /* d0 */ \ - moveml %d1-%d5/%a0-%a1/%curptr,%sp@-; \ - moveml %d6-%d7,SYMBOL_NAME(kgdb_registers)+GDBOFFA_D6; \ - moveml %a3-%a6,SYMBOL_NAME(kgdb_registers)+GDBOFFA_A3; -#endif - -#define RESTORE_ALL \ - moveml %sp@+,%a0-%a1/%curptr/%d1-%d5; \ - movel %sp@+,%d0; \ - addql #4,%sp; /* orig d0 */ \ - addl %sp@+,%sp; /* stk adj */ \ - rte - -#define SWITCH_STACK_SIZE (6*4+4) /* includes return address */ - -#define SAVE_SWITCH_STACK \ - moveml %a3-%a6/%d6-%d7,%sp@- - -#define RESTORE_SWITCH_STACK \ - moveml %sp@+,%a3-%a6/%d6-%d7 - -#define GET_CURRENT(tmp) \ - movel %sp,tmp; \ - andw &-8192,tmp; \ - movel tmp,%curptr; .globl SYMBOL_NAME(system_call), SYMBOL_NAME(buserr), SYMBOL_NAME(trap) .globl SYMBOL_NAME(resume), SYMBOL_NAME(ret_from_exception) @@ -146,12 +46,7 @@ .text ENTRY(buserr) - SAVE_ALL - moveq #-1,%d0 - movel %d0,%sp@(LORIG_D0) | a -1 in the ORIG_D0 field - | signifies that the stack frame - | is NOT for syscall - + SAVE_ALL_INT GET_CURRENT(%d0) movel %sp,%sp@- | stack frame pointer argument bsrl SYMBOL_NAME(buserr_c) @@ -159,11 +54,7 @@ jra SYMBOL_NAME(ret_from_exception) ENTRY(trap) - SAVE_ALL - moveq #-1,%d0 - movel %d0,%sp@(LORIG_D0) | a -1 in the ORIG_D0 field - | signifies that the stack frame - | is NOT for syscall + SAVE_ALL_INT GET_CURRENT(%d0) movel %sp,%sp@- | stack frame pointer argument bsrl SYMBOL_NAME(trap_c) @@ -180,18 +71,18 @@ jmp SYMBOL_NAME(schedule) badsys: - movel #-LENOSYS,LD0(%sp) + movel #-LENOSYS,LPT_OFF_D0(%sp) jra SYMBOL_NAME(ret_from_exception) do_trace: - movel #-LENOSYS,LD0(%sp) | needed for strace + movel #-LENOSYS,LPT_OFF_D0(%sp) | needed for strace subql #4,%sp SAVE_SWITCH_STACK jbsr SYMBOL_NAME(syscall_trace) RESTORE_SWITCH_STACK addql #4,%sp jbsr @(SYMBOL_NAME(sys_call_table),%d2:l:4)@(0) - movel %d0,%sp@(LD0) | save the return value + movel %d0,%sp@(LPT_OFF_D0) | save the return value subql #4,%sp | dummy return address SAVE_SWITCH_STACK jbsr SYMBOL_NAME(syscall_trace) @@ -202,7 +93,7 @@ jra SYMBOL_NAME(ret_from_exception) ENTRY(system_call) - SAVE_ALL + SAVE_ALL_SYS movel %d0,%d2 GET_CURRENT(%d0) @@ -213,19 +104,20 @@ cmpl #NR_syscalls,%d2 jcc badsys - btst #5,%curptr@(LTASK_FLAGS+3) | PF_TRACESYS + btst #LPF_TRACESYS_BIT,%curptr@(LTASK_FLAGS+LPF_TRACESYS_OFF) jne do_trace jbsr @(SYMBOL_NAME(sys_call_table),%d2:l:4)@(0) - movel %d0,%sp@(LD0) | save the return value + movel %d0,%sp@(LPT_OFF_D0) | save the return value SYMBOL_NAME_LABEL(ret_from_exception) - btst #5,%sp@(LSR) | check if returning to kernel + btst #5,%sp@(LPT_OFF_SR) | check if returning to kernel bnes 2f | if so, skip resched, signals tstl SYMBOL_NAME(need_resched) jne SYMBOL_NAME(reschedule) cmpl #SYMBOL_NAME(task),%curptr | task[0] cannot have signals jeq 2f - bclr #5,%curptr@(LTASK_FLAGS+1) | check for delayed trace + | check for delayed trace + bclr #LPF_DTRACE_BIT,%curptr@(LTASK_FLAGS+LPF_DTRACE_OFF) jne do_delayed_trace 5: tstl %curptr@(LTASK_STATE) | state @@ -236,7 +128,7 @@ movel %curptr@(LTASK_BLOCKED),%d0 movel %d0,%d1 | save blocked in d1 for sig handling notl %d0 - btst #4,%curptr@(LTASK_FLAGS+3) | PF_PTRACED + btst #LPF_PTRACED_BIT,%curptr@(LTASK_FLAGS+LPF_PTRACED_OFF) jeq 1f moveq #-1,%d0 | let the debugger see all signals 1: andl %curptr@(LTASK_SIGNAL),%d0 @@ -255,10 +147,10 @@ RESTORE_ALL do_delayed_trace: - bclr #7,%sp@(LSR) | clear trace bit in SR + bclr #7,%sp@(LPT_OFF_SR) | clear trace bit in SR pea 1 | send SIGTRAP - movel %a0,%sp@- - pea 5 + movel %curptr,%sp@- + pea LSIGTRAP jbsr SYMBOL_NAME(send_sig) addql #8,%sp addql #4,%sp @@ -268,15 +160,11 @@ ** This is the main interrupt handler, responsible for calling process_int() */ SYMBOL_NAME_LABEL(inthandler) - SAVE_ALL - moveq #-1,%d0 - movel %d0,%sp@(LORIG_D0) | a -1 in the ORIG_D0 field - | signifies that the stack frame - | is NOT for syscall + SAVE_ALL_INT GET_CURRENT(%d0) addql #1,SYMBOL_NAME(local_irq_count) | put exception # in d0 - bfextu %sp@(LFORMATVEC){#4,#10},%d0 + bfextu %sp@(LPT_OFF_FORMATVEC){#4,#10},%d0 movel %sp,%sp@- movel %d0,%sp@- | put vector # on stack @@ -290,7 +178,7 @@ RESTORE_ALL 1: #if 1 - bfextu %sp@(LSR){#5,#3},%d0 | Check for nested interrupt. + bfextu %sp@(LPT_OFF_SR){#5,#3},%d0 | Check for nested interrupt. #if MAX_NOINT_IPL > 0 cmpiw #MAX_NOINT_IPL,%d0 #endif @@ -347,14 +235,6 @@ RESTORE_SWITCH_STACK rts -LFLUSH_I_AND_D = 0x00000808 -LTSS_KSP = 0 -LTSS_USP = 4 -LTSS_SR = 8 -LTSS_FS = 10 -LTSS_CRP = 12 -LTSS_FPCTXT = 24 - SYMBOL_NAME_LABEL(resume) /* * Beware - when entering resume, offset of tss is in d1, @@ -460,8 +340,10 @@ #if defined (CONFIG_M68060) /* is it a '060 ? */ +#if !defined(CPU_M68060_ONLY) btst #3,SYMBOL_NAME(m68k_cputype)+3 beqs 2f +#endif /* clear user entries in the branch cache */ movec %cacr,%d0 orl #0x00200000,%d0 diff -u --recursive --new-file v2.1.42/linux/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c --- v2.1.42/linux/arch/m68k/kernel/setup.c Tue May 13 22:41:02 1997 +++ linux/arch/m68k/kernel/setup.c Thu Jun 12 16:22:05 1997 @@ -142,8 +142,8 @@ } } - __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p, - unsigned long * memory_end_p)) +__initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p, + unsigned long * memory_end_p)) { unsigned long memory_start, memory_end; extern int _etext, _edata, _end; diff -u --recursive --new-file v2.1.42/linux/arch/m68k/kernel/traps.c linux/arch/m68k/kernel/traps.c --- v2.1.42/linux/arch/m68k/kernel/traps.c Sat May 24 09:10:22 1997 +++ linux/arch/m68k/kernel/traps.c Thu Jun 12 16:22:05 1997 @@ -201,7 +201,7 @@ if ((!(fslw & MMU060_ERR_BITS)) && !(fslw & MMU060_SEE)) return; } - + if (fslw & (MMU060_DESC_ERR | MMU060_WP)) { unsigned long errorcode; unsigned long addr = fp->un.fmt4.effaddr; diff -u --recursive --new-file v2.1.42/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c --- v2.1.42/linux/arch/m68k/mm/init.c Sat May 24 09:10:22 1997 +++ linux/arch/m68k/mm/init.c Thu Jun 12 16:22:05 1997 @@ -296,7 +296,8 @@ * The parameters are pointers to where to stick the starting and ending * addresses of available kernel virtual memory. */ -__initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)) +__initfunc(unsigned long paging_init(unsigned long start_mem, + unsigned long end_mem)) { int chunk; unsigned long mem_avail = 0; diff -u --recursive --new-file v2.1.42/linux/arch/m68k/mm/memory.c linux/arch/m68k/mm/memory.c --- v2.1.42/linux/arch/m68k/mm/memory.c Sat May 24 09:10:22 1997 +++ linux/arch/m68k/mm/memory.c Thu Jun 12 16:22:05 1997 @@ -552,39 +552,26 @@ void cache_clear (unsigned long paddr, int len) { if (CPU_IS_040_OR_060) { + int tmp; + /* * cwe need special treatment for the first page, in case it * is not page-aligned. */ - if (paddr & (PAGE_SIZE - 1)){ + if ((tmp = -paddr & (PAGE_SIZE - 1))) { pushcl040(paddr); - if (len <= PAGE_SIZE){ - if (((paddr + len - 1) ^ paddr) & PAGE_MASK) { - pushcl040(paddr + len - 1); - } + if ((len -= tmp) <= 0) return; - }else{ - len -=PAGE_SIZE; - paddr += PAGE_SIZE; - } + paddr += tmp; } - - while (len > PAGE_SIZE) { -#if 0 - pushcl040(paddr); -#else + tmp = PAGE_SIZE; + while ((len -= tmp) >= 0) { clear040(paddr); -#endif - len -= PAGE_SIZE; - paddr += PAGE_SIZE; + paddr += tmp; } - if (len > 0) { + if ((len += tmp)) + /* a page boundary gets crossed at the end */ pushcl040(paddr); - if (((paddr + len - 1) ^ paddr) & PAGE_MASK) { - /* a page boundary gets crossed at the end */ - pushcl040(paddr + len - 1); - } - } } else /* 68030 or 68020 */ asm volatile ("movec %/cacr,%/d0\n\t" @@ -605,26 +592,19 @@ void cache_push (unsigned long paddr, int len) { if (CPU_IS_040_OR_060) { + int tmp = PAGE_SIZE; + /* * on 68040 or 68060, push cache lines for pages in the range; * on the '040 this also invalidates the pushed lines, but not on * the '060! */ - while (len > PAGE_SIZE) { + len += paddr & (PAGE_SIZE - 1); + do { pushcli040(paddr); - len -= PAGE_SIZE; - paddr += PAGE_SIZE; - } - if (len > 0) { - pushcli040(paddr); - if (((paddr + len - 1) ^ paddr) & PAGE_MASK) { - /* a page boundary gets crossed at the end */ - pushcli040(paddr + len - 1); - } - } - } - - + paddr += tmp; + } while ((len -= tmp) > 0); + } /* * 68030/68020 have no writeback cache. On the other hand, * cache_push is actually a superset of cache_clear (the lines @@ -654,34 +634,24 @@ void cache_push_v (unsigned long vaddr, int len) { if (CPU_IS_040) { + int tmp = PAGE_SIZE; + /* on 68040, push cache lines for pages in the range */ - while (len > PAGE_SIZE) { + len += vaddr & (PAGE_SIZE - 1); + do { pushv040(vaddr); - len -= PAGE_SIZE; - vaddr += PAGE_SIZE; - } - if (len > 0) { - pushv040(vaddr); - if (((vaddr + len - 1) ^ vaddr) & PAGE_MASK) { - /* a page boundary gets crossed at the end */ - pushv040(vaddr + len - 1); - } - } - } + vaddr += tmp; + } while ((len -= tmp) > 0); + } else if (CPU_IS_060) { + int tmp = PAGE_SIZE; + /* on 68040, push cache lines for pages in the range */ - while (len > PAGE_SIZE) { + len += vaddr & (PAGE_SIZE - 1); + do { pushv060(vaddr); - len -= PAGE_SIZE; - vaddr += PAGE_SIZE; - } - if (len > 0) { - pushv060(vaddr); - if (((vaddr + len - 1) ^ vaddr) & PAGE_MASK) { - /* a page boundary gets crossed at the end */ - pushv060(vaddr + len - 1); - } - } + vaddr += tmp; + } while ((len -= tmp) > 0); } /* 68030/68020 have no writeback cache; still need to clear icache. */ else /* 68030 or 68020 */ diff -u --recursive --new-file v2.1.42/linux/arch/sparc/config.in linux/arch/sparc/config.in --- v2.1.42/linux/arch/sparc/config.in Mon Apr 14 16:28:06 1997 +++ linux/arch/sparc/config.in Thu Jun 12 16:22:05 1997 @@ -54,6 +54,7 @@ tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA fi endmenu diff -u --recursive --new-file v2.1.42/linux/arch/sparc/defconfig linux/arch/sparc/defconfig --- v2.1.42/linux/arch/sparc/defconfig Wed Apr 23 19:01:16 1997 +++ linux/arch/sparc/defconfig Thu Jun 12 16:22:05 1997 @@ -42,6 +42,7 @@ SUN_FB_BWTWO=y SUN_FB_LEO=y TADPOLE_FB_WEITEK=y +SUN_FB_CREATOR=y # # Misc Linux/SPARC drivers @@ -177,6 +178,9 @@ # Filesystems # CONFIG_QUOTA=y +# CONFIG_DCACHE_PRELOAD is not set +# CONFIG_OMIRR is not set +# CONFIG_TRANS_NAMES is not set CONFIG_MINIX_FS=m CONFIG_EXT2_FS=y CONFIG_FAT_FS=m diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/config.in linux/arch/sparc64/config.in --- v2.1.42/linux/arch/sparc64/config.in Wed Apr 23 19:01:16 1997 +++ linux/arch/sparc64/config.in Thu Jun 12 16:22:05 1997 @@ -59,6 +59,9 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA fi +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC +fi endmenu mainmenu_option next_comment diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S --- v2.1.42/linux/arch/sparc64/kernel/entry.S Thu May 29 21:53:04 1997 +++ linux/arch/sparc64/kernel/entry.S Thu Jun 12 16:22:05 1997 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.27 1997/05/27 19:30:11 jj Exp $ +/* $Id: entry.S,v 1.31 1997/06/02 06:33:25 davem Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -18,7 +18,7 @@ #include #include -/* define SYSCALL_TRACING */ +/* #define SYSCALL_TRACING */ #define curptr g6 @@ -39,82 +39,84 @@ * it will not get updated properly. */ sparc64_dtlb_prot_catch: - wr %g0, ASI_DMMU, %asi - rdpr %pstate, %g1 - wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate - rdpr %tl, %g2 - ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5 - ldxa [%g0 + TLB_SFSR] %asi, %g4 - cmp %g2, 1 - stxa %g0, [%g0 + TLB_SFSR] %asi - bgu,a %icc, winfix_trampoline - rdpr %tpc, %g5 - ba,pt %xcc, etrap - rd %pc, %g7 - b,a,pt %xcc, 1f + wr %g0, ASI_DMMU, %asi + rdpr %pstate, %g1 + wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate + rdpr %tl, %g3 + ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5 + ldxa [%g0 + TLB_SFSR] %asi, %g4 + cmp %g3, 1 + stxa %g0, [%g0 + TLB_SFSR] %asi + bgu,a,pn %icc, winfix_trampoline + rdpr %tpc, %g3 + ba,pt %xcc, etrap + rd %pc, %g7 + b,a,pt %xcc, 1f sparc64_dtlb_refbit_catch: - srlx %g5, 9, %g4 - and %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4 - cmp %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9) - be,a,pt %xcc, 2f - mov 1, %g4 - wr %g0, ASI_DMMU, %asi - rdpr %pstate, %g1 - wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate - rdpr %tl, %g2 - ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5 - cmp %g2, 1 - clr %g4 ! sfsr not updated for tlb misses - bgu,a %icc, winfix_trampoline - rdpr %tpc, %g5 - ba,pt %xcc, etrap - rd %pc, %g7 + srlx %g5, 9, %g4 + and %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4 + cmp %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9) + be,a,pt %xcc, 2f + mov 1, %g4 + wr %g0, ASI_DMMU, %asi + rdpr %pstate, %g1 + wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate + rdpr %tl, %g3 + ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5 + cmp %g3, 1 + clr %g4 ! sfsr not updated for tlb misses + bgu,a,pn %icc, winfix_trampoline + rdpr %tpc, %g3 + ba,pt %xcc, etrap + rd %pc, %g7 1: - mov %l5, %o4 ! raw tag access - mov %l4, %o5 ! raw sfsr - srlx %l5, PAGE_SHIFT, %o3 - clr %o1 ! text_fault == 0 - sllx %o3, PAGE_SHIFT, %o3 ! address - and %l4, 0x4, %o2 ! write == sfsr.W - call do_sparc64_fault - add %sp, STACK_BIAS + REGWIN_SZ, %o0 ! pt_regs ptr - ba,a,pt %xcc, rtrap + mov %l5, %o4 ! raw tag access + mov %l4, %o5 ! raw sfsr + srlx %l5, PAGE_SHIFT, %o3 + clr %o1 ! text_fault == 0 + sllx %o3, PAGE_SHIFT, %o3 ! address + and %l4, 0x4, %o2 ! write == sfsr.W + call do_sparc64_fault + add %sp, STACK_BIAS + REGWIN_SZ, %o0 ! pt_regs ptr + ba,pt %xcc, rtrap + clr %l6 sparc64_itlb_refbit_catch: - srlx %g5, 9, %g4 - and %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4 - cmp %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9) - be,a,pt %xcc, 3f - mov 1, %g4 - rdpr %pstate, %g1 - wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate - ba,pt %xcc, etrap - rd %pc, %g7 - - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %o3 - mov 1, %o1 ! text_fault == 1 - clr %o2 ! write == 0 - clr %o4 ! tag access (N/A) - clr %o5 ! raw sfsr (N/A) - call do_sparc64_fault - add %sp, STACK_BIAS + REGWIN_SZ, %o0 ! pt_regs ptr - ba,a,pt %xcc, rtrap + srlx %g5, 9, %g4 + and %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4 + cmp %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9) + be,a,pt %xcc, 3f + mov 1, %g4 + rdpr %pstate, %g1 + wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate + ba,pt %xcc, etrap + rd %pc, %g7 + + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %o3 + mov 1, %o1 ! text_fault == 1 + clr %o2 ! write == 0 + clr %o4 ! tag access (N/A) + clr %o5 ! raw sfsr (N/A) + call do_sparc64_fault + add %sp, STACK_BIAS + REGWIN_SZ, %o0 ! pt_regs ptr + ba,pt %xcc, rtrap + clr %l6 2: - sllx %g4, 63, %g4 ! _PAGE_VALID - or %g5, _PAGE_ACCESSED, %g5 - or %g5, %g4, %g5 - stxa %g5, [%g3 + %g1] ASI_PHYS_USE_EC ! store new PTE - stxa %g5, [%g0] ASI_DTLB_DATA_IN ! TLB load + sllx %g4, 63, %g4 ! _PAGE_VALID + or %g5, _PAGE_ACCESSED, %g5 + or %g5, %g4, %g5 + stxa %g5, [%g3 + %g1] ASI_PHYS_USE_EC ! store new PTE + stxa %g5, [%g0] ASI_DTLB_DATA_IN ! TLB load retry 3: - sllx %g4, 63, %g4 ! _PAGE_VALID - or %g5, _PAGE_ACCESSED, %g5 - or %g5, %g4, %g5 - stxa %g5, [%g3 + %g1] ASI_PHYS_USE_EC ! store new PTE - stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load + sllx %g4, 63, %g4 ! _PAGE_VALID + or %g5, _PAGE_ACCESSED, %g5 + or %g5, %g4, %g5 + stxa %g5, [%g3 + %g1] ASI_PHYS_USE_EC ! store new PTE + stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load retry /* Note check out head.h, this code isn't even used for UP, @@ -131,268 +133,285 @@ .align 4 .globl do_ivec do_ivec: - ldxa [%g0] ASI_INTR_RECEIVE, %g1 - andcc %g1, 0x20, %g0 - be,pn %xcc, do_ivec_return - mov 0x40, %g2 + ldxa [%g0] ASI_INTR_RECEIVE, %g1 + andcc %g1, 0x20, %g0 + be,pn %xcc, do_ivec_return + mov 0x40, %g2 /* Load up Interrupt Vector Data 0 register. */ - sethi %uhi(ivector_to_mask), %g4 - ldxa [%g2] ASI_UDB_INTR_R, %g3 - or %g4, %ulo(ivector_to_mask), %g4 - and %g3, 0x7ff, %g3 - sllx %g4, 32, %g4 - sethi %hi(ivector_to_mask), %g5 - sllx %g3, 3, %g3 - or %g5, %lo(ivector_to_mask), %g5 - add %g5, %g4, %g4 - ldx [%g4 + %g3], %g2 - brz,pn %g2, do_ivec_spurious + sethi %uhi(ivector_to_mask), %g4 + ldxa [%g2] ASI_UDB_INTR_R, %g3 + or %g4, %ulo(ivector_to_mask), %g4 + and %g3, 0x7ff, %g3 + sllx %g4, 32, %g4 + sethi %hi(ivector_to_mask), %g5 + sllx %g3, 3, %g3 + or %g5, %lo(ivector_to_mask), %g5 + add %g5, %g4, %g4 + ldx [%g4 + %g3], %g2 + brz,pn %g2, do_ivec_spurious nop /* No branches, worse case we don't know about this interrupt * yet, so we would just write a zero into the softint register * which is completely harmless. */ - wr %g2, 0x0, %set_softint + wr %g2, 0x0, %set_softint do_ivec_return: /* Acknowledge the UPA */ - stxa %g0, [%g0] ASI_INTR_RECEIVE - membar #Sync + stxa %g0, [%g0] ASI_INTR_RECEIVE + membar #Sync retry do_ivec_spurious: - stxa %g0, [%g0] ASI_INTR_RECEIVE - rdpr %pstate, %g1 - wrpr %g1, PSTATE_IG | PSTATE_AG, %pstate - ba,pt %xcc, etrap - rd %pc, %g7 - call report_spurious_ivec - add %sp, STACK_BIAS + REGWIN_SZ, %o0 - ba,pt %xcc, rtrap - nop + stxa %g0, [%g0] ASI_INTR_RECEIVE + rdpr %pstate, %g1 + wrpr %g1, PSTATE_IG | PSTATE_AG, %pstate + ba,pt %xcc, etrap + rd %pc, %g7 + call report_spurious_ivec + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,pt %xcc, rtrap + clr %l6 + + .globl do_mna +do_mna: + rdpr %tl, %g3 + cmp %g3, 1 + bgu,a,pn %icc, winfix_mna + rdpr %tpc, %g3 + ba,pt %xcc, etrap + rd %pc, %g7 + call mem_address_unaligned + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,pt %xcc, rtrap + clr %l6 -breakpoint_t: - .asciz "Breakpoint Trap %lx\n" - .align 4 .globl breakpoint_trap breakpoint_trap: - mov %o0, %o1 - sethi %hi(breakpoint_t), %o0 - or %o0, %lo(breakpoint_t), %o0 - call prom_printf - add %o0, %g4, %o0 - call prom_cmdline + call sparc_breakpoint + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,pt %xcc, rtrap nop - ba,a,pt %xcc, rtrap .globl sys_pipe, sys_execve, sys_sigpause, sys_nis_syscall .globl sys_sigsuspend, sys_sigreturn .globl sys32_execve, sys_ptrace sys_pipe: - sethi %hi(sparc_pipe), %g1 - add %g1, %g4, %g1 - jmpl %g1 + %lo(sparc_pipe), %g0 - add %sp, STACK_BIAS + REGWIN_SZ, %o0 + sethi %hi(sparc_pipe), %g1 + add %g1, %g4, %g1 + jmpl %g1 + %lo(sparc_pipe), %g0 + add %sp, STACK_BIAS + REGWIN_SZ, %o0 sys_nis_syscall: - sethi %hi(c_sys_nis_syscall), %g1 - add %g1, %g4, %g1 - jmpl %g1 + %lo(c_sys_nis_syscall), %g0 - add %sp, STACK_BIAS + REGWIN_SZ, %o0 + sethi %hi(c_sys_nis_syscall), %g1 + add %g1, %g4, %g1 + jmpl %g1 + %lo(c_sys_nis_syscall), %g0 + add %sp, STACK_BIAS + REGWIN_SZ, %o0 sys_execve: - sethi %hi(sparc_execve), %g1 - add %g1, %g4, %g1 - jmpl %g1 + %lo(sparc_execve), %g0 - add %sp, STACK_BIAS + REGWIN_SZ, %o0 + sethi %hi(sparc_execve), %g1 + add %g1, %g4, %g1 + jmpl %g1 + %lo(sparc_execve), %g0 + add %sp, STACK_BIAS + REGWIN_SZ, %o0 sys32_execve: - sethi %hi(sparc32_execve), %g1 - add %g1, %g4, %g1 - jmpl %g1 + %lo(sparc32_execve), %g0 - add %sp, STACK_BIAS + REGWIN_SZ, %o0 + sethi %hi(sparc32_execve), %g1 + add %g1, %g4, %g1 + jmpl %g1 + %lo(sparc32_execve), %g0 + add %sp, STACK_BIAS + REGWIN_SZ, %o0 sys_sigpause: /* NOTE: %o0 has a correct value already */ - call do_sigpause - add %sp, STACK_BIAS + REGWIN_SZ, %o1 + call do_sigpause + add %sp, STACK_BIAS + REGWIN_SZ, %o1 - ld [%curptr + AOFF_task_flags], %l5 - andcc %l5, 0x20, %g0 - be,pt %icc, rtrap + ld [%curptr + AOFF_task_flags], %l5 + andcc %l5, 0x20, %g0 + be,pt %icc, rtrap + clr %l6 + call syscall_trace nop - call syscall_trace - nop - ba,a,pt %xcc, rtrap + ba,pt %xcc, rtrap + clr %l6 sys_sigsuspend: - call do_sigsuspend - add %sp, STACK_BIAS + REGWIN_SZ, %o0 + call do_sigsuspend + add %sp, STACK_BIAS + REGWIN_SZ, %o0 - ld [%curptr + AOFF_task_flags], %l5 - andcc %l5, 0x20, %g0 - be,pt %icc, rtrap - nop - call syscall_trace + ld [%curptr + AOFF_task_flags], %l5 + andcc %l5, 0x20, %g0 + be,pt %icc, rtrap + clr %l6 + call syscall_trace nop - ba,a,pt %xcc, rtrap + ba,pt %xcc, rtrap + clr %l6 sys_sigreturn: - call do_sigreturn - add %sp, STACK_BIAS + REGWIN_SZ, %o0 + call do_sigreturn + add %sp, STACK_BIAS + REGWIN_SZ, %o0 - ld [%curptr + AOFF_task_flags], %l5 - andcc %l5, 0x20, %g0 - be,pt %icc, rtrap + ld [%curptr + AOFF_task_flags], %l5 + andcc %l5, 0x20, %g0 + be,pt %icc, rtrap + clr %l6 + call syscall_trace nop - call syscall_trace - nop - ba,a,pt %xcc, rtrap + ba,pt %xcc, rtrap + clr %l6 sys_ptrace: - call do_ptrace - add %sp, STACK_BIAS + REGWIN_SZ, %o0 + call do_ptrace + add %sp, STACK_BIAS + REGWIN_SZ, %o0 - ld [%curptr + AOFF_task_flags], %l5 - andcc %l5, 0x20, %g0 - be,pt %icc, rtrap - nop - call syscall_trace + ld [%curptr + AOFF_task_flags], %l5 + andcc %l5, 0x20, %g0 + be,pt %icc, rtrap + clr %l6 + call syscall_trace nop - ba,a,pt %xcc, rtrap + ba,pt %xcc, rtrap + clr %l6 - /* This is how fork() was meant to be done, 10 instruction entry. -DaveM */ + /* This is how fork() was meant to be done, 12 instruction entry. -DaveM */ .globl sys_fork, sys_vfork, sys_clone sys_fork: sys_vfork: - mov SIGCHLD, %o0 - clr %o1 + mov SIGCHLD, %o0 + clr %o1 sys_clone: - mov %o7, %l5 + mov %o7, %l5 + save %sp, -REGWIN_SZ, %sp flushw - rdpr %cwp, %o4 - add %sp, STACK_BIAS + REGWIN_SZ, %o2 - movrz %o1, %fp, %o1 + restore %g0, %g0, %g0 + rdpr %cwp, %o4 + add %sp, STACK_BIAS + REGWIN_SZ, %o2 + movrz %o1, %fp, %o1 /* Don't try this at home. */ - stx %o4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G0] - call do_fork - mov %l5, %o7 + stx %o4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G0] + call do_fork + mov %l5, %o7 linux_sparc_ni_syscall: - sethi %hi(sys_ni_syscall), %l7 - or %l7, %lo(sys_ni_syscall), %l7 - ba,pt %xcc,syscall_is_too_hard - add %l7, %g4, %l7 + sethi %hi(sys_ni_syscall), %l7 + or %l7, %lo(sys_ni_syscall), %l7 + ba,pt %xcc,syscall_is_too_hard + add %l7, %g4, %l7 linux_fast_syscall: - andn %l7, 3, %l7 - mov %i0, %o0 - mov %i1, %o1 - mov %i2, %o2 - jmpl %l7 + %g0, %g0 - mov %i3, %o3 + andn %l7, 3, %l7 + mov %i0, %o0 + mov %i1, %o1 + mov %i2, %o2 + jmpl %l7 + %g0, %g0 + mov %i3, %o3 linux_syscall_trace: - call syscall_trace + call syscall_trace nop - mov %i0, %o0 - mov %i1, %o1 - mov %i2, %o2 - mov %i3, %o3 - ba,pt %xcc, 2f - mov %i4, %o4 + mov %i0, %o0 + mov %i1, %o1 + mov %i2, %o2 + mov %i3, %o3 + ba,pt %xcc, 2f + mov %i4, %o4 .globl ret_from_syscall ret_from_syscall: - ba,pt %xcc, ret_sys_call - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0 + ba,pt %xcc, ret_sys_call + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0 /* Linux native and SunOS system calls enter here... */ .align 4 .globl linux_sparc_syscall linux_sparc_syscall: /* Direct access to user regs, must faster. */ - cmp %g1, NR_SYSCALLS - add %l7, %g4, %l7 - bgeu,pn %xcc, linux_sparc_ni_syscall - sll %g1, 3, %l4 - ldx [%l7 + %l4], %l7 - andcc %l7, 1, %g0 - bne,pn %icc, linux_fast_syscall + cmp %g1, NR_SYSCALLS + add %l7, %g4, %l7 + bgeu,pn %xcc, linux_sparc_ni_syscall + sll %g1, 3, %l4 + ldx [%l7 + %l4], %l7 + andcc %l7, 1, %g0 + bne,pn %icc, linux_fast_syscall /* Just do the next insn in the delay slot */ .globl syscall_is_too_hard syscall_is_too_hard: #ifdef SYSCALL_TRACING /* Debugging... */ - mov %g1, %o0 ! o0=scall, o1=ptregs - call syscall_trace_entry - add %sp, STACK_BIAS + REGWIN_SZ, %o1 + mov %g1, %o0 ! o0=scall, o1=ptregs + call syscall_trace_entry + add %sp, STACK_BIAS + REGWIN_SZ, %o1 #endif - mov %i0, %o0 - mov %i1, %o1 - mov %i2, %o2 - - ldx [%curptr + AOFF_task_flags], %l5 - mov %i3, %o3 - mov %i4, %o4 - andcc %l5, 0x20, %g0 - bne,pn %icc, linux_syscall_trace - mov %i0, %l5 + mov %i0, %o0 + mov %i1, %o1 + mov %i2, %o2 + + ldx [%curptr + AOFF_task_flags], %l5 + mov %i3, %o3 + mov %i4, %o4 + andcc %l5, 0x20, %g0 + bne,pn %icc, linux_syscall_trace + mov %i0, %l5 2: - call %l7 - mov %i5, %o5 + call %l7 + mov %i5, %o5 #ifdef SYSCALL_TRACING /* Debugging... */ - call syscall_trace_exit ! o0=sysret, o1=ptregs - add %sp, STACK_BIAS + REGWIN_SZ, %o1 + call syscall_trace_exit ! o0=sysret, o1=ptregs + add %sp, STACK_BIAS + REGWIN_SZ, %o1 #endif - stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] + stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] .globl ret_sys_call ret_sys_call: - ldx [%curptr + AOFF_task_flags], %l6 - mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3 - cmp %o0, -ENOIOCTLCMD - sllx %g2, 32, %g2 - bgeu,pn %xcc, 1f - andcc %l6, 0x20, %l6 + ldx [%curptr + AOFF_task_flags], %l6 + ldx [%curptr + AOFF_task_tss + AOFF_thread_flags], %l2 + mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2 + and %l2, SPARC_FLAG_32BIT, %l2 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3 + brnz,a,pn %l2, 1f + sra %o0, 0, %o0 +1: + cmp %o0, -ENOIOCTLCMD + sllx %g2, 32, %g2 + bgeu,pn %xcc, 1f + andcc %l6, 0x20, %l6 /* System call success, clear Carry condition code. */ - andn %g3, %g2, %g3 - clr %l6 - stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE] - bne,pn %icc, linux_syscall_trace2 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 /* pc = npc */ - add %l1, 0x4, %l2 /* npc = npc+4 */ - stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC] - ba,pt %xcc, rtrap - stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC] + andn %g3, %g2, %g3 + clr %l6 + stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE] + bne,pn %icc, linux_syscall_trace2 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 ! pc = npc + add %l1, 0x4, %l2 !npc = npc+4 + stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC] + ba,pt %xcc, rtrap + stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC] 1: /* System call failure, set Carry condition code. * Also, get abs(errno) to return to the process. */ - sub %g0, %o0, %o0 - or %g3, %g2, %g3 - stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] - mov 1, %l6 - stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE] - bne,pn %icc, linux_syscall_trace2 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 /* pc = npc */ - add %l1, 0x4, %l2 /* npc = npc+4 */ - stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC] - ba,pt %xcc, rtrap - stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC] + sub %g0, %o0, %o0 + or %g3, %g2, %g3 + stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] + mov 1, %l6 + stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE] + bne,pn %icc, linux_syscall_trace2 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 ! pc = npc + add %l1, 0x4, %l2 !npc = npc+4 + stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC] + ba,pt %xcc, rtrap + stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC] linux_syscall_trace2: - call syscall_trace - add %l1, 0x4, %l2 /* npc = npc+4 */ - stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC] - ba,pt %xcc, rtrap - stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC] + call syscall_trace + add %l1, 0x4, %l2 /* npc = npc+4 */ + stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC] + ba,pt %xcc, rtrap + stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC] /* End of entry.S */ diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/etrap.S linux/arch/sparc64/kernel/etrap.S --- v2.1.42/linux/arch/sparc64/kernel/etrap.S Thu May 29 21:53:04 1997 +++ linux/arch/sparc64/kernel/etrap.S Thu Jun 12 16:22:05 1997 @@ -1,4 +1,4 @@ -/* $Id: etrap.S,v 1.18 1997/05/19 05:58:51 davem Exp $ +/* $Id: etrap.S,v 1.21 1997/06/02 06:33:28 davem Exp $ * etrap.S: Preparing for entry into the kernel on Sparc V9. * * Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -22,7 +22,7 @@ .text .align 32 - .globl etrap, etrap_irq + .globl etrap, etrap_irq, etraptl1 etrap: rdpr %pil, %g2 etrap_irq: @@ -45,13 +45,14 @@ stx %g3, [%g2 + REGWIN_SZ + PT_V9_TNPC] stx %g1, [%g2 + REGWIN_SZ + PT_V9_Y] - rdpr %pstate, %g1 - save %g2, -STACK_BIAS, %sp - bne,pn %xcc, 1f + save %g2, -STACK_BIAS, %sp ! The ordering of these two instructions + rdpr %pstate, %g1 ! is critical, see winfixup.S for details + bne,pn %xcc, 2f rdpr %canrestore, %g3 rdpr %wstate, %g6 - wrpr %g0, 0, %canrestore + wrpr %g0, 7, %cleanwin + wrpr %g0, 0, %canrestore sll %g6, 3, %g6 wrpr %g3, 0, %otherwin wrpr %g6, %wstate @@ -59,17 +60,17 @@ sllx %g3, 32, %g3 mov PRIMARY_CONTEXT, %g2 stxa %g0, [%g2] ASI_DMMU + flush %g3 -1: - wrpr %g0, 0x0, %tl +2: wrpr %g0, 0x0, %tl mov %g1, %l1 mov %g4, %l4 mov %g5, %l5 mov %g7, %l2 wrpr %l1, PSTATE_AG, %pstate stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1] - stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2] + stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2] stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3] stx %g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4] stx %g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5] @@ -77,8 +78,8 @@ stx %g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7] stx %i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] stx %i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] - stx %i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2] + stx %i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2] stx %i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3] stx %i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4] stx %i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5] @@ -86,16 +87,13 @@ stx %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7] wrpr %l1, (PSTATE_IE | PSTATE_AG), %pstate sethi %uhi(KERNBASE), %g4 - rd %pic, %g6 + rd %pic, %g6 jmpl %l2 + 0x4, %g0 sllx %g4, 32, %g4 - - .globl etraptl1 etraptl1: rdpr %tstate, %g1 + sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 ba,pt %xcc, 1b - sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 - nop - nop + andcc %g1, TSTATE_PRIV, %g0 nop diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/hack.S linux/arch/sparc64/kernel/hack.S --- v2.1.42/linux/arch/sparc64/kernel/hack.S Thu May 29 21:53:04 1997 +++ linux/arch/sparc64/kernel/hack.S Thu Jun 12 16:22:05 1997 @@ -24,16 +24,12 @@ do_iae_tl1: retl;nop .globl do_ill_tl1 do_ill_tl1: retl;nop - .globl do_irq -do_irq: retl;nop .globl do_irq_tl1 do_irq_tl1: retl;nop .globl do_lddfmna do_lddfmna: retl;nop .globl do_lddfmna_tl1 do_lddfmna_tl1: retl;nop - .globl do_mna_tl1 -do_mna_tl1: retl;nop .globl do_paw do_paw: retl;nop .globl do_paw_tl1 @@ -51,7 +47,7 @@ .globl floppy_hardint floppy_hardint: retl;nop .globl get_cpuid -get_cpuid: retl;nop +get_cpuid: retl;mov 0, %o0 .globl getcc getcc: retl;nop .globl halt diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/head.S linux/arch/sparc64/kernel/head.S --- v2.1.42/linux/arch/sparc64/kernel/head.S Sat May 24 09:10:23 1997 +++ linux/arch/sparc64/kernel/head.S Thu Jun 12 16:22:05 1997 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.30 1997/05/18 22:52:12 davem Exp $ +/* $Id: head.S,v 1.31 1997/05/30 22:35:28 davem Exp $ * head.S: Initial boot code for the Sparc64 port of Linux. * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -55,7 +55,7 @@ .word 0 ramdisk_size: .word 0 - .word reboot_command + .xword reboot_command /* We must be careful, 32-bit OpenBOOT will get confused if it * tries to save away a register window to a 64-bit kernel diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c --- v2.1.42/linux/arch/sparc64/kernel/ioctl32.c Thu May 29 21:53:04 1997 +++ linux/arch/sparc64/kernel/ioctl32.c Thu Jun 12 16:22:05 1997 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.3 1997/05/27 19:30:13 jj Exp $ +/* $Id: ioctl32.c,v 1.8 1997/06/04 13:05:15 jj Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -7,22 +7,369 @@ * ioctls. */ +#include #include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include #include #include -/* As gcc will warn about casting u32 to some ptr, we have to cast it to unsigned long first, and that's what is A() for. - * You just do (void *)A(x), instead of having to type (void *)((unsigned long)x) or instead of just (void *)x, which will - * produce warnings */ +/* As gcc will warn about casting u32 to some ptr, we have to cast it to + * unsigned long first, and that's what is A() for. + * You just do (void *)A(x), instead of having to type (void *)((unsigned long)x) + * or instead of just (void *)x, which will produce warnings. + */ #define A(x) ((unsigned long)x) extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); + +static int w_long(unsigned int fd, unsigned int cmd, u32 arg) +{ + unsigned long old_fs = get_fs(); + int err; + unsigned long val; + + set_fs (KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long)&val); + set_fs (old_fs); + if (!err && put_user(val, (u32 *)A(arg))) + return -EFAULT; + return err; +} +struct ifmap32 { + u32 mem_start; + u32 mem_end; + unsigned short base_addr; + unsigned char irq; + unsigned char dma; + unsigned char port; +}; + +struct ifreq32 { +#define IFHWADDRLEN 6 +#define IFNAMSIZ 16 + union { + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + } ifr_ifrn; + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_dstaddr; + struct sockaddr ifru_broadaddr; + struct sockaddr ifru_netmask; + struct sockaddr ifru_hwaddr; + short ifru_flags; + int ifru_ivalue; + int ifru_mtu; + struct ifmap32 ifru_map; + char ifru_slave[IFNAMSIZ]; /* Just fits the size */ + __kernel_caddr_t32 ifru_data; + } ifr_ifru; +}; + +struct ifconf32 { + int ifc_len; /* size of buffer */ + __kernel_caddr_t32 ifcbuf; +}; + +static inline int dev_ifconf(unsigned int fd, u32 arg) +{ + struct ifconf32 ifc32; + struct ifconf ifc; + struct ifreq32 *ifr32; + struct ifreq *ifr; + unsigned long old_fs; + unsigned int i, j; + int err; + + if (copy_from_user(&ifc32, (struct ifconf32 *)A(arg), sizeof(struct ifconf32))) + return -EFAULT; + ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) * sizeof (struct ifreq); + ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL); + if (!ifc.ifc_buf) return -ENOMEM; + ifr = ifc.ifc_req; + ifr32 = (struct ifreq32 *)A(ifc32.ifcbuf); + for (i = 0; i < ifc32.ifc_len; i += sizeof (struct ifreq32)) { + if (copy_from_user(ifr++, ifr32++, sizeof (struct ifreq32))) { + kfree (ifc.ifc_buf); + return -EFAULT; + } + } + old_fs = get_fs(); set_fs (KERNEL_DS); + err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)&ifc); + set_fs (old_fs); + if (!err) { + ifr = ifc.ifc_req; + ifr32 = (struct ifreq32 *)A(ifc32.ifcbuf); + for (i = 0, j = 0; i < ifc32.ifc_len && j < ifc.ifc_len; + i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) { + if (copy_to_user(ifr32++, ifr++, sizeof (struct ifreq32))) { + err = -EFAULT; + break; + } + } + if (!err) { + if (i <= ifc32.ifc_len) + ifc32.ifc_len = i; + else + ifc32.ifc_len = i - sizeof (struct ifreq32); + if (copy_to_user((struct ifconf32 *)A(arg), &ifc32, sizeof(struct ifconf32))) + err = -EFAULT; + } + } + kfree (ifc.ifc_buf); + return err; +} + +static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg) +{ + struct ifreq ifr; + unsigned long old_fs; + int err; + + if (cmd == SIOCSIFMAP) { + if (copy_from_user(&ifr, (struct ifreq32 *)A(arg), sizeof(ifr.ifr_name)) || + __get_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_start)) || + __get_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_end)) || + __get_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.base_addr)) || + __get_user(ifr.ifr_map.irq, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.irq)) || + __get_user(ifr.ifr_map.dma, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.dma)) || + __get_user(ifr.ifr_map.port, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.port))) + return -EFAULT; + } else { + if (copy_from_user(&ifr, (struct ifreq32 *)A(arg), sizeof(struct ifreq32))) + return -EFAULT; + } + old_fs = get_fs(); + set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)&ifr); + set_fs (old_fs); + if (!err) { + switch (cmd) { + case SIOCGIFFLAGS: + case SIOCGIFMETRIC: + case SIOCGIFMTU: + case SIOCGIFMEM: + case SIOCGIFHWADDR: + case SIOGIFINDEX: + case SIOCGIFADDR: + case SIOCGIFBRDADDR: + case SIOCGIFDSTADDR: + case SIOCGIFNETMASK: + if (copy_to_user((struct ifreq32 *)A(arg), &ifr, sizeof(struct ifreq32))) + return -EFAULT; + break; + case SIOCGIFMAP: + if (copy_to_user((struct ifreq32 *)A(arg), &ifr, sizeof(ifr.ifr_name)) || + __put_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_start)) || + __put_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_end)) || + __put_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.base_addr)) || + __put_user(ifr.ifr_map.irq, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.irq)) || + __put_user(ifr.ifr_map.dma, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.dma)) || + __put_user(ifr.ifr_map.port, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.port))) + return -EFAULT; + break; + } + } + return err; +} + +struct rtentry32 { + u32 rt_pad1; + struct sockaddr rt_dst; /* target address */ + struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */ + struct sockaddr rt_genmask; /* target network mask (IP) */ + unsigned short rt_flags; + short rt_pad2; + u32 rt_pad3; + unsigned char rt_tos; + unsigned char rt_class; + short rt_pad4; + short rt_metric; /* +1 for binary compatibility! */ + /* char * */ u32 rt_dev; /* forcing the device at add */ + u32 rt_mtu; /* per route MTU/Window */ + u32 rt_window; /* Window clamping */ + unsigned short rt_irtt; /* Initial RTT */ + +}; + +static inline int routing_ioctl(unsigned int fd, unsigned int cmd, u32 arg) +{ + struct rtentry r; + char devname[16]; + u32 rtdev; + int ret; + unsigned long old_fs = get_fs(); + + if (get_user (r.rt_pad1, &(((struct rtentry32 *)A(arg))->rt_pad1)) || + copy_from_user (&r.rt_dst, &(((struct rtentry32 *)A(arg))->rt_dst), 3 * sizeof(struct sockaddr)) || + __get_user (r.rt_flags, &(((struct rtentry32 *)A(arg))->rt_flags)) || + __get_user (r.rt_pad2, &(((struct rtentry32 *)A(arg))->rt_pad2)) || + __get_user (r.rt_pad3, &(((struct rtentry32 *)A(arg))->rt_pad3)) || + __get_user (r.rt_tos, &(((struct rtentry32 *)A(arg))->rt_tos)) || + __get_user (r.rt_class, &(((struct rtentry32 *)A(arg))->rt_class)) || + __get_user (r.rt_pad4, &(((struct rtentry32 *)A(arg))->rt_pad4)) || + __get_user (r.rt_metric, &(((struct rtentry32 *)A(arg))->rt_metric)) || + __get_user (r.rt_mtu, &(((struct rtentry32 *)A(arg))->rt_mtu)) || + __get_user (r.rt_window, &(((struct rtentry32 *)A(arg))->rt_window)) || + __get_user (r.rt_irtt, &(((struct rtentry32 *)A(arg))->rt_irtt)) || + __get_user (rtdev, &(((struct rtentry32 *)A(arg))->rt_dev)) || + (rtdev && copy_from_user (devname, (char *)A(rtdev), 15))) + return -EFAULT; + if (rtdev) { + r.rt_dev = devname; devname[15] = 0; + } else + r.rt_dev = 0; + set_fs (KERNEL_DS); + ret = sys_ioctl (fd, cmd, (long)&r); + set_fs (old_fs); + return ret; +} + +struct nlmsghdr32 { + u32 nlmsg_len; /* Length of message including header */ + u32 nlmsg_type; /* Message type */ + u32 nlmsg_seq; /* Sequence number */ + u32 nlmsg_pid; /* Sending process PID */ + unsigned char nlmsg_data[0]; +}; + +struct in_rtmsg32 { + struct in_addr rtmsg_prefix; + struct in_addr rtmsg_gateway; + unsigned rtmsg_flags; + u32 rtmsg_mtu; + u32 rtmsg_window; + unsigned short rtmsg_rtt; + short rtmsg_metric; + unsigned char rtmsg_tos; + unsigned char rtmsg_class; + unsigned char rtmsg_prefixlen; + unsigned char rtmsg_reserved; + int rtmsg_ifindex; +}; + +struct in_ifmsg32 { + struct sockaddr ifmsg_lladdr; + struct in_addr ifmsg_prefix; + struct in_addr ifmsg_brd; + unsigned ifmsg_flags; + u32 ifmsg_mtu; + short ifmsg_metric; + unsigned char ifmsg_prefixlen; + unsigned char ifmsg_reserved; + int ifmsg_index; + char ifmsg_name[16]; +}; + +static inline int rtmsg_ioctl(unsigned int fd, u32 arg) +{ + struct { + struct nlmsghdr n; + union { + struct in_rtmsg rt; + struct in_ifmsg iff; + struct in_rtctlmsg ctl; + struct in_rtrulemsg rule; + } u; + } nn; + char *p; + int ret; + unsigned long old_fs = get_fs(); + + if (get_user (nn.n.nlmsg_len, &(((struct nlmsghdr32 *)A(arg))->nlmsg_len)) || + __get_user (nn.n.nlmsg_type, &(((struct nlmsghdr32 *)A(arg))->nlmsg_type)) || + __get_user (nn.n.nlmsg_seq, &(((struct nlmsghdr32 *)A(arg))->nlmsg_seq)) || + __get_user (nn.n.nlmsg_pid, &(((struct nlmsghdr32 *)A(arg))->nlmsg_pid)) || + __get_user (nn.n.nlmsg_data[0], &(((struct nlmsghdr32 *)A(arg))->nlmsg_data[0]))) + return -EFAULT; + p = ((char *)(&nn.n)) + sizeof(struct nlmsghdr); + arg += sizeof(struct nlmsghdr32); + switch (nn.n.nlmsg_type) { + case RTMSG_NEWRULE: + case RTMSG_DELRULE: + if (nn.n.nlmsg_len < sizeof(struct nlmsghdr32) + sizeof(struct in_rtrulemsg) + - sizeof(struct in_rtmsg) + sizeof(struct in_rtmsg32)) + return -EINVAL; + if (copy_from_user (p, (struct in_rtrulemsg *)A(arg), sizeof(struct in_rtrulemsg) - sizeof(struct in_rtmsg))) + return -EFAULT; + nn.n.nlmsg_len = sizeof(struct nlmsghdr) + sizeof(struct in_rtrulemsg); + p += sizeof (struct in_rtrulemsg) - sizeof(struct in_rtmsg); + arg += sizeof (struct in_rtrulemsg) - sizeof(struct in_rtmsg); + goto newroute; + case RTMSG_NEWROUTE: + case RTMSG_DELROUTE: + if (nn.n.nlmsg_len < sizeof(struct nlmsghdr32) + sizeof(struct in_rtmsg)) + return -EINVAL; + nn.n.nlmsg_len = sizeof(struct nlmsghdr) + sizeof(struct in_rtmsg); +newroute: + if (copy_from_user (p, (struct in_rtmsg32 *)A(arg), 2*sizeof(struct in_addr) + sizeof(unsigned)) || + __get_user (((struct in_rtmsg *)p)->rtmsg_mtu, &((struct in_rtmsg32 *)A(arg))->rtmsg_mtu) || + __get_user (((struct in_rtmsg *)p)->rtmsg_window, &((struct in_rtmsg32 *)A(arg))->rtmsg_window) || + copy_from_user (&(((struct in_rtmsg *)p)->rtmsg_rtt), &((struct in_rtmsg32 *)A(arg))->rtmsg_rtt, + 2 * sizeof(short) + 4 + sizeof(int))) + return -EFAULT; + break; + case RTMSG_NEWDEVICE: + case RTMSG_DELDEVICE: + if (nn.n.nlmsg_len < sizeof(struct nlmsghdr32) + sizeof(struct in_ifmsg)) + return -EINVAL; + nn.n.nlmsg_len = sizeof(struct nlmsghdr) + sizeof(struct in_ifmsg); + if (copy_from_user (p, (struct in_ifmsg32 *)A(arg), + sizeof(struct sockaddr) + 2*sizeof(struct in_addr) + sizeof(unsigned)) || + __get_user (((struct in_ifmsg *)p)->ifmsg_mtu, &((struct in_ifmsg32 *)A(arg))->ifmsg_mtu) || + copy_from_user (&(((struct in_ifmsg *)p)->ifmsg_metric), &((struct in_ifmsg32 *)A(arg))->ifmsg_metric, + sizeof(short) + 2 + sizeof(int) + 16)) + return -EFAULT; + break; + case RTMSG_CONTROL: + if (nn.n.nlmsg_len < sizeof(struct nlmsghdr32) + sizeof(struct in_rtctlmsg)) + return -EINVAL; + nn.n.nlmsg_len = sizeof(struct nlmsghdr) + sizeof(struct in_rtctlmsg); + if (copy_from_user (p, (struct in_rtctlmsg *)A(arg), sizeof(struct in_rtctlmsg))) + return -EFAULT; + break; + } + set_fs (KERNEL_DS); + ret = sys_ioctl (fd, SIOCRTMSG, (long)&(nn.n)); + set_fs (old_fs); + return ret; +} + +struct hd_geometry32 { + unsigned char heads; + unsigned char sectors; + unsigned short cylinders; + u32 start; +}; + +static inline int hdio_getgeo(unsigned int fd, u32 arg) +{ + unsigned long old_fs = get_fs(); + struct hd_geometry geo; + int err; + + set_fs (KERNEL_DS); + err = sys_ioctl(fd, HDIO_GETGEO, (unsigned long)&geo); + set_fs (old_fs); + if (!err) { + if (copy_to_user ((struct hd_geometry32 *)A(arg), &geo, 4) || + __put_user (geo.start, &(((struct hd_geometry32 *)A(arg))->start))) + return -EFAULT; + } + return err; +} + asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) { struct file * filp; @@ -35,16 +382,149 @@ error = sys_ioctl (fd, cmd, (unsigned long)arg); goto out; } - error = 0; + error = -EFAULT; switch (cmd) { - default: - error = sys_ioctl (fd, cmd, (unsigned long)arg); - goto out; + case SIOCGIFCONF: + error = dev_ifconf(fd, arg); + goto out; + + case SIOCGIFFLAGS: + case SIOCSIFFLAGS: + case SIOCGIFMETRIC: + case SIOCSIFMETRIC: + case SIOCGIFMTU: + case SIOCSIFMTU: + case SIOCGIFMEM: + case SIOCSIFMEM: + case SIOCGIFHWADDR: + case SIOCSIFHWADDR: + case SIOCADDMULTI: + case SIOCDELMULTI: + case SIOGIFINDEX: + case SIOCGIFMAP: + case SIOCSIFMAP: + case SIOCGIFADDR: + case SIOCSIFADDR: + case SIOCGIFBRDADDR: + case SIOCSIFBRDADDR: + case SIOCGIFDSTADDR: + case SIOCSIFDSTADDR: + case SIOCGIFNETMASK: + case SIOCSIFNETMASK: + error = dev_ifsioc(fd, cmd, arg); + goto out; + + case SIOCADDRT: + case SIOCDELRT: + error = routing_ioctl(fd, cmd, arg); + goto out; + + case SIOCRTMSG: + error = rtmsg_ioctl(fd, arg); + goto out; + + case HDIO_GETGEO: + error = hdio_getgeo(fd, arg); + goto out; + + case BLKRAGET: + case BLKGETSIZE: + error = w_long(fd, cmd, arg); + goto out; + + /* List here exlicitly which ioctl's are known to have + * compatable types passed or none at all... + */ + + /* Bit T */ + case TCGETA: + case TCSETA: + case TCSETAW: + case TCSETAF: + case TCSBRK: + case TCXONC: + case TCFLSH: + case TCGETS: + case TCSETS: + case TCSETSW: + case TCSETSF: + case TIOCLINUX: + + /* Little t */ + case TIOCGETD: + case TIOCSETD: + case TIOCEXCL: + case TIOCNXCL: + case TIOCCONS: + case TIOCGSOFTCAR: + case TIOCSSOFTCAR: + case TIOCSWINSZ: + case TIOCGWINSZ: + case TIOCMGET: + case TIOCMBIC: + case TIOCMBIS: + case TIOCMSET: + case TIOCPKT: + case TIOCNOTTY: + case TIOCSTI: + case TIOCOUTQ: + case TIOCSPGRP: + case TIOCGPGRP: + case TIOCSCTTY: + + /* Little f */ + case FIOCLEX: + case FIONCLEX: + case FIOASYNC: + case FIONBIO: + case FIONREAD: /* This is also TIOCINQ */ + + /* 0x12 */ + case BLKRRPART: + case BLKFLSBUF: + case BLKRASET: + + /* 0x09 */ + case REGISTER_DEV: + case START_MD: + case STOP_MD: + + /* Big K */ + case PIO_FONT: + case GIO_FONT: + case KDSIGACCEPT: + case KDGETKEYCODE: + case KDSETKEYCODE: + + /* Socket level stuff */ + case FIOSETOWN: + case SIOCSPGRP: + case FIOGETOWN: + case SIOCGPGRP: + case SIOCATMARK: + case SIOCGSTAMP: + case SIOCSIFLINK: + case SIOCSIFENCAP: + case SIOCGIFENCAP: + case SIOCSIFBR: + case SIOCGIFBR: + case SIOCSARP: + case SIOCGARP: + case SIOCDARP: + case SIOCADDDLCI: + case SIOCDELDLCI: + error = sys_ioctl (fd, cmd, (unsigned long)arg); + goto out; + break; + + default: + printk("sys32_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n", + (int)fd, (unsigned int)cmd, (unsigned int)arg); + error = -EINVAL; + goto out; + break; } out: - if (error == -EINVAL) { - printk ("sys32_ioctl on %016lx's %08x returns EINVAL\n", filp->f_op ? (long)filp->f_op->ioctl : 0UL, cmd); - } unlock_kernel(); return error; } diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c --- v2.1.42/linux/arch/sparc64/kernel/process.c Thu May 29 21:53:04 1997 +++ linux/arch/sparc64/kernel/process.c Thu Jun 12 16:22:05 1997 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.12 1997/05/23 09:35:43 jj Exp $ +/* $Id: process.c,v 1.17 1997/06/02 06:33:32 davem Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) @@ -317,6 +317,13 @@ #else if(current->flags & PF_USEDFPU) { #endif + fprs_write(FPRS_FEF); + if(current->tss.flags & SPARC_FLAG_32BIT) + fpsave32((unsigned long *)¤t->tss.float_regs[0], + ¤t->tss.fsr); + else + fpsave((unsigned long *)¤t->tss.float_regs[0], + ¤t->tss.fsr); #ifndef __SMP__ last_task_used_math = NULL; #else @@ -338,6 +345,13 @@ #else if(current->flags & PF_USEDFPU) { #endif + fprs_write(FPRS_FEF); + if(current->tss.flags & SPARC_FLAG_32BIT) + fpsave32((unsigned long *)¤t->tss.float_regs[0], + ¤t->tss.fsr); + else + fpsave((unsigned long *)¤t->tss.float_regs[0], + ¤t->tss.fsr); #ifndef __SMP__ last_task_used_math = NULL; #else @@ -424,6 +438,8 @@ return sp; } +/* #define DEBUG_WINFIXUPS */ + /* Standard stuff. */ static inline void shift_window_buffer(int first_win, int last_win, struct thread_struct *tp) @@ -440,12 +456,15 @@ void synchronize_user_stack(void) { struct thread_struct *tp = ¤t->tss; - unsigned long window = tp->w_saved; + unsigned long window; flush_user_windows(); - if(window) { + if((window = tp->w_saved) != 0) { int winsize = REGWIN_SZ; +#ifdef DEBUG_WINFIXUPS + printk("sus(%d", (int)window); +#endif if(tp->flags & SPARC_FLAG_32BIT) winsize = REGWIN32_SZ; @@ -459,18 +478,26 @@ tp->w_saved--; } } while(window--); +#ifdef DEBUG_WINFIXUPS + printk(")"); +#endif } } void fault_in_user_windows(struct pt_regs *regs) { struct thread_struct *tp = ¤t->tss; - unsigned long window = tp->w_saved; + unsigned long window; int winsize = REGWIN_SZ; if(tp->flags & SPARC_FLAG_32BIT) winsize = REGWIN32_SZ; - if(window) { + flush_user_windows(); + window = tp->w_saved; +#ifdef DEBUG_WINFIXUPS + printk("fiuw(%d", (int)window); +#endif + if(window != 0) { window -= 1; do { unsigned long sp = tp->rwbuf_stkptrs[window]; @@ -481,6 +508,9 @@ } while(window--); } current->tss.w_saved = 0; +#ifdef DEBUG_WINFIXUPS + printk(")"); +#endif } /* Copy a Sparc thread. The fork() return value conventions @@ -504,19 +534,17 @@ struct reg_window *new_stack, *old_stack; unsigned long stack_offset; -#if 0 #ifndef __SMP__ if(last_task_used_math == current) { #else if(current->flags & PF_USEDFPU) { #endif - put_psr(get_psr() | PSR_EF); - fpsave(&p->tss.float_regs[0], &p->tss.fsr); + fprs_write(FPRS_FEF); + fpsave((unsigned long *)&p->tss.float_regs[0], &p->tss.fsr); #ifdef __SMP__ current->flags &= ~PF_USEDFPU; #endif } -#endif /* Calculate offset to stack_frame & pt_regs */ stack_offset = ((PAGE_SIZE<<1) - TRACEREG_SZ); diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/rtrap.S linux/arch/sparc64/kernel/rtrap.S --- v2.1.42/linux/arch/sparc64/kernel/rtrap.S Thu May 29 21:53:04 1997 +++ linux/arch/sparc64/kernel/rtrap.S Thu Jun 12 16:22:05 1997 @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.18 1997/05/27 06:28:05 davem Exp $ +/* $Id: rtrap.S,v 1.21 1997/06/02 07:26:54 davem Exp $ * rtrap.S: Preparing for return from trap on Sparc V9. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -17,109 +17,114 @@ .text .align 32 - .globl rtrap -rtrap: - sethi %hi(bh_active), %l2 - or %l2, %lo(bh_active), %l2 - sethi %hi(bh_mask), %l1 - or %l1, %lo(bh_mask), %l1 - ldx [%l2 + %g4], %l3 - ldx [%l1 + %g4], %l4 - andcc %l3, %l4, %g0 - nop + .globl rtrap_clr_l6, rtrap +rtrap_clr_l6: + ba,pt %xcc, rtrap + clr %l6 +rtrap: sethi %hi(bh_active), %l2 + or %l2, %lo(bh_active), %l2 + sethi %hi(bh_mask), %l1 + or %l1, %lo(bh_mask), %l1 + ldx [%l2 + %g4], %l3 + ldx [%l1 + %g4], %l4 - be,pt %xcc, 2f + andcc %l3, %l4, %g0 + be,pt %xcc, 2f nop - call do_bottom_half + call do_bottom_half nop -2: ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %l1 - sethi %hi(0xf << 20), %l4 - andcc %l1, TSTATE_PRIV, %l3 - and %l1, %l4, %l4 - - rdpr %pstate, %l7 - andn %l1, %l4, %l1 - be,pt %icc, to_user - andn %l7, PSTATE_IE, %l7 -3: ldx [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l6 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1], %g1 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2], %g2 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3], %g3 - - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4], %g4 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5], %g5 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6], %g6 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7], %g7 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %i0 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1], %i1 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2], %i2 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3], %i3 - - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4], %i4 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5], %i5 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6], %i6 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7], %i7 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_Y], %o3 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %l2 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %o2 - wr %o3, %g0, %y - - srl %l4, 20, %l4 - wrpr %l7, %g0, %pstate - wrpr %l4, 0x0, %pil - wrpr %g0, 0x1, %tl - wrpr %l1, %g0, %tstate - wrpr %l2, %g0, %tpc - brnz,pn %l3, 1f - wrpr %o2, %g0, %tnpc - - mov PRIMARY_CONTEXT, %l7 - sethi %uhi(KERNBASE), %l5 - sllx %l5, 32, %l5 - stxa %l6, [%l7] ASI_DMMU - flush %l5 - rdpr %wstate, %l1 - rdpr %otherwin, %l2 - srl %l1, 3, %l1 - - wrpr %l2, %g0, %canrestore - wrpr %l1, %g0, %wstate - wrpr %g0, %g0, %otherwin -1: restore - retry +2: ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %l1 + sethi %hi(0xf << 20), %l4 + andcc %l1, TSTATE_PRIV, %l3 + + and %l1, %l4, %l4 + rdpr %pstate, %l7 + andn %l1, %l4, %l1 + be,pt %icc, to_user + andn %l7, PSTATE_IE, %l7 +3: ldx [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1], %g1 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2], %g2 + + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3], %g3 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4], %g4 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5], %g5 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6], %g6 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7], %g7 + wrpr %l7, PSTATE_AG, %pstate + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %i0 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1], %i1 + + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2], %i2 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3], %i3 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4], %i4 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5], %i5 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6], %i6 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7], %i7 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_Y], %o3 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %l2 + + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %o2 + wr %o3, %g0, %y + srl %l4, 20, %l4 + wrpr %l4, 0x0, %pil + wrpr %g0, 0x1, %tl + wrpr %l1, %g0, %tstate + wrpr %l2, %g0, %tpc + mov PRIMARY_CONTEXT, %l7 + + wrpr %o2, %g0, %tnpc + brnz,a,pn %l3, 1f + restore + sethi %uhi(KERNBASE), %l5 + sllx %l5, 32, %l5 + stxa %l0, [%l7] ASI_DMMU + flush %l5 + rdpr %wstate, %l1 + + rdpr %otherwin, %l2 + srl %l1, 3, %l1 + wrpr %l2, %g0, %canrestore + wrpr %l1, %g0, %wstate + wrpr %g0, %g0, %otherwin + restore + rdpr %canrestore, %g1 + wrpr %g1, 0x0, %cleanwin + +1: retry to_user: sethi %hi(need_resched), %l0 or %l0, %lo(need_resched), %l0 ld [%l0 + %g4], %l0 - wrpr %l7, PSTATE_IE, %pstate brz,pt %l0, check_signal ldx [%g6 + AOFF_task_signal], %l0 + nop + call schedule nop - ldx [%g6 + AOFF_task_signal], %l0 - nop + ba,pt %xcc, check_signal + ldx [%g6 + AOFF_task_signal], %l0 check_signal: ldx [%g6 + AOFF_task_blocked], %o0 - - or %l7, PSTATE_AG, %l7 ! Will need this for setting back wstate andncc %l0, %o0, %g0 - be,pt %xcc, check_user_wins - mov %l5, %o2 + be,a,pt %xcc, check_user_wins + ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 + + mov %l5, %o2 mov %l6, %o3 call do_signal add %sp, STACK_BIAS + REGWIN_SZ, %o1 -check_user_wins: -#if 0 - call user_rtrap_report - add %sp, STACK_BIAS + REGWIN_SZ, %o0 -#endif ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 - + clr %l6 +check_user_wins: brz,pt %o2, 3b - add %sp, STACK_BIAS + REGWIN_SZ, %o1 + nop + call fault_in_user_windows - add %o7, 3b-.-4, %o7 + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,a,pt %xcc, 3b + nop nop nop nop diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/signal.c linux/arch/sparc64/kernel/signal.c --- v2.1.42/linux/arch/sparc64/kernel/signal.c Thu May 29 21:53:04 1997 +++ linux/arch/sparc64/kernel/signal.c Thu Jun 12 16:22:05 1997 @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.4 1997/05/27 06:28:05 davem Exp $ +/* $Id: signal.c,v 1.6 1997/05/29 12:44:48 jj Exp $ * arch/sparc64/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -193,13 +193,17 @@ { #ifdef __SMP__ if (current->flags & PF_USEDFPU) { - fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr); + fprs_write(FPRS_FEF); + fpsave((unsigned long *)¤t->tss.float_regs[0], + ¤t->tss.fsr); regs->tstate &= ~(TSTATE_PEF); current->flags &= ~(PF_USEDFPU); } #else if (current == last_task_used_math) { - fpsave((unsigned long *)¤t->tss.float_regs[0], ¤t->tss.fsr); + fprs_write(FPRS_FEF); + fpsave((unsigned long *)¤t->tss.float_regs[0], + ¤t->tss.fsr); last_task_used_math = 0; regs->tstate &= ~(TSTATE_PEF); } diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c --- v2.1.42/linux/arch/sparc64/kernel/signal32.c Thu May 29 21:53:04 1997 +++ linux/arch/sparc64/kernel/signal32.c Thu Jun 12 16:22:05 1997 @@ -1,4 +1,4 @@ -/* $Id: signal32.c,v 1.10 1997/05/27 06:28:07 davem Exp $ +/* $Id: signal32.c,v 1.13 1997/06/01 05:46:09 davem Exp $ * arch/sparc64/kernel/signal32.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -139,35 +139,51 @@ void do_new_sigreturn32(struct pt_regs *regs) { struct new_signal_frame32 *sf; - unsigned int psr, i; + unsigned int psr; unsigned pc, npc, fpu_save, mask; sf = (struct new_signal_frame32 *) regs->u_regs [UREG_FP]; + /* 1. Make sure we are not getting garbage from the user */ - if (verify_area (VERIFY_READ, sf, sizeof (*sf))){ - goto segv; - } - if (((unsigned long) sf) & 3){ + if (verify_area (VERIFY_READ, sf, sizeof (*sf)) || + (((unsigned long) sf) & 3)) goto segv; - } + get_user(pc, &sf->info.si_regs.pc); __get_user(npc, &sf->info.si_regs.npc); - if ((pc | npc) & 3){ + + if ((pc | npc) & 3) goto segv; - } + regs->tpc = pc; regs->tnpc = npc; /* 2. Restore the state */ __get_user(regs->y, &sf->info.si_regs.y); __get_user(psr, &sf->info.si_regs.psr); - for (i = 0; i < 16; i++) - __get_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]); + + __get_user(regs->u_regs[UREG_G1], &sf->info.si_regs.u_regs[UREG_G1]); + __get_user(regs->u_regs[UREG_G2], &sf->info.si_regs.u_regs[UREG_G2]); + __get_user(regs->u_regs[UREG_G3], &sf->info.si_regs.u_regs[UREG_G3]); + __get_user(regs->u_regs[UREG_G4], &sf->info.si_regs.u_regs[UREG_G4]); + __get_user(regs->u_regs[UREG_G5], &sf->info.si_regs.u_regs[UREG_G5]); + __get_user(regs->u_regs[UREG_G6], &sf->info.si_regs.u_regs[UREG_G6]); + __get_user(regs->u_regs[UREG_G7], &sf->info.si_regs.u_regs[UREG_G7]); + __get_user(regs->u_regs[UREG_I0], &sf->info.si_regs.u_regs[UREG_I0]); + __get_user(regs->u_regs[UREG_I1], &sf->info.si_regs.u_regs[UREG_I1]); + __get_user(regs->u_regs[UREG_I2], &sf->info.si_regs.u_regs[UREG_I2]); + __get_user(regs->u_regs[UREG_I3], &sf->info.si_regs.u_regs[UREG_I3]); + __get_user(regs->u_regs[UREG_I4], &sf->info.si_regs.u_regs[UREG_I4]); + __get_user(regs->u_regs[UREG_I5], &sf->info.si_regs.u_regs[UREG_I5]); + __get_user(regs->u_regs[UREG_I6], &sf->info.si_regs.u_regs[UREG_I6]); + __get_user(regs->u_regs[UREG_I7], &sf->info.si_regs.u_regs[UREG_I7]); /* User can only change condition codes and FPU enabling in %tstate. */ regs->tstate &= ~(TSTATE_ICC | TSTATE_PEF); regs->tstate |= psr_to_tstate_icc(psr); - if (psr & PSR_EF) regs->tstate |= TSTATE_PEF; + + if (psr & PSR_EF) + regs->tstate |= TSTATE_PEF; __get_user(fpu_save, &sf->fpu_save); if (fpu_save) @@ -193,11 +209,12 @@ scptr = (struct sigcontext32 *) regs->u_regs[UREG_I0]; /* Check sanity of the user arg. */ if(verify_area(VERIFY_READ, scptr, sizeof(struct sigcontext32)) || - (((unsigned long) scptr) & 3)) { + (((unsigned long) scptr) & 3)) goto segv; - } + __get_user(pc, &scptr->sigc_pc); __get_user(npc, &scptr->sigc_npc); + if((pc | npc) & 3) goto segv; /* Nice try. */ @@ -241,7 +258,6 @@ int old_status = current->tss.sstk_info.cur_status; unsigned psr; int i; - u32 temp; synchronize_user_stack(); sframep = (struct signal_sframe32 *) regs->u_regs[UREG_FP]; @@ -285,7 +301,10 @@ } else #endif + /* XXX Perhaps we need a copy_in_user()? -DaveM */ for (i = 0; i < 16; i++) { + u32 temp; + get_user (temp, (((u32 *)(regs->u_regs[UREG_FP]))+i)); put_user (temp, (((u32 *)sframep)+i)); } @@ -315,13 +334,17 @@ { #ifdef __SMP__ if (current->flags & PF_USEDFPU) { - fpsave32(¤t->tss.float_regs[0], ¤t->tss.fsr); + fprs_write(FPRS_FEF); + fpsave32((unsigned long *)¤t->tss.float_regs[0], + ¤t->tss.fsr); regs->tstate &= ~(TSTATE_PEF); current->flags &= ~(PF_USEDFPU); } #else if (current == last_task_used_math) { - fpsave32((unsigned long *)¤t->tss.float_regs[0], ¤t->tss.fsr); + fprs_write(FPRS_FEF); + fpsave32((unsigned long *)¤t->tss.float_regs[0], + ¤t->tss.fsr); last_task_used_math = 0; regs->tstate &= ~(TSTATE_PEF); } @@ -338,7 +361,7 @@ { struct new_signal_frame32 *sf; int sigframe_size; - u32 psr, tmp; + u32 psr; int i; /* 1. Make sure everything is clean */ @@ -349,12 +372,12 @@ sf = (struct new_signal_frame32 *)(regs->u_regs[UREG_FP] - sigframe_size); - if (invalid_frame_pointer (sf, sigframe_size)){ + if (invalid_frame_pointer (sf, sigframe_size)) { lock_kernel (); do_exit(SIGILL); } - if (current->tss.w_saved != 0){ + if (current->tss.w_saved != 0) { printk ("%s[%d]: Invalid user stack frame for " "signal delivery.\n", current->comm, current->pid); lock_kernel (); @@ -378,7 +401,11 @@ } __put_user(oldmask, &sf->info.si_mask); + + /* XXX Perhaps we need a copy_in_user()? -DaveM */ for (i = 0; i < sizeof(struct reg_window32)/4; i++) { + u32 tmp; + __get_user(tmp, (((u32 *)regs->u_regs[UREG_FP])+i)); __put_user(tmp, (((u32 *)sf)+i)); } diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c --- v2.1.42/linux/arch/sparc64/kernel/sys_sparc32.c Thu May 29 21:53:04 1997 +++ linux/arch/sparc64/kernel/sys_sparc32.c Thu Jun 12 16:22:05 1997 @@ -1,7 +1,8 @@ -/* $Id: sys_sparc32.c,v 1.18 1997/05/27 06:28:08 davem Exp $ +/* $Id: sys_sparc32.c,v 1.26 1997/06/04 13:05:21 jj Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) * * These routines maintain argument size conversion between 32bit and 64bit * environment. @@ -28,6 +29,7 @@ #include #include #include +#include #include #include @@ -42,112 +44,7 @@ */ #define A(x) ((unsigned long)x) -extern asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on); -extern asmlinkage unsigned long sys_brk(unsigned long brk); -extern asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long off); -extern asmlinkage int sys_bdflush(int func, long data); -extern asmlinkage int sys_uselib(const char * library); -extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg); -extern asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev); -extern asmlinkage int sys_mkdir(const char * pathname, int mode); -extern asmlinkage int sys_rmdir(const char * pathname); -extern asmlinkage int sys_unlink(const char * pathname); -extern asmlinkage int sys_symlink(const char * oldname, const char * newname); -extern asmlinkage int sys_link(const char * oldname, const char * newname); -extern asmlinkage int sys_rename(const char * oldname, const char * newname); -extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr); -extern asmlinkage int sys_statfs(const char * path, struct statfs * buf); -extern asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf); -extern asmlinkage int sys_truncate(const char * path, unsigned long length); -extern asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length); -extern asmlinkage int sys_utime(char * filename, struct utimbuf * times); -extern asmlinkage int sys_utimes(char * filename, struct timeval * utimes); -extern asmlinkage int sys_access(const char * filename, int mode); -extern asmlinkage int sys_chdir(const char * filename); -extern asmlinkage int sys_chroot(const char * filename); -extern asmlinkage int sys_chmod(const char * filename, mode_t mode); -extern asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group); -extern asmlinkage int sys_open(const char * filename,int flags,int mode); -extern asmlinkage int sys_creat(const char * pathname, int mode); -extern asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int origin); -extern asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high, unsigned long offset_low, loff_t *result, unsigned int origin); -extern asmlinkage long sys_read(unsigned int fd, char * buf, unsigned long count); -extern asmlinkage long sys_write(unsigned int fd, const char * buf, unsigned long count); -extern asmlinkage long sys_readv(unsigned long fd, const struct iovec * vector, unsigned long count); -extern asmlinkage long sys_writev(unsigned long fd, const struct iovec * vector, unsigned long count); -extern asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp); -extern asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout); -extern asmlinkage int sys_newstat(char * filename, struct stat * statbuf); -extern asmlinkage int sys_newlstat(char * filename, struct stat * statbuf); -extern asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf); -extern asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz); -extern asmlinkage int sys_sysfs(int option, ...); -extern asmlinkage int sys_ustat(dev_t dev, struct ustat * ubuf); -extern asmlinkage int sys_umount(char * name); -extern asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, unsigned long new_flags, void *data); -extern asmlinkage int sys_syslog(int type, char * bug, int count); -extern asmlinkage int sys_personality(unsigned long personality); -extern asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru); -extern asmlinkage int sys_waitpid(pid_t pid,unsigned int * stat_addr, int options); -extern asmlinkage int sys_sysinfo(struct sysinfo *info); -extern asmlinkage int sys_getitimer(int which, struct itimerval *value); -extern asmlinkage int sys_setitimer(int which, struct itimerval *value, struct itimerval *ovalue); -extern asmlinkage int sys_sched_setscheduler(pid_t pid, int policy, struct sched_param *param); -extern asmlinkage int sys_sched_setparam(pid_t pid, struct sched_param *param); -extern asmlinkage int sys_sched_getparam(pid_t pid, struct sched_param *param); -extern asmlinkage int sys_sched_rr_get_interval(pid_t pid, struct timespec *interval); -extern asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp); -extern asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset); -extern asmlinkage int sys_sigpending(sigset_t *set); -extern asmlinkage unsigned long sys_signal(int signum, __sighandler_t handler); -extern asmlinkage int sys_reboot(int magic1, int magic2, int cmd, void * arg); -extern asmlinkage int sys_acct(const char *name); -extern asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); -extern asmlinkage long sys_times(struct tms * tbuf); -extern asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist); -extern asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist); -extern asmlinkage int sys_newuname(struct new_utsname * name); -extern asmlinkage int sys_olduname(struct oldold_utsname * name); -extern asmlinkage int sys_sethostname(char *name, int len); -extern asmlinkage int sys_gethostname(char *name, int len); -extern asmlinkage int sys_setdomainname(char *name, int len); -extern asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim); -extern asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim); -extern asmlinkage int sys_getrusage(int who, struct rusage *ru); -extern asmlinkage int sys_time(int * tloc); -extern asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz); -extern asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz); -extern asmlinkage int sys_adjtimex(struct timex *txc_p); -extern asmlinkage int sys_msync(unsigned long start, size_t len, int flags); -extern asmlinkage int sys_mlock(unsigned long start, size_t len); -extern asmlinkage int sys_munlock(unsigned long start, size_t len); -extern asmlinkage int sys_munmap(unsigned long addr, size_t len); -extern asmlinkage int sys_mprotect(unsigned long start, size_t len, unsigned long prot); -extern asmlinkage unsigned long sys_mremap(unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags); -extern asmlinkage int sys_swapoff(const char * specialfile); -extern asmlinkage int sys_swapon(const char * specialfile, int swap_flags); -extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen); -extern asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen); -extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen); -extern asmlinkage int sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len); -extern asmlinkage int sys_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len); -extern asmlinkage int sys_send(int fd, void * buff, size_t len, unsigned flags); -extern asmlinkage int sys_sendto(int fd, void * buff, size_t len, unsigned flags, struct sockaddr *addr, int addr_len); -extern asmlinkage int sys_recv(int fd, void * ubuf, size_t size, unsigned flags); -extern asmlinkage int sys_recvfrom(int fd, void * ubuf, size_t size, unsigned flags, struct sockaddr *addr, int *addr_len); -extern asmlinkage int sys_setsockopt(int fd, int level, int optname, char *optval, int optlen); -extern asmlinkage int sys_getsockopt(int fd, int level, int optname, char *optval, int *optlen); -extern asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags); -extern asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags); -extern asmlinkage int sys_socketcall(int call, unsigned long *args); -extern asmlinkage int sys_nfsservctl(int cmd, void *argp, void *resp); -extern asmlinkage int sys_listen(int fd, int backlog); -extern asmlinkage int sys_socket(int family, int type, int protocol); -extern asmlinkage int sys_socketpair(int family, int type, int protocol, int usockvec[2]); -extern asmlinkage int sys_shutdown(int fd, int how); - -/* - * In order to reduce some races, while at the same time doing additional +/* In order to reduce some races, while at the same time doing additional * checking and hopefully speeding things up, we copy filenames to the * kernel data space before using them.. * @@ -168,8 +65,7 @@ return retval; } -/* - * This is a single page for faster getname. +/* This is a single page for faster getname. * If the page is available when entering getname, use it. * If the page is not available, call __get_free_page instead. * This works even though do_getname can block (think about it). @@ -209,6 +105,8 @@ return retval; } +extern asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on); + asmlinkage int sys32_ioperm(u32 from, u32 num, int on) { return sys_ioperm((unsigned long)from, (unsigned long)num, on); @@ -571,22 +469,56 @@ return err; } -asmlinkage unsigned long sys32_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 off) +extern asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long off); + +asmlinkage unsigned long sys32_mmap(u32 addr, u32 len, u32 prot, + u32 flags, u32 fd, u32 off) { - return sys_mmap((unsigned long)addr, (unsigned long)len, (unsigned long)prot, (unsigned long)flags, + return sys_mmap((unsigned long)addr, (unsigned long)len, + (unsigned long)prot, (unsigned long)flags, (unsigned long)fd, (unsigned long)off); } +extern asmlinkage int sys_bdflush(int func, long data); + asmlinkage int sys32_bdflush(int func, s32 data) { return sys_bdflush(func, (long)data); } +extern asmlinkage int sys_uselib(const char * library); + asmlinkage int sys32_uselib(u32 library) { return sys_uselib((const char *)A(library)); } +static inline int get_flock(struct flock *kfl, struct flock32 *ufl) +{ + if(get_user(kfl->l_type, &ufl->l_type) || + __get_user(kfl->l_whence, &ufl->l_whence) || + __get_user(kfl->l_start, &ufl->l_start) || + __get_user(kfl->l_len, &ufl->l_len) || + __get_user(kfl->l_pid, &ufl->l_pid)) + return -EFAULT; + return 0; +} + +static inline int put_flock(struct flock *kfl, struct flock32 *ufl) +{ + if(__put_user(kfl->l_type, &ufl->l_type) || + __put_user(kfl->l_whence, &ufl->l_whence) || + __put_user(kfl->l_start, &ufl->l_start) || + __put_user(kfl->l_len, &ufl->l_len) || + __put_user(kfl->l_pid, &ufl->l_pid)) + return -EFAULT; + return 0; +} + +extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg); + asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, u32 arg) { switch (cmd) { @@ -598,20 +530,12 @@ unsigned long old_fs; long ret; - if (get_user (f.l_type, &(((struct flock32 *)A(arg))->l_type)) || - __get_user (f.l_whence, &(((struct flock32 *)A(arg))->l_whence)) || - __get_user (f.l_start, &(((struct flock32 *)A(arg))->l_start)) || - __get_user (f.l_len, &(((struct flock32 *)A(arg))->l_len)) || - __get_user (f.l_pid, &(((struct flock32 *)A(arg))->l_pid))) + if(get_flock(&f, (struct flock32 *)A(arg))) return -EFAULT; old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_fcntl(fd, cmd, (unsigned long)&f); set_fs (old_fs); - if (__put_user (f.l_type, &(((struct flock32 *)A(arg))->l_type)) || - __put_user (f.l_whence, &(((struct flock32 *)A(arg))->l_whence)) || - __put_user (f.l_start, &(((struct flock32 *)A(arg))->l_start)) || - __put_user (f.l_len, &(((struct flock32 *)A(arg))->l_len)) || - __put_user (f.l_pid, &(((struct flock32 *)A(arg))->l_pid))) + if(put_flock(&f, (struct flock32 *)A(arg))) return -EFAULT; return ret; } @@ -620,36 +544,50 @@ } } +extern asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev); + asmlinkage int sys32_mknod(u32 filename, int mode, __kernel_dev_t32 dev) { return sys_mknod((const char *)A(filename), mode, dev); } +extern asmlinkage int sys_mkdir(const char * pathname, int mode); + asmlinkage int sys32_mkdir(u32 pathname, int mode) { return sys_mkdir((const char *)A(pathname), mode); } +extern asmlinkage int sys_rmdir(const char * pathname); + asmlinkage int sys32_rmdir(u32 pathname) { return sys_rmdir((const char *)A(pathname)); } +extern asmlinkage int sys_unlink(const char * pathname); + asmlinkage int sys32_unlink(u32 pathname) { return sys_unlink((const char *)A(pathname)); } +extern asmlinkage int sys_symlink(const char * oldname, const char * newname); + asmlinkage int sys32_symlink(u32 oldname, u32 newname) { return sys_symlink((const char *)A(oldname), (const char *)A(newname)); } +extern asmlinkage int sys_link(const char * oldname, const char * newname); + asmlinkage int sys32_link(u32 oldname, u32 newname) { return sys_link((const char *)A(oldname), (const char *)A(newname)); } +extern asmlinkage int sys_rename(const char * oldname, const char * newname); + asmlinkage int sys32_rename(u32 oldname, u32 newname) { return sys_rename((const char *)A(oldname), (const char *)A(newname)); @@ -666,12 +604,15 @@ __kernel_time_t32 dqb_itime; }; +extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr); + asmlinkage int sys32_quotactl(int cmd, u32 special, int id, u32 addr) { int cmds = cmd >> SUBCMDSHIFT; int err; struct dqblk d; unsigned long old_fs; + char *spec; switch (cmds) { case Q_GETQUOTA: @@ -679,57 +620,73 @@ case Q_SETQUOTA: case Q_SETUSE: case Q_SETQLIM: - if (copy_from_user (&d, (struct dqblk32 *)A(addr), sizeof (struct dqblk32))) + if (copy_from_user (&d, (struct dqblk32 *)A(addr), + sizeof (struct dqblk32))) return -EFAULT; d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime; d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime; break; default: - return sys_quotactl(cmd, (const char *)A(special), id, (caddr_t)A(addr)); + return sys_quotactl(cmd, (const char *)A(special), + id, (caddr_t)A(addr)); } + err = getname32 (special, &spec); + if (err) return err; old_fs = get_fs (); set_fs (KERNEL_DS); - err = sys_quotactl(cmd, (const char *)A(special), id, (caddr_t)A(addr)); + err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)A(addr)); set_fs (old_fs); + putname32 (spec); if (cmds == Q_GETQUOTA) { __kernel_time_t b = d.dqb_btime, i = d.dqb_itime; ((struct dqblk32 *)&d)->dqb_itime = i; ((struct dqblk32 *)&d)->dqb_btime = b; - if (copy_to_user ((struct dqblk32 *)A(addr), &d, sizeof (struct dqblk32))) + if (copy_to_user ((struct dqblk32 *)A(addr), &d, + sizeof (struct dqblk32))) return -EFAULT; } return err; } -static int put_statfs (u32 buf, struct statfs *s) +static inline int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf) { - if (put_user (s->f_type, &(((struct statfs32 *)A(buf))->f_type)) || - __put_user (s->f_bsize, &(((struct statfs32 *)A(buf))->f_bsize)) || - __put_user (s->f_blocks, &(((struct statfs32 *)A(buf))->f_blocks)) || - __put_user (s->f_bfree, &(((struct statfs32 *)A(buf))->f_bfree)) || - __put_user (s->f_bavail, &(((struct statfs32 *)A(buf))->f_bavail)) || - __put_user (s->f_files, &(((struct statfs32 *)A(buf))->f_files)) || - __put_user (s->f_ffree, &(((struct statfs32 *)A(buf))->f_ffree)) || - __put_user (s->f_namelen, &(((struct statfs32 *)A(buf))->f_namelen)) || - __put_user (s->f_fsid.val[0], &(((struct statfs32 *)A(buf))->f_fsid.val[0])) || - __put_user (s->f_fsid.val[1], &(((struct statfs32 *)A(buf))->f_fsid.val[1]))) + if (put_user (kbuf->f_type, &ubuf->f_type) || + __put_user (kbuf->f_bsize, &ubuf->f_bsize) || + __put_user (kbuf->f_blocks, &ubuf->f_blocks) || + __put_user (kbuf->f_bfree, &ubuf->f_bfree) || + __put_user (kbuf->f_bavail, &ubuf->f_bavail) || + __put_user (kbuf->f_files, &ubuf->f_files) || + __put_user (kbuf->f_ffree, &ubuf->f_ffree) || + __put_user (kbuf->f_namelen, &ubuf->f_namelen) || + __put_user (kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) || + __put_user (kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1])) return -EFAULT; return 0; } +extern asmlinkage int sys_statfs(const char * path, struct statfs * buf); + asmlinkage int sys32_statfs(u32 path, u32 buf) { int ret; struct statfs s; unsigned long old_fs = get_fs(); + char *pth; - set_fs (KERNEL_DS); - ret = sys_statfs((const char *)A(path), &s); - set_fs (old_fs); - if (put_statfs(buf, &s)) return -EFAULT; + ret = getname32 (path, &pth); + if (!ret) { + set_fs (KERNEL_DS); + ret = sys_statfs((const char *)pth, &s); + set_fs (old_fs); + putname32 (pth); + if (put_statfs((struct statfs32 *)A(buf), &s)) + return -EFAULT; + } return ret; } +extern asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf); + asmlinkage int sys32_fstatfs(unsigned int fd, u32 buf) { int ret; @@ -739,20 +696,27 @@ set_fs (KERNEL_DS); ret = sys_fstatfs(fd, &s); set_fs (old_fs); - if (put_statfs(buf, &s)) return -EFAULT; + if (put_statfs((struct statfs32 *)A(buf), &s)) + return -EFAULT; return ret; } +extern asmlinkage int sys_truncate(const char * path, unsigned long length); + asmlinkage int sys32_truncate(u32 path, u32 length) { return sys_truncate((const char *)A(path), (unsigned long)length); } +extern asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length); + asmlinkage int sys32_ftruncate(unsigned int fd, u32 length) { return sys_ftruncate(fd, (unsigned long)length); } +extern asmlinkage int sys_utime(char * filename, struct utimbuf * times); + asmlinkage int sys32_utime(u32 filename, u32 times) { struct utimbuf32 { __kernel_time_t32 actime, modtime; }; @@ -777,63 +741,91 @@ return ret; } +extern asmlinkage int sys_utimes(char * filename, struct timeval * utimes); + asmlinkage int sys32_utimes(u32 filename, u32 utimes) { /* struct timeval is the same :)) */ return sys_utimes((char *)A(filename), (struct timeval *)A(utimes)); } +extern asmlinkage int sys_access(const char * filename, int mode); + asmlinkage int sys32_access(u32 filename, int mode) { return sys_access((const char *)A(filename), mode); } +extern asmlinkage int sys_chdir(const char * filename); + asmlinkage int sys32_chdir(u32 filename) { return sys_chdir((const char *)A(filename)); } +extern asmlinkage int sys_chroot(const char * filename); + asmlinkage int sys32_chroot(u32 filename) { return sys_chroot((const char *)A(filename)); } +extern asmlinkage int sys_chmod(const char * filename, mode_t mode); + asmlinkage int sys32_chmod(u32 filename, __kernel_mode_t32 mode) { return sys_chmod((const char *)A(filename), mode); } +extern asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group); + asmlinkage int sys32_chown(u32 filename, __kernel_uid_t32 user, __kernel_gid_t32 group) { return sys_chown((const char *)A(filename), user, group); } +extern asmlinkage int sys_open(const char * filename,int flags,int mode); + asmlinkage int sys32_open(u32 filename, int flags, int mode) { return sys_open((const char *)A(filename), flags, mode); } +extern asmlinkage int sys_creat(const char * pathname, int mode); + asmlinkage int sys32_creat(u32 pathname, int mode) { return sys_creat((const char *)A(pathname), mode); } +extern asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int origin); + asmlinkage long sys32_lseek(unsigned int fd, s32 offset, unsigned int origin) { return sys_lseek(fd, (off_t)offset, origin); } -asmlinkage int sys32_llseek(unsigned int fd, u32 offset_high, u32 offset_low, u32 result, unsigned int origin) +extern asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high, + unsigned long offset_low, + loff_t *result, unsigned int origin); + +asmlinkage int sys32_llseek(unsigned int fd, u32 offset_high, + u32 offset_low, u32 result, unsigned int origin) { /* loff_t is the same :)) */ - return sys_llseek(fd, (unsigned long)offset_high, (unsigned long)offset_low, (loff_t *)A(result), origin); + return sys_llseek(fd, (unsigned long)offset_high, (unsigned long)offset_low, + (loff_t *)A(result), origin); } +extern asmlinkage long sys_read(unsigned int fd, char * buf, unsigned long count); + asmlinkage long sys32_read(unsigned int fd, u32 buf, u32 count) { return sys_read(fd, (char *)A(buf), (unsigned long)count); } +extern asmlinkage long sys_write(unsigned int fd, const char * buf, unsigned long count); + asmlinkage long sys32_write(unsigned int fd, u32 buf, u32 count) { return sys_write(fd, (const char *)A(buf), (unsigned long)count); @@ -841,86 +833,146 @@ struct iovec32 { u32 iov_base; __kernel_size_t32 iov_len; }; -asmlinkage long sys32_readv(u32 fd, u32 vector, u32 count) +typedef long (*IO_fn_t)(struct inode *, struct file *, char *, unsigned long); + +static long do_readv_writev32(int type, struct inode *inode, struct file *file, + const struct iovec32 *vector, u32 count) { - struct iovec *v; - struct iovec vf[UIO_FASTIOV]; - u32 i; - long ret; - unsigned long old_fs; - - if (!count) return 0; if (count > UIO_MAXIOV) return -EINVAL; - if (count <= UIO_FASTIOV) - v = vf; - else { - lock_kernel (); - v = kmalloc (count * sizeof (struct iovec), GFP_KERNEL); - if (!v) { - ret = -ENOMEM; - goto out; - } + unsigned long tot_len; + struct iovec iovstack[UIO_FASTIOV]; + struct iovec *iov=iovstack, *ivp; + long retval, i; + IO_fn_t fn; + + /* First get the "struct iovec" from user memory and + * verify all the pointers + */ + if (!count) + return 0; + if(verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count)) + return -EFAULT; + if (count > UIO_MAXIOV) + return -EINVAL; + if (count > UIO_FASTIOV) { + iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL); + if (!iov) + return -ENOMEM; } - for (i = 0; i < count; i++) { - if (__get_user ((unsigned long)(v[i].iov_base), &((((struct iovec32 *)A(vector))+i)->iov_base)) || - __get_user (v[i].iov_len, &((((struct iovec32 *)A(vector))+i)->iov_len))) { - ret = -EFAULT; - goto out; - } + + tot_len = 0; + i = count; + ivp = iov; + while(i > 0) { + u32 len; + u32 buf; + + __get_user(len, &vector->iov_len); + __get_user(buf, &vector->iov_base); + tot_len += len; + ivp->iov_base = (void *)A(buf); + ivp->iov_len = (__kernel_size_t) len; + vector++; + ivp++; + i--; + } + + retval = locks_verify_area((type == VERIFY_READ) ? + FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE, + inode, file, file->f_pos, tot_len); + if (retval) { + if (iov != iovstack) + kfree(iov); + return retval; } - old_fs = get_fs(); - set_fs (KERNEL_DS); - ret = sys_readv((unsigned long)fd, v, (unsigned long)count); - set_fs (old_fs); -out: - if (count > UIO_FASTIOV) { - kfree (v); - unlock_kernel (); + + /* Then do the actual IO. Note that sockets need to be handled + * specially as they have atomicity guarantees and can handle + * iovec's natively + */ + if (inode->i_sock) { + int err; + err = sock_readv_writev(type, inode, file, iov, count, tot_len); + if (iov != iovstack) + kfree(iov); + return err; } - return ret; -} -asmlinkage long sys32_writev(u32 fd, u32 vector, u32 count) -{ - struct iovec *v; - struct iovec vf[UIO_FASTIOV]; - u32 i; - long ret; - unsigned long old_fs; - - if (!count) return 0; if (count > UIO_MAXIOV) return -EINVAL; - if (count <= UIO_FASTIOV) - v = vf; - else { - lock_kernel (); - v = kmalloc (count * sizeof (struct iovec), GFP_KERNEL); - if (!v) { - ret = -ENOMEM; - goto out; - } + if (!file->f_op) { + if (iov != iovstack) + kfree(iov); + return -EINVAL; } - for (i = 0; i < count; i++) { - if (__get_user ((unsigned long)(v[i].iov_base), &((((struct iovec32 *)A(vector))+i)->iov_base)) || - __get_user (v[i].iov_len, &((((struct iovec32 *)A(vector))+i)->iov_len))) { - ret = -EFAULT; - goto out; + /* VERIFY_WRITE actually means a read, as we write to user space */ + fn = file->f_op->read; + if (type == VERIFY_READ) + fn = (IO_fn_t) file->f_op->write; + ivp = iov; + while (count > 0) { + void * base; + int len, nr; + + base = ivp->iov_base; + len = ivp->iov_len; + ivp++; + count--; + nr = fn(inode, file, base, len); + if (nr < 0) { + if (retval) + break; + retval = nr; + break; } + retval += nr; + if (nr != len) + break; } - old_fs = get_fs(); - set_fs (KERNEL_DS); - ret = sys_writev((unsigned long)fd, v, (unsigned long)count); - set_fs (old_fs); -out: - if (count > UIO_FASTIOV) { - kfree (v); - unlock_kernel (); - } - return ret; + if (iov != iovstack) + kfree(iov); + return retval; +} + +asmlinkage long sys32_readv(int fd, u32 vector, u32 count) +{ + struct file *file; + struct inode *inode; + long err = -EBADF; + + lock_kernel(); + if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode=file->f_inode)) + goto out; + if (!(file->f_mode & 1)) + goto out; + err = do_readv_writev32(VERIFY_WRITE, inode, file, + (struct iovec32 *)A(vector), count); +out: + unlock_kernel(); + return err; +} + +asmlinkage long sys32_writev(int fd, u32 vector, u32 count) +{ + int error = -EBADF; + struct file *file; + struct inode *inode; + + lock_kernel(); + if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode=file->f_inode)) + goto out; + if (!(file->f_mode & 2)) + goto out; + down(&inode->i_sem); + error = do_readv_writev32(VERIFY_READ, inode, file, + (struct iovec32 *)A(vector), count); + up(&inode->i_sem); +out: + unlock_kernel(); + return error; } /* readdir & getdents */ #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) -#define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1)) +#define ROUND_UP(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1)) struct old_linux_dirent32 { u32 d_ino; @@ -934,7 +986,8 @@ int count; }; -static int fillonedir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino) +static int fillonedir(void * __buf, const char * name, int namlen, + off_t offset, ino_t ino) { struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf; struct old_linux_dirent32 * dirent; @@ -963,7 +1016,8 @@ error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) goto out; - error = verify_area(VERIFY_WRITE, (void *)A(dirent), sizeof(struct old_linux_dirent32)); + error = verify_area(VERIFY_WRITE, (void *)A(dirent), + sizeof(struct old_linux_dirent32)); if (error) goto out; buf.count = 0; @@ -1052,84 +1106,124 @@ /* end of readdir & getdents */ +extern asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, + fd_set *exp, struct timeval *tvp); + asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp) { struct timeval kern_tv, *ktvp; unsigned long old_fs; char *p; - u32 *q; + u32 *q, *Inp, *Outp, *Exp; int i, ret = -EINVAL, nn; - u32 *Inp, *Outp, *Exp; - if (n < 0 || n > PAGE_SIZE*2) return -EINVAL; + if (n < 0 || n > PAGE_SIZE*2) + return -EINVAL; + lock_kernel (); p = (char *)__get_free_page (GFP_KERNEL); - if (!p) goto out; + if (!p) + goto out; + q = (u32 *)p; - nn = (n + 8 * sizeof(unsigned long) - 1) / (8 * sizeof (unsigned long)); - Inp = (u32 *)A(inp); Outp = (u32 *)A(outp); Exp = (u32 *)A(exp); + Inp = (u32 *)A(inp); + Outp = (u32 *)A(outp); + Exp = (u32 *)A(exp); + ret = -EFAULT; - for (i = 0; i < ret; i++, Inp += 2, Outp += 2, Exp += 2, q += 2) { - if (__get_user (q[1], Inp) || - __get_user (q[0], Inp+1) || - __get_user (q[1+PAGE_SIZE/4], Outp) || - __get_user (q[PAGE_SIZE/4], Outp+1) || - __get_user (q[1+PAGE_SIZE/2], Exp) || - __get_user (q[PAGE_SIZE/2], Exp+1)) + + nn = (n + (8 * sizeof(unsigned long)) - 1) / (8 * sizeof (unsigned long)); + for (i = 0; i < nn; i++, Inp += 2, Outp += 2, Exp += 2, q += 2) { + if(inp && (__get_user (q[1], Inp) || __get_user (q[0], Inp+1))) + goto out; + if(outp && (__get_user (q[1+(PAGE_SIZE/4/sizeof(u32))], Outp) || + __get_user (q[(PAGE_SIZE/4/sizeof(u32))], Outp+1))) + goto out; + if(exp && (__get_user (q[1+(PAGE_SIZE/2/sizeof(u32))], Exp) || + __get_user (q[(PAGE_SIZE/2/sizeof(u32))], Exp+1))) goto out; } + ktvp = NULL; if(tvp) { if(copy_from_user(&kern_tv, (struct timeval *)A(tvp), sizeof(*ktvp))) goto out; ktvp = &kern_tv; } + old_fs = get_fs (); set_fs (KERNEL_DS); - ret = sys_select(n, (fd_set *)p, (fd_set *)(p + PAGE_SIZE/4), (fd_set *)(p + PAGE_SIZE/2), ktvp); + q = (u32 *) p; + ret = sys_select(n, + inp ? (fd_set *)&q[0] : (fd_set *)0, + outp ? (fd_set *)&q[PAGE_SIZE/4/sizeof(u32)] : (fd_set *)0, + exp ? (fd_set *)&q[PAGE_SIZE/2/sizeof(u32)] : (fd_set *)0, + ktvp); set_fs (old_fs); + + if(tvp && !(current->personality & STICKY_TIMEOUTS)) + copy_to_user((struct timeval *)A(tvp), &kern_tv, sizeof(*ktvp)); + q = (u32 *)p; - Inp = (u32 *)A(inp); Outp = (u32 *)A(outp); Exp = (u32 *)A(exp); - for (i = 0; i < ret; i++, Inp += 2, Outp += 2, Exp += 2, q += 2) { - if (__put_user (q[1], Inp) || - __put_user (q[0], Inp+1) || - __put_user (q[1+PAGE_SIZE/4], Outp) || - __put_user (q[PAGE_SIZE/4], Outp+1) || - __put_user (q[1+PAGE_SIZE/2], Exp) || - __put_user (q[PAGE_SIZE/2], Exp+1)) { + Inp = (u32 *)A(inp); + Outp = (u32 *)A(outp); + Exp = (u32 *)A(exp); + + if(ret < 0) + goto out; + + for (i = 0; + i < nn; + i++, Inp += 2, Outp += 2, Exp += 2, q += 2) { + if(inp && (__put_user (q[1], Inp) || __put_user (q[0], Inp+1))) { + ret = -EFAULT; + goto out; + } + if(outp && (__put_user (q[1+(PAGE_SIZE/4/sizeof(u32))], Outp) || + __put_user (q[(PAGE_SIZE/4/sizeof(u32))], Outp+1))) { + ret = -EFAULT; + goto out; + } + if(exp && (__put_user (q[1+(PAGE_SIZE/2/sizeof(u32))], Exp) || + __put_user (q[(PAGE_SIZE/2/sizeof(u32))], Exp+1))) { ret = -EFAULT; goto out; } } out: free_page ((unsigned long)p); + unlock_kernel(); return ret; } +extern asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout); + asmlinkage int sys32_poll(u32 ufds, unsigned int nfds, int timeout) { return sys_poll((struct pollfd *)A(ufds), nfds, timeout); } -static inline int putstat(u32 statbuf, struct stat *s) +static inline int putstat(struct stat32 *ubuf, struct stat *kbuf) { - if (put_user (s->st_dev, &(((struct stat32 *)A(statbuf))->st_dev)) || - __put_user (s->st_ino, &(((struct stat32 *)A(statbuf))->st_ino)) || - __put_user (s->st_mode, &(((struct stat32 *)A(statbuf))->st_mode)) || - __put_user (s->st_nlink, &(((struct stat32 *)A(statbuf))->st_nlink)) || - __put_user (s->st_uid, &(((struct stat32 *)A(statbuf))->st_uid)) || - __put_user (s->st_gid, &(((struct stat32 *)A(statbuf))->st_gid)) || - __put_user (s->st_rdev, &(((struct stat32 *)A(statbuf))->st_rdev)) || - __put_user (s->st_size, &(((struct stat32 *)A(statbuf))->st_size)) || - __put_user (s->st_atime, &(((struct stat32 *)A(statbuf))->st_atime)) || - __put_user (s->st_mtime, &(((struct stat32 *)A(statbuf))->st_mtime)) || - __put_user (s->st_ctime, &(((struct stat32 *)A(statbuf))->st_ctime)) || - __put_user (s->st_blksize, &(((struct stat32 *)A(statbuf))->st_blksize)) || - __put_user (s->st_blocks, &(((struct stat32 *)A(statbuf))->st_blocks))) + if (put_user (kbuf->st_dev, &ubuf->st_dev) || + __put_user (kbuf->st_ino, &ubuf->st_ino) || + __put_user (kbuf->st_mode, &ubuf->st_mode) || + __put_user (kbuf->st_nlink, &ubuf->st_nlink) || + __put_user (kbuf->st_uid, &ubuf->st_uid) || + __put_user (kbuf->st_gid, &ubuf->st_gid) || + __put_user (kbuf->st_rdev, &ubuf->st_rdev) || + __put_user (kbuf->st_size, &ubuf->st_size) || + __put_user (kbuf->st_atime, &ubuf->st_atime) || + __put_user (kbuf->st_mtime, &ubuf->st_mtime) || + __put_user (kbuf->st_ctime, &ubuf->st_ctime) || + __put_user (kbuf->st_blksize, &ubuf->st_blksize) || + __put_user (kbuf->st_blocks, &ubuf->st_blocks)) return -EFAULT; return 0; } +extern asmlinkage int sys_newstat(char * filename, struct stat * statbuf); + asmlinkage int sys32_newstat(u32 filename, u32 statbuf) { int ret; @@ -1143,11 +1237,14 @@ ret = sys_newstat(filenam, &s); set_fs (old_fs); putname32 (filenam); - if (putstat (statbuf, &s)) return -EFAULT; + if (putstat ((struct stat32 *)A(statbuf), &s)) + return -EFAULT; } return ret; } +extern asmlinkage int sys_newlstat(char * filename, struct stat * statbuf); + asmlinkage int sys32_newlstat(u32 filename, u32 statbuf) { int ret; @@ -1161,11 +1258,14 @@ ret = sys_newlstat(filenam, &s); set_fs (old_fs); putname32 (filenam); - if (putstat (statbuf, &s)) return -EFAULT; + if (putstat ((struct stat32 *)A(statbuf), &s)) + return -EFAULT; } return ret; } +extern asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf); + asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf) { int ret; @@ -1175,15 +1275,20 @@ set_fs (KERNEL_DS); ret = sys_newfstat(fd, &s); set_fs (old_fs); - if (putstat (statbuf, &s)) return -EFAULT; + if (putstat ((struct stat32 *)A(statbuf), &s)) + return -EFAULT; return ret; } +extern asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz); + asmlinkage int sys32_readlink(u32 path, u32 buf, int bufsiz) { return sys_readlink((const char *)A(path), (char *)A(buf), bufsiz); } +extern asmlinkage int sys_sysfs(int option, ...); + asmlinkage int sys32_sysfs(int option, ...) { va_list args; @@ -1207,28 +1312,39 @@ return ret; } +extern asmlinkage int sys_ustat(dev_t dev, struct ustat * ubuf); + asmlinkage int sys32_ustat(dev_t dev, u32 ubuf) { /* ustat is the same :)) */ return sys_ustat(dev, (struct ustat *)A(ubuf)); } +extern asmlinkage int sys_umount(char * name); + asmlinkage int sys32_umount(u32 name) { return sys_umount((char *)A(name)); } +extern asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, + unsigned long new_flags, void *data); + asmlinkage int sys32_mount(u32 dev_name, u32 dir_name, u32 type, u32 new_flags, u32 data) { return sys_mount((char *)A(dev_name), (char *)A(dir_name), (char *)A(type), (unsigned long)new_flags, (void *)A(data)); } +extern asmlinkage int sys_syslog(int type, char * bug, int count); + asmlinkage int sys32_syslog(int type, u32 bug, int count) { return sys_syslog(type, (char *)A(bug), count); } +extern asmlinkage int sys_personality(unsigned long personality); + asmlinkage int sys32_personality(u32 personality) { return sys_personality((unsigned long)personality); @@ -1277,6 +1393,9 @@ return 0; } +extern asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr, + int options, struct rusage * ru); + asmlinkage int sys32_wait4(__kernel_pid_t32 pid, u32 stat_addr, int options, u32 ru) { if (!ru) @@ -1284,16 +1403,21 @@ else { struct rusage r; int ret; + unsigned int status; unsigned long old_fs = get_fs(); set_fs (KERNEL_DS); - ret = sys_wait4(pid, (unsigned int *)A(stat_addr), options, &r); + ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r); set_fs (old_fs); if (put_rusage (ru, &r)) return -EFAULT; + if (stat_addr && put_user (status, (unsigned int *)A(stat_addr))) + return -EFAULT; return ret; } } +extern asmlinkage int sys_waitpid(pid_t pid,unsigned int * stat_addr, int options); + asmlinkage int sys32_waitpid(__kernel_pid_t32 pid, u32 stat_addr, int options) { return sys_waitpid(pid, (unsigned int *)A(stat_addr), options); @@ -1312,6 +1436,8 @@ char _f[22]; }; +extern asmlinkage int sys_sysinfo(struct sysinfo *info); + asmlinkage int sys32_sysinfo(u32 info) { struct sysinfo s; @@ -1336,28 +1462,41 @@ return ret; } +extern asmlinkage int sys_getitimer(int which, struct itimerval *value); + asmlinkage int sys32_getitimer(int which, u32 value) { /* itimerval is the same :)) */ return sys_getitimer(which, (struct itimerval *)A(value)); } +extern asmlinkage int sys_setitimer(int which, struct itimerval *value, + struct itimerval *ovalue); + asmlinkage int sys32_setitimer(int which, u32 value, u32 ovalue) { - return sys_setitimer(which, (struct itimerval *)A(value), (struct itimerval *)A(ovalue)); + return sys_setitimer(which, (struct itimerval *)A(value), + (struct itimerval *)A(ovalue)); } +extern asmlinkage int sys_sched_setscheduler(pid_t pid, int policy, + struct sched_param *param); + asmlinkage int sys32_sched_setscheduler(__kernel_pid_t32 pid, int policy, u32 param) { /* sched_param is the same :)) */ return sys_sched_setscheduler(pid, policy, (struct sched_param *)A(param)); } +extern asmlinkage int sys_sched_setparam(pid_t pid, struct sched_param *param); + asmlinkage int sys32_sched_setparam(__kernel_pid_t32 pid, u32 param) { return sys_sched_setparam(pid, (struct sched_param *)A(param)); } +extern asmlinkage int sys_sched_getparam(pid_t pid, struct sched_param *param); + asmlinkage int sys32_sched_getparam(__kernel_pid_t32 pid, u32 param) { return sys_sched_getparam(pid, (struct sched_param *)A(param)); @@ -1368,6 +1507,8 @@ s32 tv_nsec; }; +extern asmlinkage int sys_sched_rr_get_interval(pid_t pid, struct timespec *interval); + asmlinkage int sys32_sched_rr_get_interval(__kernel_pid_t32 pid, u32 interval) { struct timespec t; @@ -1383,6 +1524,8 @@ return ret; } +extern asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp); + asmlinkage int sys32_nanosleep(u32 rqtp, u32 rmtp) { struct timespec t; @@ -1403,6 +1546,8 @@ return ret; } +extern asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset); + asmlinkage int sys32_sigprocmask(int how, u32 set, u32 oset) { sigset_t s; @@ -1417,6 +1562,8 @@ return ret; } +extern asmlinkage int sys_sigpending(sigset_t *set); + asmlinkage int sys32_sigpending(u32 set) { sigset_t s; @@ -1430,21 +1577,29 @@ return ret; } +extern asmlinkage unsigned long sys_signal(int signum, __sighandler_t handler); + asmlinkage unsigned long sys32_signal(int signum, u32 handler) { return sys_signal(signum, (__sighandler_t)A(handler)); } +extern asmlinkage int sys_reboot(int magic1, int magic2, int cmd, void * arg); + asmlinkage int sys32_reboot(int magic1, int magic2, int cmd, u32 arg) { return sys_reboot(magic1, magic2, cmd, (void *)A(arg)); } +extern asmlinkage int sys_acct(const char *name); + asmlinkage int sys32_acct(u32 name) { return sys_acct((const char *)A(name)); } +extern asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); + asmlinkage int sys32_getresuid(u32 ruid, u32 euid, u32 suid) { uid_t a, b, c; @@ -1468,6 +1623,8 @@ __kernel_clock_t32 tms_cstime; }; +extern asmlinkage long sys_times(struct tms * tbuf); + asmlinkage long sys32_times(u32 tbuf) { struct tms t; @@ -1486,6 +1643,8 @@ return ret; } +extern asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist); + asmlinkage int sys32_getgroups(int gidsetsize, u32 grouplist) { gid_t gl[NGROUPS]; @@ -1502,6 +1661,8 @@ return ret; } +extern asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist); + asmlinkage int sys32_setgroups(int gidsetsize, u32 grouplist) { gid_t gl[NGROUPS]; @@ -1519,27 +1680,37 @@ return ret; } +extern asmlinkage int sys_newuname(struct new_utsname * name); + asmlinkage int sys32_newuname(u32 name) { /* utsname is the same :)) */ return sys_newuname((struct new_utsname *)A(name)); } +extern asmlinkage int sys_olduname(struct oldold_utsname * name); + asmlinkage int sys32_olduname(u32 name) { return sys_olduname((struct oldold_utsname *)A(name)); } +extern asmlinkage int sys_sethostname(char *name, int len); + asmlinkage int sys32_sethostname(u32 name, int len) { return sys_sethostname((char *)A(name), len); } +extern asmlinkage int sys_gethostname(char *name, int len); + asmlinkage int sys32_gethostname(u32 name, int len) { return sys_gethostname((char *)A(name), len); } +extern asmlinkage int sys_setdomainname(char *name, int len); + asmlinkage int sys32_setdomainname(u32 name, int len) { return sys_setdomainname((char *)A(name), len); @@ -1550,6 +1721,8 @@ s32 rlim_max; }; +extern asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim); + asmlinkage int sys32_getrlimit(unsigned int resource, u32 rlim) { struct rlimit r; @@ -1566,6 +1739,8 @@ return ret; } +extern asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim); + asmlinkage int sys32_setrlimit(unsigned int resource, u32 rlim) { struct rlimit r; @@ -1582,6 +1757,8 @@ return ret; } +extern asmlinkage int sys_getrusage(int who, struct rusage *ru); + asmlinkage int sys32_getrusage(int who, u32 ru) { struct rusage r; @@ -1595,17 +1772,23 @@ return ret; } +extern asmlinkage int sys_time(int * tloc); + asmlinkage int sys32_time(u32 tloc) { return sys_time((int *)A(tloc)); } +extern asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz); + asmlinkage int sys32_gettimeofday(u32 tv, u32 tz) { /* both timeval and timezone are ok :)) */ return sys_gettimeofday((struct timeval *)A(tv), (struct timezone *)A(tz)); } +extern asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz); + asmlinkage int sys32_settimeofday(u32 tv, u32 tz) { return sys_settimeofday((struct timeval *)A(tv), (struct timezone *)A(tz)); @@ -1636,6 +1819,8 @@ int :32; int :32; int :32; int :32; }; +extern asmlinkage int sys_adjtimex(struct timex *txc_p); + asmlinkage int sys32_adjtimex(u32 txc_p) { struct timex t; @@ -1680,98 +1865,154 @@ return ret; } +extern asmlinkage int sys_msync(unsigned long start, size_t len, int flags); + asmlinkage int sys32_msync(u32 start, __kernel_size_t32 len, int flags) { return sys_msync((unsigned long)start, (size_t)len, flags); } +extern asmlinkage int sys_mlock(unsigned long start, size_t len); + asmlinkage int sys32_mlock(u32 start, __kernel_size_t32 len) { return sys_mlock((unsigned long)start, (size_t)len); } +extern asmlinkage int sys_munlock(unsigned long start, size_t len); + asmlinkage int sys32_munlock(u32 start, __kernel_size_t32 len) { return sys_munlock((unsigned long)start, (size_t)len); } +extern asmlinkage unsigned long sys_brk(unsigned long brk); + asmlinkage unsigned long sparc32_brk(u32 brk) { return sys_brk((unsigned long)brk); } +extern asmlinkage int sys_munmap(unsigned long addr, size_t len); + asmlinkage int sys32_munmap(u32 addr, __kernel_size_t32 len) { return sys_munmap((unsigned long)addr, (size_t)len); } +extern asmlinkage int sys_mprotect(unsigned long start, size_t len, unsigned long prot); + asmlinkage int sys32_mprotect(u32 start, __kernel_size_t32 len, u32 prot) { return sys_mprotect((unsigned long)start, (size_t)len, (unsigned long)prot); } +extern asmlinkage unsigned long sys_mremap(unsigned long addr, unsigned long old_len, + unsigned long new_len, unsigned long flags); + asmlinkage unsigned long sys32_mremap(u32 addr, u32 old_len, u32 new_len, u32 flags) { - return sys_mremap((unsigned long)addr, (unsigned long)old_len, (unsigned long)new_len, (unsigned long)flags); + return sys_mremap((unsigned long)addr, (unsigned long)old_len, + (unsigned long)new_len, (unsigned long)flags); } +extern asmlinkage int sys_swapoff(const char * specialfile); + asmlinkage int sys32_swapoff(u32 specialfile) { return sys_swapoff((const char *)A(specialfile)); } +extern asmlinkage int sys_swapon(const char * specialfile, int swap_flags); + asmlinkage int sys32_swapon(u32 specialfile, int swap_flags) { return sys_swapon((const char *)A(specialfile), swap_flags); } -asmlinkage int sys32_bind(int fd, u32 umyaddr, int addrlen) +extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen); + +asmlinkage inline int sys32_bind(int fd, u32 umyaddr, int addrlen) { /* sockaddr is the same :)) */ return sys_bind(fd, (struct sockaddr *)A(umyaddr), addrlen); } -asmlinkage int sys32_accept(int fd, u32 upeer_sockaddr, u32 upeer_addrlen) +extern asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, + int *upeer_addrlen); + +asmlinkage inline int sys32_accept(int fd, u32 upeer_sockaddr, u32 upeer_addrlen) { - return sys_accept(fd, (struct sockaddr *)A(upeer_sockaddr), (int *)A(upeer_addrlen)); + return sys_accept(fd, (struct sockaddr *)A(upeer_sockaddr), + (int *)A(upeer_addrlen)); } -asmlinkage int sys32_connect(int fd, u32 uservaddr, int addrlen) +extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen); + +asmlinkage inline int sys32_connect(int fd, u32 uservaddr, int addrlen) { return sys_connect(fd, (struct sockaddr *)A(uservaddr), addrlen); } +extern asmlinkage int sys_getsockname(int fd, struct sockaddr *usockaddr, + int *usockaddr_len); + asmlinkage int sys32_getsockname(int fd, u32 usockaddr, u32 usockaddr_len) { - return sys_getsockname(fd, (struct sockaddr *)A(usockaddr), (int *)A(usockaddr_len)); + return sys_getsockname(fd, (struct sockaddr *)A(usockaddr), + (int *)A(usockaddr_len)); } +extern asmlinkage int sys_getpeername(int fd, struct sockaddr *usockaddr, + int *usockaddr_len); + asmlinkage int sys32_getpeername(int fd, u32 usockaddr, u32 usockaddr_len) { - return sys_getpeername(fd, (struct sockaddr *)A(usockaddr), (int *)A(usockaddr_len)); + return sys_getpeername(fd, (struct sockaddr *)A(usockaddr), + (int *)A(usockaddr_len)); } -asmlinkage int sys32_send(int fd, u32 buff, __kernel_size_t32 len, unsigned flags) +extern asmlinkage int sys_send(int fd, void * buff, size_t len, unsigned flags); + +asmlinkage inline int sys32_send(int fd, u32 buff, + __kernel_size_t32 len, unsigned flags) { return sys_send(fd, (void *)A(buff), (size_t)len, flags); } -asmlinkage int sys32_sendto(int fd, u32 buff, __kernel_size_t32 len, unsigned flags, u32 addr, int addr_len) +extern asmlinkage int sys_sendto(int fd, void * buff, size_t len, unsigned flags, + struct sockaddr *addr, int addr_len); + +asmlinkage inline int sys32_sendto(int fd, u32 buff, __kernel_size_t32 len, + unsigned flags, u32 addr, int addr_len) { - return sys_sendto(fd, (void *)A(buff), (size_t)len, flags, (struct sockaddr *)A(addr), addr_len); + return sys_sendto(fd, (void *)A(buff), (size_t)len, flags, + (struct sockaddr *)A(addr), addr_len); } -asmlinkage int sys32_recv(int fd, u32 ubuf, __kernel_size_t32 size, unsigned flags) +extern asmlinkage int sys_recv(int fd, void * ubuf, size_t size, unsigned flags); + +asmlinkage inline int sys32_recv(int fd, u32 ubuf, + __kernel_size_t32 size, unsigned flags) { return sys_recv(fd, (void *)A(ubuf), (size_t)size, flags); } -asmlinkage int sys32_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size, unsigned flags, u32 addr, u32 addr_len) +extern asmlinkage int sys_recvfrom(int fd, void * ubuf, size_t size, unsigned flags, + struct sockaddr *addr, int *addr_len); + +asmlinkage inline int sys32_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size, + unsigned flags, u32 addr, u32 addr_len) { - return sys_recvfrom(fd, (void *)A(ubuf), (size_t)size, flags, (struct sockaddr *)A(addr), (int *)A(addr_len)); + return sys_recvfrom(fd, (void *)A(ubuf), (size_t)size, flags, + (struct sockaddr *)A(addr), (int *)A(addr_len)); } -asmlinkage int sys32_setsockopt(int fd, int level, int optname, u32 optval, int optlen) +extern asmlinkage int sys_setsockopt(int fd, int level, int optname, + char *optval, int optlen); + +asmlinkage inline int sys32_setsockopt(int fd, int level, int optname, + u32 optval, int optlen) { /* XXX handle ip_fw32->ip_fw conversion for IP firewalling and accounting. Do it using some macro in ip_sockglue.c @@ -1779,11 +2020,54 @@ return sys_setsockopt(fd, level, optname, (char *)A(optval), optlen); } -asmlinkage int sys32_getsockopt(int fd, int level, int optname, u32 optval, u32 optlen) +extern asmlinkage int sys_getsockopt(int fd, int level, int optname, + char *optval, int *optlen); + +asmlinkage inline int sys32_getsockopt(int fd, int level, int optname, + u32 optval, u32 optlen) { return sys_getsockopt(fd, level, optname, (char *)A(optval), (int *)A(optlen)); } +/* XXX This really belongs in some header file... -DaveM */ +#define MAX_SOCK_ADDR 128 /* 108 for Unix domain - + 16 for IP, 16 for IPX, + 24 for IPv6, + about 80 for AX.25 */ + +/* XXX These as well... */ +extern __inline__ struct socket *socki_lookup(struct inode *inode) +{ + return &inode->u.socket_i; +} + +extern __inline__ struct socket *sockfd_lookup(int fd, int *err) +{ + struct file *file; + struct inode *inode; + + if (!(file = fget(fd))) + { + *err = -EBADF; + return NULL; + } + + inode = file->f_inode; + if (!inode || !inode->i_sock || !socki_lookup(inode)) + { + *err = -ENOTSOCK; + fput(file,inode); + return NULL; + } + + return socki_lookup(inode); +} + +extern __inline__ void sockfd_put(struct socket *sock) +{ + fput(sock->file,sock->inode); +} + struct msghdr32 { u32 msg_name; int msg_namelen; @@ -1801,207 +2085,270 @@ unsigned char cmsg_data[0]; }; -asmlinkage int sys32_sendmsg(int fd, u32 msg, unsigned flags) +static inline int iov_from_user32_to_kern(struct iovec *kiov, + struct iovec32 *uiov32, + int niov) +{ + int tot_len = 0; + + while(niov > 0) { + u32 len, buf; + + if(get_user(len, &uiov32->iov_len) || + get_user(buf, &uiov32->iov_base)) { + tot_len = -EFAULT; + break; + } + tot_len += len; + kiov->iov_base = (void *)A(buf); + kiov->iov_len = (__kernel_size_t) len; + uiov32++; + kiov++; + niov--; + } + return tot_len; +} + +static inline int msghdr_from_user32_to_kern(struct msghdr *kmsg, + struct msghdr32 *umsg) { - struct msghdr m; - int count; - struct iovec *v; - struct iovec vf[UIO_FASTIOV]; - u32 i, vector; - long ret; - unsigned long old_fs; - - if (get_user ((long)m.msg_name, &(((struct msghdr32 *)A(msg))->msg_name)) || - __get_user (m.msg_namelen, &(((struct msghdr32 *)A(msg))->msg_namelen)) || - __get_user (vector, &(((struct msghdr32 *)A(msg))->msg_iov)) || - __get_user (m.msg_iovlen, &(((struct msghdr32 *)A(msg))->msg_iovlen)) || - __get_user ((long)m.msg_control, &(((struct msghdr32 *)A(msg))->msg_control)) || - __get_user (m.msg_controllen, &(((struct msghdr32 *)A(msg))->msg_controllen)) || - __get_user (m.msg_flags, &(((struct msghdr32 *)A(msg))->msg_flags))) + u32 tmp1, tmp2, tmp3; + + if(get_user(tmp1, &umsg->msg_name) || + get_user(tmp2, &umsg->msg_iov) || + get_user(tmp3, &umsg->msg_control)) return -EFAULT; - - count = m.msg_iovlen; - if (!count) return 0; if (count > UIO_MAXIOV) return -EINVAL; - if (count <= UIO_FASTIOV) - v = vf; - else { - lock_kernel (); - v = kmalloc (count * sizeof (struct iovec), GFP_KERNEL); - if (!v) { - ret = -ENOMEM; - goto out; + + kmsg->msg_name = (void *)A(tmp1); + kmsg->msg_iov = (struct iovec *)A(tmp2); + kmsg->msg_control = (void *)A(tmp3); + + if(get_user(kmsg->msg_namelen, &umsg->msg_namelen) || + get_user(kmsg->msg_controllen, &umsg->msg_controllen) || + get_user(kmsg->msg_flags, &umsg->msg_flags)) + return -EFAULT; + + return 0; +} + +/* I've named the args so it is easy to tell whose space the pointers are in. */ +static int verify_iovec32(struct msghdr *kern_msg, struct iovec *kern_iov, + char *kern_address, int mode) +{ + int tot_len; + + if(kern_msg->msg_namelen) { + if(mode==VERIFY_READ) { + int err = move_addr_to_kernel(kern_msg->msg_name, + kern_msg->msg_namelen, + kern_address); + if(err < 0) + return err; } + kern_msg->msg_name = kern_address; + } else + kern_msg->msg_name = NULL; + + if(kern_msg->msg_iovlen > UIO_FASTIOV) { + kern_iov = kmalloc(kern_msg->msg_iovlen * sizeof(struct iovec), + GFP_KERNEL); + if(!kern_iov) + return -ENOMEM; } - for (i = 0; i < count; i++) { - if (__get_user ((unsigned long)(v[i].iov_base), &((((struct iovec32 *)A(vector))+i)->iov_base)) || - __get_user (v[i].iov_len, &((((struct iovec32 *)A(vector))+i)->iov_len))) { - ret = -EFAULT; - goto out; + tot_len = iov_from_user32_to_kern(kern_iov, + (struct iovec32 *)kern_msg->msg_iov, + kern_msg->msg_iovlen); + if(tot_len >= 0) + kern_msg->msg_iov = kern_iov; + else if(kern_msg->msg_iovlen > UIO_FASTIOV) + kfree(kern_iov); + + return tot_len; +} + +asmlinkage int sys32_sendmsg(int fd, u32 user_msg, unsigned user_flags) +{ + struct socket *sock; + char address[MAX_SOCK_ADDR]; + struct iovec iov[UIO_FASTIOV]; + unsigned char ctl[sizeof(struct cmsghdr) + 20]; + struct msghdr kern_msg; + int err; + int total_len; + unsigned char *ctl_buf = ctl; + + if(msghdr_from_user32_to_kern(&kern_msg, (struct msghdr32 *)A(user_msg))) + return -EFAULT; + if(kern_msg.msg_iovlen > UIO_MAXIOV) + return -EINVAL; + total_len = verify_iovec32(&kern_msg, iov, address, VERIFY_READ); + if(total_len < 0) + return total_len; + if(kern_msg.msg_controllen) { + struct cmsghdr32 *ucmsg = (struct cmsghdr32 *)kern_msg.msg_control; + unsigned long *kcmsg; + __kernel_size_t32 cmlen; + + if(kern_msg.msg_controllen > sizeof(ctl) && + kern_msg.msg_controllen <= 256) { + ctl_buf = kmalloc(kern_msg.msg_controllen, GFP_KERNEL); + if(!ctl_buf) { + if(kern_msg.msg_iov != iov) + kfree(kern_msg.msg_iov); + return -ENOBUFS; + } } + __get_user(cmlen, &ucmsg->cmsg_len); + kcmsg = (unsigned long *) ctl_buf; + *kcmsg++ = (unsigned long)cmlen; + if(copy_from_user(kcmsg, &ucmsg->cmsg_level, + kern_msg.msg_controllen - sizeof(__kernel_size_t32))) { + if(ctl_buf != ctl) + kfree_s(ctl_buf, kern_msg.msg_controllen); + if(kern_msg.msg_iov != iov) + kfree(kern_msg.msg_iov); + return -EFAULT; + } + kern_msg.msg_control = ctl_buf; } - - m.msg_iov = v; + kern_msg.msg_flags = user_flags; - if (m.msg_controllen) { - /* XXX Handle msg_control stuff... Or should that go into ip_sockglue.c etc.? */ - } - old_fs = get_fs(); - set_fs (KERNEL_DS); - ret = sys_sendmsg(fd, &m, flags); - set_fs (old_fs); -out: - if (count > UIO_FASTIOV) { - kfree (v); - unlock_kernel (); + lock_kernel(); + if(current->files->fd[fd]->f_flags & O_NONBLOCK) + kern_msg.msg_flags |= MSG_DONTWAIT; + if((sock = sockfd_lookup(fd, &err)) != NULL) { + err = sock_sendmsg(sock, &kern_msg, total_len); + sockfd_put(sock); } - return ret; + unlock_kernel(); + + if(ctl_buf != ctl) + kfree_s(ctl_buf, kern_msg.msg_controllen); + if(kern_msg.msg_iov != iov) + kfree(kern_msg.msg_iov); + return err; } -asmlinkage int sys32_recvmsg(int fd, u32 msg, unsigned int flags) +asmlinkage int sys32_recvmsg(int fd, u32 user_msg, unsigned int user_flags) { - struct msghdr m; - int count; - struct iovec *v; - struct iovec vf[UIO_FASTIOV]; - u32 i, vector; - long ret; - unsigned long old_fs; - - if (get_user ((long)m.msg_name, &(((struct msghdr32 *)A(msg))->msg_name)) || - __get_user (m.msg_namelen, &(((struct msghdr32 *)A(msg))->msg_namelen)) || - __get_user (vector, &(((struct msghdr32 *)A(msg))->msg_iov)) || - __get_user (m.msg_iovlen, &(((struct msghdr32 *)A(msg))->msg_iovlen)) || - __get_user ((long)m.msg_control, &(((struct msghdr32 *)A(msg))->msg_control)) || - __get_user (m.msg_controllen, &(((struct msghdr32 *)A(msg))->msg_controllen)) || - __get_user (m.msg_flags, &(((struct msghdr32 *)A(msg))->msg_flags))) + struct iovec iovstack[UIO_FASTIOV]; + struct msghdr kern_msg; + char addr[MAX_SOCK_ADDR]; + struct socket *sock; + struct iovec *iov = iovstack; + struct sockaddr *uaddr; + int *uaddr_len; + unsigned long cmsg_ptr; + int err, total_len, len = 0; + + if(msghdr_from_user32_to_kern(&kern_msg, (struct msghdr32 *)A(user_msg))) return -EFAULT; - - count = m.msg_iovlen; - if (!count) return 0; if (count > UIO_MAXIOV) return -EINVAL; - if (count <= UIO_FASTIOV) - v = vf; - else { - lock_kernel (); - v = kmalloc (count * sizeof (struct iovec), GFP_KERNEL); - if (!v) { - ret = -ENOMEM; - goto out; - } - } + if(kern_msg.msg_iovlen > UIO_MAXIOV) + return -EINVAL; - for (i = 0; i < count; i++) { - if (__get_user ((unsigned long)(v[i].iov_base), &((((struct iovec32 *)A(vector))+i)->iov_base)) || - __get_user (v[i].iov_len, &((((struct iovec32 *)A(vector))+i)->iov_len))) { - ret = -EFAULT; - goto out; - } - } - - m.msg_iov = v; + uaddr = kern_msg.msg_name; + uaddr_len = &((struct msghdr32 *)A(user_msg))->msg_namelen; + err = verify_iovec32(&kern_msg, iov, addr, VERIFY_WRITE); + if(err < 0) + return err; + total_len = err; - if (m.msg_controllen) { - /* XXX Handle msg_control stuff... Or should that go into ip_sockglue.c etc.? */ - } - old_fs = get_fs(); - set_fs (KERNEL_DS); - ret = sys_recvmsg(fd, &m, flags); - set_fs (old_fs); - if (ret >= 0) { - /* XXX Handle msg_control stuff... */ - if (put_user (m.msg_flags, &(((struct msghdr32 *)A(msg))->msg_flags)) || - __put_user (m.msg_controllen, &(((struct msghdr32 *)A(msg))->msg_controllen))) - return -EFAULT; + cmsg_ptr = (unsigned long) kern_msg.msg_control; + kern_msg.msg_flags = 0; + + lock_kernel(); + if(current->files->fd[fd]->f_flags & O_NONBLOCK) + user_flags |= MSG_DONTWAIT; + if((sock = sockfd_lookup(fd, &err)) != NULL) { + err = sock_recvmsg(sock, &kern_msg, total_len, user_flags); + if(err >= 0) + len = err; + sockfd_put(sock); } -out: - if (count > UIO_FASTIOV) { - kfree (v); - unlock_kernel (); + unlock_kernel(); + + if(kern_msg.msg_iov != iov) + kfree(kern_msg.msg_iov); + if(uaddr != NULL && err >= 0) + err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len); + if(err >= 0) { + err = __put_user(kern_msg.msg_flags, + &((struct msghdr32 *)A(user_msg))->msg_flags); + if(!err) { + /* XXX Convert cmsg back into userspace 32-bit format... */ + err = __put_user((unsigned long)kern_msg.msg_control - cmsg_ptr, + &((struct msghdr32 *)A(user_msg))->msg_controllen); + } } - return ret; + if(err < 0) + return err; + return len; } +/* Argument list sizes for sys_socketcall */ +#define AL(x) ((x) * sizeof(u32)) +static unsigned char nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), + AL(3),AL(3),AL(4),AL(4),AL(4),AL(6), + AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)}; +#undef AL + +extern asmlinkage int sys_socket(int family, int type, int protocol); +extern asmlinkage int sys_socketpair(int family, int type, int protocol, + int usockvec[2]); +extern asmlinkage int sys_shutdown(int fd, int how); +extern asmlinkage int sys_listen(int fd, int backlog); + asmlinkage int sys32_socketcall(int call, u32 args) { - static unsigned char nargs[18]={0,3,3,3,2,3,3,3, - 4,4,4,6,6,2,5,5,3,3}; u32 a[6]; u32 a0,a1; - int err = -EINVAL; - int i; - lock_kernel(); - if(call<1||call>SYS_RECVMSG) - goto out; - err = -EFAULT; - - for (i = 0; i < nargs[call]; i++, args += sizeof (u32)) - if (get_user(a[i], (u32 *)A(args))) - goto out; - + if (callSYS_RECVMSG) + return -EINVAL; + if (copy_from_user(a, (u32 *)A(args), nargs[call])) + return -EFAULT; a0=a[0]; a1=a[1]; switch(call) { case SYS_SOCKET: - err = sys_socket(a0, a1, a[2]); - break; + return sys_socket(a0, a1, a[2]); case SYS_BIND: - err = sys32_bind(a0, a1, a[2]); - break; + return sys32_bind(a0, a1, a[2]); case SYS_CONNECT: - err = sys32_connect(a0, a1, a[2]); - break; + return sys32_connect(a0, a1, a[2]); case SYS_LISTEN: - err = sys_listen(a0, a1); - break; + return sys_listen(a0, a1); case SYS_ACCEPT: - err = sys32_accept(a0, a1, a[2]); - break; + return sys32_accept(a0, a1, a[2]); case SYS_GETSOCKNAME: - err = sys32_getsockname(a0, a1, a[2]); - break; + return sys32_getsockname(a0, a1, a[2]); case SYS_GETPEERNAME: - err = sys32_getpeername(a0, a1, a[2]); - break; + return sys32_getpeername(a0, a1, a[2]); case SYS_SOCKETPAIR: - err = sys_socketpair(a0, a1, a[2], (int *)A(a[3])); - break; + return sys_socketpair(a0, a1, a[2], (int *)A(a[3])); case SYS_SEND: - err = sys32_send(a0, a1, a[2], a[3]); - break; + return sys32_send(a0, a1, a[2], a[3]); case SYS_SENDTO: - err = sys32_sendto(a0, a1, a[2], a[3], a[4], a[5]); - break; + return sys32_sendto(a0, a1, a[2], a[3], a[4], a[5]); case SYS_RECV: - err = sys32_recv(a0, a1, a[2], a[3]); - break; + return sys32_recv(a0, a1, a[2], a[3]); case SYS_RECVFROM: - err = sys32_recvfrom(a0, a1, a[2], a[3], a[4], a[5]); - break; + return sys32_recvfrom(a0, a1, a[2], a[3], a[4], a[5]); case SYS_SHUTDOWN: - err = sys_shutdown(a0,a1); - break; + return sys_shutdown(a0,a1); case SYS_SETSOCKOPT: - err = sys32_setsockopt(a0, a1, a[2], a[3], a[4]); - break; + return sys32_setsockopt(a0, a1, a[2], a[3], a[4]); case SYS_GETSOCKOPT: - err = sys32_getsockopt(a0, a1, a[2], a[3], a[4]); - break; + return sys32_getsockopt(a0, a1, a[2], a[3], a[4]); case SYS_SENDMSG: - err = sys32_sendmsg(a0, a1, a[2]); - break; + return sys32_sendmsg(a0, a1, a[2]); case SYS_RECVMSG: - err = sys32_recvmsg(a0, a1, a[2]); - break; - default: - err = -EINVAL; - break; + return sys32_recvmsg(a0, a1, a[2]); } -out: - unlock_kernel(); - return err; + return -EINVAL; } extern void check_pending(int signum); @@ -2060,6 +2407,8 @@ return err; } +extern asmlinkage int sys_nfsservctl(int cmd, void *argp, void *resp); + asmlinkage int sys32_nfsservctl(int cmd, u32 argp, u32 resp) { /* XXX handle argp and resp args */ @@ -2202,6 +2551,12 @@ (u32 *)A((u32)regs->u_regs[base + UREG_I2]), regs); putname(filename); return error; +} + +/* Modules will be supported with 64bit modutils only */ +asmlinkage int sys32_no_modules(void) +{ + return -ENOSYS; } struct ncp_mount_data32 { diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/systbls.S linux/arch/sparc64/kernel/systbls.S --- v2.1.42/linux/arch/sparc64/kernel/systbls.S Thu May 29 21:53:04 1997 +++ linux/arch/sparc64/kernel/systbls.S Thu Jun 12 16:22:05 1997 @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.11 1997/05/27 19:30:20 jj Exp $ +/* $Id: systbls.S,v 1.13 1997/06/04 13:05:29 jj Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -53,20 +53,20 @@ .xword sys32_quotactl, sys_nis_syscall, sys32_mount, sys32_ustat, sys_nis_syscall /*170*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents .xword sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*180*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys_nis_syscall +/*180*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_no_modules .xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname -/*190*/ .xword sys_nis_syscall, sys32_personality, sys_prof, sys_break, sys_lock +/*190*/ .xword sys32_no_modules, sys32_personality, sys_prof, sys_break, sys_lock .xword sys_mpx, sys_ulimit, sys_getppid, sparc32_sigaction, sys_sgetmask /*200*/ .xword sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys32_uselib, old32_readdir .xword sys_nis_syscall, sys32_socketcall, sys32_syslog, sys32_olduname, sys_nis_syscall /*210*/ .xword sys_idle, sys_nis_syscall, sys32_waitpid, sys32_swapoff, sys32_sysinfo .xword sys32_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex -/*220*/ .xword sys32_sigprocmask, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getpgid +/*220*/ .xword sys32_sigprocmask, sys32_no_modules, sys32_no_modules, sys32_no_modules, sys_getpgid .xword sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid /*230*/ .xword sys32_llseek, sys32_time, sys_nis_syscall, sys_stime, sys_nis_syscall .xword sys_nis_syscall, sys32_llseek, sys32_mlock, sys32_munlock, sys_mlockall /*240*/ .xword sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys_nis_syscall, sys_nis_syscall - .xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys_nanosleep + .xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep /*250*/ .xword sys32_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl .xword sys_aplib, sys_nis_syscall diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/traps.c linux/arch/sparc64/kernel/traps.c --- v2.1.42/linux/arch/sparc64/kernel/traps.c Thu May 29 21:53:04 1997 +++ linux/arch/sparc64/kernel/traps.c Thu Jun 12 16:22:05 1997 @@ -1,7 +1,7 @@ -/* $Id: traps.c,v 1.13 1997/05/27 19:30:08 jj Exp $ +/* $Id: traps.c,v 1.19 1997/06/05 06:22:49 davem Exp $ * arch/sparc/kernel/traps.c * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ @@ -23,6 +23,7 @@ #include #include #include +#include /* #define SYSCALL_TRACING */ /* #define VERBOSE_SYSCALL_TRACING */ @@ -122,7 +123,8 @@ int i; #endif - printk("SYS[%s:%d]: <%d> ", current->comm, current->pid, (int)g1); + printk("SYS[%s:%d]: PC(%016lx) <%3d> ", + current->comm, current->pid, regs->tpc, (int)g1); #ifdef VERBOSE_SYSCALL_TRACING sdp = NULL; for(i = 0; i < NUM_SDESC_ENTRIES; i++) @@ -151,7 +153,7 @@ unsigned long syscall_trace_exit(unsigned long retval, struct pt_regs *regs) { - printk("ret[%08x]\n", (unsigned int) retval); + printk("ret[%016lx]\n", retval); return retval; } #endif /* SYSCALL_TRACING */ @@ -254,25 +256,143 @@ barrier(); } +static unsigned long init_fsr = 0x0UL; +static unsigned int init_fregs[64] __attribute__ ((aligned (64))) = + { ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, + ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, + ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, + ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, + ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, + ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, + ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, + ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U }; + void do_fpdis(struct pt_regs *regs) { - printk("FPDIS: at %016lx\n", regs->tpc); - while(1) - barrier(); + lock_kernel(); + + regs->tstate |= TSTATE_PEF; + fprs_write(FPRS_FEF); + + /* This is allowed now because the V9 ABI varargs passes floating + * point args in floating point registers, so vsprintf() and sprintf() + * cause problems. Luckily we never actually pass floating point values + * to those routines in the kernel and the code generated just does + * stores of them to the stack. Therefore, for the moment this fix + * is sufficient. -DaveM + */ + if(regs->tstate & TSTATE_PRIV) + goto out; + +#ifndef __SMP__ + if(last_task_used_math == current) + goto out; + if(last_task_used_math) { + struct task_struct *fptask = last_task_used_math; + + if(fptask->tss.flags & SPARC_FLAG_32BIT) + fpsave32((unsigned long *)&fptask->tss.float_regs[0], + &fptask->tss.fsr); + else + fpsave((unsigned long *)&fptask->tss.float_regs[0], + &fptask->tss.fsr); + } + last_task_used_math = current; + if(current->used_math) { + if(current->tss.flags & SPARC_FLAG_32BIT) + fpload32(¤t->tss.float_regs[0], + ¤t->tss.fsr); + else + fpload(¤t->tss.float_regs[0], + ¤t->tss.fsr); + } else { + /* Set inital sane state. */ + fpload(&init_fregs[0], &init_fsr); + current->used_math = 1; + } +#else + if(!current->used_math) { + fpload(&init_fregs[0], &init_fsr); + current->used_math = 1; + } else { + if(current->tss.flags & SPARC_FLAG_32BIT) + fpload32(¤t->tss.float_regs[0], + ¤t->tss.fsr); + else + fpload(¤t->tss.float_regs[0], + ¤t->tss.fsr); + } + current->flags |= PF_USEDFPU; +#endif +#ifndef __SMP__ +out: +#endif + unlock_kernel(); +} + +static unsigned long fake_regs[32] __attribute__ ((aligned (8))); +static unsigned long fake_fsr; + +void do_fpe_common(struct pt_regs *regs) +{ + static int calls = 0; +#ifndef __SMP__ + struct task_struct *fpt = last_task_used_math; +#else + struct task_struct *fpt = current; +#endif + + lock_kernel(); + fprs_write(FPRS_FEF); + +#ifndef __SMP__ + if(!fpt) { +#else + if(!(fpt->flags & PF_USEDFPU)) { +#endif + fpsave(&fake_regs[0], &fake_fsr); + regs->tstate &= ~(TSTATE_PEF); + goto out; + } + if(fpt->tss.flags & SPARC_FLAG_32BIT) + fpsave32((unsigned long *)&fpt->tss.float_regs[0], &fpt->tss.fsr); + else + fpsave((unsigned long *)&fpt->tss.float_regs[0], &fpt->tss.fsr); + fpt->tss.sig_address = regs->tpc; + fpt->tss.sig_desc = SUBSIG_FPERROR; +#ifdef __SMP__ + fpt->flags &= ~PF_USEDFPU; +#endif + if(regs->tstate & TSTATE_PRIV) { + printk("WARNING: FPU exception from kernel mode. at pc=%016lx\n", + regs->tpc); + regs->tpc = regs->tnpc; + regs->tnpc += 4; + calls++; + if(calls > 2) + die_if_kernel("Too many Penguin-FPU traps from kernel mode", + regs); + goto out; + } + send_sig(SIGFPE, fpt, 1); +#ifndef __SMP__ + last_task_used_math = NULL; +#endif + regs->tstate &= ~TSTATE_PEF; + if(calls > 0) + calls = 0; +out: + unlock_kernel(); } void do_fpieee(struct pt_regs *regs) { - printk("FPIEEE: at %016lx\n", regs->tpc); - while(1) - barrier(); + do_fpe_common(regs); } void do_fpother(struct pt_regs *regs) { - printk("FPOTHER: at %016lx\n", regs->tpc); - while(1) - barrier(); + do_fpe_common(regs); } void do_tof(struct pt_regs *regs) @@ -352,23 +472,29 @@ printk("Ill instr. at pc=%016lx ", pc); get_user(insn, ((unsigned int *)pc)); printk("insn=[%08x]\n", insn); + show_regs(regs); } #endif current->tss.sig_address = pc; current->tss.sig_desc = SUBSIG_ILLINST; send_sig(SIGILL, current, 1); unlock_kernel(); - - while(1) - barrier(); } -void do_mna(struct pt_regs *regs) +void mem_address_unaligned(struct pt_regs *regs) { printk("AIEEE: do_mna at %016lx\n", regs->tpc); show_regs(regs); - while(1) - barrier(); + if(regs->tstate & TSTATE_PRIV) { + printk("MNA from kernel, spinning\n"); + sti(); + while(1) + barrier(); + } else { + current->tss.sig_address = regs->tpc; + current->tss.sig_desc = SUBSIG_PRIVINST; + send_sig(SIGBUS, current, 1); + } } void do_privop(struct pt_regs *regs) diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/ttable.S linux/arch/sparc64/kernel/ttable.S --- v2.1.42/linux/arch/sparc64/kernel/ttable.S Sat May 24 09:10:23 1997 +++ linux/arch/sparc64/kernel/ttable.S Thu Jun 12 16:22:06 1997 @@ -1,4 +1,4 @@ -/* $Id: ttable.S,v 1.12 1997/05/17 08:22:30 davem Exp $ +/* $Id: ttable.S,v 1.13 1997/06/02 06:33:34 davem Exp $ * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -30,7 +30,7 @@ tl0_resv031: BTRAP(0x31) tl0_dae: TRAP(do_dae) tl0_resv033: BTRAP(0x33) -tl0_mna: TRAP(do_mna) +tl0_mna: TRAP_NOSAVE(do_mna) tl0_lddfmna: TRAP(do_lddfmna) tl0_stdfmna: TRAP(do_stdfmna) tl0_privact: TRAP(do_privact) @@ -163,7 +163,7 @@ tl1_resv031: BTRAPTL1(0x31) tl1_dae: TRAPTL1(do_dae_tl1) tl1_resv033: BTRAPTL1(0x33) -tl1_mna: TRAPTL1(do_mna_tl1) +tl1_mna: TRAP_NOSAVE(do_mna) tl1_lddfmna: TRAPTL1(do_lddfmna_tl1) tl1_stdfmna: TRAPTL1(do_stdfmna_tl1) tl1_privact: BTRAPTL1(0x37) diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/winfixup.S linux/arch/sparc64/kernel/winfixup.S --- v2.1.42/linux/arch/sparc64/kernel/winfixup.S Sat May 24 09:10:23 1997 +++ linux/arch/sparc64/kernel/winfixup.S Thu Jun 12 16:22:06 1997 @@ -1,4 +1,4 @@ -/* $Id: winfixup.S,v 1.3 1997/05/18 22:52:26 davem Exp $ +/* $Id: winfixup.S,v 1.8 1997/06/02 06:33:35 davem Exp $ * * winfixup.S: Handle cases where user stack pointer is found to be bogus. * @@ -10,6 +10,7 @@ #include #include #include +#include #include .text @@ -28,74 +29,223 @@ */ .globl winfix_trampoline, fill_fixup, spill_fixup fill_fixup: - ba,pt %xcc, etrap - rd %pc, %g7 - mov %l5, %o4 - mov %l4, %o5 - srlx %l5, PAGE_SHIFT, %o3 - clr %o1 - sllx %o3, PAGE_SHIFT, %o3 - and %l4, 0x4, %o2 - - call do_sparc64_fault - add %sp, STACK_BIAS + REGWIN_SZ, %o0 - ba,a,pt %xcc, rtrap + rdpr %tstate, %g1 + andcc %g1, TSTATE_PRIV, %g0 + be,pt %xcc, window_scheisse_from_user_common + and %g1, TSTATE_CWP, %g1 + + /* This is the extremely complex case, but it does happen from + * time to time if things are just right. Essentially the restore + * done in rtrap right before going back to user mode, with tl=1 + * and that levels trap stack registers all setup, took a fill trap, + * the user stack was not mapped in the tlb, and tlb miss occurred, + * the pte found was not valid, and a simple ref bit watch update + * could not satisfy the miss, so we got here. + * + * We must carefully unwind the state so we get back to tl=0, preserve + * all the register values we were going to give to the user. Luckily + * most things are where they need to be, we also have the address + * which triggered the fault handy as well. + * + * First, get into the window where the original restore was executed. + */ + + rdpr %wstate, %g2 ! Grab user mode wstate. + wrpr %g1, %cwp ! Get into the right window. + sll %g2, 3, %g2 ! NORMAL-->OTHER + wrpr %g0, 0x0, %canrestore ! Standard etrap stuff. + + wrpr %g2, 0x0, %wstate ! This must be consistant. + wrpr %g0, 0x0, %otherwin ! We know this. + sethi %uhi(KERNBASE), %g2 ! Set this up + sllx %g2, 32, %g2 ! for the iflush + mov PRIMARY_CONTEXT, %g1 ! Change contexts... + stxa %g0, [%g1] ASI_DMMU ! Back into the nucleus. + flush %g2 ! Flush instruction buffers + rdpr %pstate, %l1 ! Prepare to change globals. + mov %g4, %o5 ! Setup args for + mov %g5, %o4 ! final call to do_sparc64_fault. + + wrpr %g0, 0x0, %tl ! Out of trap levels. + wrpr %l1, (PSTATE_IE | PSTATE_AG), %pstate + sethi %uhi(KERNBASE), %g4 ! Restore med-any global reg. + rd %pic, %g6 ! Get current as well. + b,pt %xcc, window_scheisse_merge ! And merge. + sllx %g4, 32, %g4 ! Finish med-any reg setup. + + /* Be very careful about usage of the alternate globals here. + * You cannot touch %g4/%g5 as that has the fault information + * should this be from usermode. Also be careful for the case + * where we get here from the save instruction in etrap.S when + * coming from either user or kernel (does not matter which, it + * is the same problem in both cases). Essentially this means + * do not touch %g7 or %g2 so we handle the two cases fine. + */ +spill_fixup: + rd %pic, %g1 + ldx [%g1 + AOFF_task_tss + AOFF_thread_flags], %g6 + andcc %g6, SPARC_FLAG_32BIT, %g0 + ldx [%g1 + AOFF_task_tss + AOFF_thread_w_saved], %g6 + sll %g6, 3, %g3 + add %g1, %g3, %g3 + stx %sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs] + sll %g6, 7, %g3 + + bne,pt %xcc, 1f + add %g1, %g3, %g3 + stx %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] + stx %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] + stx %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] + stx %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] + stx %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] + stx %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] + + stx %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] + stx %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] + stx %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x40] + stx %i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x48] + stx %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x50] + stx %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x58] + stx %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x60] + stx %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68] + + stx %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70] + stx %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78] + b,pt %xcc, 2f + add %g6, 1, %g6 +1: std %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] + std %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] + std %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] + std %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] + + std %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] + std %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] + std %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] + std %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] + add %g6, 1, %g6 +2: stx %g6, [%g1 + AOFF_task_tss + AOFF_thread_w_saved] + rdpr %tstate, %g1 nop + + andcc %g1, TSTATE_PRIV, %g0 + saved + and %g1, TSTATE_CWP, %g1 + be,a,pn %xcc, window_scheisse_from_user_common + or %g4, 0x4, %g4 ! we know it was a write + retry +window_scheisse_from_user_common: + nop + wrpr %g1, %cwp + + ba,pt %xcc, etrap + rd %pc, %g7 + mov %l5, %o4 + mov %l4, %o5 +window_scheisse_merge: + srlx %o4, PAGE_SHIFT, %o3 + clr %o1 + sllx %o3, PAGE_SHIFT, %o3 + and %o5, 0x4, %o2 + + call do_sparc64_fault + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,pt %xcc, rtrap + clr %l6 winfix_trampoline: - andn %g5, 0x7f, %g5 - add %g5, 0x7c, %g5 - wrpr %g5, %tnpc + andn %g3, 0x7f, %g3 + add %g3, 0x7c, %g3 + wrpr %g3, %tnpc done -spill_fixup: - rd %pic, %g1 - ldx [%g1 + AOFF_task_tss + AOFF_thread_w_saved], %g2 - sll %g2, 3, %g5 - ldx [%g1 + AOFF_task_tss + AOFF_thread_flags], %g7 - add %g1, %g5, %g5 - andcc %g7, SPARC_FLAG_32BIT, %g0 - stx %sp, [%g5 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs] - sll %g2, 5, %g5 - - bne,pt %xcc, 1f - add %g1, %g5, %g5 - stx %l0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] - stx %l1, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] - stx %l2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] - stx %l3, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] - stx %l4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] - stx %l5, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] - - stx %l6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] - stx %l7, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] - stx %i0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x40] - stx %i1, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x48] - stx %i2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x50] - stx %i3, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x58] - stx %i4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x60] - stx %i5, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x68] - - stx %i6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x70] - stx %i7, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x78] - b,a,pt %xcc, 2f - add %g2, 1, %g2 -1: - std %l0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] - std %l2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] - std %l4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] - std %l6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] - - std %i0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] - std %i2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] - std %i4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] - std %i6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] - add %g2, 1, %g2 -2: - stx %g2, [%g1 + AOFF_task_tss + AOFF_thread_w_saved] - rdpr %tstate, %g1 + .globl winfix_mna, fill_fixup_mna, spill_fixup_mna +winfix_mna: + andn %g3, 0x7f, %g3 + add %g3, 0x78, %g3 + wrpr %g3, %tnpc + done +fill_fixup_mna: + rdpr %tstate, %g1 + andcc %g1, TSTATE_PRIV, %g0 + be,pt %xcc, window_mna_from_user_common + and %g1, TSTATE_CWP, %g1 + rdpr %wstate, %g2 ! Grab user mode wstate. + wrpr %g1, %cwp ! Get into the right window. + sll %g2, 3, %g2 ! NORMAL-->OTHER + wrpr %g0, 0x0, %canrestore ! Standard etrap stuff. + wrpr %g2, 0x0, %wstate ! This must be consistant. + wrpr %g0, 0x0, %otherwin ! We know this. + sethi %uhi(KERNBASE), %g2 ! Set this up + sllx %g2, 32, %g2 ! for the iflush + mov PRIMARY_CONTEXT, %g1 ! Change contexts... + stxa %g0, [%g1] ASI_DMMU ! Back into the nucleus. + flush %g2 ! Flush instruction buffers + rdpr %pstate, %l1 ! Prepare to change globals. + mov %g4, %o5 ! Setup args for + mov %g5, %o4 ! final call to do_sparc64_fault. + wrpr %g0, 0x0, %tl ! Out of trap levels. + wrpr %l1, (PSTATE_IE | PSTATE_AG), %pstate + sethi %uhi(KERNBASE), %g4 ! Restore med-any global reg. + rd %pic, %g6 ! Get current as well. + b,pt %xcc, window_mna_merge ! And merge. + sllx %g4, 32, %g4 ! Finish med-any reg setup. +spill_fixup_mna: + rd %pic, %g1 + ldx [%g1 + AOFF_task_tss + AOFF_thread_flags], %g6 + andcc %g6, SPARC_FLAG_32BIT, %g0 + ldx [%g1 + AOFF_task_tss + AOFF_thread_w_saved], %g6 + sll %g6, 3, %g3 + add %g1, %g3, %g3 + stx %sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs] + sll %g6, 7, %g3 + + bne,pt %xcc, 1f + add %g1, %g3, %g3 + stx %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] + stx %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] + stx %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] + stx %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] + stx %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] + stx %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] + + stx %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] + stx %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] + stx %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x40] + stx %i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x48] + stx %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x50] + stx %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x58] + stx %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x60] + stx %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68] + + stx %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70] + stx %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78] + b,pt %xcc, 2f + add %g6, 1, %g6 +1: std %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] + std %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] + std %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] + std %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] + + std %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] + std %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] + std %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] + std %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] + add %g6, 1, %g6 +2: stx %g6, [%g1 + AOFF_task_tss + AOFF_thread_w_saved] + rdpr %tstate, %g1 nop - andcc %g1, TSTATE_PRIV, %g0 - be,pn %xcc, fill_fixup - saved + andcc %g1, TSTATE_PRIV, %g0 + saved + be,pn %xcc, window_mna_from_user_common + and %g1, TSTATE_CWP, %g1 retry +window_mna_from_user_common: + wrpr %g1, %cwp + ba,pt %xcc, etrap + rd %pc, %g7 +window_mna_merge: + call mem_address_unaligned + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,pt %xcc, rtrap + clr %l6 + diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/lib/checksum.S linux/arch/sparc64/lib/checksum.S --- v2.1.42/linux/arch/sparc64/lib/checksum.S Thu May 15 16:48:02 1997 +++ linux/arch/sparc64/lib/checksum.S Thu Jun 12 16:22:06 1997 @@ -71,8 +71,9 @@ or %o5, %o4, %o4 ! coalese with hword (if any) 6: addcc %o4, %o2, %o2 ! add to sum 1: sllx %g4, 32, %g4 ! give gfp back + addc %g0, %o2, %o0 ! add final carry into retval retl ! get outta here - addc %g0, %o2, %o0 ! add final carry into retval + srl %o0, 0, %o0 /* Also do alignment out of band to get better cache patterns. */ csum_partial_fix_alignment: @@ -82,7 +83,9 @@ */ .globl csum_partial csum_partial: /* %o0=buf, %o1=len, %o2=sum */ + srl %o1, 0, %o1 ! doof scheiss andcc %o0, 0x7, %g0 ! alignment problems? + srl %o2, 0, %o2 be,pt %icc, csum_partial_fix_aligned ! yep, handle it andn %o1, 0x7f, %o3 ! num loop iterations cmp %o1, 6 @@ -154,31 +157,31 @@ 99: ba,pt %xcc, 30f; \ a, b, %o3; \ .section __ex_table,z##alloc; \ - .align 4; \ - .word 98b, 99b; \ + .align 8; \ + .xword 98b, 99b; \ .text; \ .align 4 #define EX2(x,y,z) \ 98: x,y; \ .section __ex_table,z##alloc; \ - .align 4; \ - .word 98b, 30f; \ + .align 8; \ + .xword 98b, 30f; \ .text; \ .align 4 #define EX3(x,y,z) \ 98: x,y; \ .section __ex_table,z##alloc; \ - .align 4; \ - .word 98b, 96f; \ + .align 8; \ + .xword 98b, 96f; \ .text; \ .align 4 #define EXT(start,end,handler,z) \ .section __ex_table,z##alloc; \ - .align 4; \ - .word start, 0, end, handler; \ + .align 8; \ + .xword start, 0, end, handler; \ .text; \ .align 4 @@ -189,12 +192,12 @@ * please check the fixup code below as well. */ #define CSUMCOPY_BIGCHUNK_ALIGNED(src, dst, sum, off, t0, t1, t2, t3, t4, t5, t6, t7) \ - ldd [src + off + 0x00], t0; \ - ldd [src + off + 0x08], t2; \ + ldda [src + off + 0x00] %asi, t0; \ + ldda [src + off + 0x08] %asi, t2; \ addccc t0, sum, sum; \ - ldd [src + off + 0x10], t4; \ + ldda [src + off + 0x10] %asi, t4; \ addccc t1, sum, sum; \ - ldd [src + off + 0x18], t6; \ + ldda [src + off + 0x18] %asi, t6; \ addccc t2, sum, sum; \ std t0, [dst + off + 0x00]; \ addccc t3, sum, sum; \ @@ -211,10 +214,10 @@ * Viking MXCC into streaming mode. Ho hum... */ #define CSUMCOPY_BIGCHUNK(src, dst, sum, off, t0, t1, t2, t3, t4, t5, t6, t7) \ - ldd [src + off + 0x00], t0; \ - ldd [src + off + 0x08], t2; \ - ldd [src + off + 0x10], t4; \ - ldd [src + off + 0x18], t6; \ + ldda [src + off + 0x00] %asi, t0; \ + ldda [src + off + 0x08] %asi, t2; \ + ldda [src + off + 0x10] %asi, t4; \ + ldda [src + off + 0x18] %asi, t6; \ st t0, [dst + off + 0x00]; \ addccc t0, sum, sum; \ st t1, [dst + off + 0x04]; \ @@ -234,8 +237,8 @@ /* Yuck, 6 superscalar cycles... */ #define CSUMCOPY_LASTCHUNK(src, dst, sum, off, t0, t1, t2, t3) \ - ldd [src - off - 0x08], t0; \ - ldd [src - off - 0x00], t2; \ + ldda [src - off - 0x08] %asi, t0; \ + ldda [src - off - 0x00] %asi, t2; \ addccc t0, sum, sum; \ st t0, [dst - off - 0x08]; \ addccc t1, sum, sum; \ @@ -250,7 +253,7 @@ andcc %o3, 8, %g0 ! begin checks for that code be,pn %icc, 1f and %o3, 4, %g5 - EX(ldd [%o0 + 0x00], %g2, and %o3, 0xf,#) + EX(ldda [%o0 + 0x00] %asi, %g2, and %o3, 0xf,#) add %o1, 8, %o1 addcc %g2, %g7, %g7 add %o0, 8, %o0 @@ -260,7 +263,7 @@ EX2(st %g3, [%o1 - 0x04],#) 1: brz,pt %g5, 1f andcc %o3, 3, %o3 - EX(ld [%o0 + 0x00], %g2, add %o3, 4,#) + EX(lda [%o0 + 0x00] %asi, %g2, add %o3, 4,#) add %o1, 4, %o1 addcc %g2, %g7, %g7 EX2(st %g2, [%o1 - 0x04],#) @@ -272,20 +275,21 @@ subcc %o3, 2, %o3 ba,pt %xcc, 4f clr %o4 -2: EX(lduh [%o0 + 0x00], %o4, add %o3, 2,#) +2: EX(lduha [%o0 + 0x00] %asi, %o4, add %o3, 2,#) add %o0, 2, %o0 EX2(sth %o4, [%o1 + 0x00],#) be,pn %icc, 6f add %o1, 2, %o1 sll %o4, 16, %o4 -4: EX(ldub [%o0 + 0x00], %o5, add %g0, 1,#) +4: EX(lduba [%o0 + 0x00] %asi, %o5, add %g0, 1,#) EX2(stb %o5, [%o1 + 0x00],#) sll %o5, 8, %o5 or %o5, %o4, %o4 6: addcc %o4, %g7, %g7 1: sllx %g4, 32, %g4 + addc %g0, %g7, %o0 retl - addc %g0, %g7, %o0 + srl %o0, 0, %o0 /* Sun, you just can't beat me, you just can't. Stop trying, * give up. I'm serious, I am going to kick the living shit @@ -295,7 +299,9 @@ .globl __csum_partial_copy_sparc_generic __csum_partial_copy_sparc_generic: /* %o0=src, %o1=dest, %g1=len, %g7=sum */ + srl %g7, 0, %g7 ! you neve know... xor %o0, %o1, %o4 ! get changing bits + srl %g1, 0, %g1 ! doof scheiss andcc %o4, 3, %g0 ! check for mismatched alignment bne,pn %icc, ccslow ! better this than unaligned/fixups andcc %o0, 7, %g0 ! need to align things? @@ -309,7 +315,7 @@ andcc %o0, 0x2, %g0 be,pn %icc, 1f andcc %o0, 0x4, %g0 - EX(lduh [%o0 + 0x00], %g4, add %g1, 0,#) + EX(lduha [%o0 + 0x00] %asi, %g4, add %g1, 0,#) sub %g1, 2, %g1 EX2(sth %g4, [%o1 + 0x00],#) add %o0, 2, %o0 @@ -325,7 +331,7 @@ or %g3, %g7, %g7 1: be,pt %icc, 3f andn %g1, 0x7f, %g2 - EX(ld [%o0 + 0x00], %g4, add %g1, 0,#) + EX(lda [%o0 + 0x00] %asi, %g4, add %g1, 0,#) sub %g1, 4, %g1 EX2(st %g4, [%o1 + 0x00],#) add %o0, 4, %o0 @@ -372,8 +378,9 @@ ccte: bne,pn %icc, cc_end_cruft ! something left, handle it out of band sethi %uhi(KERNBASE), %g4 ! restore gfp mov %g7, %o0 ! give em the computed checksum + sllx %g4, 32, %g4 ! finish gfp restoration retl ! return - sllx %g4, 32, %g4 ! finish gfp restoration + srl %o0, 0, %o0 ccdbl: CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x00,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3) CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x20,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3) CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x40,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3) @@ -394,7 +401,7 @@ be,a,pt %icc, 1f srl %g1, 1, %o3 sub %g1, 1, %g1 - EX(ldub [%o0], %g5, add %g1, 1,#) + EX(lduba [%o0] %asi, %g5, add %g1, 1,#) add %o0, 1, %o0 EX2(stb %g5, [%o1],#) srl %g1, 1, %o3 @@ -404,7 +411,7 @@ andcc %o0, 2, %g0 be,a,pt %icc, 1f srl %o3, 1, %o3 - EX(lduh [%o0], %o4, add %g1, 0,#) + EX(lduha [%o0] %asi, %o4, add %g1, 0,#) sub %g1, 2, %g1 srl %o4, 8, %g2 sub %o3, 1, %o3 @@ -416,7 +423,7 @@ add %o1, 2, %o1 1: brz,a,pn %o3, 2f andcc %g1, 2, %g0 - EX3(ld [%o0], %o4,#) + EX3(lda [%o0] %asi, %o4,#) 5: srl %o4, 24, %g2 srl %o4, 16, %g3 EX2(stb %g2, [%o1],#) @@ -430,7 +437,7 @@ add %o1, 4, %o1 ! is worthy). Maybe some day - with the sll/srl subcc %o3, 1, %o3 ! tricks bne,a,pt %icc, 5b - EX3(ld [%o0], %o4,#) + EX3(lda [%o0] %asi, %o4,#) sll %g5, 16, %g2 srl %g5, 16, %g5 srl %g2, 16, %g2 @@ -438,7 +445,7 @@ add %g2, %g5, %g5 2: be,a,pt %icc, 3f andcc %g1, 1, %g0 - EX(lduh [%o0], %o4, and %g1, 3,#) + EX(lduha [%o0] %asi, %o4, and %g1, 3,#) andcc %g1, 1, %g0 srl %o4, 8, %g2 add %o0, 2, %o0 @@ -448,7 +455,7 @@ add %o1, 2, %o1 3: be,a,pt %icc, 1f sll %g5, 16, %o4 - EX(ldub [%o0], %g2, add %g0, 1,#) + EX(lduba [%o0] %asi, %g2, add %g0, 1,#) sll %g2, 8, %o4 EX2(stb %g2, [%o1],#) add %g5, %o4, %g5 @@ -463,8 +470,9 @@ sll %g2, 8, %g2 or %g2, %o4, %g5 4: addcc %g7, %g5, %g7 + addc %g0, %g7, %o0 retl - addc %g0, %g7, %o0 + srl %o0, 0, %o0 __csum_partial_copy_end: .section .fixup,#alloc,#execinstr diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/lib/copy_from_user.S linux/arch/sparc64/lib/copy_from_user.S --- v2.1.42/linux/arch/sparc64/lib/copy_from_user.S Tue May 13 22:41:04 1997 +++ linux/arch/sparc64/lib/copy_from_user.S Thu Jun 12 16:22:06 1997 @@ -27,8 +27,8 @@ retl; \ a, b, %o0; \ .section __ex_table,z##alloc; \ - .align 4; \ - .word 98b, 99b; \ + .align 8; \ + .xword 98b, 99b; \ .text; \ .align 4 @@ -41,23 +41,23 @@ retl; \ a, b, %o0; \ .section __ex_table,z##alloc; \ - .align 4; \ - .word 98b, 99b; \ + .align 8; \ + .xword 98b, 99b; \ .text; \ .align 4 #define EXO2(x,y,z) \ 98: x,##y; \ .section __ex_table,z##alloc; \ - .align 4; \ - .word 98b, 97f; \ + .align 8; \ + .xword 98b, 97f; \ .text; \ .align 4 #define EXT(start,end,handler,z) \ .section __ex_table,z##alloc; \ - .align 4; \ - .word start, 0, end, handler; \ + .align 8; \ + .xword start, 0, end, handler; \ .text; \ .align 4 diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/lib/copy_to_user.S linux/arch/sparc64/lib/copy_to_user.S --- v2.1.42/linux/arch/sparc64/lib/copy_to_user.S Tue May 13 22:41:04 1997 +++ linux/arch/sparc64/lib/copy_to_user.S Thu Jun 12 16:22:06 1997 @@ -27,8 +27,8 @@ retl; \ a, b, %o0; \ .section __ex_table,z##alloc; \ - .align 4; \ - .word 98b, 99b; \ + .align 8; \ + .xword 98b, 99b; \ .text; \ .align 4 @@ -41,23 +41,23 @@ retl; \ a, b, %o0; \ .section __ex_table,z##alloc; \ - .align 4; \ - .word 98b, 99b; \ + .align 8; \ + .xword 98b, 99b; \ .text; \ .align 4 #define EXO2(x,y,z) \ 98: x,##y; \ .section __ex_table,z##alloc; \ - .align 4; \ - .word 98b, 97f; \ + .align 8; \ + .xword 98b, 97f; \ .text; \ .align 4 #define EXT(start,end,handler,z) \ .section __ex_table,z##alloc; \ - .align 4; \ - .word start, 0, end, handler; \ + .align 8; \ + .xword start, 0, end, handler; \ .text; \ .align 4 diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/lib/memset.S linux/arch/sparc64/lib/memset.S --- v2.1.42/linux/arch/sparc64/lib/memset.S Mon Apr 14 16:28:10 1997 +++ linux/arch/sparc64/lib/memset.S Thu Jun 12 16:22:06 1997 @@ -17,15 +17,15 @@ 99: ba,pt %xcc, 30f; \ a, b, %o0; \ .section __ex_table,z##alloc; \ - .align 4; \ - .word 98b, 99b; \ + .align 8; \ + .xword 98b, 99b; \ .text; \ .align 4 #define EXT(start,end,handler,z) \ .section __ex_table,z##alloc; \ - .align 4; \ - .word start, 0, end, handler; \ + .align 8; \ + .xword start, 0, end, handler; \ .text; \ .align 4 diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/lib/strlen_user.S linux/arch/sparc64/lib/strlen_user.S --- v2.1.42/linux/arch/sparc64/lib/strlen_user.S Sat May 24 09:10:23 1997 +++ linux/arch/sparc64/lib/strlen_user.S Thu Jun 12 16:22:06 1997 @@ -92,10 +92,10 @@ clr %o0 .section __ex_table,#alloc - .align 4 + .align 8 - .word 10b, 30b - .word 11b, 30b - .word 12b, 30b - .word 13b, 30b - .word 14b, 30b + .xword 10b, 30b + .xword 11b, 30b + .xword 12b, 30b + .xword 13b, 30b + .xword 14b, 30b diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/lib/strncpy_from_user.S linux/arch/sparc64/lib/strncpy_from_user.S --- v2.1.42/linux/arch/sparc64/lib/strncpy_from_user.S Sat May 24 09:10:23 1997 +++ linux/arch/sparc64/lib/strncpy_from_user.S Thu Jun 12 16:22:06 1997 @@ -49,6 +49,6 @@ mov -EFAULT, %o0 .section __ex_table,#alloc - .align 4 - .word 10b, 4b - .word 11b, 4b + .align 8 + .xword 10b, 4b + .xword 11b, 4b diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c --- v2.1.42/linux/arch/sparc64/mm/fault.c Thu May 29 21:53:04 1997 +++ linux/arch/sparc64/mm/fault.c Thu Jun 12 16:22:06 1997 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.9 1997/05/19 05:58:54 davem Exp $ +/* $Id: fault.c,v 1.11 1997/06/01 05:46:15 davem Exp $ * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -135,6 +135,7 @@ } /* #define FAULT_TRACER */ +/* #define FAULT_TRACER_VERBOSE */ asmlinkage void do_sparc64_fault(struct pt_regs *regs, int text_fault, int write, unsigned long address, unsigned long tag, @@ -150,12 +151,23 @@ static unsigned long last_addr = 0; static int rcnt = 0; - printk("FAULT(PC[%016lx],t[%d],w[%d],addr[%016lx])\n", +#ifdef FAULT_TRACER_VERBOSE + printk("FAULT(PC[%016lx],t[%d],w[%d],addr[%016lx])...", regs->tpc, text_fault, write, address); - if(address == last_addr && rcnt++ > 5) { - printk("Wheee lotsa bogus faults, something wrong, spinning\n"); - while(1) - barrier(); +#else + printk("F[%016lx:%016lx:w(%d)", regs->tpc, address, write); +#endif + if(address == last_addr) { + if(rcnt++ > 15) { + printk("Wheee lotsa bogus faults, something wrong, spinning\n"); + __asm__ __volatile__("flushw"); + printk("o7[%016lx] i7[%016lx]\n", + regs->u_regs[UREG_I7], + ((struct reg_window *)(regs->u_regs[UREG_FP]+STACK_BIAS))->ins[7]); + sti(); + while(1) + barrier(); + } } else rcnt = 0; last_addr = address; #endif @@ -205,6 +217,13 @@ goto out; } if(from_user) { +#if 1 + unsigned long cpc; + __asm__ __volatile__("mov %%i7, %0" : "=r" (cpc)); + printk("[%s:%d] SIGSEGV pc[%016lx] addr[%016lx] w[%d] sfsr[%016lx] " + "caller[%016lx]\n", current->comm, current->pid, regs->tpc, + address, write, sfsr, cpc); +#endif tsk->tss.sig_address = address; tsk->tss.sig_desc = SUBSIG_NOMAPPING; send_sig(SIGSEGV, tsk, 1); @@ -213,4 +232,12 @@ unhandled_fault (address, tsk, regs); out: unlock_kernel(); +#ifdef FAULT_TRACER +#ifdef FAULT_TRACER_VERBOSE + printk(" done\n"); +#else + printk("]"); +#endif +#endif } + diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/vmlinux.lds linux/arch/sparc64/vmlinux.lds --- v2.1.42/linux/arch/sparc64/vmlinux.lds Mon Apr 14 16:28:11 1997 +++ linux/arch/sparc64/vmlinux.lds Thu Jun 12 16:22:06 1997 @@ -26,6 +26,7 @@ _edata = .; PROVIDE (edata = .); .fixup : { *(.fixup) } + . = ALIGN(16); __start___ex_table = .; __ex_table : { *(__ex_table) } __stop___ex_table = .; diff -u --recursive --new-file v2.1.42/linux/drivers/ap1000/ringbuf.c linux/drivers/ap1000/ringbuf.c --- v2.1.42/linux/drivers/ap1000/ringbuf.c Sun Jan 26 02:07:10 1997 +++ linux/drivers/ap1000/ringbuf.c Thu Jun 12 16:22:06 1997 @@ -318,7 +318,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/drivers/block/genhd.c linux/drivers/block/genhd.c --- v2.1.42/linux/drivers/block/genhd.c Sat May 24 09:10:23 1997 +++ linux/drivers/block/genhd.c Thu Jun 12 16:22:06 1997 @@ -380,7 +380,7 @@ && (q->sector & 63) == 1 && (q->end_sector & 63) == 63) { unsigned int heads = q->end_head + 1; - if (heads == 32 || heads == 64 || heads == 128) { + if (heads == 32 || heads == 64 || heads == 128 || heads == 255) { (void) ide_xlate_1024(dev, heads, " [PTBL]"); break; @@ -672,6 +672,141 @@ } #endif /* CONFIG_AMIGA_PARTITION */ +#ifdef CONFIG_ATARI_PARTITION +#include + +/* ++guenther: this should be settable by the user ("make config")?. + */ +#define ICD_PARTS + +static int atari_partition (struct gendisk *hd, kdev_t dev, + unsigned long first_sector) +{ + int minor = current_minor, m_lim = current_minor + hd->max_p; + struct buffer_head *bh; + struct rootsector *rs; + struct partition_info *pi; + ulong extensect; +#ifdef ICD_PARTS + int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */ +#endif + + bh = bread (dev, 0, get_ptable_blocksize(dev)); + if (!bh) + { + printk (" unable to read block 0\n"); + return -1; + } + + rs = (struct rootsector *) bh->b_data; + pi = &rs->part[0]; + printk (" AHDI"); + for (; pi < &rs->part[4] && minor < m_lim; minor++, pi++) + { + if (pi->flg & 1) + /* active partition */ + { + if (memcmp (pi->id, "XGM", 3) == 0) + /* extension partition */ + { + struct rootsector *xrs; + struct buffer_head *xbh; + ulong partsect; + +#ifdef ICD_PARTS + part_fmt = 1; +#endif + printk(" XGM<"); + partsect = extensect = pi->st; + while (1) + { + xbh = bread (dev, partsect / 2, 1024); + if (!xbh) + { + printk (" block %ld read failed\n", partsect); + brelse(bh); + return 0; + } + if (partsect & 1) + xrs = (struct rootsector *) &xbh->b_data[512]; + else + xrs = (struct rootsector *) &xbh->b_data[0]; + + /* ++roman: sanity check: bit 0 of flg field must be set */ + if (!(xrs->part[0].flg & 1)) { + printk( "\nFirst sub-partition in extended partition is not valid!\n" ); + break; + } + + add_partition(hd, minor, partsect + xrs->part[0].st, + xrs->part[0].siz); + + if (!(xrs->part[1].flg & 1)) { + /* end of linked partition list */ + brelse( xbh ); + break; + } + if (memcmp( xrs->part[1].id, "XGM", 3 ) != 0) { + printk( "\nID of extended partition is not XGM!\n" ); + brelse( xbh ); + break; + } + + partsect = xrs->part[1].st + extensect; + brelse (xbh); + minor++; + if (minor >= m_lim) { + printk( "\nMaximum number of partitions reached!\n" ); + break; + } + } + printk(" >"); + } + else + { + /* we don't care about other id's */ + add_partition (hd, minor, pi->st, pi->siz); + } + } + } +#ifdef ICD_PARTS + if ( part_fmt!=1 ) /* no extended partitions -> test ICD-format */ + { + pi = &rs->icdpart[0]; + /* sanity check: no ICD format if first partition invalid */ + if (memcmp (pi->id, "GEM", 3) == 0 || + memcmp (pi->id, "BGM", 3) == 0 || + memcmp (pi->id, "LNX", 3) == 0 || + memcmp (pi->id, "SWP", 3) == 0 || + memcmp (pi->id, "RAW", 3) == 0 ) + { + printk(" ICD<"); + for (; pi < &rs->icdpart[8] && minor < m_lim; minor++, pi++) + { + /* accept only GEM,BGM,RAW,LNX,SWP partitions */ + if (pi->flg & 1 && + (memcmp (pi->id, "GEM", 3) == 0 || + memcmp (pi->id, "BGM", 3) == 0 || + memcmp (pi->id, "LNX", 3) == 0 || + memcmp (pi->id, "SWP", 3) == 0 || + memcmp (pi->id, "RAW", 3) == 0) ) + { + part_fmt = 2; + add_partition (hd, minor, pi->st, pi->siz); + } + } + printk(" >"); + } + } +#endif + brelse (bh); + + printk ("\n"); + + return 1; +} +#endif /* CONFIG_ATARI_PARTITION */ + static void check_partition(struct gendisk *hd, kdev_t dev) { static int first_time = 1; @@ -707,6 +842,10 @@ #endif #ifdef CONFIG_AMIGA_PARTITION if(amiga_partition(hd, dev, first_sector)) + return; +#endif +#ifdef CONFIG_ATARI_PARTITION + if(atari_partition(hd, dev, first_sector)) return; #endif printk(" unknown partition table\n"); diff -u --recursive --new-file v2.1.42/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v2.1.42/linux/drivers/block/ide.c Tue May 13 22:41:05 1997 +++ linux/drivers/block/ide.c Thu Jun 12 16:22:06 1997 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide.c Version 6.02 Mar 11, 1997 + * linux/drivers/block/ide.c Version 6.03 June 4, 1997 * * Copyright (C) 1994-1997 Linus Torvalds & authors (see below) */ @@ -280,6 +280,7 @@ * support HDIO_GETGEO for floppies * Version 6.02 fix ide_ack_intr() call * check partition table on floppies + * Version 6.03 handle bad status bit sequencing in ide_wait_stat() * * Some additional driver compile-time options are in ide.h * @@ -1044,27 +1045,24 @@ byte stat; unsigned long flags; -test: - udelay(1); /* spec allows drive 400ns to change "BUSY" */ - if (OK_STAT((stat = GET_STAT()), good, bad)) - return 0; /* fast exit for most frequent case */ - if (!(stat & BUSY_STAT)) { - ide_error(drive, "status error", stat); - return 1; - } - - save_flags(flags); - ide_sti(); - timeout += jiffies; - do { - if (!((stat = GET_STAT()) & BUSY_STAT)) { - restore_flags(flags); - goto test; + udelay(1); /* spec allows drive 400ns to assert "BUSY" */ + if ((stat = GET_STAT()) & BUSY_STAT) { + save_flags(flags); + ide_sti(); + timeout += jiffies; + while ((stat = GET_STAT()) & BUSY_STAT) { + if (jiffies > timeout) { + restore_flags(flags); + ide_error(drive, "status timeout", stat); + return 1; + } } - } while (jiffies <= timeout); - - restore_flags(flags); - ide_error(drive, "status timeout", GET_STAT()); + restore_flags(flags); + } + udelay(1); /* allow status to settle, then read it again */ + if (OK_STAT((stat = GET_STAT()), good, bad)) + return 0; + ide_error(drive, "status error", stat); return 1; } diff -u --recursive --new-file v2.1.42/linux/drivers/block/ide.h linux/drivers/block/ide.h --- v2.1.42/linux/drivers/block/ide.h Thu Jun 12 15:28:48 1997 +++ linux/drivers/block/ide.h Sun Jun 15 15:12:43 1997 @@ -134,7 +134,7 @@ #define BAD_W_STAT (BAD_R_STAT | WRERR_STAT) #define BAD_STAT (BAD_R_STAT | DRQ_STAT) #define DRIVE_READY (READY_STAT | SEEK_STAT) -#define DATA_READY (DRIVE_READY | DRQ_STAT) +#define DATA_READY (DRQ_STAT) /* * Some more useful definitions diff -u --recursive --new-file v2.1.42/linux/drivers/block/loop.c linux/drivers/block/loop.c --- v2.1.42/linux/drivers/block/loop.c Tue May 13 22:41:05 1997 +++ linux/drivers/block/loop.c Thu Jun 12 16:22:06 1997 @@ -318,7 +318,7 @@ } lo->lo_inode = inode; - lo->lo_inode->i_count++; + atomic_inc(&lo->lo_inode->i_count); lo->transfer = NULL; figure_loop_size(lo); MOD_INC_USE_COUNT; diff -u --recursive --new-file v2.1.42/linux/drivers/block/md.c linux/drivers/block/md.c --- v2.1.42/linux/drivers/block/md.c Tue May 13 22:41:05 1997 +++ linux/drivers/block/md.c Thu Jun 12 16:22:06 1997 @@ -202,9 +202,10 @@ { int i; - if (inode->i_count>1 || md_dev[minor].busy>1) /* ioctl : one open channel */ + if (atomic_read(&inode->i_count)>1 || md_dev[minor].busy>1) /* ioctl : one open channel */ { - printk ("STOP_MD md%x failed : i_count=%d, busy=%d\n", minor, inode->i_count, md_dev[minor].busy); + printk ("STOP_MD md%x failed : i_count=%d, busy=%d\n", minor, + atomic_read(&inode->i_count), md_dev[minor].busy); return -EBUSY; } diff -u --recursive --new-file v2.1.42/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.1.42/linux/drivers/char/Makefile Sat May 24 09:10:23 1997 +++ linux/drivers/char/Makefile Thu Jun 12 16:22:06 1997 @@ -44,6 +44,9 @@ ifneq ($(ARCH),m68k) L_OBJS += pc_keyb.o defkeymap.o endif +ifdef CONFIG_MAGIC_SYSRQ +L_OBJS += sysrq.o +endif endif ifeq ($(CONFIG_ATARI_DSP56K),y) diff -u --recursive --new-file v2.1.42/linux/drivers/char/atarimouse.c linux/drivers/char/atarimouse.c --- v2.1.42/linux/drivers/char/atarimouse.c Wed Apr 23 19:01:17 1997 +++ linux/drivers/char/atarimouse.c Thu Jun 12 16:22:06 1997 @@ -176,7 +176,7 @@ #define MIN_THRESHOLD 1 #define MAX_THRESHOLD 20 /* more seems not reasonable... */ -void atari_mouse_setup( char *str, int *ints ) +__initfunc(void atari_mouse_setup( char *str, int *ints )) { if (ints[0] < 1) { printk( "atari_mouse_setup: no arguments!\n" ); diff -u --recursive --new-file v2.1.42/linux/drivers/char/console.c linux/drivers/char/console.c --- v2.1.42/linux/drivers/char/console.c Tue May 13 22:41:06 1997 +++ linux/drivers/char/console.c Thu Jun 12 16:22:06 1997 @@ -111,11 +111,11 @@ #include #include -#include "kbd_kern.h" -#include "vt_kern.h" -#include "consolemap.h" -#include "selection.h" -#include "console_struct.h" +#include +#include +#include +#include +#include #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) diff -u --recursive --new-file v2.1.42/linux/drivers/char/console_struct.h linux/drivers/char/console_struct.h --- v2.1.42/linux/drivers/char/console_struct.h Mon Nov 20 22:34:54 1995 +++ linux/drivers/char/console_struct.h Wed Dec 31 16:00:00 1969 @@ -1,141 +0,0 @@ -/* - * console_struct.h - * - * Data structure and defines shared between console.c, vga.c and tga.c - */ - -#define NPAR 16 - -struct vc_data { - unsigned long vc_screenbuf_size; - unsigned short vc_video_erase_char; /* Background erase character */ - unsigned char vc_attr; /* Current attributes */ - unsigned char vc_def_color; /* Default colors */ - unsigned char vc_color; /* Foreground & background */ - unsigned char vc_s_color; /* Saved foreground & background */ - unsigned char vc_ulcolor; /* Colour for underline mode */ - unsigned char vc_halfcolor; /* Colour for half intensity mode */ - unsigned long vc_origin; /* Used for EGA/VGA fast scroll */ - unsigned long vc_scr_end; /* Used for EGA/VGA fast scroll */ - unsigned long vc_pos; - unsigned long vc_x,vc_y; - unsigned long vc_top,vc_bottom; - unsigned long vc_state; - unsigned long vc_npar,vc_par[NPAR]; - unsigned long vc_video_mem_start; /* Start of video RAM */ - unsigned long vc_video_mem_end; /* End of video RAM (sort of) */ - unsigned long vc_saved_x; - unsigned long vc_saved_y; - /* mode flags */ - unsigned long vc_charset : 1; /* Character set G0 / G1 */ - unsigned long vc_s_charset : 1; /* Saved character set */ - unsigned long vc_disp_ctrl : 1; /* Display chars < 32? */ - unsigned long vc_toggle_meta : 1; /* Toggle high bit? */ - unsigned long vc_decscnm : 1; /* Screen Mode */ - unsigned long vc_decom : 1; /* Origin Mode */ - unsigned long vc_decawm : 1; /* Autowrap Mode */ - unsigned long vc_deccm : 1; /* Cursor Visible */ - unsigned long vc_decim : 1; /* Insert Mode */ - unsigned long vc_deccolm : 1; /* 80/132 Column Mode */ - /* attribute flags */ - unsigned long vc_intensity : 2; /* 0=half-bright, 1=normal, 2=bold */ - unsigned long vc_underline : 1; - unsigned long vc_blink : 1; - unsigned long vc_reverse : 1; - unsigned long vc_s_intensity : 2; /* saved rendition */ - unsigned long vc_s_underline : 1; - unsigned long vc_s_blink : 1; - unsigned long vc_s_reverse : 1; - /* misc */ - unsigned long vc_ques : 1; - unsigned long vc_need_wrap : 1; - unsigned long vc_has_scrolled : 1; /* Info for unblank_screen */ - unsigned long vc_kmalloced : 1; /* kfree_s() needed */ - unsigned long vc_report_mouse : 2; - unsigned char vc_utf : 1; /* Unicode UTF-8 encoding */ - unsigned char vc_utf_count; - long vc_utf_char; - unsigned long vc_tab_stop[5]; /* Tab stops. 160 columns. */ - unsigned char vc_palette[16*3]; /* Colour palette for VGA+ */ - unsigned short * vc_translate; - unsigned char vc_G0_charset; - unsigned char vc_G1_charset; - unsigned char vc_saved_G0; - unsigned char vc_saved_G1; - unsigned int vc_bell_pitch; /* Console bell pitch */ - unsigned int vc_bell_duration; /* Console bell duration */ - /* additional information is in vt_kern.h */ -}; - -struct vc { - struct vc_data *d; - - /* might add scrmem, vt_struct, kbd at some time, - to have everything in one place - the disadvantage - would be that vc_cons etc can no longer be static */ -}; - -extern struct vc vc_cons [MAX_NR_CONSOLES]; - -#define screenbuf_size (vc_cons[currcons].d->vc_screenbuf_size) -#define origin (vc_cons[currcons].d->vc_origin) -#define scr_end (vc_cons[currcons].d->vc_scr_end) -#define pos (vc_cons[currcons].d->vc_pos) -#define top (vc_cons[currcons].d->vc_top) -#define bottom (vc_cons[currcons].d->vc_bottom) -#define x (vc_cons[currcons].d->vc_x) -#define y (vc_cons[currcons].d->vc_y) -#define vc_state (vc_cons[currcons].d->vc_state) -#define npar (vc_cons[currcons].d->vc_npar) -#define par (vc_cons[currcons].d->vc_par) -#define ques (vc_cons[currcons].d->vc_ques) -#define attr (vc_cons[currcons].d->vc_attr) -#define saved_x (vc_cons[currcons].d->vc_saved_x) -#define saved_y (vc_cons[currcons].d->vc_saved_y) -#define translate (vc_cons[currcons].d->vc_translate) -#define G0_charset (vc_cons[currcons].d->vc_G0_charset) -#define G1_charset (vc_cons[currcons].d->vc_G1_charset) -#define saved_G0 (vc_cons[currcons].d->vc_saved_G0) -#define saved_G1 (vc_cons[currcons].d->vc_saved_G1) -#define utf (vc_cons[currcons].d->vc_utf) -#define utf_count (vc_cons[currcons].d->vc_utf_count) -#define utf_char (vc_cons[currcons].d->vc_utf_char) -#define video_mem_start (vc_cons[currcons].d->vc_video_mem_start) -#define video_mem_end (vc_cons[currcons].d->vc_video_mem_end) -#define video_erase_char (vc_cons[currcons].d->vc_video_erase_char) -#define disp_ctrl (vc_cons[currcons].d->vc_disp_ctrl) -#define toggle_meta (vc_cons[currcons].d->vc_toggle_meta) -#define decscnm (vc_cons[currcons].d->vc_decscnm) -#define decom (vc_cons[currcons].d->vc_decom) -#define decawm (vc_cons[currcons].d->vc_decawm) -#define deccm (vc_cons[currcons].d->vc_deccm) -#define decim (vc_cons[currcons].d->vc_decim) -#define deccolm (vc_cons[currcons].d->vc_deccolm) -#define need_wrap (vc_cons[currcons].d->vc_need_wrap) -#define has_scrolled (vc_cons[currcons].d->vc_has_scrolled) -#define kmalloced (vc_cons[currcons].d->vc_kmalloced) -#define report_mouse (vc_cons[currcons].d->vc_report_mouse) -#define color (vc_cons[currcons].d->vc_color) -#define s_color (vc_cons[currcons].d->vc_s_color) -#define def_color (vc_cons[currcons].d->vc_def_color) -#define foreground (color & 0x0f) -#define background (color & 0xf0) -#define charset (vc_cons[currcons].d->vc_charset) -#define s_charset (vc_cons[currcons].d->vc_s_charset) -#define intensity (vc_cons[currcons].d->vc_intensity) -#define underline (vc_cons[currcons].d->vc_underline) -#define blink (vc_cons[currcons].d->vc_blink) -#define reverse (vc_cons[currcons].d->vc_reverse) -#define s_intensity (vc_cons[currcons].d->vc_s_intensity) -#define s_underline (vc_cons[currcons].d->vc_s_underline) -#define s_blink (vc_cons[currcons].d->vc_s_blink) -#define s_reverse (vc_cons[currcons].d->vc_s_reverse) -#define ulcolor (vc_cons[currcons].d->vc_ulcolor) -#define halfcolor (vc_cons[currcons].d->vc_halfcolor) -#define tab_stop (vc_cons[currcons].d->vc_tab_stop) -#define palette (vc_cons[currcons].d->vc_palette) -#define bell_pitch (vc_cons[currcons].d->vc_bell_pitch) -#define bell_duration (vc_cons[currcons].d->vc_bell_duration) - -#define vcmode (vt_cons[currcons]->vc_mode) -#define structsize (sizeof(struct vc_data) + sizeof(struct vt_struct)) diff -u --recursive --new-file v2.1.42/linux/drivers/char/consolemap.c linux/drivers/char/consolemap.c --- v2.1.42/linux/drivers/char/consolemap.c Tue May 13 22:41:06 1997 +++ linux/drivers/char/consolemap.c Thu Jun 12 16:22:06 1997 @@ -13,7 +13,7 @@ #include #include #include -#include "consolemap.h" +#include static unsigned short translations[][256] = { /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */ diff -u --recursive --new-file v2.1.42/linux/drivers/char/consolemap.h linux/drivers/char/consolemap.h --- v2.1.42/linux/drivers/char/consolemap.h Sun Sep 17 21:42:44 1995 +++ linux/drivers/char/consolemap.h Wed Dec 31 16:00:00 1969 @@ -1,14 +0,0 @@ -/* - * consolemap.h - * - * Interface between console.c, selection.c and consolemap.c - */ -#define LAT1_MAP 0 -#define GRAF_MAP 1 -#define IBMPC_MAP 2 -#define USER_MAP 3 - -extern int hashtable_contents_valid; -extern unsigned char inverse_translate(int glyph); -extern unsigned short *set_translate(int m); -extern int conv_uni_to_pc(long ucs); diff -u --recursive --new-file v2.1.42/linux/drivers/char/diacr.h linux/drivers/char/diacr.h --- v2.1.42/linux/drivers/char/diacr.h Thu Feb 6 02:55:18 1997 +++ linux/drivers/char/diacr.h Wed Dec 31 16:00:00 1969 @@ -1,8 +0,0 @@ -#ifndef _DIACR_H -#define _DIACR_H -#include - -extern struct kbdiacr accent_table[]; -extern unsigned int accent_table_size; - -#endif /* _DIACR_H */ diff -u --recursive --new-file v2.1.42/linux/drivers/char/dsp56k.c linux/drivers/char/dsp56k.c --- v2.1.42/linux/drivers/char/dsp56k.c Tue May 13 22:41:06 1997 +++ linux/drivers/char/dsp56k.c Thu Jun 12 16:22:06 1997 @@ -488,7 +488,7 @@ return 0; } -static void dsp56k_release(struct inode *inode, struct file *file) +static int dsp56k_release(struct inode *inode, struct file *file) { int dev = MINOR(inode->i_rdev) & 0x0f; @@ -501,12 +501,13 @@ break; default: printk("DSP56k driver: Unknown minor device: %d\n", dev); - return; + return -ENXIO; } #ifdef MODULE MOD_DEC_USE_COUNT; -#endif /* MODULE */ +#endif + return 0; } static struct file_operations dsp56k_fops = { diff -u --recursive --new-file v2.1.42/linux/drivers/char/fbmem.c linux/drivers/char/fbmem.c --- v2.1.42/linux/drivers/char/fbmem.c Tue May 13 22:41:07 1997 +++ linux/drivers/char/fbmem.c Thu Jun 12 16:22:06 1997 @@ -222,7 +222,7 @@ vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; vma->vm_inode = inode; - inode->i_count++; + atomic_inc(&inode->i_count); return 0; } diff -u --recursive --new-file v2.1.42/linux/drivers/char/kbd_kern.h linux/drivers/char/kbd_kern.h --- v2.1.42/linux/drivers/char/kbd_kern.h Thu Jun 12 15:29:05 1997 +++ linux/drivers/char/kbd_kern.h Wed Dec 31 16:00:00 1969 @@ -1,141 +0,0 @@ -#ifndef _KBD_KERN_H -#define _KBD_KERN_H - -#include -#include - -extern int shift_state; - -extern char *func_table[MAX_NR_FUNC]; -extern char func_buf[]; -extern char *funcbufptr; -extern int funcbufsize, funcbufleft; - -/* - * kbd->xxx contains the VC-local things (flag settings etc..) - * - * Note: externally visible are LED_SCR, LED_NUM, LED_CAP defined in kd.h - * The code in KDGETLED / KDSETLED depends on the internal and - * external order being the same. - * - * Note: lockstate is used as index in the array key_map. - */ -struct kbd_struct { - - unsigned char lockstate; -/* 8 modifiers - the names do not have any meaning at all; - they can be associated to arbitrarily chosen keys */ -#define VC_SHIFTLOCK KG_SHIFT /* shift lock mode */ -#define VC_ALTGRLOCK KG_ALTGR /* altgr lock mode */ -#define VC_CTRLLOCK KG_CTRL /* control lock mode */ -#define VC_ALTLOCK KG_ALT /* alt lock mode */ -#define VC_SHIFTLLOCK KG_SHIFTL /* shiftl lock mode */ -#define VC_SHIFTRLOCK KG_SHIFTR /* shiftr lock mode */ -#define VC_CTRLLLOCK KG_CTRLL /* ctrll lock mode */ -#define VC_CTRLRLOCK KG_CTRLR /* ctrlr lock mode */ - unsigned char slockstate; /* for `sticky' Shift, Ctrl, etc. */ - - unsigned char ledmode:2; /* one 2-bit value */ -#define LED_SHOW_FLAGS 0 /* traditional state */ -#define LED_SHOW_IOCTL 1 /* only change leds upon ioctl */ -#define LED_SHOW_MEM 2 /* `heartbeat': peek into memory */ - - unsigned char ledflagstate:3; /* flags, not lights */ - unsigned char default_ledflagstate:3; -#define VC_SCROLLOCK 0 /* scroll-lock mode */ -#define VC_NUMLOCK 1 /* numeric lock mode */ -#define VC_CAPSLOCK 2 /* capslock mode */ - - unsigned char kbdmode:2; /* one 2-bit value */ -#define VC_XLATE 0 /* translate keycodes using keymap */ -#define VC_MEDIUMRAW 1 /* medium raw (keycode) mode */ -#define VC_RAW 2 /* raw (scancode) mode */ -#define VC_UNICODE 3 /* Unicode mode */ - - unsigned char modeflags:5; -#define VC_APPLIC 0 /* application key mode */ -#define VC_CKMODE 1 /* cursor key mode */ -#define VC_REPEAT 2 /* keyboard repeat */ -#define VC_CRLF 3 /* 0 - enter sends CR, 1 - enter sends CRLF */ -#define VC_META 4 /* 0 - meta, 1 - meta=prefix with ESC */ -}; - -extern struct kbd_struct kbd_table[]; - -extern int kbd_init(void); - -extern unsigned char getledstate(void); -extern void setledstate(struct kbd_struct *kbd, unsigned int led); - -extern int do_poke_blanked_console; - -extern inline void show_console(void) -{ - do_poke_blanked_console = 1; - mark_bh(CONSOLE_BH); -} - -extern inline void set_console(int nr) -{ - want_console = nr; - mark_bh(CONSOLE_BH); -} - -extern inline void set_leds(void) -{ - mark_bh(KEYBOARD_BH); -} - -extern inline int vc_kbd_mode(struct kbd_struct * kbd, int flag) -{ - return ((kbd->modeflags >> flag) & 1); -} - -extern inline int vc_kbd_led(struct kbd_struct * kbd, int flag) -{ - return ((kbd->ledflagstate >> flag) & 1); -} - -extern inline void set_vc_kbd_mode(struct kbd_struct * kbd, int flag) -{ - kbd->modeflags |= 1 << flag; -} - -extern inline void set_vc_kbd_led(struct kbd_struct * kbd, int flag) -{ - kbd->ledflagstate |= 1 << flag; -} - -extern inline void clr_vc_kbd_mode(struct kbd_struct * kbd, int flag) -{ - kbd->modeflags &= ~(1 << flag); -} - -extern inline void clr_vc_kbd_led(struct kbd_struct * kbd, int flag) -{ - kbd->ledflagstate &= ~(1 << flag); -} - -extern inline void chg_vc_kbd_lock(struct kbd_struct * kbd, int flag) -{ - kbd->lockstate ^= 1 << flag; -} - -extern inline void chg_vc_kbd_slock(struct kbd_struct * kbd, int flag) -{ - kbd->slockstate ^= 1 << flag; -} - -extern inline void chg_vc_kbd_mode(struct kbd_struct * kbd, int flag) -{ - kbd->modeflags ^= 1 << flag; -} - -extern inline void chg_vc_kbd_led(struct kbd_struct * kbd, int flag) -{ - kbd->ledflagstate ^= 1 << flag; -} - -#define U(x) ((x) ^ 0xf000) - -#endif diff -u --recursive --new-file v2.1.42/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c --- v2.1.42/linux/drivers/char/keyboard.c Sat May 24 09:10:23 1997 +++ linux/drivers/char/keyboard.c Thu Jun 12 16:22:06 1997 @@ -17,8 +17,11 @@ * Modified to provide 'generic' keyboard support by Hamish Macdonald * Merge with the m68k keyboard driver and split-off of the PC low-level * parts by Geert Uytterhoeven, May 1997 + * + * 27-05-97: Added support for the Magic SysRq Key (Martin Mares) */ +#include #include #include #include @@ -30,9 +33,10 @@ #include #include -#include "kbd_kern.h" -#include "diacr.h" -#include "vt_kern.h" +#include +#include +#include +#include #define SIZE(x) (sizeof(x)/sizeof((x)[0])) @@ -82,7 +86,7 @@ * the variable must be global, or a new procedure must be created to * return the value. I chose the former way. */ -/*static*/ int shift_state = 0; +int shift_state = 0; static int npadch = -1; /* -1 or number assembled on pad */ static unsigned char diacr = 0; static char rep = 0; /* flag telling character repeat */ @@ -140,8 +144,14 @@ static void put_queue(int); static unsigned char handle_diacr(unsigned char); -/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */ -struct pt_regs * pt_regs; +/* kbd_pt_regs - set by keyboard_interrupt(), used by show_ptregs() */ +struct pt_regs * kbd_pt_regs; + +#ifdef CONFIG_MAGIC_SYSRQ +#define SYSRQ_KEY 0x54 +extern void handle_sysrq(int, struct pt_regs *, struct kbd_struct *, struct tty_struct *); +static int sysrq_pressed; +#endif /* * Many other routines do put_queue, but I think either @@ -223,6 +233,17 @@ } else rep = test_and_set_bit(keycode, key_down); +#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ + if (keycode == SYSRQ_KEY) { + sysrq_pressed = !up_flag; + return; + } else if (sysrq_pressed) { + if (!up_flag) + handle_sysrq(keycode, kbd_pt_regs, kbd, tty); + return; + } +#endif + if (kbd->kbdmode == VC_MEDIUMRAW) { /* soon keycodes will require more than one byte */ put_queue(keycode + up_flag); @@ -346,8 +367,8 @@ static void show_ptregs(void) { - if (pt_regs) - show_regs(pt_regs); + if (kbd_pt_regs) + show_regs(kbd_pt_regs); } static void hold(void) diff -u --recursive --new-file v2.1.42/linux/drivers/char/lp_m68k.c linux/drivers/char/lp_m68k.c --- v2.1.42/linux/drivers/char/lp_m68k.c Tue May 13 22:41:07 1997 +++ linux/drivers/char/lp_m68k.c Thu Jun 12 16:22:06 1997 @@ -462,7 +462,6 @@ EXPORT_SYMBOL(lp_table); EXPORT_SYMBOL(lp_irq); EXPORT_SYMBOL(lp_interrupt); -EXPORT_SYMBOL(lp_init); EXPORT_SYMBOL(register_parallel); EXPORT_SYMBOL(unregister_parallel); diff -u --recursive --new-file v2.1.42/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v2.1.42/linux/drivers/char/mem.c Thu May 15 16:48:02 1997 +++ linux/drivers/char/mem.c Thu Jun 12 16:22:06 1997 @@ -35,6 +35,33 @@ void pcwatchdog_init(void); #endif +static long do_write_mem(struct file * file, + void *p, unsigned long realp, + const char * buf, unsigned long count) +{ + unsigned long written; + + written = 0; +#if defined(__sparc__) || defined(__mc68000__) + /* we don't have page 0 mapped on sparc and m68k.. */ + if (realp < PAGE_SIZE) { + unsigned long sz = PAGE_SIZE-realp; + if (sz > count) sz = count; + /* Hmm. Do something? */ + buf+=sz; + p+=sz; + count-=sz; + written+=sz; + } +#endif + if (copy_from_user(p, buf, count) < 0) + return -EFAULT; + written += count; + file->f_pos += written; + return count; +} + + /* * This funcion reads the *physical* memory. The f_pos points directly to the * memory location. @@ -45,7 +72,7 @@ unsigned long p = file->f_pos; unsigned long end_mem; unsigned long read; - + end_mem = __pa(high_memory); if (p >= end_mem) return 0; @@ -54,15 +81,22 @@ read = 0; #if defined(__sparc__) || defined(__mc68000__) /* we don't have page 0 mapped on sparc and m68k.. */ - while (p < PAGE_SIZE && count > 0) { - put_user(0,buf); - buf++; - p++; - count--; - read++; + if (p < PAGE_SIZE) { + unsigned long sz = PAGE_SIZE-p; + if (sz > count) + sz = count; + if (sz > 0) { + if (clear_user(buf, sz)) + return -EFAULT; + buf += sz; + p += sz; + count -= sz; + read += sz; + } } #endif - copy_to_user(buf, __va(p), count); + if (copy_to_user(buf, __va(p), count) < 0) + return -EFAULT; read += count; file->f_pos += read; return read; @@ -73,35 +107,19 @@ { unsigned long p = file->f_pos; unsigned long end_mem; - unsigned long written; end_mem = __pa(high_memory); if (p >= end_mem) return 0; if (count > end_mem - p) count = end_mem - p; - written = 0; -#if defined(__sparc__) || defined(__mc68000__) - /* we don't have page 0 mapped on sparc and m68k.. */ - while (p < PAGE_SIZE && count > 0) { - /* Hmm. Do something? */ - buf++; - p++; - count--; - written++; - } -#endif - copy_from_user(__va(p), buf, count); - written += count; - file->f_pos += written; - return count; + return do_write_mem(file,__va(p),p,buf,count); } static int mmap_mem(struct inode * inode, struct file * file, struct vm_area_struct * vma) { unsigned long offset = vma->vm_offset; - if (offset & ~PAGE_MASK) return -ENXIO; #if defined(__i386__) @@ -117,7 +135,7 @@ if (remap_page_range(vma->vm_start, offset, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; vma->vm_inode = inode; - inode->i_count++; + atomic_inc(&inode->i_count); return 0; } @@ -166,27 +184,12 @@ const char * buf, unsigned long count) { unsigned long p = file->f_pos; - unsigned long written; if (p >= (unsigned long) high_memory) return 0; if (count > (unsigned long) high_memory - p) count = (unsigned long) high_memory - p; - written = 0; -#if defined(__sparc__) || defined(__mc68000__) - /* we don't have page 0 mapped on sparc and m68k.. */ - while (p < PAGE_SIZE && count > 0) { - /* Hmm. Do something? */ - buf++; - p++; - count--; - written++; - } -#endif - copy_from_user((char *) p, buf, count); - written += count; - file->f_pos += written; - return count; + return do_write_mem(file,(void*)p,p,buf,count); } static long read_port(struct inode * inode, struct file * file, @@ -195,8 +198,11 @@ unsigned int i = file->f_pos; char * tmp = buf; + if (verify_area(VERIFY_WRITE,buf,count)) + return -EFAULT; while (count-- > 0 && i < 65536) { - put_user(inb(i),tmp); + if (__put_user(inb(i),tmp) < 0) + return -EFAULT; i++; tmp++; } @@ -210,9 +216,12 @@ unsigned int i = file->f_pos; const char * tmp = buf; + if (verify_area(VERIFY_READ,buf,count)) + return -EFAULT; while (count-- > 0 && i < 65536) { char c; - get_user(c, tmp); + if (__get_user(c, tmp)) + return -EFAULT; outb(c,i); i++; tmp++; diff -u --recursive --new-file v2.1.42/linux/drivers/char/misc.c linux/drivers/char/misc.c --- v2.1.42/linux/drivers/char/misc.c Tue May 13 22:41:07 1997 +++ linux/drivers/char/misc.c Thu Jun 12 16:22:06 1997 @@ -44,8 +44,8 @@ #include #endif -#include /* needed by selection.h */ -#include "selection.h" /* export its symbols */ +#include +#include #ifdef CONFIG_KERNELD #include #endif diff -u --recursive --new-file v2.1.42/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c --- v2.1.42/linux/drivers/char/pc_keyb.c Thu May 29 21:53:05 1997 +++ linux/drivers/char/pc_keyb.c Thu Jun 12 16:22:06 1997 @@ -1,20 +1,10 @@ /* * linux/drivers/char/pc_keyb.c * - * Written for linux by Johan Myreen as a translation from - * the assembly version by Linus (with diacriticals added) - * - * Some additional features added by Christoph Niemann (ChN), March 1993 - * - * Loadable keymaps by Risto Kankkunen, May 1993 - * - * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993 - * Added decr/incr_console, dynamic keymaps, Unicode support, - * dynamic function/string keys, led setting, Sept 1994 - * `Sticky' modifier keys, 951006. - * 11-11-96: SAK should now work in the raw mode (Martin Mares) - * * Separation of the PC low-level part by Geert Uytterhoeven, May 1997 + * See keyboard.c for the whole history. + * + * Major cleanup by Martin Mares, May 1997 */ #include @@ -24,46 +14,181 @@ #include #include #include +#include #include #include +#include +#include + +/* Some configuration switches are present in the include file... */ + +#include "pc_keyb.h" /* - * On non-x86 hardware we do a full keyboard controller - * initialization, in case the bootup software hasn't done - * it. On a x86, the BIOS will already have initialized the - * keyboard. + * In case we run on a non-x86 hardware we need to initialize both the keyboard + * controller and the keyboard. On a x86, the BIOS will already have initialized + * them. */ + #ifdef INIT_KBD -static int initialize_kbd(void); -#endif -#include -#include +__initfunc(static int kbd_wait_for_input(void)) +{ + int n; + int status, data; -unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */ + n = KBD_TIMEOUT; + do { + status = inb(KBD_STATUS_REG); + /* + * Wait for input data to become available. This bit will + * then be cleared by the following read of the DATA + * register. + */ + + if (!(status & KBD_STAT_OBF)) + continue; + + data = inb(KBD_DATA_REG); + + /* + * Check to see if a timeout error has occurred. This means + * that transmission was started but did not complete in the + * normal time cycle. PERR is set when a parity error occurred + * in the last transmission. + */ + if (status & (KBD_STAT_GTO | KBD_STAT_PERR)) { + continue; + } + return (data & 0xff); + } while (--n); + return -1; /* timed-out if fell through to here... */ +} + +__initfunc(static void kbd_write(int address, int data)) +{ + int status; + + do { + status = inb(KBD_STATUS_REG); + } while (status & KBD_STAT_IBF); + outb(data, address); +} + +__initfunc(static char *initialize_kbd2(void)) +{ + /* Flush any pending input. */ + + while (kbd_wait_for_input() != -1) + ; + + /* + * Test the keyboard interface. + * This seems to be the only way to get it going. + * If the test is successful a x55 is placed in the input buffer. + */ + + kbd_write(KBD_CNTL_REG, KBD_CCMD_SELF_TEST); + if (kbd_wait_for_input() != 0x55) + return "Keyboard failed self test"; + + /* + * Perform a keyboard interface test. This causes the controller + * to test the keyboard clock and data lines. The results of the + * test are placed in the input buffer. + */ + + kbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_TEST); + if (kbd_wait_for_input() != 0x00) + return "Keyboard interface failed self test"; + + /* Enable the keyboard by allowing the keyboard clock to run. */ + + kbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_ENABLE); + + /* + * Reset keyboard. If the read times out + * then the assumption is that no keyboard is + * plugged into the machine. + * This defaults the keyboard to scan-code set 2. + */ + + kbd_write(KBD_DATA_REG, KBD_CMD_RESET); + if (kbd_wait_for_input() != KBD_REPLY_ACK) + return "Keyboard reset failed, no ACK"; + if (kbd_wait_for_input() != KBD_REPLY_POR) + return "Keyboard reset failed, no POR"; + + /* + * Set keyboard controller mode. During this, the keyboard should be + * in the disabled state. + */ + + kbd_write(KBD_DATA_REG, KBD_CMD_DISABLE); + if (kbd_wait_for_input() != KBD_REPLY_ACK) + return "Disable keyboard: no ACK"; + + kbd_write(KBD_CNTL_REG, KBD_CCMD_WRITE_MODE); + kbd_write(KBD_DATA_REG, KBD_MODE_KBD_INT + | KBD_MODE_SYS + | KBD_MODE_DISABLE_MOUSE + | KBD_MODE_KCC); + + kbd_write(KBD_DATA_REG, KBD_CMD_ENABLE); + if (kbd_wait_for_input() != KBD_REPLY_ACK) + return "Enable keyboard: no ACK"; + + /* + * Finally, set the typematic rate to maximum. + */ + + kbd_write(KBD_DATA_REG, KBD_CMD_SET_RATE); + if (kbd_wait_for_input() != KBD_REPLY_ACK) + return "Set rate: no ACK"; + kbd_write(KBD_DATA_REG, 0x00); + if (kbd_wait_for_input() != KBD_REPLY_ACK) + return "Set rate: no ACK"; + + return NULL; +} + +__initfunc(static void initialize_kbd(void)) +{ + unsigned long flags; + char *msg; + + save_flags(flags); cli(); + msg = initialize_kbd2(); + restore_flags(flags); + + if (msg) + printk(KERN_WARNING "initialize_kbd: %s\n", msg); +} + +#endif /* INIT_KBD */ + +unsigned char kbd_read_mask = KBD_STAT_OBF; /* Modified by psaux.c */ /* used only by send_data - set by keyboard_interrupt */ static volatile unsigned char reply_expected = 0; static volatile unsigned char acknowledge = 0; static volatile unsigned char resend = 0; -/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */ +/* + * Wait for keyboard controller input buffer is empty. + */ + static inline void kb_wait(void) { int i; - for (i=0; i<0x100000; i++) - if ((inb_p(0x64) & 0x02) == 0) + for (i=0; i + */ + +/* + * Configuration Switches + */ + +#define KBD_REPORT_ERR /* Report keyboard errors */ +#define KBD_REPORT_UNKN /* Report unknown scan codes */ +#undef KBD_IS_FOCUS_9000 /* We have the brain-damaged FOCUS-9000 keyboard */ +#define KBD_TIMEOUT 0x100000 /* Timeout for sending of commands */ + +/* + * Internal variables of the driver + */ + +extern unsigned char kbd_read_mask; +extern unsigned char aux_device_present; + +/* + * Keyboard Controller Registers + */ + +#define KBD_STATUS_REG 0x64 /* Status register (R) */ +#define KBD_CNTL_REG 0x64 /* Controller command register (W) */ +#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */ + +/* + * Keyboard Controller Commands + */ + +#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ +#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ +#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ +#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ +#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ +#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ +#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ +#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ +#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ +#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ +#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */ + +/* + * Keyboard Commands + */ + +#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ +#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ +#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ +#define KBD_CMD_DISABLE 0xF5 /* Disable scanning */ +#define KBD_CMD_RESET 0xFF /* Reset */ + +/* + * Keyboard Replies + */ + +#define KBD_REPLY_POR 0xAA /* Power on reset */ +#define KBD_REPLY_ACK 0xFA /* Command ACK */ +#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ + +/* + * Status Register Bits + */ + +#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ +#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ +#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ +#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */ +#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ +#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ +#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ +#define KBD_STAT_PERR 0x80 /* Parity error */ + +#define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF) + +/* + * Controller Mode Register Bits + */ + +#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generage IRQ1 */ +#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */ +#define KBD_MODE_SYS 0x04 /* The system flag (?) */ +#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */ +#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ +#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ +#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ +#define KBD_MODE_RFU 0x80 + +/* + * Mouse Commands + */ + +#define AUX_SET_RES 0xE8 /* Set resolution */ +#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ +#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ +#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ +#define AUX_SET_STREAM 0xEA /* Set stream mode */ +#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ +#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ +#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ +#define AUX_RESET 0xFF /* Reset aux device */ diff -u --recursive --new-file v2.1.42/linux/drivers/char/psaux.c linux/drivers/char/psaux.c --- v2.1.42/linux/drivers/char/psaux.c Wed Apr 23 19:01:17 1997 +++ linux/drivers/char/psaux.c Thu Jun 12 16:22:06 1997 @@ -28,6 +28,8 @@ * * Fixed keyboard lockups at open time * 3-Jul-96, 22-Aug-96 Roman Hodek + * + * Cleanup by Martin Mares, 01-Jun-97 (now uses the new PC kbd include) */ /* Uncomment the following line if your mouse needs initialization. */ @@ -54,66 +56,15 @@ #include -#define PSMOUSE_MINOR 1 /* minor device # for this mouse */ +#include "pc_keyb.h" -/* aux controller ports */ -#define AUX_INPUT_PORT 0x60 /* Aux device output buffer */ -#define AUX_OUTPUT_PORT 0x60 /* Aux device input buffer */ -#define AUX_COMMAND 0x64 /* Aux device command buffer */ -#define AUX_STATUS 0x64 /* Aux device status reg */ - -/* aux controller status bits */ -#define AUX_OBUF_FULL 0x21 /* output buffer (from device) full */ -#define AUX_IBUF_FULL 0x02 /* input buffer (to device) full */ - -/* aux controller commands */ -#define AUX_CMD_WRITE 0x60 /* value to write to controller */ -#define AUX_MAGIC_WRITE 0xd4 /* value to send aux device data */ - -#define AUX_INTS_ON 0x47 /* enable controller interrupts */ -#define AUX_INTS_OFF 0x65 /* disable controller interrupts */ - -#define AUX_DISABLE 0xa7 /* disable aux */ -#define AUX_ENABLE 0xa8 /* enable aux */ - -/* aux device commands */ -#define AUX_SET_RES 0xe8 /* set resolution */ -#define AUX_SET_SCALE11 0xe6 /* set 1:1 scaling */ -#define AUX_SET_SCALE21 0xe7 /* set 2:1 scaling */ -#define AUX_GET_SCALE 0xe9 /* get scaling factor */ -#define AUX_SET_STREAM 0xea /* set stream mode */ -#define AUX_SET_SAMPLE 0xf3 /* set sample rate */ -#define AUX_ENABLE_DEV 0xf4 /* enable aux device */ -#define AUX_DISABLE_DEV 0xf5 /* disable aux device */ -#define AUX_RESET 0xff /* reset aux device */ +/* + * Generic declarations for both PS2 and 82C710 + */ -#define MAX_RETRIES 60 /* some aux operations take long time*/ -#if defined(__alpha__) && !defined(CONFIG_PCI) -# define AUX_IRQ 9 /* Jensen is odd indeed */ -#else -# define AUX_IRQ 12 -#endif +#define PSMOUSE_MINOR 1 /* Minor device # for this mouse */ #define AUX_BUF_SIZE 2048 -/* 82C710 definitions */ - -#define QP_DATA 0x310 /* Data Port I/O Address */ -#define QP_STATUS 0x311 /* Status Port I/O Address */ - -#define QP_DEV_IDLE 0x01 /* Device Idle */ -#define QP_RX_FULL 0x02 /* Device Char received */ -#define QP_TX_IDLE 0x04 /* Device XMIT Idle */ -#define QP_RESET 0x08 /* Device Reset */ -#define QP_INTS_ON 0x10 /* Device Interrupt On */ -#define QP_ERROR_FLAG 0x20 /* Device Error */ -#define QP_CLEAR 0x40 /* Device Clear */ -#define QP_ENABLE 0x80 /* Device Enable */ - -#define QP_IRQ 12 - -extern unsigned char aux_device_present; -extern unsigned char kbd_read_mask; /* from keyboard.c */ - struct aux_queue { unsigned long head; unsigned long tail; @@ -126,20 +77,84 @@ static int aux_ready = 0; static int aux_count = 0; static int aux_present = 0; -static int poll_aux_status(void); -static int poll_aux_status_nosleep(void); -static int fasync_aux(struct inode *inode, struct file *filp, int on); -#ifdef CONFIG_82C710_MOUSE -static int qp_present = 0; -static int qp_count = 0; -static int qp_data = QP_DATA; -static int qp_status = QP_STATUS; +/* + * Shared subroutines + */ -static int poll_qp_status(void); -static int probe_qp(void); +static unsigned int get_from_queue(void) +{ + unsigned int result; + unsigned long flags; + + save_flags(flags); + cli(); + result = queue->buf[queue->tail]; + queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); + restore_flags(flags); + return result; +} + + +static inline int queue_empty(void) +{ + return queue->head == queue->tail; +} + +static int fasync_aux(struct inode *inode, struct file *filp, int on) +{ + int retval; + + retval = fasync_helper(inode, filp, on, &queue->fasync); + if (retval < 0) + return retval; + return 0; +} + +/* + * PS/2 Aux Device + */ + +#define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT) +#define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT) + +#define MAX_RETRIES 60 /* some aux operations take long time*/ +#if defined(__alpha__) && !defined(CONFIG_PCI) +# define AUX_IRQ 9 /* Jensen is odd indeed */ +#else +# define AUX_IRQ 12 #endif +/* + * Status polling + */ + +static int poll_aux_status(void) +{ + int retries=0; + + while ((inb(KBD_STATUS_REG) & (KBD_STAT_IBF | KBD_STAT_OBF)) && retries < MAX_RETRIES) { + if ((inb_p(KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF) + inb_p(KBD_DATA_REG); + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + (5*HZ + 99) / 100; + schedule(); + retries++; + } + return !(retries==MAX_RETRIES); +} + +static int poll_aux_status_nosleep(void) +{ + int retries = 0; + + while ((inb(KBD_STATUS_REG) & (KBD_STAT_IBF | KBD_STAT_OBF)) && retries < 1000000) { + if ((inb_p(KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF) + inb_p(KBD_DATA_REG); + retries++; + } + return !(retries == 1000000); +} /* * Write to aux device @@ -148,28 +163,32 @@ static void aux_write_dev(int val) { poll_aux_status(); - outb_p(AUX_MAGIC_WRITE,AUX_COMMAND); /* write magic cookie */ + outb_p(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG); /* Write magic cookie */ poll_aux_status(); - outb_p(val,AUX_OUTPUT_PORT); /* write data */ + outb_p(val, KBD_DATA_REG); /* Write data */ +} + +__initfunc(static void aux_write_dev_nosleep(int val)) +{ + poll_aux_status_nosleep(); + outb_p(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG); + poll_aux_status_nosleep(); + outb_p(val, KBD_DATA_REG); } /* * Write to device & handle returned ack */ -#if defined INITIALIZE_DEVICE -static int aux_write_ack(int val) -{ - int retries = 0; - poll_aux_status_nosleep(); - outb_p(AUX_MAGIC_WRITE,AUX_COMMAND); - poll_aux_status_nosleep(); - outb_p(val,AUX_OUTPUT_PORT); +#ifdef INITIALIZE_DEVICE +__initfunc(static int aux_write_ack(int val)) +{ + aux_write_dev_nosleep(val); poll_aux_status_nosleep(); - if ((inb(AUX_STATUS) & AUX_OBUF_FULL) == AUX_OBUF_FULL) + if ((inb(KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF) { - return (inb(AUX_INPUT_PORT)); + return (inb(KBD_DATA_REG)); } return 0; } @@ -182,33 +201,11 @@ static void aux_write_cmd(int val) { poll_aux_status(); - outb_p(AUX_CMD_WRITE,AUX_COMMAND); + outb_p(KBD_CCMD_WRITE_MODE, KBD_CNTL_REG); poll_aux_status(); - outb_p(val,AUX_OUTPUT_PORT); -} - - -static unsigned int get_from_queue(void) -{ - unsigned int result; - unsigned long flags; - - save_flags(flags); - cli(); - result = queue->buf[queue->tail]; - queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); - restore_flags(flags); - return result; + outb_p(val, KBD_DATA_REG); } - -static inline int queue_empty(void) -{ - return queue->head == queue->tail; -} - - - /* * Interrupt from the auxiliary device: a character * is waiting in the keyboard/aux controller. @@ -219,10 +216,10 @@ int head = queue->head; int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1); - if ((inb(AUX_STATUS) & AUX_OBUF_FULL) != AUX_OBUF_FULL) + if ((inb(KBD_STATUS_REG) & AUX_STAT_OBF) != AUX_STAT_OBF) return; - add_mouse_randomness(queue->buf[head] = inb(AUX_INPUT_PORT)); + add_mouse_randomness(queue->buf[head] = inb(KBD_DATA_REG)); if (head != maxhead) { head++; head &= AUX_BUF_SIZE-1; @@ -234,31 +231,6 @@ wake_up_interruptible(&queue->proc_list); } -/* - * Interrupt handler for the 82C710 mouse port. A character - * is waiting in the 82C710. - */ - -#ifdef CONFIG_82C710_MOUSE -static void qp_interrupt(int cpl, void *dev_id, struct pt_regs * regs) -{ - int head = queue->head; - int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1); - - add_mouse_randomness(queue->buf[head] = inb(qp_data)); - if (head != maxhead) { - head++; - head &= AUX_BUF_SIZE-1; - } - queue->head = head; - aux_ready = 1; - if (queue->fasync) - kill_fasync(queue->fasync, SIGIO); - wake_up_interruptible(&queue->proc_list); -} -#endif - - static int release_aux(struct inode * inode, struct file * file) { fasync_aux(inode, file, 0); @@ -266,9 +238,9 @@ return 0; /* disable kbd bh to avoid mixing of cmd bytes */ disable_bh(KEYBOARD_BH); - aux_write_cmd(AUX_INTS_OFF); /* disable controller ints */ + aux_write_cmd(AUX_INTS_OFF); /* Disable controller ints */ poll_aux_status(); - outb_p(AUX_DISABLE,AUX_COMMAND); /* Disable Aux device */ + outb_p(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG); /* Disable Aux device */ poll_aux_status(); /* reenable kbd bh */ enable_bh(KEYBOARD_BH); @@ -281,36 +253,6 @@ return 0; } -#ifdef CONFIG_82C710_MOUSE -static int release_qp(struct inode * inode, struct file * file) -{ - unsigned char status; - - fasync_aux(inode, file, 0); - if (!--qp_count) { - if (!poll_qp_status()) - printk("Warning: Mouse device busy in release_qp()\n"); - status = inb_p(qp_status); - outb_p(status & ~(QP_ENABLE|QP_INTS_ON), qp_status); - if (!poll_qp_status()) - printk("Warning: Mouse device busy in release_qp()\n"); - free_irq(QP_IRQ, NULL); - MOD_DEC_USE_COUNT; - } - return 0; -} -#endif - -static int fasync_aux(struct inode *inode, struct file *filp, int on) -{ - int retval; - - retval = fasync_helper(inode, filp, on, &queue->fasync); - if (retval < 0) - return retval; - return 0; -} - /* * Install interrupt handler. * Enable auxiliary device. @@ -339,9 +281,9 @@ /* disable kbd bh to avoid mixing of cmd bytes */ disable_bh(KEYBOARD_BH); poll_aux_status(); - outb_p(AUX_ENABLE,AUX_COMMAND); /* Enable Aux */ - aux_write_dev(AUX_ENABLE_DEV); /* enable aux device */ - aux_write_cmd(AUX_INTS_ON); /* enable controller ints */ + outb_p(KBD_CCMD_MOUSE_ENABLE, KBD_CNTL_REG); /* Enable Aux */ + aux_write_dev(AUX_ENABLE_DEV); /* Enable aux device */ + aux_write_cmd(AUX_INTS_ON); /* Enable controller ints */ poll_aux_status(); /* reenable kbd bh */ enable_bh(KEYBOARD_BH); @@ -350,7 +292,112 @@ return 0; } +/* + * Write to the aux device. + */ + +static long write_aux(struct inode * inode, struct file * file, + const char * buffer, unsigned long count) +{ + int retval = 0; + + if (count) { + int written = 0; + + /* disable kbd bh to avoid mixing of cmd bytes */ + disable_bh(KEYBOARD_BH); + + do { + char c; + if (!poll_aux_status()) + break; + outb_p(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG); + if (!poll_aux_status()) + break; + get_user(c, buffer++); + outb_p(c, KBD_DATA_REG); + written++; + } while (--count); + /* reenable kbd bh */ + enable_bh(KEYBOARD_BH); + retval = -EIO; + if (written) { + retval = written; + inode->i_mtime = CURRENT_TIME; + } + } + + return retval; +} + +/* + * 82C710 Interface + */ + #ifdef CONFIG_82C710_MOUSE + +#define QP_DATA 0x310 /* Data Port I/O Address */ +#define QP_STATUS 0x311 /* Status Port I/O Address */ + +#define QP_DEV_IDLE 0x01 /* Device Idle */ +#define QP_RX_FULL 0x02 /* Device Char received */ +#define QP_TX_IDLE 0x04 /* Device XMIT Idle */ +#define QP_RESET 0x08 /* Device Reset */ +#define QP_INTS_ON 0x10 /* Device Interrupt On */ +#define QP_ERROR_FLAG 0x20 /* Device Error */ +#define QP_CLEAR 0x40 /* Device Clear */ +#define QP_ENABLE 0x80 /* Device Enable */ + +#define QP_IRQ 12 + +static int qp_present = 0; +static int qp_count = 0; +static int qp_data = QP_DATA; +static int qp_status = QP_STATUS; + +static int poll_qp_status(void); +static int probe_qp(void); + +/* + * Interrupt handler for the 82C710 mouse port. A character + * is waiting in the 82C710. + */ + +static void qp_interrupt(int cpl, void *dev_id, struct pt_regs * regs) +{ + int head = queue->head; + int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1); + + add_mouse_randomness(queue->buf[head] = inb(qp_data)); + if (head != maxhead) { + head++; + head &= AUX_BUF_SIZE-1; + } + queue->head = head; + aux_ready = 1; + if (queue->fasync) + kill_fasync(queue->fasync, SIGIO); + wake_up_interruptible(&queue->proc_list); +} + +static int release_qp(struct inode * inode, struct file * file) +{ + unsigned char status; + + fasync_aux(inode, file, 0); + if (!--qp_count) { + if (!poll_qp_status()) + printk("Warning: Mouse device busy in release_qp()\n"); + status = inb_p(qp_status); + outb_p(status & ~(QP_ENABLE|QP_INTS_ON), qp_status); + if (!poll_qp_status()) + printk("Warning: Mouse device busy in release_qp()\n"); + free_irq(QP_IRQ, NULL); + MOD_DEC_USE_COUNT; + } + return 0; +} + /* * Install interrupt handler. * Enable the device, enable interrupts. @@ -394,48 +441,7 @@ MOD_INC_USE_COUNT; return 0; } -#endif - -/* - * Write to the aux device. - */ - -static long write_aux(struct inode * inode, struct file * file, - const char * buffer, unsigned long count) -{ - int retval = 0; - - if (count) { - int written = 0; - - /* disable kbd bh to avoid mixing of cmd bytes */ - disable_bh(KEYBOARD_BH); - - do { - char c; - if (!poll_aux_status()) - break; - outb_p(AUX_MAGIC_WRITE,AUX_COMMAND); - if (!poll_aux_status()) - break; - get_user(c, buffer++); - outb_p(c, AUX_OUTPUT_PORT); - written++; - } while (--count); - /* reenable kbd bh */ - enable_bh(KEYBOARD_BH); - retval = -EIO; - if (written) { - retval = written; - inode->i_mtime = CURRENT_TIME; - } - } - - return retval; -} - -#ifdef CONFIG_82C710_MOUSE /* * Write to the 82C710 mouse device. */ @@ -455,8 +461,64 @@ inode->i_mtime = CURRENT_TIME; return count; } + +/* + * Wait for device to send output char and flush any input char. + */ + +static int poll_qp_status(void) +{ + int retries=0; + + while ((inb(qp_status)&(QP_RX_FULL|QP_TX_IDLE|QP_DEV_IDLE)) + != (QP_DEV_IDLE|QP_TX_IDLE) + && retries < MAX_RETRIES) { + + if (inb_p(qp_status)&(QP_RX_FULL)) + inb_p(qp_data); + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + (5*HZ + 99) / 100; + schedule(); + retries++; + } + return !(retries==MAX_RETRIES); +} + +/* + * Function to read register in 82C710. + */ + +static inline unsigned char read_710(unsigned char index) +{ + outb_p(index, 0x390); /* Write index */ + return inb_p(0x391); /* Read the data */ +} + +/* + * See if we can find a 82C710 device. Read mouse address. + */ + +__initfunc(static int probe_qp(void)) +{ + outb_p(0x55, 0x2fa); /* Any value except 9, ff or 36 */ + outb_p(0xaa, 0x3fa); /* Inverse of 55 */ + outb_p(0x36, 0x3fa); /* Address the chip */ + outb_p(0xe4, 0x3fa); /* 390/4; 390 = config address */ + outb_p(0x1b, 0x2fa); /* Inverse of e4 */ + if (read_710(0x0f) != 0xe4) /* Config address found? */ + return 0; /* No: no 82C710 here */ + qp_data = read_710(0x0d)*4; /* Get mouse I/O address */ + qp_status = qp_data+1; + outb_p(0x0f, 0x390); + outb_p(0x0f, 0x391); /* Close config mode */ + return 1; +} + #endif +/* + * Generic part continues... + */ /* * Put bytes from input queue to buffer. @@ -497,7 +559,6 @@ return 0; } - static unsigned int aux_poll(struct file *file, poll_table * wait) { poll_wait(&queue->proc_list, wait); @@ -506,7 +567,6 @@ return 0; } - struct file_operations psaux_fops = { NULL, /* seek */ read_aux, @@ -521,7 +581,6 @@ fasync_aux, }; - /* * Initialize driver. First check for a 82C710 chip; if found * forget about the Aux port and use the *_qp functions. @@ -548,7 +607,7 @@ printk(KERN_INFO "PS/2 auxiliary pointing device detected -- driver installed.\n"); aux_present = 1; #ifdef CONFIG_VT - kbd_read_mask = AUX_OBUF_FULL; + kbd_read_mask = AUX_STAT_OBF; #endif } else { return -EIO; @@ -559,8 +618,8 @@ queue->head = queue->tail = 0; queue->proc_list = NULL; if (!qp_found) { -#if defined INITIALIZE_DEVICE - outb_p(AUX_ENABLE,AUX_COMMAND); /* Enable Aux */ +#ifdef INITIALIZE_DEVICE + outb_p(KBD_CCMD_MOUSE_ENABLE, KBD_CNTL_REG); /* Enable Aux */ aux_write_ack(AUX_SET_SAMPLE); aux_write_ack(100); /* 100 samples/sec */ aux_write_ack(AUX_SET_RES); @@ -568,11 +627,8 @@ aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */ poll_aux_status_nosleep(); #endif /* INITIALIZE_DEVICE */ - outb_p(AUX_DISABLE,AUX_COMMAND); /* Disable Aux device */ - poll_aux_status_nosleep(); - outb_p(AUX_CMD_WRITE,AUX_COMMAND); - poll_aux_status_nosleep(); /* Disable interrupts */ - outb_p(AUX_INTS_OFF, AUX_OUTPUT_PORT); /* on the controller */ + outb_p(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG); /* Disable Aux device */ + aux_write_dev_nosleep(AUX_INTS_OFF); /* Disable controller interrupts */ } return 0; } @@ -580,93 +636,12 @@ #ifdef MODULE int init_module(void) { - return psaux_init(); /*?? Bjorn */ + return psaux_init(); } void cleanup_module(void) { misc_deregister(&psaux_mouse); kfree(queue); -} -#endif - -static int poll_aux_status(void) -{ - int retries=0; - - while ((inb(AUX_STATUS)&0x03) && retries < MAX_RETRIES) { - if ((inb_p(AUX_STATUS) & AUX_OBUF_FULL) == AUX_OBUF_FULL) - inb_p(AUX_INPUT_PORT); - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + (5*HZ + 99) / 100; - schedule(); - retries++; - } - return !(retries==MAX_RETRIES); -} - -static int poll_aux_status_nosleep(void) -{ - int retries = 0; - - while ((inb(AUX_STATUS)&0x03) && retries < 1000000) { - if ((inb_p(AUX_STATUS) & AUX_OBUF_FULL) == AUX_OBUF_FULL) - inb_p(AUX_INPUT_PORT); - retries++; - } - return !(retries == 1000000); -} - -#ifdef CONFIG_82C710_MOUSE -/* - * Wait for device to send output char and flush any input char. - */ - -static int poll_qp_status(void) -{ - int retries=0; - - while ((inb(qp_status)&(QP_RX_FULL|QP_TX_IDLE|QP_DEV_IDLE)) - != (QP_DEV_IDLE|QP_TX_IDLE) - && retries < MAX_RETRIES) { - - if (inb_p(qp_status)&(QP_RX_FULL)) - inb_p(qp_data); - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + (5*HZ + 99) / 100; - schedule(); - retries++; - } - return !(retries==MAX_RETRIES); -} - -/* - * Function to read register in 82C710. - */ - -static inline unsigned char read_710(unsigned char index) -{ - outb_p(index, 0x390); /* Write index */ - return inb_p(0x391); /* Read the data */ -} - -/* - * See if we can find a 82C710 device. Read mouse address. - */ - -__initfunc(static int probe_qp(void)) -{ - outb_p(0x55, 0x2fa); /* Any value except 9, ff or 36 */ - outb_p(0xaa, 0x3fa); /* Inverse of 55 */ - outb_p(0x36, 0x3fa); /* Address the chip */ - outb_p(0xe4, 0x3fa); /* 390/4; 390 = config address */ - outb_p(0x1b, 0x2fa); /* Inverse of e4 */ - if (read_710(0x0f) != 0xe4) /* Config address found? */ - return 0; /* No: no 82C710 here */ - qp_data = read_710(0x0d)*4; /* Get mouse I/O address */ - qp_status = qp_data+1; - outb_p(0x0f, 0x390); - outb_p(0x0f, 0x391); /* Close config mode */ - return 1; } #endif diff -u --recursive --new-file v2.1.42/linux/drivers/char/rtc.c linux/drivers/char/rtc.c --- v2.1.42/linux/drivers/char/rtc.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/char/rtc.c Thu Jun 12 16:22:06 1997 @@ -43,6 +43,7 @@ * this driver.) */ +#include #include #include #include @@ -156,10 +157,6 @@ if (count < sizeof(unsigned long)) return -EINVAL; - retval = verify_area(VERIFY_WRITE, buf, sizeof(unsigned long)); - if (retval) - return retval; - add_wait_queue(&rtc_wait, &wait); current->state = TASK_INTERRUPTIBLE; @@ -183,8 +180,7 @@ data = rtc_irq_data; rtc_irq_data = 0; restore_flags(flags); - copy_to_user(buf, &data, sizeof(unsigned long)); - retval = sizeof(unsigned long); + retval = put_user(data, (unsigned long *)buf)) ?: sizeof(unsigned long); } current->state = TASK_RUNNING; @@ -198,6 +194,7 @@ { unsigned long flags; + struct rtc_time wtime; switch (cmd) { case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ @@ -254,18 +251,9 @@ * means "don't care" or "match all". Only the tm_hour, * tm_min, and tm_sec values are filled in. */ - int retval; - struct rtc_time alm_tm; - - retval = verify_area(VERIFY_WRITE, (struct rtc_time*)arg, sizeof(struct rtc_time)); - if (retval != 0 ) - return retval; - - get_rtc_alm_time(&alm_tm); - copy_to_user((struct rtc_time*)arg, &alm_tm, sizeof(struct rtc_time)); - - return 0; + get_rtc_alm_time(&wtime); + break; } case RTC_ALM_SET: /* Store a time into the alarm */ { @@ -278,11 +266,8 @@ unsigned char hrs, min, sec; struct rtc_time alm_tm; - retval = verify_area(VERIFY_READ, (struct rtc_time*)arg, sizeof(struct rtc_time)); - if (retval != 0 ) - return retval; - - copy_from_user(&alm_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)); + if (copy_from_user(&alm_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) + return -EFAULT; hrs = alm_tm.tm_hour; min = alm_tm.tm_min; @@ -315,16 +300,8 @@ } case RTC_RD_TIME: /* Read the time/date from RTC */ { - int retval; - struct rtc_time rtc_tm; - - retval = verify_area(VERIFY_WRITE, (struct rtc_time*)arg, sizeof(struct rtc_time)); - if (retval !=0 ) - return retval; - - get_rtc_time(&rtc_tm); - copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time)); - return 0; + get_rtc_time(&wtime); + break; } case RTC_SET_TIME: /* Set the RTC */ { @@ -338,11 +315,8 @@ if (!suser()) return -EACCES; - retval = verify_area(VERIFY_READ, (struct rtc_time*)arg, sizeof(struct rtc_time)); - if (retval !=0 ) - return retval; - - copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)); + if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) + return -EFAULT; yrs = rtc_tm.tm_year + 1900 + ARCFUDGE; mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ @@ -403,14 +377,7 @@ } case RTC_IRQP_READ: /* Read the periodic IRQ rate. */ { - int retval; - - retval = verify_area(VERIFY_WRITE, (unsigned long*)arg, sizeof(unsigned long)); - if (retval != 0) - return retval; - - copy_to_user((unsigned long*)arg, &rtc_freq, sizeof(unsigned long)); - return 0; + return put_user(rtc_freq, (unsigned long *)arg); } case RTC_IRQP_SET: /* Set periodic IRQ rate. */ { @@ -451,6 +418,7 @@ default: return -EINVAL; } + return copy_to_user(arg, &wtime, sizeof wtime) ? -EFAULT : 0; } /* @@ -536,11 +504,11 @@ { unsigned long flags; - printk("Real Time Clock Driver v%s\n", RTC_VERSION); + printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION); if(request_irq(RTC_IRQ, rtc_interrupt, SA_INTERRUPT, "rtc", NULL)) { /* Yeah right, seeing as irq 8 doesn't even hit the bus. */ - printk("rtc: IRQ %d is not free.\n", RTC_IRQ); + printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ); return -EIO; } misc_register(&rtc_dev); diff -u --recursive --new-file v2.1.42/linux/drivers/char/selection.c linux/drivers/char/selection.c --- v2.1.42/linux/drivers/char/selection.c Thu May 29 21:53:05 1997 +++ linux/drivers/char/selection.c Thu Jun 12 16:22:06 1997 @@ -21,9 +21,9 @@ #include -#include "vt_kern.h" -#include "consolemap.h" -#include "selection.h" +#include +#include +#include #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -101,9 +101,9 @@ } /* does screen address p correspond to character at LH/RH edge of screen? */ -static inline int atedge(const int p) +static inline int atedge(const int p, int size_row) { - return (!(p % video_size_row) || !((p + 2) % video_size_row)); + return (!(p % size_row) || !((p + 2) % size_row)); } /* constrain v such that v <= u */ @@ -227,9 +227,9 @@ /* select to end of line if on trailing space */ if (new_sel_end > new_sel_start && - !atedge(new_sel_end) && isspace(sel_pos(new_sel_end))) { + !atedge(new_sel_end, size_row) && isspace(sel_pos(new_sel_end))) { for (pe = new_sel_end + 2; ; pe += 2) - if (!isspace(sel_pos(pe)) || atedge(pe)) + if (!isspace(sel_pos(pe)) || atedge(pe, size_row)) break; if (isspace(sel_pos(pe))) new_sel_end = pe; diff -u --recursive --new-file v2.1.42/linux/drivers/char/selection.h linux/drivers/char/selection.h --- v2.1.42/linux/drivers/char/selection.h Thu Jun 12 15:29:05 1997 +++ linux/drivers/char/selection.h Wed Dec 31 16:00:00 1969 @@ -1,210 +0,0 @@ -/* - * selection.h - * - * Interface between console.c, tty_io.c, vt.c, vc_screen.c and selection.c - */ - -#include - -extern int sel_cons; - -extern void clear_selection(void); -extern int set_selection(const unsigned long arg, struct tty_struct *tty, int user); -extern int paste_selection(struct tty_struct *tty); -extern int sel_loadlut(const unsigned long arg); -extern int mouse_reporting(void); -extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry); - -#ifdef CONFIG_FB_CONSOLE -extern unsigned long get_video_num_columns(unsigned int console); -extern unsigned long get_video_num_lines(unsigned int console); -extern unsigned long get_video_size_row(unsigned int console); -#else -#define get_video_num_columns(dummy) video_num_columns -#define get_video_num_lines(dummy) video_num_lines -#define get_video_size_row(dummy) video_size_row -#endif - -extern unsigned long video_num_columns; -extern unsigned long video_num_lines; -extern unsigned long video_size_row; -extern unsigned char video_type; -extern unsigned long video_mem_base; -extern unsigned long video_mem_term; -extern unsigned long video_screen_size; -extern unsigned short video_port_reg; -extern unsigned short video_port_val; - -extern int console_blanked; -extern int can_do_color; - -extern unsigned long video_font_height; -extern unsigned long video_scan_lines; -extern unsigned long default_font_height; -extern int video_font_is_default; - -extern unsigned char color_table[]; -extern int default_red[]; -extern int default_grn[]; -extern int default_blu[]; - -extern unsigned short __real_origin; -extern unsigned short __origin; -extern unsigned char has_wrapped; - -extern unsigned short *vc_scrbuf[MAX_NR_CONSOLES]; - -extern void do_unblank_screen(void); -extern unsigned short *screen_pos(int currcons, int w_offset, int viewed); -extern unsigned short screen_word(int currcons, int offset, int viewed); -extern int scrw2glyph(unsigned short scr_word); -extern void complement_pos(int currcons, int offset); -extern void invert_screen(int currcons, int offset, int count, int shift); - -#define reverse_video_char(a) (((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77)) -#define reverse_video_short(a) (((a) & 0x88ff) | \ - (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4)) -/* this latter line used to have masks 0xf000 and 0x0f00, but selection - requires a self-inverse operation; moreover, the old version looks wrong */ - -extern void getconsxy(int currcons, char *p); -extern void putconsxy(int currcons, char *p); - - -/* how to access screen memory */ - -#include - -#if defined(CONFIG_TGA_CONSOLE) - -extern int tga_blitc(unsigned int, unsigned long); -extern unsigned long video_mem_term; - -/* - * TGA console screen memory access - * - * TGA is *not* a character/attribute cell device; font bitmaps must be rendered - * to the screen pixels. - * - * We must test for an Alpha kernel virtual address that falls within - * the "shadow screen" memory. This condition indicates we really want - * to write to the screen, so, we do... :-) - * - * NOTE also: there's only *TWO* operations: to put/get a character/attribute. - * All the others needed by VGA support go away, as Not Applicable for TGA. - */ -static inline void scr_writew(unsigned short val, unsigned short * addr) -{ - /* - * always deposit the char/attr, then see if it was to "screen" mem. - * if so, then render the char/attr onto the real screen. - */ - *addr = val; - if ((unsigned long)addr < video_mem_term && - (unsigned long)addr >= video_mem_base) { - tga_blitc(val, (unsigned long) addr); - } -} - -static inline unsigned short scr_readw(unsigned short * addr) -{ - return *addr; -} - -#elif defined(CONFIG_SUN_CONSOLE) -#include "vt_kern.h" -#include -extern int sun_blitc(unsigned int, unsigned long); -extern void memsetw(void * s, unsigned short c, unsigned int count); -extern void memcpyw(unsigned short *to, unsigned short *from, unsigned int count); -extern unsigned long video_mem_term; - -/* Basically the same as the TGA stuff. */ -static inline void scr_writew(unsigned short val, unsigned short * addr) -{ - /* - * always deposit the char/attr, then see if it was to "screen" mem. - * if so, then render the char/attr onto the real screen. - */ - if (*addr != val) { - *addr = val; - if ((unsigned long)addr < video_mem_term && - (unsigned long)addr >= video_mem_base && - vt_cons [fg_console]->vc_mode == KD_TEXT) - sun_blitc(val, (unsigned long) addr); - } -} - -static inline unsigned short scr_readw(unsigned short * addr) -{ - return *addr; -} - -#else /* CONFIG_TGA_CONSOLE || CONFIG_SUN_CONSOLE */ - -/* - * normal VGA console access - * - */ - -#include - -/* - * NOTE: "(long) addr < 0" tests for an Alpha kernel virtual address; this - * indicates a VC's backing store; otherwise, it's a bus memory address, for - * the VGA's screen memory, so we do the Alpha "swizzle"... :-) - */ -static inline void scr_writeb(unsigned char val, unsigned char * addr) -{ - if ((long) addr < 0) - *addr = val; - else - writeb(val, (unsigned long) addr); -} - -static inline unsigned char scr_readb(unsigned char * addr) -{ - if ((long) addr < 0) - return *addr; - return readb((unsigned long) addr); -} - -static inline void scr_writew(unsigned short val, unsigned short * addr) -{ - if ((long) addr < 0) - *addr = val; - else - writew(val, (unsigned long) addr); -} - -static inline unsigned short scr_readw(unsigned short * addr) -{ - if ((long) addr < 0) - return *addr; - return readw((unsigned long) addr); -} - -#endif /* CONFIG_TGA_CONSOLE */ - -#ifndef CONFIG_SUN_CONSOLE -static inline void memsetw(void * s, unsigned short c, unsigned int count) -{ - unsigned short * addr = (unsigned short *) s; - - count /= 2; - while (count) { - count--; - scr_writew(c, addr++); - } -} - -static inline void memcpyw(unsigned short *to, unsigned short *from, - unsigned int count) -{ - count /= 2; - while (count) { - count--; - scr_writew(scr_readw(from++), to++); - } -} -#endif /* CONFIG_SUN_CONSOLE */ diff -u --recursive --new-file v2.1.42/linux/drivers/char/softdog.c linux/drivers/char/softdog.c --- v2.1.42/linux/drivers/char/softdog.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/char/softdog.c Thu Jun 12 16:22:06 1997 @@ -42,6 +42,10 @@ static int soft_margin = TIMER_MARGIN; /* in seconds */ +#ifdef MODULE +MODULE_PARM(soft_margin,"i"); +#endif + /* * Our timer */ diff -u --recursive --new-file v2.1.42/linux/drivers/char/sysrq.c linux/drivers/char/sysrq.c --- v2.1.42/linux/drivers/char/sysrq.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/sysrq.c Thu Jun 12 16:22:06 1997 @@ -0,0 +1,248 @@ +/* -*- linux-c -*- + * + * $Id: sysrq.c,v 1.2 1997/05/31 18:33:11 mj Exp $ + * + * Linux Magic System Request Key Hacks + * + * (c) 1997 Martin Mares + * based on ideas by Pavel Machek + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_APM +#include +#endif + +extern void wakeup_bdflush(int); +extern void reset_vc(unsigned int); +extern int console_loglevel; +extern struct vfsmount *vfsmntlist; + +#ifdef __sparc__ +extern void halt_now(void); +#endif + +/* Send a signal to all user processes */ + +static void send_sig_all(int sig, int even_init) +{ + struct task_struct *p; + + for_each_task(p) { + if (p->pid && p->mm != &init_mm) { /* Not swapper nor kernel thread */ + if (p->pid == 1 && even_init) /* Ugly hack to kill init */ + p->pid = 0x8000; + force_sig(sig, p); + } + } +} + +/* + * This function is called by the keyboard handler when SysRq is pressed + * and any other keycode arrives. + */ + +void handle_sysrq(int key, struct pt_regs *pt_regs, + struct kbd_struct *kbd, struct tty_struct *tty) +{ + int orig_log_level = console_loglevel; + + console_loglevel = 7; + printk(KERN_INFO "SysRq: "); + switch (key) { + case 19: /* R -- Reset raw mode */ + kbd->kbdmode = VC_XLATE; + printk("Keyboard mode set to XLATE\n"); + break; + case 30: /* A -- SAK */ + printk("SAK\n"); + do_SAK(tty); + reset_vc(fg_console); + break; + case 48: /* B -- boot immediately */ + printk("Resetting\n"); + machine_restart(NULL); + break; +#ifdef __sparc__ + case 35: /* H -- halt immediately */ + printk("Halting\n"); + halt_now(); + break; +#endif +#ifdef CONFIG_APM + case 24: /* O -- power off */ + printk("Power off\n"); + apm_set_power_state(APM_STATE_OFF); + break; +#endif + case 31: /* S -- emergency sync */ + printk("Emergency Sync\n"); + emergency_sync_scheduled = EMERG_SYNC; + wakeup_bdflush(0); + break; + case 22: /* U -- emergency remount R/O */ + printk("Emergency Remount R/O\n"); + emergency_sync_scheduled = EMERG_REMOUNT; + wakeup_bdflush(0); + break; + case 25: /* P -- show PC */ + printk("Show Regs\n"); + if (pt_regs) + show_regs(pt_regs); + break; + case 20: /* T -- show task info */ + printk("Show State\n"); + show_state(); + break; + case 50: /* M -- show memory info */ + printk("Show Memory\n"); + show_mem(); + break; + case 2 ... 11: /* 0-9 -- set console logging level */ + key -= 2; + if (key == 10) + key = 0; + orig_log_level = key; + printk("Log level set to %d\n", key); + break; + case 18: /* E -- terminate all user processes */ + printk("Terminate All Tasks\n"); + send_sig_all(SIGTERM, 0); + orig_log_level = 8; /* We probably have killed syslogd */ + break; + case 37: /* K -- kill all user processes */ + printk("Kill All Tasks\n"); + send_sig_all(SIGKILL, 0); + orig_log_level = 8; + break; + case 38: /* L -- kill all processes including init */ + printk("Kill ALL Tasks (even init)\n"); + send_sig_all(SIGKILL, 1); + orig_log_level = 8; + break; + default: /* Unknown: help */ + printk("unRaw sAk Boot " +#ifdef __sparc__ + "Halt " +#endif +#ifdef CONFIG_APM + "Off " +#endif + "Sync Unmount showPc showTasks showMem loglevel0-8 tErm Kill killalL\n"); + } + + console_loglevel = orig_log_level; +} + +/* Aux routines for the syncer */ + +static void all_files_read_only(void) /* Kill write permissions of all files */ +{ + struct file *file; + + for (file = inuse_filps; file; file = file->f_next) + if (file->f_inode && file->f_count && S_ISREG(file->f_inode->i_mode)) + file->f_mode &= ~2; +} + +static int is_local_disk(kdev_t dev) /* Guess if the device is a local hard drive */ +{ + unsigned int major = MAJOR(dev); + + switch (major) { + case IDE0_MAJOR: + case IDE1_MAJOR: + case IDE2_MAJOR: + case IDE3_MAJOR: + case SCSI_DISK_MAJOR: + return 1; + default: + return 0; + } +} + +static void go_sync(kdev_t dev, int remount_flag) +{ + printk(KERN_INFO "%sing device %04x ... ", + remount_flag ? "Remount" : "Sync", + dev); + + if (remount_flag) { /* Remount R/O */ + struct super_block *sb = get_super(dev); + struct vfsmount *vfsmnt; + int ret, flags; + + if (!sb) { + printk("Superblock not found\n"); + return; + } + if (sb->s_flags & MS_RDONLY) { + printk("R/O\n"); + return; + } + quota_off(dev, -1); + fsync_dev(dev); + flags = MS_RDONLY; + if (sb->s_op && sb->s_op->remount_fs) { + ret = sb->s_op->remount_fs(sb, &flags, NULL); + if (ret) + printk("error %d\n", ret); + else { + sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK); + if ((vfsmnt = lookup_vfsmnt(sb->s_dev))) + vfsmnt->mnt_flags = sb->s_flags; + printk("OK\n"); + } + } else + printk("nothing to do\n"); + } else { + fsync_dev(dev); /* Sync only */ + printk("OK\n"); + } +} + +/* + * Emergency Sync or Unmount. We cannot do it directly, so we set a special + * flag and wake up the bdflush kernel thread which immediately calls this function. + * We process all mounted hard drives first to recover from crashed experimental + * block devices and malfunctional network filesystems. + */ + +int emergency_sync_scheduled; + +void do_emergency_sync(void) +{ + struct vfsmount *mnt; + int remount_flag; + + lock_kernel(); + remount_flag = (emergency_sync_scheduled == EMERG_REMOUNT); + emergency_sync_scheduled = 0; + + if (remount_flag) + all_files_read_only(); + + for (mnt = vfsmntlist; mnt; mnt = mnt->mnt_next) + if (is_local_disk(mnt->mnt_dev)) + go_sync(mnt->mnt_dev, remount_flag); + + for (mnt = vfsmntlist; mnt; mnt = mnt->mnt_next) + if (!is_local_disk(mnt->mnt_dev) && MAJOR(mnt->mnt_dev)) + go_sync(mnt->mnt_dev, remount_flag); + + unlock_kernel(); + printk(KERN_INFO "Done.\n"); +} diff -u --recursive --new-file v2.1.42/linux/drivers/char/tga.c linux/drivers/char/tga.c --- v2.1.42/linux/drivers/char/tga.c Tue May 13 22:41:07 1997 +++ linux/drivers/char/tga.c Thu Jun 12 16:22:06 1997 @@ -33,11 +33,11 @@ #include #include -#include "kbd_kern.h" -#include "vt_kern.h" -#include "consolemap.h" -#include "selection.h" -#include "console_struct.h" +#include +#include +#include +#include +#include extern struct console vt_console_driver; diff -u --recursive --new-file v2.1.42/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.1.42/linux/drivers/char/tty_io.c Mon May 19 12:57:38 1997 +++ linux/drivers/char/tty_io.c Thu Jun 12 16:22:06 1997 @@ -77,9 +77,9 @@ #include #include -#include "kbd_kern.h" -#include "vt_kern.h" -#include "selection.h" +#include +#include +#include #ifdef CONFIG_KERNELD #include diff -u --recursive --new-file v2.1.42/linux/drivers/char/vc_screen.c linux/drivers/char/vc_screen.c --- v2.1.42/linux/drivers/char/vc_screen.c Thu May 29 21:53:05 1997 +++ linux/drivers/char/vc_screen.c Thu Jun 12 16:22:06 1997 @@ -31,9 +31,9 @@ #include #include #include +#include +#include #include -#include "vt_kern.h" -#include "selection.h" #undef attr #undef org diff -u --recursive --new-file v2.1.42/linux/drivers/char/vga.c linux/drivers/char/vga.c --- v2.1.42/linux/drivers/char/vga.c Tue May 13 22:41:07 1997 +++ linux/drivers/char/vga.c Thu Jun 12 16:22:06 1997 @@ -60,11 +60,11 @@ #include #include -#include "kbd_kern.h" -#include "vt_kern.h" -#include "consolemap.h" -#include "selection.h" -#include "console_struct.h" +#include +#include +#include +#include +#include #define CAN_LOAD_EGA_FONTS /* undefine if the user must not do this */ #define CAN_LOAD_PALETTE /* undefine if the user must not do this */ diff -u --recursive --new-file v2.1.42/linux/drivers/char/vt.c linux/drivers/char/vt.c --- v2.1.42/linux/drivers/char/vt.c Tue May 13 22:41:07 1997 +++ linux/drivers/char/vt.c Thu Jun 12 16:22:06 1997 @@ -26,10 +26,10 @@ #include #include -#include "kbd_kern.h" -#include "vt_kern.h" -#include "diacr.h" -#include "selection.h" +#include +#include +#include +#include char vt_dont_switch = 0; extern struct tty_driver console_driver; diff -u --recursive --new-file v2.1.42/linux/drivers/char/vt_kern.h linux/drivers/char/vt_kern.h --- v2.1.42/linux/drivers/char/vt_kern.h Sun Mar 24 03:35:08 1996 +++ linux/drivers/char/vt_kern.h Wed Dec 31 16:00:00 1969 @@ -1,39 +0,0 @@ -#ifndef _VT_KERN_H -#define _VT_KERN_H - -/* - * this really is an extension of the vc_cons structure in console.c, but - * with information needed by the vt package - */ - -#include - -/* - * Presently, a lot of graphics programs do not restore the contents of - * the higher font pages. Defining this flag will avoid use of them, but - * will lose support for PIO_FONTRESET. Note that many font operations are - * not likely to work with these programs anyway; they need to be - * fixed. The linux/Documentation directory includes a code snippet - * to save and restore the text font. - */ -#define BROKEN_GRAPHICS_PROGRAMS 1 - -extern struct vt_struct { - int vc_num; /* The console number */ - unsigned char vc_mode; /* KD_TEXT, ... */ - unsigned char vc_kbdraw; - unsigned char vc_kbde0; - unsigned char vc_kbdleds; - struct vt_mode vt_mode; - int vt_pid; - int vt_newvt; - struct wait_queue *paste_wait; -} *vt_cons[MAX_NR_CONSOLES]; - -void (*kd_mksound)(unsigned int hz, unsigned int ticks); -int vc_allocate(unsigned int console); -int vc_cons_allocated(unsigned int console); -int vc_resize(unsigned long lines, unsigned long cols); -void vc_disallocate(unsigned int console); - -#endif /* _VT_KERN_H */ diff -u --recursive --new-file v2.1.42/linux/drivers/isdn/hisax/callc.c linux/drivers/isdn/hisax/callc.c --- v2.1.42/linux/drivers/isdn/hisax/callc.c Thu May 29 21:53:05 1997 +++ linux/drivers/isdn/hisax/callc.c Thu Jun 12 16:22:06 1997 @@ -1,4 +1,4 @@ -/* $Id: callc.c,v 1.29 1997/04/23 20:09:49 fritz Exp $ +/* $Id: callc.c,v 1.30 1997/05/29 10:40:43 keil Exp $ * Author Karsten Keil (keil@temic-ech.spacenet.de) * based on the teles driver from Jan den Ouden @@ -7,6 +7,9 @@ * Fritz Elfert * * $Log: callc.c,v $ + * Revision 1.30 1997/05/29 10:40:43 keil + * chanp->impair was uninitialised + * * Revision 1.29 1997/04/23 20:09:49 fritz * Removed tmp, used by removed debugging code. * @@ -109,7 +112,7 @@ #endif #endif /* MODULE */ -const char *l4_revision = "$Revision: 1.29 $"; +const char *l4_revision = "$Revision: 1.30 $"; extern struct IsdnCard cards[]; extern int nrcards; @@ -1504,6 +1507,7 @@ chanp->debug = 0; chanp->Flags = 0; chanp->leased = 0; + chanp->impair = 0; init_is(chanp, ces); chanp->fi.fsm = &callcfsm; diff -u --recursive --new-file v2.1.42/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.1.42/linux/drivers/net/Config.in Thu May 29 21:53:07 1997 +++ linux/drivers/net/Config.in Thu Jun 12 16:22:06 1997 @@ -139,10 +139,15 @@ bool 'Soundmodem support for Soundblaster and compatible cards' CONFIG_SOUNDMODEM_SBC bool 'Soundmodem support for WSS and Crystal cards' CONFIG_SOUNDMODEM_WSS bool 'Soundmodem support for 1200 baud AFSK modulation' CONFIG_SOUNDMODEM_AFSK1200 + bool 'Soundmodem support for 2400 baud AFSK modulation (7.3728MHz crystal)' CONFIG_SOUNDMODEM_AFSK2400_7 + bool 'Soundmodem support for 2400 baud AFSK modulation (8MHz crystal)' CONFIG_SOUNDMODEM_AFSK2400_8 bool 'Soundmodem support for 4800 baud HAPN-1 modulation' CONFIG_SOUNDMODEM_HAPN4800 bool 'Soundmodem support for 9600 baud FSK G3RUH modulation' CONFIG_SOUNDMODEM_FSK9600 - if [ "$CONFIG_M586" = "y" -o "$CONFIG_M686" = "y" ]; then - bool 'Soundmodem using floating point' CONFIG_SOUNDMODEM_FLOAT + if [ -f drivers/net/soundmodem/sm_afsk2666.c ]; then + bool 'Soundmodem support for 2666 baud AFSK modulation' CONFIG_SOUNDMODEM_AFSK2666 + fi + if [ -f drivers/net/soundmodem/sm_psk4800.c ]; then + bool 'Soundmodem support for 4800 baud PSK modulation' CONFIG_SOUNDMODEM_PSK4800 fi fi fi diff -u --recursive --new-file v2.1.42/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c --- v2.1.42/linux/drivers/net/arcnet.c Tue May 13 22:41:08 1997 +++ linux/drivers/net/arcnet.c Thu Jun 12 16:22:06 1997 @@ -751,8 +751,8 @@ * FIXME: grab all devices in one shot and eliminate the big static array. */ -static int ports[(0x3f0 - 0x200) / 16 + 1] __initdata; -static u_long shmems[(0xFF800 - 0xA0000) / 2048 + 1] __initdata; +static int ports[(0x3f0 - 0x200) / 16 + 1] __initdata = { 0 }; +static u_long shmems[(0xFF800 - 0xA0000) / 2048 + 1] __initdata = { 0 }; __initfunc(int arcnet_probe(struct device *dev)) { diff -u --recursive --new-file v2.1.42/linux/drivers/net/baycom.c linux/drivers/net/baycom.c --- v2.1.42/linux/drivers/net/baycom.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/net/baycom.c Thu Jun 12 16:22:06 1997 @@ -68,6 +68,7 @@ * History: * 0.1 26.06.96 Adapted from baycom.c and made network driver interface * 18.10.96 Changed to new user space access routines (copy_{to,from}_user) + * 0.3 26.04.96 init code/data tagged */ /*****************************************************************************/ @@ -89,7 +90,6 @@ #include #include #include -#include /* --------------------------------------------------------------------- */ @@ -133,6 +133,14 @@ } #endif +#if LINUX_VERSION_CODE >= 0x20123 +#include +#else +#define __init +#define __initdata +#define __initfunc(x) x +#endif + /* --------------------------------------------------------------------- */ #define BAYCOM_DEBUG @@ -1001,7 +1009,7 @@ #endif -int init_module(void) +__initfunc(int init_module(void)) { baycom_ports[0].mode = mode; baycom_ports[0].iobase = iobase; diff -u --recursive --new-file v2.1.42/linux/drivers/net/defxx.c linux/drivers/net/defxx.c --- v2.1.42/linux/drivers/net/defxx.c Sat May 24 09:10:23 1997 +++ linux/drivers/net/defxx.c Thu Jun 12 16:22:06 1997 @@ -229,7 +229,11 @@ #define DYNAMIC_BUFFERS 1 #define SKBUFF_RX_COPYBREAK 200 -#define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX) +/* + * NEW_SKB_SIZE = PI_RCV_DATA_K_SIZE_MAX+128 to allow 128 byte + * alignment for compatibility with old EISA boards. + */ +#define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX+128) /* Define global routines */ @@ -2944,6 +2948,12 @@ bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP | ((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN)); newskb = dev_alloc_skb(NEW_SKB_SIZE); + /* + * align to 128 bytes for compatibility with + * the old EISA boards. + */ + newskb->data = (char *)((unsigned long) + (newskb->data+127) & ~128); bp->descr_block_virt->rcv_data[i+j].long_1 = virt_to_bus(newskb->data); /* * p_rcv_buff_va is only used inside the @@ -3012,8 +3022,6 @@ u32 descr, pkt_len; /* FMC descriptor field and packet length */ struct sk_buff *skb; /* pointer to a sk_buff to hold incoming packet data */ - static int testing_dyn; - /* Service all consumed LLC receive frames */ p_type_2_cons = (PI_TYPE_2_CONSUMER *)(&bp->cons_block_virt->xmt_rcv_data); @@ -3056,18 +3064,12 @@ newskb = dev_alloc_skb(NEW_SKB_SIZE); if (newskb){ rx_in_place = 1; -#define JES_TESTING -#ifdef JES_TESTING - if(testing_dyn++ < 5) - printk("Skipping a memcpy\n"); + + newskb->data = (char *)((unsigned long)(newskb->data+127) & ~128); skb = (struct sk_buff *)bp->p_rcv_buff_va[entry]; skb->data += RCV_BUFF_K_PADDING; bp->p_rcv_buff_va[entry] = (char *)newskb; bp->descr_block_virt->rcv_data[entry].long_1 = virt_to_bus(newskb->data); -#else - memcpy(newskb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3); - skb = newskb; -#endif } else skb = 0; } else @@ -3240,12 +3242,14 @@ p_xmt_descr = &(bp->descr_block_virt->xmt_data[prod]); /* - * Get pointer to auxiliary queue entry to contain information for this packet. + * Get pointer to auxiliary queue entry to contain information + * for this packet. * - * Note: The current xmt producer index will become the current xmt completion - * index when we complete this packet later on. So, we'll get the - * pointer to the next auxiliary queue entry now before we bump the - * producer index. + * Note: The current xmt producer index will become the + * current xmt completion index when we complete this + * packet later on. So, we'll get the pointer to the + * next auxiliary queue entry now before we bump the + * producer index. */ p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[prod++]); /* also bump producer index */ @@ -3290,15 +3294,15 @@ * Verify that descriptor is actually available * * Note: If descriptor isn't available, return 1 which tells - * the upper layer to requeue the packet for later - * transmission. + * the upper layer to requeue the packet for later + * transmission. * * We need to ensure that the producer never reaches the - * completion, except to indicate that the queue is empty. + * completion, except to indicate that the queue is empty. */ if (prod == bp->rcv_xmt_reg.index.xmt_comp) - return(1); /* requeue packet for later */ + return(1); /* requeue packet for later */ /* * Save info for this packet for xmt done indication routine @@ -3311,9 +3315,9 @@ * one (1) for each completed packet. * * Note: If this assumption changes and we're presented with - * an inconsistent number of transmit fragments for packet - * data, we'll need to modify this code to save the current - * transmit producer index. + * an inconsistent number of transmit fragments for packet + * data, we'll need to modify this code to save the current + * transmit producer index. */ p_xmt_drv_descr->p_skb = skb; diff -u --recursive --new-file v2.1.42/linux/drivers/net/hdlcdrv.c linux/drivers/net/hdlcdrv.c --- v2.1.42/linux/drivers/net/hdlcdrv.c Tue May 13 22:41:09 1997 +++ linux/drivers/net/hdlcdrv.c Thu Jun 12 16:22:06 1997 @@ -32,6 +32,7 @@ * (copy_{to,from}_user) * 0.2 21.11.96 various small changes * 0.3 03.03.97 fixed (hopefully) IP not working with ax.25 as a module + * 0.4 16.04.97 init code/data tagged */ /*****************************************************************************/ @@ -119,6 +120,23 @@ /* --------------------------------------------------------------------- */ +#if LINUX_VERSION_CODE >= 0x20123 +#include +#else +#define __init +#define __initdata +#define __initfunc(x) x +#endif + +/* --------------------------------------------------------------------- */ + +#if LINUX_VERSION_CODE < 0x20125 +#define test_and_set_bit set_bit +#define test_and_clear_bit clear_bit +#endif + +/* --------------------------------------------------------------------- */ + /* * The name of the card. Is used for messages and in the requests for * io regions, irqs and dma channels @@ -998,10 +1016,10 @@ /* --------------------------------------------------------------------- */ -int init_module(void) +__initfunc(int init_module(void)) { printk(KERN_INFO "hdlcdrv: (C) 1996 Thomas Sailer HB9JNX/AE4WA\n"); - printk(KERN_INFO "hdlcdrv: version 0.3 compiled " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "hdlcdrv: version 0.4 compiled " __TIME__ " " __DATE__ "\n"); #if LINUX_VERSION_CODE < 0x20115 register_symtab(&hdlcdrv_syms); #endif diff -u --recursive --new-file v2.1.42/linux/drivers/net/net_init.c linux/drivers/net/net_init.c --- v2.1.42/linux/drivers/net/net_init.c Sun Apr 13 10:18:21 1997 +++ linux/drivers/net/net_init.c Thu Jun 12 16:22:06 1997 @@ -248,7 +248,7 @@ #endif -#ifdef CONFIG_ATALK +#if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) static int ltalk_change_mtu(struct device *dev, int mtu) { diff -u --recursive --new-file v2.1.42/linux/drivers/net/soundmodem/Makefile linux/drivers/net/soundmodem/Makefile --- v2.1.42/linux/drivers/net/soundmodem/Makefile Thu Feb 27 10:57:31 1997 +++ linux/drivers/net/soundmodem/Makefile Thu Jun 12 16:22:06 1997 @@ -21,6 +21,12 @@ ifeq ($(CONFIG_SOUNDMODEM_AFSK1200),y) O_OBJS += sm_afsk1200.o endif +ifeq ($(CONFIG_SOUNDMODEM_AFSK2400_7),y) +O_OBJS += sm_afsk2400_7.o +endif +ifeq ($(CONFIG_SOUNDMODEM_AFSK2400_8),y) +O_OBJS += sm_afsk2400_8.o +endif ifeq ($(CONFIG_SOUNDMODEM_AFSK2666),y) O_OBJS += sm_afsk2666.o endif @@ -39,7 +45,8 @@ gentbl: gentbl.c $(HOSTCC) -Wall $< -o $@ -lm -TBLHDR := sm_tbl_afsk1200.h sm_tbl_afsk2666.h sm_tbl_psk4800.h +TBLHDR := sm_tbl_afsk1200.h sm_tbl_afsk2400_8.h +TBLHDR += sm_tbl_afsk2666.h sm_tbl_psk4800.h TBLHDR += sm_tbl_hapn4800.h sm_tbl_fsk9600.h $(TBLHDR): gentbl diff -u --recursive --new-file v2.1.42/linux/drivers/net/soundmodem/gentbl.c linux/drivers/net/soundmodem/gentbl.c --- v2.1.42/linux/drivers/net/soundmodem/gentbl.c Thu Feb 27 10:57:31 1997 +++ linux/drivers/net/soundmodem/gentbl.c Thu Jun 12 16:22:06 1997 @@ -31,27 +31,44 @@ /* -------------------------------------------------------------------- */ -#define OFFSCOSTABBITS 6 -#define OFFSCOSTABSIZE (1<>%d)&0x%x]\n\n", - 16-OFFSCOSTABBITS, OFFSCOSTABSIZE-1); + 16-nbits, (1<>%d)&0x%x]\n" + "#define SIN(x) COS((x)+0xc000)\n\n", 16-nbits, + (1<= 0; o--) { fprintf(f, "\t{\n"); for (i = 0; i < AFSK26_NUMCAR; i++) { j = cfreq[i]; fprintf(f, "\t\t{{ "); - for (l = AFSK26_DEMCORRLEN-1, - k = (j * o)/AFSK26_RXOVER; l >= 0; - l--, k = (k+j)&0xffffu) - fprintf(f, "%6d%s", (int) - (AFSK26_AMPL(i)* - window[l*AFSK26_RXOVER+o]* - cos(M_PI*k/32768.0)), - l ? ", " : " }, { "); - for (l = AFSK26_DEMCORRLEN-1, - k = (j * o)/AFSK26_RXOVER; l >= 0; - l--, k = (k+j)&0xffffu) - fprintf(f, "%6d%s", (int) - (AFSK26_AMPL(i)* - window[l*AFSK26_RXOVER+o]* - sin(M_PI*k/32768.0)), - l ? ", " : " }}"); + for (l = AFSK26_DEMCORRLEN-1, k = (j * o)/AFSK26_RXOVER, sumi = 0; l >= 0; + l--, k = (k+j)&0xffffu) { + sumi += (v = AFSK26_AMPL(i)*window[l*AFSK26_RXOVER+o]* + cos(M_PI*k/32768.0)); + fprintf(f, "%6d%s", v, l ? ", " : " }, { "); + } + for (l = AFSK26_DEMCORRLEN-1, k = (j * o)/AFSK26_RXOVER, sumq = 0; l >= 0; + l--, k = (k+j)&0xffffu) { + sumq += (v = AFSK26_AMPL(i)*window[l*AFSK26_RXOVER+o]* + sin(M_PI*k/32768.0)); + fprintf(f, "%6d%s", v, l ? ", " : " }}"); + } if (i < 1) fprintf(f, ","); - fprintf(f, "\n"); + fprintf(f, "\n#define AFSK26_DEM_SUM_I_%d_%d %d\n" + "#define AFSK26_DEM_SUM_Q_%d_%d %d\n", + AFSK26_RXOVER-1-o, i, sumi, AFSK26_RXOVER-1-o, i, sumq); } fprintf(f, "\t}%s\n", o ? "," : ""); } @@ -308,28 +340,6 @@ /* -------------------------------------------------------------------- */ -#define COSTABBITS 8 - -static void gentbl_costab(FILE *f) -{ - int i; - - fprintf(f, "\n/*\n * more accurate cosine table\n */\n\n" - "static const short costab[%d] = {", (1<>%d)&0x%x]\n" - "#define SIN(x) COS((x)+0xc000)\n\n", 16-COSTABBITS, - (1<\n\n"); +} + /* -------------------------------------------------------------------- */ void main(int argc, char *argv[]) @@ -596,20 +690,23 @@ if (!(f = fopen("sm_tbl_afsk1200.h", "w"))) exit(1); gentbl_banner(f); - gentbl_offscostab(f); + gentbl_needs_config(f); + gentbl_offscostab(f, 6); + gentbl_costab(f, 6); gentbl_afsk1200(f); fclose(f); if (!(f = fopen("sm_tbl_afsk2666.h", "w"))) exit(1); gentbl_banner(f); - gentbl_offscostab(f); + gentbl_offscostab(f, 6); + gentbl_costab(f, 6); gentbl_afsk2666(f); fclose(f); if (!(f = fopen("sm_tbl_psk4800.h", "w"))) exit(1); gentbl_banner(f); gentbl_psk4800(f); - gentbl_costab(f); + gentbl_costab(f, 8); gentbl_atantab(f); fclose(f); if (!(f = fopen("sm_tbl_hapn4800.h", "w"))) @@ -621,6 +718,22 @@ exit(1); gentbl_banner(f); gentbl_fsk9600(f); + fclose(f); + if (!(f = fopen("sm_tbl_afsk2400_8.h", "w"))) + exit(1); + gentbl_banner(f); + gentbl_needs_config(f); + gentbl_offscostab(f, 6); + gentbl_costab(f, 6); + gentbl_afsk2400(f, 8000000); + fclose(f); + if (!(f = fopen("sm_tbl_afsk2400_7.h", "w"))) + exit(1); + gentbl_banner(f); + gentbl_needs_config(f); + gentbl_offscostab(f, 6); + gentbl_costab(f, 6); + gentbl_afsk2400(f, 7372800); fclose(f); exit(0); } diff -u --recursive --new-file v2.1.42/linux/drivers/net/soundmodem/sm.c linux/drivers/net/soundmodem/sm.c --- v2.1.42/linux/drivers/net/soundmodem/sm.c Thu May 29 21:53:07 1997 +++ linux/drivers/net/soundmodem/sm.c Thu Jun 12 16:22:07 1997 @@ -38,6 +38,7 @@ * 18.10.96 Changed to new user space access routines (copy_{to,from}_user) * 0.4 21.01.97 Separately compileable soundcard/modem modules * 0.5 03.03.97 fixed LPT probing (check_lpt result was interpreted the wrong way round) + * 0.6 16.04.97 init code/data tagged */ /*****************************************************************************/ @@ -56,7 +57,6 @@ #include #include #include -#include #include "sm.h" /* --------------------------------------------------------------------- */ @@ -101,18 +101,32 @@ } #endif +#if LINUX_VERSION_CODE >= 0x20123 +#include +#else +#define __init +#define __initdata +#define __initfunc(x) x +#endif + /* --------------------------------------------------------------------- */ -const char sm_drvname[] = "soundmodem"; -static const char sm_drvinfo[] = KERN_INFO "soundmodem: (C) 1996 Thomas Sailer, HB9JNX/AE4WA\n" -KERN_INFO "soundmodem: version 0.5 compiled " __TIME__ " " __DATE__ "\n"; +/*static*/ const char sm_drvname[] = "soundmodem"; +static const char sm_drvinfo[] = KERN_INFO "soundmodem: (C) 1996-1997 Thomas Sailer, HB9JNX/AE4WA\n" +KERN_INFO "soundmodem: version 0.6 compiled " __TIME__ " " __DATE__ "\n"; /* --------------------------------------------------------------------- */ -const struct modem_tx_info *sm_modem_tx_table[] = { +/*static*/ const struct modem_tx_info *sm_modem_tx_table[] = { #ifdef CONFIG_SOUNDMODEM_AFSK1200 &sm_afsk1200_tx, #endif /* CONFIG_SOUNDMODEM_AFSK1200 */ +#ifdef CONFIG_SOUNDMODEM_AFSK2400_7 + &sm_afsk2400_7_tx, +#endif /* CONFIG_SOUNDMODEM_AFSK2400_7 */ +#ifdef CONFIG_SOUNDMODEM_AFSK2400_8 + &sm_afsk2400_8_tx, +#endif /* CONFIG_SOUNDMODEM_AFSK2400_8 */ #ifdef CONFIG_SOUNDMODEM_AFSK2666 &sm_afsk2666_tx, #endif /* CONFIG_SOUNDMODEM_AFSK2666 */ @@ -132,10 +146,16 @@ NULL }; -const struct modem_rx_info *sm_modem_rx_table[] = { +/*static*/ const struct modem_rx_info *sm_modem_rx_table[] = { #ifdef CONFIG_SOUNDMODEM_AFSK1200 &sm_afsk1200_rx, #endif /* CONFIG_SOUNDMODEM_AFSK1200 */ +#ifdef CONFIG_SOUNDMODEM_AFSK2400_7 + &sm_afsk2400_7_rx, +#endif /* CONFIG_SOUNDMODEM_AFSK2400_7 */ +#ifdef CONFIG_SOUNDMODEM_AFSK2400_8 + &sm_afsk2400_8_rx, +#endif /* CONFIG_SOUNDMODEM_AFSK2400_8 */ #ifdef CONFIG_SOUNDMODEM_AFSK2666 &sm_afsk2666_rx, #endif /* CONFIG_SOUNDMODEM_AFSK2666 */ @@ -344,7 +364,7 @@ int invert_dcd = 0; int invert_ptt = 0; - int ptt = hdlcdrv_ptt(&sm->hdrv) ^ invert_ptt; + int ptt = /*hdlcdrv_ptt(&sm->hdrv)*/(sm->dma.ptt_cnt > 0) ^ invert_ptt; int dcd = (!!sm->hdrv.hdlcrx.dcd) ^ invert_dcd; if (sm->hdrv.ptt_out.flags & SP_SER) { @@ -457,9 +477,9 @@ return err; sm_output_open(sm); MOD_INC_USE_COUNT; - printk(KERN_INFO "%s: %s mode %s.%s at iobase 0x%lx irq %u dma %u\n", + printk(KERN_INFO "%s: %s mode %s.%s at iobase 0x%lx irq %u dma %u dma2 %u\n", sm_drvname, sm->hwdrv->hw_name, sm->mode_tx->name, - sm->mode_rx->name, dev->base_addr, dev->irq, dev->dma); + sm->mode_rx->name, dev->base_addr, dev->irq, dev->dma, sm->hdrv.ptt_out.dma2); return 0; } @@ -664,7 +684,56 @@ /* --------------------------------------------------------------------- */ +#ifdef __i386__ + +int sm_x86_capability = 0; + +__initfunc(static void i386_capability(void)) +{ + unsigned long flags; + unsigned long fl1; + union { + struct { + unsigned int ebx, edx, ecx; + } r; + unsigned char s[13]; + } id; + unsigned int eax; + + save_flags(flags); + flags |= 0x200000; + restore_flags(flags); + save_flags(flags); + fl1 = flags; + flags &= ~0x200000; + restore_flags(flags); + save_flags(flags); + if (!(fl1 & 0x200000) || (flags & 0x200000)) { + printk(KERN_WARNING "%s: cpu does not support CPUID\n", sm_drvname); + return; + } + __asm__ ("cpuid" : "=a" (eax), "=b" (id.r.ebx), "=c" (id.r.ecx), "=d" (id.r.edx) : + "0" (0)); + id.s[12] = 0; + if (eax < 1) { + printk(KERN_WARNING "%s: cpu (vendor string %s) does not support capability " + "list\n", sm_drvname, id.s); + return; + } + printk(KERN_INFO "%s: cpu: vendor string %s ", sm_drvname, id.s); + __asm__ ("cpuid" : "=a" (eax), "=d" (sm_x86_capability) : "0" (1) : "ebx", "ecx"); + printk("fam %d mdl %d step %d cap 0x%x\n", (eax >> 8) & 15, (eax >> 4) & 15, + eax & 15, sm_x86_capability); +} +#endif /* __i386__ */ + +/* --------------------------------------------------------------------- */ + +#ifdef MODULE +__initfunc(static int sm_init(void)) +#else /* MODULE */ __initfunc(int sm_init(void)) +#endif /* MODULE */ { int i, j, found = 0; char set_hw = 1; @@ -672,6 +741,9 @@ char ifname[HDLCDRV_IFNAMELEN]; printk(sm_drvinfo); +#ifdef __i386__ + i386_capability(); +#endif /* __i386__ */ /* * register net devices */ @@ -745,7 +817,7 @@ #endif -int init_module(void) +__initfunc(int init_module(void)) { if (mode) { if (iobase == -1) diff -u --recursive --new-file v2.1.42/linux/drivers/net/soundmodem/sm.h linux/drivers/net/soundmodem/sm.h --- v2.1.42/linux/drivers/net/soundmodem/sm.h Thu May 29 21:53:07 1997 +++ linux/drivers/net/soundmodem/sm.h Thu Jun 12 16:22:07 1997 @@ -30,16 +30,11 @@ /* ---------------------------------------------------------------------- */ -#include #include #include #define SM_DEBUG -/* --------------------------------------------------------------------- */ - -#define DMA_MODE_AUTOINIT 0x10 - /* ---------------------------------------------------------------------- */ /* * Information that need to be kept for each board. @@ -56,6 +51,18 @@ /* * Hardware (soundcard) access routines state */ + struct { + void *ibuf; + unsigned int ifragsz; + unsigned int ifragptr; + unsigned int i16bit; + void *obuf; + unsigned int ofragsz; + unsigned int ofragptr; + unsigned int o16bit; + int ptt_cnt; + } dma; + union { long hw[32/sizeof(long)]; } hw; @@ -101,9 +108,9 @@ unsigned int loc_storage; int srate; int bitrate; - unsigned int dmabuflenmodulo; - void (*modulator)(struct sm_state *, unsigned char *, int); - void (*init)(struct sm_state *); + void (*modulator_u8)(struct sm_state *, unsigned char *, unsigned int); + void (*modulator_s16)(struct sm_state *, short *, unsigned int); + void (*init)(struct sm_state *); }; struct modem_rx_info { @@ -111,10 +118,11 @@ unsigned int loc_storage; int srate; int bitrate; - unsigned int dmabuflenmodulo; + unsigned int overlap; unsigned int sperbit; - void (*demodulator)(struct sm_state *, unsigned char *, int); - void (*init)(struct sm_state *); + void (*demodulator_u8)(struct sm_state *, const unsigned char *, unsigned int); + void (*demodulator_s16)(struct sm_state *, const short *, unsigned int); + void (*init)(struct sm_state *); }; /* ---------------------------------------------------------------------- */ @@ -281,30 +289,41 @@ */ -#if defined(SM_DEBUG) && (defined(CONFIG_M586) || defined(CONFIG_M686)) +#ifdef __i386__ + +extern int sm_x86_capability; + +#define HAS_RDTSC (sm_x86_capability & 0x10) /* * only do 32bit cycle counter arithmetic; we hope we won't overflow :-) * in fact, overflowing modems would require over 2THz clock speeds :-) */ -#define time_exec(var,cmd) \ -({ \ - unsigned int cnt1, cnt2, cnt3; \ - __asm__(".byte 0x0f,0x31" : "=a" (cnt1), "=d" (cnt3)); \ - cmd; \ - __asm__(".byte 0x0f,0x31" : "=a" (cnt2), "=d" (cnt3)); \ - var = cnt2-cnt1; \ +#define time_exec(var,cmd) \ +({ \ + if (HAS_RDTSC) { \ + unsigned int cnt1, cnt2, cnt3; \ + __asm__(".byte 0x0f,0x31" : "=a" (cnt1), "=d" (cnt3)); \ + cmd; \ + __asm__(".byte 0x0f,0x31" : "=a" (cnt2), "=d" (cnt3)); \ + var = cnt2-cnt1; \ + } else { \ + cmd; \ + } \ }) -#else /* defined(SM_DEBUG) && (defined(CONFIG_M586) || defined(CONFIG_M686)) */ + +#else /* __i386__ */ #define time_exec(var,cmd) cmd -#endif /* defined(SM_DEBUG) && (defined(CONFIG_M586) || defined(CONFIG_M686)) */ +#endif /* __i386__ */ /* --------------------------------------------------------------------- */ extern const struct modem_tx_info sm_afsk1200_tx; +extern const struct modem_tx_info sm_afsk2400_7_tx; +extern const struct modem_tx_info sm_afsk2400_8_tx; extern const struct modem_tx_info sm_afsk2666_tx; extern const struct modem_tx_info sm_psk4800_tx; extern const struct modem_tx_info sm_hapn4800_8_tx; @@ -315,6 +334,8 @@ extern const struct modem_tx_info sm_fsk9600_5_tx; extern const struct modem_rx_info sm_afsk1200_rx; +extern const struct modem_rx_info sm_afsk2400_7_rx; +extern const struct modem_rx_info sm_afsk2400_8_rx; extern const struct modem_rx_info sm_afsk2666_rx; extern const struct modem_rx_info sm_psk4800_rx; extern const struct modem_rx_info sm_hapn4800_8_rx; diff -u --recursive --new-file v2.1.42/linux/drivers/net/soundmodem/sm_afsk1200.c linux/drivers/net/soundmodem/sm_afsk1200.c --- v2.1.42/linux/drivers/net/soundmodem/sm_afsk1200.c Thu May 29 21:53:07 1997 +++ linux/drivers/net/soundmodem/sm_afsk1200.c Thu Jun 12 16:22:07 1997 @@ -38,174 +38,176 @@ int dcd_sum0, dcd_sum1, dcd_sum2; unsigned int dcd_time; unsigned char last_rxbit; - union { - signed char c[8]; - float f[8]; - } filt; }; struct mod_state_afsk12 { unsigned int shreg; unsigned char tx_bit; unsigned int bit_pll; + unsigned int dds_inc; + unsigned int txphase; }; /* --------------------------------------------------------------------- */ -static void modulator_1200(struct sm_state *sm, unsigned char *buf, int buflen) +static const int dds_inc[2] = { + AFSK12_TX_FREQ_LO*0x10000/AFSK12_SAMPLE_RATE, + AFSK12_TX_FREQ_HI*0x10000/AFSK12_SAMPLE_RATE +}; + +static void modulator_1200_u8(struct sm_state *sm, unsigned char *buf, + unsigned int buflen) { struct mod_state_afsk12 *st = (struct mod_state_afsk12 *)(&sm->m); - static const int dds_inc[2] = { AFSK12_TX_FREQ_LO*0x10000/AFSK12_SAMPLE_RATE, - AFSK12_TX_FREQ_HI*0x10000/AFSK12_SAMPLE_RATE }; - int j, k; - - for (; buflen >= 8; buflen -= 8) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->tx_bit = (st->tx_bit ^ - (!(st->shreg & 1))) & 1; - st->shreg >>= 1; - k = dds_inc[st->tx_bit & 1]; - for (j = 0; j < 8; j++) { - *buf++ = OFFSCOS(st->bit_pll); - st->bit_pll += k; + + for (; buflen > 0; buflen--) { + if (!((st->txphase++) & 7)) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1; + st->shreg >>= 1; } + st->dds_inc = dds_inc[st->tx_bit & 1]; + *buf++ = OFFSCOS(st->bit_pll); + st->bit_pll += st->dds_inc; } } /* --------------------------------------------------------------------- */ +static void modulator_1200_s16(struct sm_state *sm, short *buf, unsigned int buflen) +{ + struct mod_state_afsk12 *st = (struct mod_state_afsk12 *)(&sm->m); -/* - * should eventually move to an asm header file - */ - - -#if defined (CONFIG_SOUNDMODEM__AFSK1200_FP) && (defined(CONFIG_M586) || defined(CONFIG_M686)) - - - -#define ENV_STORAGE unsigned char fpu_save[108]; - -#define ENV_SAVE asm("fsave %0;\n\tfninit;\n\t" : "=m" (*fpu_save) : : "memory"); -#define ENV_RESTORE asm("frstor %0;\n\t" : : "m" (*fpu_save)); - -static inline float convolution8(const float *st, const float *coeff) -{ - float f; - - /* - * from Phil Karn, KA9Q's home page - */ - asm volatile ("flds (%1);\n\t" - "fmuls (%2);\n\t" - "flds 4(%1);\n\t" - "fmuls 4(%2);\n\t" - "flds 8(%1);\n\t" - "fmuls 8(%2);\n\t" - "fxch %%st(2);\n\t" - "faddp;\n\t" - "flds 12(%1);\n\t" - "fmuls 12(%2);\n\t" - "fxch %%st(2);\n\t" - "faddp;\n\t" - "flds 16(%1);\n\t" - "fmuls 16(%2);\n\t" - "fxch %%st(2);\n\t" - "faddp;\n\t" - "flds 20(%1);\n\t" - "fmuls 20(%2);\n\t" - "fxch %%st(2);\n\t" - "faddp;\n\t" - "flds 24(%1);\n\t" - "fmuls 24(%2);\n\t" - "fxch %%st(2);\n\t" - "faddp;\n\t" - "flds 28(%1);\n\t" - "fmuls 28(%2);\n\t" - "fxch %%st(2);\n\t" - "faddp;\n\t" - "faddp;\n\t" - "fmul %%st(0),%%st;\n\t" : - "=t" (f) : - "r" (st), - "r" (coeff) : "memory"); - - return f; -} - -static inline int do_filter_1200(struct demod_state_afsk12 *st, unsigned char newval) -{ - float sum; - - memmove(st->filt.f+1, st->filt.f,sizeof(st->filt.f) - sizeof(st->filt.f[0])); - st->filt.f[0] = (((int)newval)-0x80); - - sum = convolution8(st->filt.f, afsk12_tx_lo_i_f); - sum += convolution8(st->filt.f, afsk12_tx_lo_q_f); - sum -= convolution8(st->filt.f, afsk12_tx_hi_i_f); - sum -= convolution8(st->filt.f, afsk12_tx_hi_q_f); - return sum; + for (; buflen > 0; buflen--) { + if (!((st->txphase++) & 7)) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1; + st->shreg >>= 1; + } + st->dds_inc = dds_inc[st->tx_bit & 1]; + *buf++ = COS(st->bit_pll); + st->bit_pll += st->dds_inc; + } } -#else /* defined (CONFIG_SOUNDMODEM__AFSK1200_FP) && (defined(CONFIG_M586) || defined(CONFIG_M686)) */ - -#define ENV_STORAGE -#define ENV_SAVE -#define ENV_RESTORE +/* --------------------------------------------------------------------- */ -static inline void datamove8(signed char *st, unsigned char newval) +extern __inline__ int convolution8_u8(const unsigned char *st, const int *coeff, int csum) { - memmove(st+1, st, 7); - *st = newval - 0x80; + int sum = -0x80 * csum; + + sum += (st[0] * coeff[0]); + sum += (st[-1] * coeff[1]); + sum += (st[-2] * coeff[2]); + sum += (st[-3] * coeff[3]); + sum += (st[-4] * coeff[4]); + sum += (st[-5] * coeff[5]); + sum += (st[-6] * coeff[6]); + sum += (st[-7] * coeff[7]); + + sum >>= 7; + return sum * sum; } -static inline int convolution8(const signed char *st, const signed char *coeff) +extern __inline__ int convolution8_s16(const short *st, const int *coeff, int csum) { - int sum = (st[0] * coeff[0]); + int sum = 0; - sum += (st[1] * coeff[1]); - sum += (st[2] * coeff[2]); - sum += (st[3] * coeff[3]); - sum += (st[4] * coeff[4]); - sum += (st[5] * coeff[5]); - sum += (st[6] * coeff[6]); - sum += (st[7] * coeff[7]); + sum += (st[0] * coeff[0]); + sum += (st[-1] * coeff[1]); + sum += (st[-2] * coeff[2]); + sum += (st[-3] * coeff[3]); + sum += (st[-4] * coeff[4]); + sum += (st[-5] * coeff[5]); + sum += (st[-6] * coeff[6]); + sum += (st[-7] * coeff[7]); - sum >>= 7; + sum >>= 15; return sum * sum; } -static inline int do_filter_1200(struct demod_state_afsk12 *st, unsigned char newval) +extern __inline__ int do_filter_1200_u8(const unsigned char *buf) { - int sum; + int sum = convolution8_u8(buf, afsk12_tx_lo_i, SUM_AFSK12_TX_LO_I); + sum += convolution8_u8(buf, afsk12_tx_lo_q, SUM_AFSK12_TX_LO_Q); + sum -= convolution8_u8(buf, afsk12_tx_hi_i, SUM_AFSK12_TX_HI_I); + sum -= convolution8_u8(buf, afsk12_tx_hi_q, SUM_AFSK12_TX_HI_Q); + return sum; +} - datamove8(st->filt.c, newval); - - sum = convolution8(st->filt.c, afsk12_tx_lo_i); - sum += convolution8(st->filt.c, afsk12_tx_lo_q); - sum -= convolution8(st->filt.c, afsk12_tx_hi_i); - sum -= convolution8(st->filt.c, afsk12_tx_hi_q); +extern __inline__ int do_filter_1200_s16(const short *buf) +{ + int sum = convolution8_s16(buf, afsk12_tx_lo_i, SUM_AFSK12_TX_LO_I); + sum += convolution8_s16(buf, afsk12_tx_lo_q, SUM_AFSK12_TX_LO_Q); + sum -= convolution8_s16(buf, afsk12_tx_hi_i, SUM_AFSK12_TX_HI_I); + sum -= convolution8_s16(buf, afsk12_tx_hi_q, SUM_AFSK12_TX_HI_Q); return sum; } -#endif /* defined (CONFIG_SOUNDMODEM__AFSK1200_FP) && (defined(CONFIG_M586) || defined(CONFIG_M686)) */ +/* --------------------------------------------------------------------- */ +static const int pll_corr[2] = { -0x1000, 0x1000 }; + +static void demodulator_1200_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) +{ + struct demod_state_afsk12 *st = (struct demod_state_afsk12 *)(&sm->d); + int j; + int sum; + unsigned char newsample; + + for (; buflen > 0; buflen--, buf++) { + sum = do_filter_1200_u8(buf); + st->dcd_shreg <<= 1; + st->bit_pll += 0x2000; + newsample = (sum > 0); + if (st->last_sample ^ newsample) { + st->last_sample = newsample; + st->dcd_shreg |= 1; + st->bit_pll += pll_corr + [st->bit_pll < 0x9000]; + j = 4 * hweight8(st->dcd_shreg & 0x38) + - hweight16(st->dcd_shreg & 0x7c0); + st->dcd_sum0 += j; + } + hdlcdrv_channelbit(&sm->hdrv, st->last_sample); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 120; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->shreg >>= 1; + st->shreg |= (!(st->last_rxbit ^ + st->last_sample)) << 16; + st->last_rxbit = st->last_sample; + diag_trigger(sm); + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + } + diag_add(sm, (((int)*buf)-0x80) << 8, sum); + } +} /* --------------------------------------------------------------------- */ -static void demodulator_1200(struct sm_state *sm, unsigned char *buf, int buflen) +static void demodulator_1200_s16(struct sm_state *sm, const short *buf, unsigned int buflen) { struct demod_state_afsk12 *st = (struct demod_state_afsk12 *)(&sm->d); - static const int pll_corr[2] = { -0x1000, 0x1000 }; int j; int sum; unsigned char newsample; - ENV_STORAGE; - ENV_SAVE; for (; buflen > 0; buflen--, buf++) { - sum = do_filter_1200(st, *buf); + sum = do_filter_1200_s16(buf); st->dcd_shreg <<= 1; st->bit_pll += 0x2000; newsample = (sum > 0); @@ -240,9 +242,8 @@ st->shreg = 0x10000; } } - diag_add(sm, (((int)*buf)-0x80) << 8, sum); + diag_add(sm, *buf, sum); } - ENV_RESTORE; } /* --------------------------------------------------------------------- */ @@ -259,13 +260,13 @@ const struct modem_tx_info sm_afsk1200_tx = { "afsk1200", sizeof(struct mod_state_afsk12), - AFSK12_SAMPLE_RATE, 1200, AFSK12_SAMPLE_RATE/1200, modulator_1200, NULL + AFSK12_SAMPLE_RATE, 1200, modulator_1200_u8, modulator_1200_s16, NULL }; const struct modem_rx_info sm_afsk1200_rx = { "afsk1200", sizeof(struct demod_state_afsk12), - AFSK12_SAMPLE_RATE, 1200, AFSK12_SAMPLE_RATE/1200, - AFSK12_SAMPLE_RATE/1200, demodulator_1200, demod_init_1200 + AFSK12_SAMPLE_RATE, 1200, 8, AFSK12_SAMPLE_RATE/1200, + demodulator_1200_u8, demodulator_1200_s16, demod_init_1200 }; /* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.42/linux/drivers/net/soundmodem/sm_afsk2400_7.c linux/drivers/net/soundmodem/sm_afsk2400_7.c --- v2.1.42/linux/drivers/net/soundmodem/sm_afsk2400_7.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/soundmodem/sm_afsk2400_7.c Thu Jun 12 16:22:07 1997 @@ -0,0 +1,297 @@ +/*****************************************************************************/ + +/* + * sm_afsk2400_7.c -- soundcard radio modem driver, 2400 baud AFSK modem + * + * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + */ + +/* + * This driver is intended to be compatible with TCM3105 modems + * overclocked to 7.3728MHz. The mark and space frequencies therefore + * lie at 3658 and 1996 Hz. + * Note that I do _not_ recommend the building of such links, I provide + * this only for the users who live in the coverage area of such + * a "legacy" link. + */ + +#include +#include "sm.h" +#include "sm_tbl_afsk2400_7.h" + +/* --------------------------------------------------------------------- */ + +struct demod_state_afsk24 { + unsigned int shreg; + unsigned int bit_pll; + unsigned char last_sample; + unsigned int dcd_shreg; + int dcd_sum0, dcd_sum1, dcd_sum2; + unsigned int dcd_time; + unsigned char last_rxbit; +}; + +struct mod_state_afsk24 { + unsigned int shreg; + unsigned char tx_bit; + unsigned int bit_pll; + unsigned int tx_seq; + unsigned int phinc; +}; + +/* --------------------------------------------------------------------- */ + +static const int dds_inc[2] = { AFSK24_TX_FREQ_LO*0x10000/AFSK24_SAMPLERATE, + AFSK24_TX_FREQ_HI*0x10000/AFSK24_SAMPLERATE }; + +static void modulator_2400_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) +{ + struct mod_state_afsk24 *st = (struct mod_state_afsk24 *)(&sm->m); + + for (; buflen > 0; buflen--, buf++) { + if (st->tx_seq < 0x5555) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1; + st->shreg >>= 1; + st->phinc = dds_inc[st->tx_bit & 1]; + } + st->tx_seq += 0x5555; + st->tx_seq &= 0xffff; + *buf = OFFSCOS(st->bit_pll); + st->bit_pll += st->phinc; + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_2400_s16(struct sm_state *sm, short *buf, unsigned int buflen) +{ + struct mod_state_afsk24 *st = (struct mod_state_afsk24 *)(&sm->m); + + for (; buflen > 0; buflen--, buf++) { + if (st->tx_seq < 0x5555) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1; + st->shreg >>= 1; + st->phinc = dds_inc[st->tx_bit & 1]; + } + st->tx_seq += 0x5555; + st->tx_seq &= 0xffff; + *buf = COS(st->bit_pll); + st->bit_pll += st->phinc; + } +} + +/* --------------------------------------------------------------------- */ + +extern __inline__ int convolution14_u8(const unsigned char *st, const int *coeff, int csum) +{ + int sum = -0x80 * csum; + + sum += (st[0] * coeff[0]); + sum += (st[-1] * coeff[1]); + sum += (st[-2] * coeff[2]); + sum += (st[-3] * coeff[3]); + sum += (st[-4] * coeff[4]); + sum += (st[-5] * coeff[5]); + sum += (st[-6] * coeff[6]); + sum += (st[-7] * coeff[7]); + sum += (st[-8] * coeff[8]); + sum += (st[-9] * coeff[9]); + sum += (st[-10] * coeff[10]); + sum += (st[-11] * coeff[11]); + sum += (st[-12] * coeff[12]); + sum += (st[-13] * coeff[13]); + + sum >>= 7; + return sum * sum; +} + +extern __inline__ int convolution14_s16(const short *st, const int *coeff, int csum) +{ + int sum = 0; + + sum += (st[0] * coeff[0]); + sum += (st[-1] * coeff[1]); + sum += (st[-2] * coeff[2]); + sum += (st[-3] * coeff[3]); + sum += (st[-4] * coeff[4]); + sum += (st[-5] * coeff[5]); + sum += (st[-6] * coeff[6]); + sum += (st[-7] * coeff[7]); + sum += (st[-8] * coeff[8]); + sum += (st[-9] * coeff[9]); + sum += (st[-10] * coeff[10]); + sum += (st[-11] * coeff[11]); + sum += (st[-12] * coeff[12]); + sum += (st[-13] * coeff[13]); + + sum >>= 15; + return sum * sum; +} + +extern __inline__ int do_filter_2400_u8(const unsigned char *buf) +{ + int sum = convolution14_u8(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I); + sum += convolution14_u8(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q); + sum -= convolution14_u8(buf, afsk24_tx_hi_i, SUM_AFSK24_TX_HI_I); + sum -= convolution14_u8(buf, afsk24_tx_hi_q, SUM_AFSK24_TX_HI_Q); + return sum; +} + +extern __inline__ int do_filter_2400_s16(const short *buf) +{ + int sum = convolution14_s16(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I); + sum += convolution14_s16(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q); + sum -= convolution14_s16(buf, afsk24_tx_hi_i, SUM_AFSK24_TX_HI_I); + sum -= convolution14_s16(buf, afsk24_tx_hi_q, SUM_AFSK24_TX_HI_Q); + return sum; +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_2400_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) +{ + struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d); + int j; + int sum; + unsigned char newsample; + + for (; buflen > 0; buflen--, buf++) { + sum = do_filter_2400_u8(buf); + st->dcd_shreg <<= 1; + st->bit_pll += AFSK24_BITPLL_INC; + newsample = (sum > 0); + if (st->last_sample ^ newsample) { + st->last_sample = newsample; + st->dcd_shreg |= 1; + if (st->bit_pll < (0x8000+AFSK24_BITPLL_INC/2)) + st->bit_pll += AFSK24_BITPLL_INC/2; + else + st->bit_pll -= AFSK24_BITPLL_INC/2; + j = /* 2 * */ hweight8(st->dcd_shreg & 0x1c) + - hweight16(st->dcd_shreg & 0x1e0); + st->dcd_sum0 += j; + } + hdlcdrv_channelbit(&sm->hdrv, st->last_sample); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 120; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->shreg >>= 1; + st->shreg |= (!(st->last_rxbit ^ + st->last_sample)) << 16; + st->last_rxbit = st->last_sample; + diag_trigger(sm); + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + } + diag_add(sm, (((int)*buf)-0x80) << 8, sum); + } +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_2400_s16(struct sm_state *sm, const short *buf, unsigned int buflen) +{ + struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d); + int j; + int sum; + unsigned char newsample; + + for (; buflen > 0; buflen--, buf++) { + sum = do_filter_2400_s16(buf); + st->dcd_shreg <<= 1; + st->bit_pll += AFSK24_BITPLL_INC; + newsample = (sum > 0); + if (st->last_sample ^ newsample) { + st->last_sample = newsample; + st->dcd_shreg |= 1; + if (st->bit_pll < (0x8000+AFSK24_BITPLL_INC/2)) + st->bit_pll += AFSK24_BITPLL_INC/2; + else + st->bit_pll -= AFSK24_BITPLL_INC/2; + j = /* 2 * */ hweight8(st->dcd_shreg & 0x1c) + - hweight16(st->dcd_shreg & 0x1e0); + st->dcd_sum0 += j; + } + hdlcdrv_channelbit(&sm->hdrv, st->last_sample); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 120; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->shreg >>= 1; + st->shreg |= (!(st->last_rxbit ^ + st->last_sample)) << 16; + st->last_rxbit = st->last_sample; + diag_trigger(sm); + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + } + diag_add(sm, *buf, sum); + } +} + +/* --------------------------------------------------------------------- */ + +static void demod_init_2400(struct sm_state *sm) +{ + struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d); + + st->dcd_time = 120; + st->dcd_sum0 = 2; +} + +/* --------------------------------------------------------------------- */ + +const struct modem_tx_info sm_afsk2400_7_tx = { + "afsk2400_7", sizeof(struct mod_state_afsk24), AFSK24_SAMPLERATE, 2400, + modulator_2400_u8, modulator_2400_s16, NULL +}; + +const struct modem_rx_info sm_afsk2400_7_rx = { + "afsk2400_7", sizeof(struct demod_state_afsk24), + AFSK24_SAMPLERATE, 2400, 14, AFSK24_SAMPLERATE/2400, + demodulator_2400_u8, demodulator_2400_s16, demod_init_2400 +}; + +/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.42/linux/drivers/net/soundmodem/sm_afsk2400_8.c linux/drivers/net/soundmodem/sm_afsk2400_8.c --- v2.1.42/linux/drivers/net/soundmodem/sm_afsk2400_8.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/soundmodem/sm_afsk2400_8.c Thu Jun 12 16:22:07 1997 @@ -0,0 +1,297 @@ +/*****************************************************************************/ + +/* + * sm_afsk2400_8.c -- soundcard radio modem driver, 2400 baud AFSK modem + * + * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + */ + +/* + * This driver is intended to be compatible with TCM3105 modems + * overclocked to 8MHz. The mark and space frequencies therefore + * lie at 3970 and 2165 Hz. + * Note that I do _not_ recommend the building of such links, I provide + * this only for the users who live in the coverage area of such + * a "legacy" link. + */ + +#include +#include "sm.h" +#include "sm_tbl_afsk2400_8.h" + +/* --------------------------------------------------------------------- */ + +struct demod_state_afsk24 { + unsigned int shreg; + unsigned int bit_pll; + unsigned char last_sample; + unsigned int dcd_shreg; + int dcd_sum0, dcd_sum1, dcd_sum2; + unsigned int dcd_time; + unsigned char last_rxbit; +}; + +struct mod_state_afsk24 { + unsigned int shreg; + unsigned char tx_bit; + unsigned int bit_pll; + unsigned int tx_seq; + unsigned int phinc; +}; + +/* --------------------------------------------------------------------- */ + +static const int dds_inc[2] = { AFSK24_TX_FREQ_LO*0x10000/AFSK24_SAMPLERATE, + AFSK24_TX_FREQ_HI*0x10000/AFSK24_SAMPLERATE }; + +static void modulator_2400_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) +{ + struct mod_state_afsk24 *st = (struct mod_state_afsk24 *)(&sm->m); + + for (; buflen > 0; buflen--, buf++) { + if (st->tx_seq < 0x5555) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1; + st->shreg >>= 1; + st->phinc = dds_inc[st->tx_bit & 1]; + } + st->tx_seq += 0x5555; + st->tx_seq &= 0xffff; + *buf = OFFSCOS(st->bit_pll); + st->bit_pll += st->phinc; + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_2400_s16(struct sm_state *sm, short *buf, unsigned int buflen) +{ + struct mod_state_afsk24 *st = (struct mod_state_afsk24 *)(&sm->m); + + for (; buflen > 0; buflen--, buf++) { + if (st->tx_seq < 0x5555) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1; + st->shreg >>= 1; + st->phinc = dds_inc[st->tx_bit & 1]; + } + st->tx_seq += 0x5555; + st->tx_seq &= 0xffff; + *buf = COS(st->bit_pll); + st->bit_pll += st->phinc; + } +} + +/* --------------------------------------------------------------------- */ + +extern __inline__ int convolution14_u8(const unsigned char *st, const int *coeff, int csum) +{ + int sum = -0x80 * csum; + + sum += (st[0] * coeff[0]); + sum += (st[-1] * coeff[1]); + sum += (st[-2] * coeff[2]); + sum += (st[-3] * coeff[3]); + sum += (st[-4] * coeff[4]); + sum += (st[-5] * coeff[5]); + sum += (st[-6] * coeff[6]); + sum += (st[-7] * coeff[7]); + sum += (st[-8] * coeff[8]); + sum += (st[-9] * coeff[9]); + sum += (st[-10] * coeff[10]); + sum += (st[-11] * coeff[11]); + sum += (st[-12] * coeff[12]); + sum += (st[-13] * coeff[13]); + + sum >>= 7; + return sum * sum; +} + +extern __inline__ int convolution14_s16(const short *st, const int *coeff, int csum) +{ + int sum = 0; + + sum += (st[0] * coeff[0]); + sum += (st[-1] * coeff[1]); + sum += (st[-2] * coeff[2]); + sum += (st[-3] * coeff[3]); + sum += (st[-4] * coeff[4]); + sum += (st[-5] * coeff[5]); + sum += (st[-6] * coeff[6]); + sum += (st[-7] * coeff[7]); + sum += (st[-8] * coeff[8]); + sum += (st[-9] * coeff[9]); + sum += (st[-10] * coeff[10]); + sum += (st[-11] * coeff[11]); + sum += (st[-12] * coeff[12]); + sum += (st[-13] * coeff[13]); + + sum >>= 15; + return sum * sum; +} + +extern __inline__ int do_filter_2400_u8(const unsigned char *buf) +{ + int sum = convolution14_u8(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I); + sum += convolution14_u8(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q); + sum -= convolution14_u8(buf, afsk24_tx_hi_i, SUM_AFSK24_TX_HI_I); + sum -= convolution14_u8(buf, afsk24_tx_hi_q, SUM_AFSK24_TX_HI_Q); + return sum; +} + +extern __inline__ int do_filter_2400_s16(const short *buf) +{ + int sum = convolution14_s16(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I); + sum += convolution14_s16(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q); + sum -= convolution14_s16(buf, afsk24_tx_hi_i, SUM_AFSK24_TX_HI_I); + sum -= convolution14_s16(buf, afsk24_tx_hi_q, SUM_AFSK24_TX_HI_Q); + return sum; +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_2400_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) +{ + struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d); + int j; + int sum; + unsigned char newsample; + + for (; buflen > 0; buflen--, buf++) { + sum = do_filter_2400_u8(buf); + st->dcd_shreg <<= 1; + st->bit_pll += AFSK24_BITPLL_INC; + newsample = (sum > 0); + if (st->last_sample ^ newsample) { + st->last_sample = newsample; + st->dcd_shreg |= 1; + if (st->bit_pll < (0x8000+AFSK24_BITPLL_INC/2)) + st->bit_pll += AFSK24_BITPLL_INC/2; + else + st->bit_pll -= AFSK24_BITPLL_INC/2; + j = /* 2 * */ hweight8(st->dcd_shreg & 0x1c) + - hweight16(st->dcd_shreg & 0x1e0); + st->dcd_sum0 += j; + } + hdlcdrv_channelbit(&sm->hdrv, st->last_sample); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 120; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->shreg >>= 1; + st->shreg |= (!(st->last_rxbit ^ + st->last_sample)) << 16; + st->last_rxbit = st->last_sample; + diag_trigger(sm); + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + } + diag_add(sm, (((int)*buf)-0x80) << 8, sum); + } +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_2400_s16(struct sm_state *sm, const short *buf, unsigned int buflen) +{ + struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d); + int j; + int sum; + unsigned char newsample; + + for (; buflen > 0; buflen--, buf++) { + sum = do_filter_2400_s16(buf); + st->dcd_shreg <<= 1; + st->bit_pll += AFSK24_BITPLL_INC; + newsample = (sum > 0); + if (st->last_sample ^ newsample) { + st->last_sample = newsample; + st->dcd_shreg |= 1; + if (st->bit_pll < (0x8000+AFSK24_BITPLL_INC/2)) + st->bit_pll += AFSK24_BITPLL_INC/2; + else + st->bit_pll -= AFSK24_BITPLL_INC/2; + j = /* 2 * */ hweight8(st->dcd_shreg & 0x1c) + - hweight16(st->dcd_shreg & 0x1e0); + st->dcd_sum0 += j; + } + hdlcdrv_channelbit(&sm->hdrv, st->last_sample); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 120; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->shreg >>= 1; + st->shreg |= (!(st->last_rxbit ^ + st->last_sample)) << 16; + st->last_rxbit = st->last_sample; + diag_trigger(sm); + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + } + diag_add(sm, *buf, sum); + } +} + +/* --------------------------------------------------------------------- */ + +static void demod_init_2400(struct sm_state *sm) +{ + struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d); + + st->dcd_time = 120; + st->dcd_sum0 = 2; +} + +/* --------------------------------------------------------------------- */ + +const struct modem_tx_info sm_afsk2400_8_tx = { + "afsk2400_8", sizeof(struct mod_state_afsk24), AFSK24_SAMPLERATE, 2400, + modulator_2400_u8, modulator_2400_s16, NULL +}; + +const struct modem_rx_info sm_afsk2400_8_rx = { + "afsk2400_8", sizeof(struct demod_state_afsk24), + AFSK24_SAMPLERATE, 2400, 14, AFSK24_SAMPLERATE/2400, + demodulator_2400_u8, demodulator_2400_s16, demod_init_2400 +}; + +/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.42/linux/drivers/net/soundmodem/sm_fsk9600.c linux/drivers/net/soundmodem/sm_fsk9600.c --- v2.1.42/linux/drivers/net/soundmodem/sm_fsk9600.c Thu May 29 21:53:07 1997 +++ linux/drivers/net/soundmodem/sm_fsk9600.c Thu Jun 12 16:22:07 1997 @@ -45,6 +45,8 @@ unsigned int shreg; unsigned long scram; unsigned char tx_bit; + unsigned char *txtbl; + unsigned int txphase; }; /* --------------------------------------------------------------------- */ @@ -62,30 +64,57 @@ /* --------------------------------------------------------------------- */ -static void modulator_9600_4(struct sm_state *sm, unsigned char *buf, int buflen) +static void modulator_9600_4_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) { struct mod_state_fsk96 *st = (struct mod_state_fsk96 *)(&sm->m); - int j; - const unsigned char *cp; - for (; buflen >= 4; buflen -= 4) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->scram = (st->scram << 1) | (st->scram & 1); - st->scram ^= !(st->shreg & 1); - st->shreg >>= 1; - if (st->scram & (SCRAM_TAP1 << 1)) - st->scram ^= SCRAM_TAPN << 1; - st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2))); - cp = fsk96_txfilt_4 + (st->tx_bit & 0xff); - for (j = 0; j < 4; j++, cp += 0x100) - *buf++ = *cp; + for (; buflen > 0; buflen--) { + if (!st->txphase++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->scram = (st->scram << 1) | (st->scram & 1); + st->scram ^= !(st->shreg & 1); + st->shreg >>= 1; + if (st->scram & (SCRAM_TAP1 << 1)) + st->scram ^= SCRAM_TAPN << 1; + st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2))); + st->txtbl = fsk96_txfilt_4 + (st->tx_bit & 0xff); + } + if (st->txphase >= 4) + st->txphase = 0; + *buf++ = *st->txtbl; + st->txtbl += 0x100; } } /* --------------------------------------------------------------------- */ -static void demodulator_9600_4(struct sm_state *sm, unsigned char *buf, int buflen) +static void modulator_9600_4_s16(struct sm_state *sm, short *buf, unsigned int buflen) +{ + struct mod_state_fsk96 *st = (struct mod_state_fsk96 *)(&sm->m); + + for (; buflen > 0; buflen--) { + if (!st->txphase++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->scram = (st->scram << 1) | (st->scram & 1); + st->scram ^= !(st->shreg & 1); + st->shreg >>= 1; + if (st->scram & (SCRAM_TAP1 << 1)) + st->scram ^= SCRAM_TAPN << 1; + st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2))); + st->txtbl = fsk96_txfilt_4 + (st->tx_bit & 0xff); + } + if (st->txphase >= 4) + st->txphase = 0; + *buf++ = ((*st->txtbl)-0x80) << 8; + st->txtbl += 0x100; + } +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_9600_4_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) { struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d); static const int pll_corr[2] = { -0x1000, 0x1000 }; @@ -133,30 +162,105 @@ /* --------------------------------------------------------------------- */ -static void modulator_9600_5(struct sm_state *sm, unsigned char *buf, int buflen) +static void demodulator_9600_4_s16(struct sm_state *sm, const short *buf, unsigned int buflen) +{ + struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d); + static const int pll_corr[2] = { -0x1000, 0x1000 }; + unsigned char curbit; + unsigned int descx; + + for (; buflen > 0; buflen--, buf++) { + st->dcd_shreg <<= 1; + st->bit_pll += 0x4000; + curbit = (*buf >= 0); + if (st->last_sample ^ curbit) { + st->dcd_shreg |= 1; + st->bit_pll += pll_corr[st->bit_pll < 0xa000]; + st->dcd_sum0 += 8 * hweight8(st->dcd_shreg & 0x0c) - + !!(st->dcd_shreg & 0x10); + } + st->last_sample = curbit; + hdlcdrv_channelbit(&sm->hdrv, st->last_sample); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 240; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->descram = (st->descram << 1) | curbit; + descx = st->descram ^ (st->descram >> 1); + descx ^= ((descx >> DESCRAM_TAPSH1) ^ + (descx >> DESCRAM_TAPSH2)); + st->shreg >>= 1; + st->shreg |= (!(descx & 1)) << 16; + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + diag_trigger(sm); + } + diag_add_one(sm, *buf); + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_9600_5_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) { struct mod_state_fsk96 *st = (struct mod_state_fsk96 *)(&sm->m); - int j; - const unsigned char *cp; - for (; buflen >= 5; buflen -= 5) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->scram = (st->scram << 1) | (st->scram & 1); - st->scram ^= !(st->shreg & 1); - st->shreg >>= 1; - if (st->scram & (SCRAM_TAP1 << 1)) - st->scram ^= SCRAM_TAPN << 1; - st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2))); - cp = fsk96_txfilt_5 + (st->tx_bit & 0xff); - for (j = 0; j < 5; j++, cp += 0x100) - *buf++ = *cp; + for (; buflen > 0; buflen--) { + if (!st->txphase++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->scram = (st->scram << 1) | (st->scram & 1); + st->scram ^= !(st->shreg & 1); + st->shreg >>= 1; + if (st->scram & (SCRAM_TAP1 << 1)) + st->scram ^= SCRAM_TAPN << 1; + st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2))); + st->txtbl = fsk96_txfilt_5 + (st->tx_bit & 0xff); + } + if (st->txphase >= 5) + st->txphase = 0; + *buf++ = *st->txtbl; + st->txtbl += 0x100; } } /* --------------------------------------------------------------------- */ -static void demodulator_9600_5(struct sm_state *sm, unsigned char *buf, int buflen) +static void modulator_9600_5_s16(struct sm_state *sm, short *buf, unsigned int buflen) +{ + struct mod_state_fsk96 *st = (struct mod_state_fsk96 *)(&sm->m); + + for (; buflen > 0; buflen--) { + if (!st->txphase++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->scram = (st->scram << 1) | (st->scram & 1); + st->scram ^= !(st->shreg & 1); + st->shreg >>= 1; + if (st->scram & (SCRAM_TAP1 << 1)) + st->scram ^= SCRAM_TAPN << 1; + st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2))); + st->txtbl = fsk96_txfilt_5 + (st->tx_bit & 0xff); + } + if (st->txphase >= 5) + st->txphase = 0; + *buf++ = ((*st->txtbl)-0x80)<<8; + st->txtbl += 0x100; + } +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_9600_5_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) { struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d); static const int pll_corr[2] = { -0x1000, 0x1000 }; @@ -204,6 +308,54 @@ /* --------------------------------------------------------------------- */ +static void demodulator_9600_5_s16(struct sm_state *sm, const short *buf, unsigned int buflen) +{ + struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d); + static const int pll_corr[2] = { -0x1000, 0x1000 }; + unsigned char curbit; + unsigned int descx; + + for (; buflen > 0; buflen--, buf++) { + st->dcd_shreg <<= 1; + st->bit_pll += 0x3333; + curbit = (*buf >= 0); + if (st->last_sample ^ curbit) { + st->dcd_shreg |= 1; + st->bit_pll += pll_corr[st->bit_pll < 0x9999]; + st->dcd_sum0 += 16 * hweight8(st->dcd_shreg & 0x0c) - + hweight8(st->dcd_shreg & 0x70); + } + st->last_sample = curbit; + hdlcdrv_channelbit(&sm->hdrv, st->last_sample); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 240; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->descram = (st->descram << 1) | curbit; + descx = st->descram ^ (st->descram >> 1); + descx ^= ((descx >> DESCRAM_TAPSH1) ^ + (descx >> DESCRAM_TAPSH2)); + st->shreg >>= 1; + st->shreg |= (!(descx & 1)) << 16; + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + diag_trigger(sm); + } + diag_add_one(sm, *buf); + } +} + +/* --------------------------------------------------------------------- */ + static void demod_init_9600(struct sm_state *sm) { struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d); @@ -215,25 +367,25 @@ /* --------------------------------------------------------------------- */ const struct modem_tx_info sm_fsk9600_4_tx = { - "fsk9600", sizeof(struct mod_state_fsk96), 38400, 9600, 4, - modulator_9600_4, NULL + "fsk9600", sizeof(struct mod_state_fsk96), 38400, 9600, + modulator_9600_4_u8, modulator_9600_4_s16, NULL }; const struct modem_rx_info sm_fsk9600_4_rx = { - "fsk9600", sizeof(struct demod_state_fsk96), 38400, 9600, 4, 4, - demodulator_9600_4, demod_init_9600 + "fsk9600", sizeof(struct demod_state_fsk96), 38400, 9600, 1, 4, + demodulator_9600_4_u8, demodulator_9600_4_s16, demod_init_9600 }; /* --------------------------------------------------------------------- */ const struct modem_tx_info sm_fsk9600_5_tx = { - "fsk9600", sizeof(struct mod_state_fsk96), 48000, 9600, 5, - modulator_9600_5, NULL + "fsk9600", sizeof(struct mod_state_fsk96), 48000, 9600, + modulator_9600_5_u8, modulator_9600_5_s16, NULL }; const struct modem_rx_info sm_fsk9600_5_rx = { - "fsk9600", sizeof(struct demod_state_fsk96), 48000, 9600, 5, 5, - demodulator_9600_5, demod_init_9600 + "fsk9600", sizeof(struct demod_state_fsk96), 48000, 9600, 1, 5, + demodulator_9600_5_u8, demodulator_9600_5_s16, demod_init_9600 }; /* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.42/linux/drivers/net/soundmodem/sm_hapn4800.c linux/drivers/net/soundmodem/sm_hapn4800.c --- v2.1.42/linux/drivers/net/soundmodem/sm_hapn4800.c Thu May 29 21:53:07 1997 +++ linux/drivers/net/soundmodem/sm_hapn4800.c Thu Jun 12 16:22:07 1997 @@ -49,133 +49,290 @@ unsigned int dcd_shreg; int dcd_sum0, dcd_sum1, dcd_sum2; unsigned int dcd_time; - int inphist[5]; int lvlhi, lvllo; }; struct mod_state_hapn48 { unsigned int shreg; unsigned char tx_bit; + unsigned int tx_seq; + const unsigned char *tbl; }; /* --------------------------------------------------------------------- */ -static void modulator_hapn4800_10(struct sm_state *sm, unsigned char *buf, int buflen) +static void modulator_hapn4800_10_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) { struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); - int j; - const unsigned char *cp; - for (; buflen >= 10; buflen -= 10) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->tx_bit = ((st->tx_bit << 1) | - (st->tx_bit & 1)); - st->tx_bit ^= (!(st->shreg & 1)); - st->shreg >>= 1; - cp = hapn48_txfilt_10 + (st->tx_bit & 0xf); - for (j = 0; j < 10; j++, cp += 0x10) - *buf++ = *cp; + for (; buflen > 0; buflen--, buf++) { + if (!st->tx_seq++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = ((st->tx_bit << 1) | + (st->tx_bit & 1)); + st->tx_bit ^= (!(st->shreg & 1)); + st->shreg >>= 1; + st->tbl = hapn48_txfilt_10 + (st->tx_bit & 0xf); + } + if (st->tx_seq >= 10) + st->tx_seq = 0; + *buf = *st->tbl; + st->tbl += 0x10; + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_hapn4800_10_s16(struct sm_state *sm, short *buf, unsigned int buflen) +{ + struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); + + for (; buflen > 0; buflen--, buf++) { + if (!st->tx_seq++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = ((st->tx_bit << 1) | + (st->tx_bit & 1)); + st->tx_bit ^= (!(st->shreg & 1)); + st->shreg >>= 1; + st->tbl = hapn48_txfilt_10 + (st->tx_bit & 0xf); + } + if (st->tx_seq >= 10) + st->tx_seq = 0; + *buf = ((*st->tbl)-0x80)<<8; + st->tbl += 0x10; + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_hapn4800_8_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) +{ + struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); + + for (; buflen > 0; buflen--, buf++) { + if (!st->tx_seq++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1); + st->tx_bit ^= !(st->shreg & 1); + st->shreg >>= 1; + st->tbl = hapn48_txfilt_8 + (st->tx_bit & 0xf); + } + if (st->tx_seq >= 8) + st->tx_seq = 0; + *buf = *st->tbl; + st->tbl += 0x10; } } /* --------------------------------------------------------------------- */ -static void modulator_hapn4800_8(struct sm_state *sm, unsigned char *buf, int buflen) +static void modulator_hapn4800_8_s16(struct sm_state *sm, short *buf, unsigned int buflen) { struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); - int j; - const unsigned char *cp; - for (; buflen >= 8; buflen -= 8) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1); - st->tx_bit ^= !(st->shreg & 1); - st->shreg >>= 1; - cp = hapn48_txfilt_8 + (st->tx_bit & 0xf); - for (j = 0; j < 8; j++, cp += 0x10) - *buf++ = *cp; + for (; buflen > 0; buflen--, buf++) { + if (!st->tx_seq++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1); + st->tx_bit ^= !(st->shreg & 1); + st->shreg >>= 1; + st->tbl = hapn48_txfilt_8 + (st->tx_bit & 0xf); + } + if (st->tx_seq >= 8) + st->tx_seq = 0; + *buf = ((*st->tbl)-0x80)<<8; + st->tbl += 0x10; } } /* --------------------------------------------------------------------- */ -static void modulator_hapn4800_pm10(struct sm_state *sm, unsigned char *buf, int buflen) +static void modulator_hapn4800_pm10_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) { struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); - int j; - const unsigned char *cp; - for (; buflen >= 10; buflen -= 10) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->tx_bit = ((st->tx_bit << 1) | - (st->tx_bit & 1)); - st->tx_bit ^= (!(st->shreg & 1)); - st->shreg >>= 1; - cp = hapn48_txfilt_pm10 + (st->tx_bit & 0xf); - for (j = 0; j < 10; j++, cp += 0x10) - *buf++ = *cp; + for (; buflen > 0; buflen--, buf++) { + if (!st->tx_seq++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = ((st->tx_bit << 1) | + (st->tx_bit & 1)); + st->tx_bit ^= (!(st->shreg & 1)); + st->shreg >>= 1; + st->tbl = hapn48_txfilt_pm10 + (st->tx_bit & 0xf); + } + if (st->tx_seq >= 10) + st->tx_seq = 0; + *buf = *st->tbl; + st->tbl += 0x10; } } /* --------------------------------------------------------------------- */ -static void modulator_hapn4800_pm8(struct sm_state *sm, unsigned char *buf, int buflen) +static void modulator_hapn4800_pm10_s16(struct sm_state *sm, short *buf, unsigned int buflen) { struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); - int j; - const unsigned char *cp; - for (; buflen >= 8; buflen -= 8) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1); - st->tx_bit ^= !(st->shreg & 1); - st->shreg >>= 1; - cp = hapn48_txfilt_pm8 + (st->tx_bit & 0xf); - for (j = 0; j < 8; j++, cp += 0x10) - *buf++ = *cp; + for (; buflen > 0; buflen--, buf++) { + if (!st->tx_seq++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = ((st->tx_bit << 1) | + (st->tx_bit & 1)); + st->tx_bit ^= (!(st->shreg & 1)); + st->shreg >>= 1; + st->tbl = hapn48_txfilt_pm10 + (st->tx_bit & 0xf); + } + if (st->tx_seq >= 10) + st->tx_seq = 0; + *buf = ((*st->tbl)-0x80)<<8; + st->tbl += 0x10; + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_hapn4800_pm8_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) +{ + struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); + + for (; buflen > 0; buflen--, buf++) { + if (!st->tx_seq++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1); + st->tx_bit ^= !(st->shreg & 1); + st->shreg >>= 1; + st->tbl = hapn48_txfilt_pm8 + (st->tx_bit & 0xf); + } + if (st->tx_seq >= 8) + st->tx_seq = 0; + *buf = *st->tbl; + st->tbl += 0x10; + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_hapn4800_pm8_s16(struct sm_state *sm, short *buf, unsigned int buflen) +{ + struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); + + for (; buflen > 0; buflen--, buf++) { + if (!st->tx_seq++) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1); + st->tx_bit ^= !(st->shreg & 1); + st->shreg >>= 1; + st->tbl = hapn48_txfilt_pm8 + (st->tx_bit & 0xf); + } + if (st->tx_seq >= 8) + st->tx_seq = 0; + *buf = ((*st->tbl)-0x80)<<8; + st->tbl += 0x10; + } +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_hapn4800_10_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) +{ + struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d); + static const int pll_corr[2] = { -0x800, 0x800 }; + int curst, cursync; + int inv; + + for (; buflen > 0; buflen--, buf++) { + inv = ((int)(buf[-2])-0x80) << 8; + st->lvlhi = (st->lvlhi * 65309) >> 16; /* decay */ + st->lvllo = (st->lvllo * 65309) >> 16; /* decay */ + if (inv > st->lvlhi) + st->lvlhi = inv; + if (inv < st->lvllo) + st->lvllo = inv; + if (buflen & 1) + st->dcd_shreg <<= 1; + st->bit_pll += 0x199a; + curst = cursync = 0; + if (inv > st->lvlhi >> 1) { + curst = 1; + cursync = (buf[-2] > buf[-1] && buf[-2] > buf[-3] && + buf[-2] > buf[-0] && buf[-2] > buf[-4]); + } else if (inv < st->lvllo >> 1) { + curst = -1; + cursync = (buf[-2] < buf[-1] && buf[-2] < buf[-3] && + buf[-2] < buf[-0] && buf[-2] < buf[-4]); + } + if (cursync) { + st->dcd_shreg |= cursync; + st->bit_pll += pll_corr[((st->bit_pll - 0x8000u) & 0xffffu) < 0x8ccdu]; + st->dcd_sum0 += 16 * hweight32(st->dcd_shreg & 0x18c6318c) - + hweight32(st->dcd_shreg & 0xe739ce70); + } + hdlcdrv_channelbit(&sm->hdrv, cursync); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 240; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->last_bit2 = st->last_bit; + if (curst < 0) + st->last_bit = 0; + else if (curst > 0) + st->last_bit = 1; + st->shreg >>= 1; + st->shreg |= ((st->last_bit ^ st->last_bit2 ^ 1) & 1) << 16; + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + diag_trigger(sm); + } + diag_add_one(sm, inv); } } /* --------------------------------------------------------------------- */ -static void demodulator_hapn4800_10(struct sm_state *sm, unsigned char *buf, int buflen) +static void demodulator_hapn4800_10_s16(struct sm_state *sm, const short *buf, unsigned int buflen) { struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d); static const int pll_corr[2] = { -0x800, 0x800 }; int curst, cursync; + int inv; for (; buflen > 0; buflen--, buf++) { - st->inphist[4] = st->inphist[3]; - st->inphist[3] = st->inphist[2]; - st->inphist[2] = st->inphist[1]; - st->inphist[1] = st->inphist[0]; - st->inphist[0] = ((int)(*buf)-0x80) << 8; + inv = buf[-2]; st->lvlhi = (st->lvlhi * 65309) >> 16; /* decay */ st->lvllo = (st->lvllo * 65309) >> 16; /* decay */ - if (st->inphist[2] > st->lvlhi) - st->lvlhi = st->inphist[2]; - if (st->inphist[2] < st->lvllo) - st->lvllo = st->inphist[2]; + if (inv > st->lvlhi) + st->lvlhi = inv; + if (inv < st->lvllo) + st->lvllo = inv; if (buflen & 1) st->dcd_shreg <<= 1; st->bit_pll += 0x199a; curst = cursync = 0; - if (st->inphist[2] > st->lvlhi >> 1) { + if (inv > st->lvlhi >> 1) { curst = 1; - cursync = (st->inphist[2] > st->inphist[1] && - st->inphist[2] > st->inphist[3] && - st->inphist[2] > st->inphist[0] && - st->inphist[2] > st->inphist[4]); - } else if (st->inphist[2] < st->lvllo >> 1) { + cursync = (buf[-2] > buf[-1] && buf[-2] > buf[-3] && + buf[-2] > buf[-0] && buf[-2] > buf[-4]); + } else if (inv < st->lvllo >> 1) { curst = -1; - cursync = (st->inphist[2] < st->inphist[1] && - st->inphist[2] < st->inphist[3] && - st->inphist[2] < st->inphist[0] && - st->inphist[2] < st->inphist[4]); + cursync = (buf[-2] < buf[-1] && buf[-2] < buf[-3] && + buf[-2] < buf[-0] && buf[-2] < buf[-4]); } if (cursync) { st->dcd_shreg |= cursync; @@ -208,46 +365,104 @@ } diag_trigger(sm); } - diag_add_one(sm, st->inphist[2]); + diag_add_one(sm, inv); + } +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_hapn4800_8_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) +{ + struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d); + static const int pll_corr[2] = { -0x800, 0x800 }; + int curst, cursync; + int inv; + + for (; buflen > 0; buflen--, buf++) { + inv = ((int)(buf[-2])-0x80) << 8; + st->lvlhi = (st->lvlhi * 65309) >> 16; /* decay */ + st->lvllo = (st->lvllo * 65309) >> 16; /* decay */ + if (inv > st->lvlhi) + st->lvlhi = inv; + if (inv < st->lvllo) + st->lvllo = inv; + if (buflen & 1) + st->dcd_shreg <<= 1; + st->bit_pll += 0x2000; + curst = cursync = 0; + if (inv > st->lvlhi >> 1) { + curst = 1; + cursync = (buf[-2] > buf[-1] && buf[-2] > buf[-3] && + buf[-2] > buf[-0] && buf[-2] > buf[-4]); + } else if (inv < st->lvllo >> 1) { + curst = -1; + cursync = (buf[-2] < buf[-1] && buf[-2] < buf[-3] && + buf[-2] < buf[-0] && buf[-2] < buf[-4]); + } + if (cursync) { + st->dcd_shreg |= cursync; + st->bit_pll += pll_corr[((st->bit_pll - 0x8000u) & 0xffffu) < 0x9000u]; + st->dcd_sum0 += 16 * hweight32(st->dcd_shreg & 0x44444444) - + hweight32(st->dcd_shreg & 0xbbbbbbbb); + } + hdlcdrv_channelbit(&sm->hdrv, cursync); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 240; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->last_bit2 = st->last_bit; + if (curst < 0) + st->last_bit = 0; + else if (curst > 0) + st->last_bit = 1; + st->shreg >>= 1; + st->shreg |= ((st->last_bit ^ st->last_bit2 ^ 1) & 1) << 16; + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + diag_trigger(sm); + } + diag_add_one(sm, inv); } } /* --------------------------------------------------------------------- */ -static void demodulator_hapn4800_8(struct sm_state *sm, unsigned char *buf, int buflen) +static void demodulator_hapn4800_8_s16(struct sm_state *sm, const short *buf, unsigned int buflen) { struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d); static const int pll_corr[2] = { -0x800, 0x800 }; int curst, cursync; + int inv; for (; buflen > 0; buflen--, buf++) { - st->inphist[4] = st->inphist[3]; - st->inphist[3] = st->inphist[2]; - st->inphist[2] = st->inphist[1]; - st->inphist[1] = st->inphist[0]; - st->inphist[0] = ((int)(*buf)-0x80) << 8; + inv = buf[-2]; st->lvlhi = (st->lvlhi * 65309) >> 16; /* decay */ st->lvllo = (st->lvllo * 65309) >> 16; /* decay */ - if (st->inphist[2] > st->lvlhi) - st->lvlhi = st->inphist[2]; - if (st->inphist[2] < st->lvllo) - st->lvllo = st->inphist[2]; + if (inv > st->lvlhi) + st->lvlhi = inv; + if (inv < st->lvllo) + st->lvllo = inv; if (buflen & 1) st->dcd_shreg <<= 1; st->bit_pll += 0x2000; curst = cursync = 0; - if (st->inphist[2] > st->lvlhi >> 1) { + if (inv > st->lvlhi >> 1) { curst = 1; - cursync = (st->inphist[2] > st->inphist[1] && - st->inphist[2] > st->inphist[3] && - st->inphist[2] > st->inphist[0] && - st->inphist[2] > st->inphist[4]); - } else if (st->inphist[2] < st->lvllo >> 1) { + cursync = (buf[-2] > buf[-1] && buf[-2] > buf[-3] && + buf[-2] > buf[-0] && buf[-2] > buf[-4]); + } else if (inv < st->lvllo >> 1) { curst = -1; - cursync = (st->inphist[2] < st->inphist[1] && - st->inphist[2] < st->inphist[3] && - st->inphist[2] < st->inphist[0] && - st->inphist[2] < st->inphist[4]); + cursync = (buf[-2] < buf[-1] && buf[-2] < buf[-3] && + buf[-2] < buf[-0] && buf[-2] < buf[-4]); } if (cursync) { st->dcd_shreg |= cursync; @@ -280,7 +495,7 @@ } diag_trigger(sm); } - diag_add_one(sm, st->inphist[2]); + diag_add_one(sm, inv); } } @@ -297,51 +512,49 @@ /* --------------------------------------------------------------------- */ const struct modem_tx_info sm_hapn4800_8_tx = { - "hapn4800", sizeof(struct mod_state_hapn48), - 38400, 4800, 8, modulator_hapn4800_8, NULL + "hapn4800", sizeof(struct mod_state_hapn48), 38400, 4800, + modulator_hapn4800_8_u8, modulator_hapn4800_8_s16, NULL }; const struct modem_rx_info sm_hapn4800_8_rx = { - "hapn4800", sizeof(struct demod_state_hapn48), - 38400, 4800, 8, 8, demodulator_hapn4800_8, demod_init_hapn4800 + "hapn4800", sizeof(struct demod_state_hapn48), 38400, 4800, 5, 8, + demodulator_hapn4800_8_u8, demodulator_hapn4800_8_s16, demod_init_hapn4800 }; /* --------------------------------------------------------------------- */ const struct modem_tx_info sm_hapn4800_10_tx = { - "hapn4800", sizeof(struct mod_state_hapn48), - 48000, 4800, 10, - modulator_hapn4800_10, NULL + "hapn4800", sizeof(struct mod_state_hapn48), 48000, 4800, + modulator_hapn4800_10_u8, modulator_hapn4800_10_s16, NULL }; const struct modem_rx_info sm_hapn4800_10_rx = { - "hapn4800", sizeof(struct demod_state_hapn48), - 48000, 4800, 10, 10, demodulator_hapn4800_10, demod_init_hapn4800 + "hapn4800", sizeof(struct demod_state_hapn48), 48000, 4800, 5, 10, + demodulator_hapn4800_10_u8, demodulator_hapn4800_10_s16, demod_init_hapn4800 }; /* --------------------------------------------------------------------- */ const struct modem_tx_info sm_hapn4800_pm8_tx = { - "hapn4800pm", sizeof(struct mod_state_hapn48), - 38400, 4800, 8, modulator_hapn4800_pm8, NULL + "hapn4800pm", sizeof(struct mod_state_hapn48), 38400, 4800, + modulator_hapn4800_pm8_u8, modulator_hapn4800_pm8_s16, NULL }; const struct modem_rx_info sm_hapn4800_pm8_rx = { - "hapn4800pm", sizeof(struct demod_state_hapn48), - 38400, 4800, 8, 8, demodulator_hapn4800_8, demod_init_hapn4800 + "hapn4800pm", sizeof(struct demod_state_hapn48), 38400, 4800, 5, 8, + demodulator_hapn4800_8_u8, demodulator_hapn4800_8_s16, demod_init_hapn4800 }; /* --------------------------------------------------------------------- */ const struct modem_tx_info sm_hapn4800_pm10_tx = { - "hapn4800pm", sizeof(struct mod_state_hapn48), - 48000, 4800, 10, - modulator_hapn4800_pm10, NULL + "hapn4800pm", sizeof(struct mod_state_hapn48), 48000, 4800, + modulator_hapn4800_pm10_u8, modulator_hapn4800_pm10_s16, NULL }; const struct modem_rx_info sm_hapn4800_pm10_rx = { - "hapn4800pm", sizeof(struct demod_state_hapn48), - 48000, 4800, 10, 10, demodulator_hapn4800_10, demod_init_hapn4800 + "hapn4800pm", sizeof(struct demod_state_hapn48), 48000, 4800, 5, 10, + demodulator_hapn4800_10_u8, demodulator_hapn4800_10_s16, demod_init_hapn4800 }; /* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.42/linux/drivers/net/soundmodem/sm_sbc.c linux/drivers/net/soundmodem/sm_sbc.c --- v2.1.42/linux/drivers/net/soundmodem/sm_sbc.c Thu May 29 21:53:07 1997 +++ linux/drivers/net/soundmodem/sm_sbc.c Thu Jun 12 16:22:07 1997 @@ -26,12 +26,14 @@ */ #include +#include #include #include #include #include #include #include "sm.h" +#include "smdma.h" /* --------------------------------------------------------------------- */ @@ -81,12 +83,6 @@ unsigned char revhi, revlo; unsigned char fmt[2]; unsigned int sr[2]; - unsigned int dmabuflen; - unsigned char *dmabuf; - unsigned char *dmabuf2; - unsigned char dmabufidx; - unsigned char dma2bufidx; - unsigned char ptt; }; #define SCSTATE ((struct sc_state_sbc *)(&sm->hw)) @@ -136,6 +132,7 @@ #define SBC4_OUT8_AI 0xc6 #define SBC4_IN8_AI 0xce #define SBC4_MODE_UNS_MONO 0x00 +#define SBC4_MODE_SIGN_MONO 0x10 #define SBC4_OUT16_AI 0xb6 #define SBC4_IN16_AI 0xbe @@ -260,9 +257,8 @@ realdma = inb(DSP_MIXER_DATA(dev->base_addr)); restore_flags(flags); if ((~realirq) & irqreg || (~realdma) & dmareg) { - printk(KERN_ERR "%s: sbc resource registers cannot be set; " - "PnP device and IRQ/DMA specified wrongly?\n", - sm_drvname); + printk(KERN_ERR "%s: sbc resource registers cannot be set; PnP device " + "and IRQ/DMA specified wrongly?\n", sm_drvname); return -EINVAL; } return 0; @@ -292,41 +288,31 @@ { SBC_HI_INPUT_AUTOINIT, SBC_HI_OUTPUT_AUTOINIT } }; static const unsigned char sbc4mode[2] = { SBC4_IN8_AI, SBC4_OUT8_AI }; - static const unsigned char dmamode[2] = { - DMA_MODE_READ | DMA_MODE_AUTOINIT, DMA_MODE_WRITE | DMA_MODE_AUTOINIT - }; static const unsigned char sbcskr[2] = { SBC_SPEAKER_OFF, SBC_SPEAKER_ON }; - unsigned long dmabufaddr = virt_to_bus(SCSTATE->dmabuf); + unsigned int nsamps; send = !!send; if (!reset_dsp(dev)) { printk(KERN_ERR "%s: sbc: cannot reset sb dsp\n", sm_drvname); return; } - if ((dmabufaddr & 0xffff) + SCSTATE->dmabuflen > 0x10000) - panic("sm: DMA buffer violates DMA boundary!"); save_flags(flags); cli(); sbc_int_ack_8bit(dev); write_dsp(dev, SBC_SAMPLE_RATE); /* set sampling rate */ write_dsp(dev, SCSTATE->fmt[send]); write_dsp(dev, sbcskr[send]); - disable_dma(dev->dma); - clear_dma_ff(dev->dma); - set_dma_mode(dev->dma, dmamode[send]); - set_dma_addr(dev->dma, dmabufaddr); - set_dma_count(dev->dma, SCSTATE->dmabuflen); - enable_dma(dev->dma); + nsamps = dma_setup(sm, send, dev->dma) - 1; sbc_int_ack_8bit(dev); if (SCSTATE->revhi >= 4) { write_dsp(dev, sbc4mode[send]); write_dsp(dev, SBC4_MODE_UNS_MONO); - write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff); - write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) >> 8); + write_dsp(dev, nsamps & 0xff); + write_dsp(dev, nsamps >> 8); } else { write_dsp(dev, SBC_BLOCKSIZE); - write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff); - write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) >> 8); + write_dsp(dev, nsamps & 0xff); + write_dsp(dev, nsamps >> 8); write_dsp(dev, sbcmode[SCSTATE->fmt[send] >= 180][send]); /* hispeed mode if sample rate > 13kHz */ } @@ -339,53 +325,41 @@ { struct device *dev = (struct device *)dev_id; struct sm_state *sm = (struct sm_state *)dev->priv; - unsigned char new_ptt; - unsigned char *buf; + unsigned int curfrag; if (!dev || !sm || sm->hdrv.magic != HDLCDRV_MAGIC) return; - new_ptt = hdlcdrv_ptt(&sm->hdrv); + cli(); sbc_int_ack_8bit(dev); - buf = SCSTATE->dmabuf; - if (SCSTATE->dmabufidx) - buf += SCSTATE->dmabuflen/2; - SCSTATE->dmabufidx = !SCSTATE->dmabufidx; + disable_dma(dev->dma); + clear_dma_ff(dev->dma); + dma_ptr(sm, sm->dma.ptt_cnt > 0, dev->dma, &curfrag); + enable_dma(dev->dma); sm_int_freq(sm); sti(); - if (new_ptt && !SCSTATE->ptt) { - /* starting to transmit */ - disable_dma(dev->dma); - SCSTATE->dmabufidx = 0; - time_exec(sm->debug_vals.demod_cyc, - sm->mode_rx->demodulator(sm, buf, SCSTATE->dmabuflen/2)); - time_exec(sm->debug_vals.mod_cyc, - sm->mode_tx->modulator(sm, SCSTATE->dmabuf, - SCSTATE->dmabuflen/2)); - setup_dma_dsp(dev, sm, 1); - time_exec(sm->debug_vals.mod_cyc, - sm->mode_tx->modulator(sm, SCSTATE->dmabuf + - SCSTATE->dmabuflen/2, - SCSTATE->dmabuflen/2)); - } else if (SCSTATE->ptt == 1 && !new_ptt) { + if (sm->dma.ptt_cnt <= 0) { + dma_receive(sm, curfrag); + if (hdlcdrv_ptt(&sm->hdrv)) { + /* starting to transmit */ + disable_dma(dev->dma); + dma_start_transmit(sm); + setup_dma_dsp(dev, sm, 1); + dma_transmit(sm); + } + } else if (dma_end_transmit(sm, curfrag)) { /* stopping transmission */ disable_dma(dev->dma); - SCSTATE->dmabufidx = 0; + sti(); + dma_init_receive(sm); setup_dma_dsp(dev, sm, 0); - SCSTATE->ptt = 0; - } else if (SCSTATE->ptt) { - SCSTATE->ptt--; - time_exec(sm->debug_vals.mod_cyc, - sm->mode_tx->modulator(sm, buf, SCSTATE->dmabuflen/2)); } else { - time_exec(sm->debug_vals.demod_cyc, - sm->mode_rx->demodulator(sm, buf, SCSTATE->dmabuflen/2)); + dma_transmit(sm); hdlcdrv_arbitrate(dev, &sm->hdrv); } - if (new_ptt) - SCSTATE->ptt = 2; sm_output_status(sm); hdlcdrv_transmitter(dev, &sm->hdrv); hdlcdrv_receiver(dev, &sm->hdrv); + } /* --------------------------------------------------------------------- */ @@ -393,6 +367,7 @@ static int sbc_open(struct device *dev, struct sm_state *sm) { int err; + unsigned int dmasz, u; if (sizeof(sm->m) < sizeof(struct sc_state_sbc)) { printk(KERN_ERR "sm sbc: sbc state too big: %d > %d\n", @@ -409,12 +384,17 @@ /* * check if a card is available */ - if (!reset_dsp(dev)) + if (!reset_dsp(dev)) { + printk(KERN_ERR "%s: sbc: no card at io address 0x%lx\n", + sm_drvname, dev->base_addr); return -ENODEV; + } write_dsp(dev, SBC_GET_REVISION); if (!read_dsp(dev, &SCSTATE->revhi) || !read_dsp(dev, &SCSTATE->revlo)) return -ENODEV; + printk(KERN_INFO "%s: SoundBlaster DSP revision %d.%d\n", sm_drvname, + SCSTATE->revhi, SCSTATE->revlo); if (SCSTATE->revhi < 2) { printk(KERN_ERR "%s: your card is an antiquity, at least DSP " "rev 2.00 required\n", sm_drvname); @@ -435,9 +415,19 @@ /* * initialize some variables */ - if (!(SCSTATE->dmabuf = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA))) + dma_init_receive(sm); + dmasz = (NUM_FRAGMENTS + 1) * sm->dma.ifragsz; + if (sm->dma.i16bit) + dmasz <<= 1; + u = NUM_FRAGMENTS * sm->dma.ofragsz; + if (sm->dma.o16bit) + u <<= 1; + if (u > dmasz) + dmasz = u; + if (!(sm->dma.ibuf = sm->dma.obuf = kmalloc(dmasz, GFP_KERNEL | GFP_DMA))) return -ENOMEM; - SCSTATE->dmabufidx = SCSTATE->ptt = 0; + dma_init_transmit(sm); + dma_init_receive(sm); memset(&sm->m, 0, sizeof(sm->m)); memset(&sm->d, 0, sizeof(sm->d)); @@ -447,13 +437,13 @@ sm->mode_rx->init(sm); if (request_dma(dev->dma, sm->hwdrv->hw_name)) { - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); + kfree_s(sm->dma.obuf, dmasz); return -EBUSY; } if (request_irq(dev->irq, sbc_interrupt, SA_INTERRUPT, sm->hwdrv->hw_name, dev)) { free_dma(dev->dma); - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); + kfree_s(sm->dma.obuf, dmasz); return -EBUSY; } request_region(dev->base_addr, SBC_EXTENT, sm->hwdrv->hw_name); @@ -475,7 +465,7 @@ free_irq(dev->irq, dev); free_dma(dev->dma); release_region(dev->base_addr, SBC_EXTENT); - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); + kfree(sm->dma.obuf); return 0; } @@ -486,7 +476,6 @@ char *cp = strchr(mode, '.'); const struct modem_tx_info **mtp = sm_modem_tx_table; const struct modem_rx_info **mrp; - int dv; if (!strcmp(mode, "off")) { sm->mode_tx = NULL; @@ -507,12 +496,16 @@ continue; if ((*mtp)->srate < 5000 || (*mtp)->srate > 44100) continue; + if (!(*mtp)->modulator_u8) + continue; for (mrp = sm_modem_rx_table; *mrp; mrp++) { if ((*mrp)->loc_storage > sizeof(sm->d)) { printk(KERN_ERR "%s: insufficient storage for demodulator %s (%d)\n", sm_drvname, (*mrp)->name, (*mrp)->loc_storage); continue; } + if (!(*mrp)->demodulator_u8) + continue; if ((*mrp)->name && !strcmp((*mrp)->name, cp) && (*mrp)->srate >= 5000 && (*mrp)->srate <= 44100) { sm->mode_tx = *mtp; @@ -521,11 +514,11 @@ sm->mode_rx->srate); SCSTATE->fmt[1] = 256-((1000000L+sm->mode_tx->srate/2)/ sm->mode_tx->srate); - dv = lcm(sm->mode_tx->dmabuflenmodulo, - sm->mode_rx->dmabuflenmodulo); - SCSTATE->dmabuflen = sm->mode_rx->srate/100+dv-1; - SCSTATE->dmabuflen /= dv; - SCSTATE->dmabuflen *= 2*dv; /* make sure DMA buf is even */ + sm->dma.ifragsz = (sm->mode_rx->srate + 50)/100; + sm->dma.ofragsz = (sm->mode_tx->srate + 50)/100; + if (sm->dma.ifragsz < sm->mode_rx->overlap) + sm->dma.ifragsz = sm->mode_rx->overlap; + sm->dma.i16bit = sm->dma.o16bit = 0; return 0; } } @@ -633,50 +626,61 @@ static void setup_dma_fdx_dsp(struct device *dev, struct sm_state *sm) { unsigned long flags; - unsigned long dmabufaddr = virt_to_bus(SCSTATE->dmabuf); - unsigned long dmabuf2addr = virt_to_bus(SCSTATE->dmabuf2); + unsigned int isamps, osamps; if (!reset_dsp(dev)) { printk(KERN_ERR "%s: sbc: cannot reset sb dsp\n", sm_drvname); return; } - if (((dmabufaddr & 0xffff) + SCSTATE->dmabuflen > 0x10000) || - ((dmabuf2addr & 0xffff) + 2*(SCSTATE->dmabuflen) > 0x10000)) - panic("sm: DMA buffer violates DMA boundary!"); save_flags(flags); cli(); sbc_int_ack_8bit(dev); sbc_int_ack_16bit(dev); /* should eventually change to set rates individually by SBC_SAMPLE_RATE_{IN/OUT} */ - write_dsp(dev, SBC_SAMPLE_RATE); /* set sampling rate */ - write_dsp(dev, SCSTATE->fmt[0]); + write_dsp(dev, SBC_SAMPLE_RATE_IN); + write_dsp(dev, SCSTATE->sr[0] >> 8); + write_dsp(dev, SCSTATE->sr[0] & 0xff); + write_dsp(dev, SBC_SAMPLE_RATE_OUT); + write_dsp(dev, SCSTATE->sr[1] >> 8); + write_dsp(dev, SCSTATE->sr[1] & 0xff); write_dsp(dev, SBC_SPEAKER_ON); - /* - * DMA channel 1 (8bit) does input (capture), - * DMA channel 2 (16bit) does output (playback) - */ - disable_dma(dev->dma); - disable_dma(sm->hdrv.ptt_out.dma2); - clear_dma_ff(dev->dma); - set_dma_mode(dev->dma, DMA_MODE_READ | DMA_MODE_AUTOINIT); - set_dma_addr(dev->dma, dmabufaddr); - set_dma_count(dev->dma, SCSTATE->dmabuflen); - clear_dma_ff(sm->hdrv.ptt_out.dma2); - set_dma_mode(sm->hdrv.ptt_out.dma2, DMA_MODE_WRITE | DMA_MODE_AUTOINIT); - set_dma_addr(sm->hdrv.ptt_out.dma2, dmabuf2addr); - set_dma_count(sm->hdrv.ptt_out.dma2, SCSTATE->dmabuflen); - enable_dma(dev->dma); - enable_dma(sm->hdrv.ptt_out.dma2); - sbc_int_ack_8bit(dev); - sbc_int_ack_16bit(dev); - write_dsp(dev, SBC4_IN8_AI); - write_dsp(dev, SBC4_MODE_UNS_MONO); - write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff); - write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) >> 8); - write_dsp(dev, SBC4_OUT16_AI); - write_dsp(dev, SBC4_MODE_UNS_MONO); - write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff); - write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) >> 8); + if (sm->dma.o16bit) { + /* + * DMA channel 1 (8bit) does input (capture), + * DMA channel 2 (16bit) does output (playback) + */ + isamps = dma_setup(sm, 0, dev->dma) - 1; + osamps = dma_setup(sm, 1, sm->hdrv.ptt_out.dma2) - 1; + sbc_int_ack_8bit(dev); + sbc_int_ack_16bit(dev); + write_dsp(dev, SBC4_IN8_AI); + write_dsp(dev, SBC4_MODE_UNS_MONO); + write_dsp(dev, isamps & 0xff); + write_dsp(dev, isamps >> 8); + write_dsp(dev, SBC4_OUT16_AI); + write_dsp(dev, SBC4_MODE_SIGN_MONO); + write_dsp(dev, osamps & 0xff); + write_dsp(dev, osamps >> 8); + } else { + /* + * DMA channel 1 (8bit) does output (playback), + * DMA channel 2 (16bit) does input (capture) + */ + isamps = dma_setup(sm, 0, sm->hdrv.ptt_out.dma2) - 1; + osamps = dma_setup(sm, 1, dev->dma) - 1; + sbc_int_ack_8bit(dev); + sbc_int_ack_16bit(dev); + write_dsp(dev, SBC4_OUT8_AI); + write_dsp(dev, SBC4_MODE_UNS_MONO); + write_dsp(dev, osamps & 0xff); + write_dsp(dev, osamps >> 8); + write_dsp(dev, SBC4_IN16_AI); + write_dsp(dev, SBC4_MODE_SIGN_MONO); + write_dsp(dev, isamps & 0xff); + write_dsp(dev, isamps >> 8); + } + dma_init_receive(sm); + dma_init_transmit(sm); restore_flags(flags); } @@ -686,41 +690,58 @@ { struct device *dev = (struct device *)dev_id; struct sm_state *sm = (struct sm_state *)dev->priv; - unsigned char *buf; - unsigned char *buf2; - unsigned char intsrc; + unsigned char intsrc, pbint = 0, captint = 0; + unsigned int ocfrag, icfrag; + unsigned long flags; if (!dev || !sm || sm->hdrv.magic != HDLCDRV_MAGIC) return; - buf = SCSTATE->dmabuf; - buf2 = SCSTATE->dmabuf2; + save_flags(flags); + cli(); outb(0x82, DSP_MIXER_ADDR(dev->base_addr)); intsrc = inb(DSP_MIXER_DATA(dev->base_addr)); if (intsrc & 0x01) { sbc_int_ack_8bit(dev); - if (SCSTATE->dmabufidx) - buf += SCSTATE->dmabuflen/2; - SCSTATE->dmabufidx = !SCSTATE->dmabufidx; + if (sm->dma.o16bit) { + captint = 1; + disable_dma(dev->dma); + clear_dma_ff(dev->dma); + dma_ptr(sm, 0, dev->dma, &icfrag); + enable_dma(dev->dma); + } else { + pbint = 1; + disable_dma(dev->dma); + clear_dma_ff(dev->dma); + dma_ptr(sm, 1, dev->dma, &ocfrag); + enable_dma(dev->dma); + } } if (intsrc & 0x02) { sbc_int_ack_16bit(dev); - if (SCSTATE->dma2bufidx) - buf2 += SCSTATE->dmabuflen/2; - SCSTATE->dma2bufidx = !SCSTATE->dma2bufidx; + if (sm->dma.o16bit) { + pbint = 1; + disable_dma(sm->hdrv.ptt_out.dma2); + clear_dma_ff(sm->hdrv.ptt_out.dma2); + dma_ptr(sm, 1, sm->hdrv.ptt_out.dma2, &ocfrag); + enable_dma(sm->hdrv.ptt_out.dma2); + } else { + captint = 1; + disable_dma(sm->hdrv.ptt_out.dma2); + clear_dma_ff(sm->hdrv.ptt_out.dma2); + dma_ptr(sm, 0, sm->hdrv.ptt_out.dma2, &icfrag); + enable_dma(sm->hdrv.ptt_out.dma2); + } } + restore_flags(flags); sm_int_freq(sm); sti(); - if (intsrc & 0x02) { - if ((SCSTATE->ptt = hdlcdrv_ptt(&sm->hdrv))) - time_exec(sm->debug_vals.mod_cyc, - sm->mode_tx->modulator(sm, buf2, SCSTATE->dmabuflen/2)); - else - time_exec(sm->debug_vals.mod_cyc, - memset(buf2, 0x80, SCSTATE->dmabuflen/2)); + if (pbint) { + if (dma_end_transmit(sm, ocfrag)) + dma_clear_transmit(sm); + dma_transmit(sm); } - if (intsrc & 0x01) { - time_exec(sm->debug_vals.demod_cyc, - sm->mode_rx->demodulator(sm, buf, SCSTATE->dmabuflen/2)); + if (captint) { + dma_receive(sm, icfrag); hdlcdrv_arbitrate(dev, &sm->hdrv); } sm_output_status(sm); @@ -749,12 +770,17 @@ /* * check if a card is available */ - if (!reset_dsp(dev)) + if (!reset_dsp(dev)) { + printk(KERN_ERR "%s: sbc: no card at io address 0x%lx\n", + sm_drvname, dev->base_addr); return -ENODEV; + } write_dsp(dev, SBC_GET_REVISION); if (!read_dsp(dev, &SCSTATE->revhi) || !read_dsp(dev, &SCSTATE->revlo)) return -ENODEV; + printk(KERN_INFO "%s: SoundBlaster DSP revision %d.%d\n", sm_drvname, + SCSTATE->revhi, SCSTATE->revlo); if (SCSTATE->revhi < 4) { printk(KERN_ERR "%s: at least DSP rev 4.00 required\n", sm_drvname); return -ENODEV; @@ -766,13 +792,14 @@ /* * initialize some variables */ - if (!(SCSTATE->dmabuf = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA))) + if (!(sm->dma.ibuf = kmalloc(sm->dma.ifragsz * (NUM_FRAGMENTS+1), GFP_KERNEL | GFP_DMA))) return -ENOMEM; - if (!(SCSTATE->dmabuf2 = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA))) { - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); + if (!(sm->dma.obuf = kmalloc(sm->dma.ofragsz * NUM_FRAGMENTS, GFP_KERNEL | GFP_DMA))) { + kfree(sm->dma.ibuf); return -ENOMEM; } - SCSTATE->dmabufidx = SCSTATE->dma2bufidx = SCSTATE->ptt = 0; + dma_init_transmit(sm); + dma_init_receive(sm); memset(&sm->m, 0, sizeof(sm->m)); memset(&sm->d, 0, sizeof(sm->d)); @@ -782,20 +809,20 @@ sm->mode_rx->init(sm); if (request_dma(dev->dma, sm->hwdrv->hw_name)) { - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); - kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen); + kfree(sm->dma.ibuf); + kfree(sm->dma.obuf); return -EBUSY; } if (request_dma(sm->hdrv.ptt_out.dma2, sm->hwdrv->hw_name)) { - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); - kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen); + kfree(sm->dma.ibuf); + kfree(sm->dma.obuf); free_dma(dev->dma); return -EBUSY; } if (request_irq(dev->irq, sbcfdx_interrupt, SA_INTERRUPT, sm->hwdrv->hw_name, dev)) { - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); - kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen); + kfree(sm->dma.ibuf); + kfree(sm->dma.obuf); free_dma(dev->dma); free_dma(sm->hdrv.ptt_out.dma2); return -EBUSY; @@ -821,8 +848,8 @@ free_dma(dev->dma); free_dma(sm->hdrv.ptt_out.dma2); release_region(dev->base_addr, SBC_EXTENT); - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); - kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen); + kfree(sm->dma.ibuf); + kfree(sm->dma.obuf); return 0; } @@ -833,7 +860,6 @@ char *cp = strchr(mode, '.'); const struct modem_tx_info **mtp = sm_modem_tx_table; const struct modem_rx_info **mrp; - int dv; if (!strcmp(mode, "off")) { sm->mode_tx = NULL; @@ -867,13 +893,25 @@ sm->mode_rx = *mrp; SCSTATE->sr[0] = sm->mode_rx->srate; SCSTATE->sr[1] = sm->mode_tx->srate; - dv = lcm(sm->mode_tx->dmabuflenmodulo, - sm->mode_rx->dmabuflenmodulo); - if (dv & 1) - dv <<= 1; /* dmabuflen must be a multiple of 4 */ - SCSTATE->dmabuflen = sm->mode_rx->srate/100+dv-1; - SCSTATE->dmabuflen /= dv; - SCSTATE->dmabuflen *= 2*dv; /* make sure DMA buf is even */ + sm->dma.ifragsz = (sm->mode_rx->srate + 50)/100; + sm->dma.ofragsz = (sm->mode_tx->srate + 50)/100; + if (sm->dma.ifragsz < sm->mode_rx->overlap) + sm->dma.ifragsz = sm->mode_rx->overlap; + if (sm->mode_rx->demodulator_s16 && sm->mode_tx->modulator_u8) { + sm->dma.i16bit = 1; + sm->dma.o16bit = 0; + sm->dma.ifragsz <<= 1; + } else if (sm->mode_rx->demodulator_u8 && sm->mode_tx->modulator_s16) { + sm->dma.i16bit = 0; + sm->dma.o16bit = 1; + sm->dma.ofragsz <<= 1; + } else { + printk(KERN_INFO "%s: mode %s or %s unusable\n", sm_drvname, + sm->mode_rx->name, sm->mode_tx->name); + sm->mode_tx = NULL; + sm->mode_rx = NULL; + return -EINVAL; + } return 0; } } diff -u --recursive --new-file v2.1.42/linux/drivers/net/soundmodem/sm_wss.c linux/drivers/net/soundmodem/sm_wss.c --- v2.1.42/linux/drivers/net/soundmodem/sm_wss.c Thu Feb 27 10:57:31 1997 +++ linux/drivers/net/soundmodem/sm_wss.c Thu Jun 12 16:22:07 1997 @@ -26,12 +26,14 @@ */ #include +#include #include #include #include #include #include #include "sm.h" +#include "smdma.h" /* --------------------------------------------------------------------- */ @@ -81,12 +83,6 @@ unsigned char revwss, revid, revv, revcid; unsigned char fmt[2]; unsigned char crystal; - unsigned int dmabuflen; - unsigned char *dmabuf; - unsigned char dmabufidx; - unsigned char ptt; - /* Full Duplex extensions */ - unsigned char *dmabuf2; }; #define SCSTATE ((struct sc_state_wss *)(&sm->hw)) @@ -156,8 +152,8 @@ /* --------------------------------------------------------------------- */ -static int wss_set_codec_fmt(struct device *dev, struct sm_state *sm, - unsigned char fmt, char fdx, char fullcalib) +static int wss_set_codec_fmt(struct device *dev, struct sm_state *sm, unsigned char fmt, + unsigned char fmt2, char fdx, char fullcalib) { unsigned long time; unsigned long flags; @@ -167,7 +163,7 @@ /* Clock and data format register */ write_codec(dev, 0x48, fmt); if (SCSTATE->crystal) { - write_codec(dev, 0x5c, fmt & 0xf0); + write_codec(dev, 0x5c, fmt2 & 0xf0); /* MCE and interface config reg */ write_codec(dev, 0x49, (fdx ? 0 : 0x4) | (fullcalib ? 0x18 : 0)); } else @@ -306,7 +302,7 @@ write_codec(dev, 0x1d, 0x00); /* right out no att */ } - if (wss_set_codec_fmt(dev, sm, SCSTATE->fmt[0], fdx, 1)) + if (wss_set_codec_fmt(dev, sm, SCSTATE->fmt[0], SCSTATE->fmt[0], fdx, 1)) goto codec_err; write_codec(dev, 0, reg0); /* left input control */ @@ -345,18 +341,14 @@ { unsigned long flags; static const unsigned char codecmode[2] = { 0x0e, 0x0d }; - static const unsigned char dmamode[2] = { - DMA_MODE_READ | DMA_MODE_AUTOINIT, - DMA_MODE_WRITE | DMA_MODE_AUTOINIT - }; unsigned char oldcodecmode; long abrt; - unsigned long dmabufaddr = virt_to_bus(SCSTATE->dmabuf); + unsigned char fmt; + unsigned int numsamps; - if ((dmabufaddr & 0xffffu) + SCSTATE->dmabuflen > 0x10000) - panic("%s: DMA buffer violates DMA boundary!", sm_drvname); send = !!send; - save_flags(flags); + fmt = SCSTATE->fmt[send]; + save_flags(flags); cli(); /* * perform the final DMA sequence to disable the codec request @@ -365,28 +357,18 @@ write_codec(dev, 9, 0xc); /* disable codec */ wss_ack_int(dev); if (read_codec(dev, 11) & 0x10) { - disable_dma(dev->dma); - clear_dma_ff(dev->dma); - set_dma_mode(dev->dma, dmamode[oldcodecmode & 1]); - set_dma_addr(dev->dma, dmabufaddr); - set_dma_count(dev->dma, SCSTATE->dmabuflen); - enable_dma(dev->dma); + dma_setup(sm, oldcodecmode & 1, dev->dma); abrt = 0; while ((read_codec(dev, 11) & 0x10) || ((++abrt) >= 0x10000)); } - disable_dma(dev->dma); - if (read_codec(dev, 0x8) != SCSTATE->fmt[send]) - wss_set_codec_fmt(dev, sm, SCSTATE->fmt[send], 0, 0); - clear_dma_ff(dev->dma); - set_dma_mode(dev->dma, dmamode[send]); - set_dma_addr(dev->dma, dmabufaddr); - set_dma_count(dev->dma, SCSTATE->dmabuflen); - enable_dma(dev->dma); - write_codec(dev, 15, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff); - write_codec(dev, 14, ((SCSTATE->dmabuflen >> 1) - 1) >> 8); + if (read_codec(dev, 0x8) != fmt) + wss_set_codec_fmt(dev, sm, fmt, fmt, 0, 0); + numsamps = dma_setup(sm, send, dev->dma) - 1; + write_codec(dev, 15, numsamps & 0xff); + write_codec(dev, 14, numsamps >> 8); if (SCSTATE->crystal) { - write_codec(dev, 31, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff); - write_codec(dev, 30, ((SCSTATE->dmabuflen >> 1) - 1) >> 8); + write_codec(dev, 31, numsamps & 0xff); + write_codec(dev, 30, numsamps >> 8); } write_codec(dev, 9, codecmode[send]); restore_flags(flags); @@ -398,74 +380,45 @@ { struct device *dev = (struct device *)dev_id; struct sm_state *sm = (struct sm_state *)dev->priv; - unsigned char new_ptt; - unsigned char *buf; - int dmares; + unsigned int curfrag; + unsigned int nums; if (!dev || !sm || !sm->mode_rx || !sm->mode_tx || sm->hdrv.magic != HDLCDRV_MAGIC) return; - new_ptt = hdlcdrv_ptt(&sm->hdrv); cli(); wss_ack_int(dev); disable_dma(dev->dma); clear_dma_ff(dev->dma); - dmares = get_dma_residue(dev->dma); - if (dmares <= 0) - dmares = SCSTATE->dmabuflen; - buf = SCSTATE->dmabuf; - if (dmares > SCSTATE->dmabuflen/2) { - buf += SCSTATE->dmabuflen/2; - dmares -= SCSTATE->dmabuflen/2; - } -#ifdef SM_DEBUG - if (!sm->debug_vals.dma_residue || - dmares < sm->debug_vals.dma_residue) - sm->debug_vals.dma_residue = dmares; -#endif /* SM_DEBUG */ - dmares--; - write_codec(dev, 15, dmares & 0xff); - write_codec(dev, 14, dmares >> 8); + nums = dma_ptr(sm, sm->dma.ptt_cnt > 0, dev->dma, &curfrag) - 1; + write_codec(dev, 15, nums & 0xff); + write_codec(dev, 14, nums >> 8); if (SCSTATE->crystal) { - write_codec(dev, 31, dmares & 0xff); - write_codec(dev, 30, dmares >> 8); + write_codec(dev, 31, nums & 0xff); + write_codec(dev, 30, nums >> 8); } enable_dma(dev->dma); sm_int_freq(sm); sti(); - if (new_ptt && !SCSTATE->ptt) { - /* starting to transmit */ - disable_dma(dev->dma); - sti(); - SCSTATE->dmabufidx = 0; - time_exec(sm->debug_vals.demod_cyc, - sm->mode_rx->demodulator(sm, buf, SCSTATE->dmabuflen/2)); - time_exec(sm->debug_vals.mod_cyc, - sm->mode_tx->modulator(sm, SCSTATE->dmabuf, - SCSTATE->dmabuflen/2)); - setup_dma_wss(dev, sm, 1); - time_exec(sm->debug_vals.mod_cyc, - sm->mode_tx->modulator(sm, SCSTATE->dmabuf + - SCSTATE->dmabuflen/2, - SCSTATE->dmabuflen/2)); - } else if (SCSTATE->ptt == 1 && !new_ptt) { + if (sm->dma.ptt_cnt <= 0) { + dma_receive(sm, curfrag); + if (hdlcdrv_ptt(&sm->hdrv)) { + /* starting to transmit */ + disable_dma(dev->dma); + dma_start_transmit(sm); + setup_dma_wss(dev, sm, 1); + dma_transmit(sm); + } + } else if (dma_end_transmit(sm, curfrag)) { /* stopping transmission */ disable_dma(dev->dma); sti(); - SCSTATE->dmabufidx = 0; + dma_init_receive(sm); setup_dma_wss(dev, sm, 0); - SCSTATE->ptt = 0; - } else if (SCSTATE->ptt) { - SCSTATE->ptt--; - time_exec(sm->debug_vals.mod_cyc, - sm->mode_tx->modulator(sm, buf, SCSTATE->dmabuflen/2)); } else { - time_exec(sm->debug_vals.demod_cyc, - sm->mode_rx->demodulator(sm, buf, SCSTATE->dmabuflen/2)); + dma_transmit(sm); hdlcdrv_arbitrate(dev, &sm->hdrv); } - if (new_ptt) - SCSTATE->ptt = 2; sm_output_status(sm); hdlcdrv_transmitter(dev, &sm->hdrv); hdlcdrv_receiver(dev, &sm->hdrv); @@ -475,6 +428,8 @@ static int wss_open(struct device *dev, struct sm_state *sm) { + unsigned int dmasz, u; + if (sizeof(sm->m) < sizeof(struct sc_state_wss)) { printk(KERN_ERR "sm wss: wss state too big: %d > %d\n", sizeof(struct sc_state_wss), sizeof(sm->m)); @@ -495,9 +450,19 @@ /* * initialize some variables */ - if (!(SCSTATE->dmabuf = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA))) + dma_init_receive(sm); + dmasz = (NUM_FRAGMENTS + 1) * sm->dma.ifragsz; + if (sm->dma.i16bit) + dmasz <<= 1; + u = NUM_FRAGMENTS * sm->dma.ofragsz; + if (sm->dma.o16bit) + u <<= 1; + if (u > dmasz) + dmasz = u; + if (!(sm->dma.ibuf = sm->dma.obuf = kmalloc(dmasz, GFP_KERNEL | GFP_DMA))) return -ENOMEM; - SCSTATE->dmabufidx = SCSTATE->ptt = 0; + dma_init_transmit(sm); + dma_init_receive(sm); memset(&sm->m, 0, sizeof(sm->m)); memset(&sm->d, 0, sizeof(sm->d)); @@ -507,13 +472,13 @@ sm->mode_rx->init(sm); if (request_dma(dev->dma, sm->hwdrv->hw_name)) { - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); + kfree_s(sm->dma.obuf, dmasz); return -EBUSY; } if (request_irq(dev->irq, wss_interrupt, SA_INTERRUPT, sm->hwdrv->hw_name, dev)) { free_dma(dev->dma); - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); + kfree_s(sm->dma.obuf, dmasz); return -EBUSY; } request_region(dev->base_addr, WSS_EXTENT, sm->hwdrv->hw_name); @@ -535,7 +500,7 @@ free_irq(dev->irq, dev); free_dma(dev->dma); release_region(dev->base_addr, WSS_EXTENT); - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); + kfree(sm->dma.obuf); return 0; } @@ -546,7 +511,7 @@ char *cp = strchr(mode, '.'); const struct modem_tx_info **mtp = sm_modem_tx_table; const struct modem_rx_info **mrp; - int i, j, dv; + int i, j; if (!strcmp(mode, "off")) { sm->mode_tx = NULL; @@ -579,11 +544,57 @@ sm->mode_rx = *mrp; SCSTATE->fmt[0] = j; SCSTATE->fmt[1] = i; - dv = lcm(sm->mode_tx->dmabuflenmodulo, - sm->mode_rx->dmabuflenmodulo); - SCSTATE->dmabuflen = sm->mode_rx->srate/100+dv-1; - SCSTATE->dmabuflen /= dv; - SCSTATE->dmabuflen *= 2*dv; /* make sure DMA buf is even */ + sm->dma.ifragsz = (sm->mode_rx->srate + 50)/100; + sm->dma.ofragsz = (sm->mode_tx->srate + 50)/100; + if (sm->dma.ifragsz < sm->mode_rx->overlap) + sm->dma.ifragsz = sm->mode_rx->overlap; + /* prefer same data format if possible to minimize switching times */ + sm->dma.i16bit = sm->dma.o16bit = 2; + if (sm->mode_rx->srate == sm->mode_tx->srate) { + if (sm->mode_rx->demodulator_s16 && sm->mode_tx->modulator_s16) + sm->dma.i16bit = sm->dma.o16bit = 1; + else if (sm->mode_rx->demodulator_u8 && sm->mode_tx->modulator_u8) + sm->dma.i16bit = sm->dma.o16bit = 0; + } + if (sm->dma.i16bit == 2) { + if (sm->mode_rx->demodulator_s16) + sm->dma.i16bit = 1; + else if (sm->mode_rx->demodulator_u8) + sm->dma.i16bit = 0; + } + if (sm->dma.o16bit == 2) { + if (sm->mode_tx->modulator_s16) + sm->dma.o16bit = 1; + else if (sm->mode_tx->modulator_u8) + sm->dma.o16bit = 0; + } + if (sm->dma.i16bit == 2 || sm->dma.o16bit == 2) { + printk(KERN_INFO "%s: mode %s or %s unusable\n", sm_drvname, + sm->mode_rx->name, sm->mode_tx->name); + sm->mode_tx = NULL; + sm->mode_rx = NULL; + return -EINVAL; + } +#ifdef __BIG_ENDIAN + /* big endian 16bit only works on crystal cards... */ + if (sm->dma.i16bit) { + SCSTATE->fmt[0] |= 0xc0; + sm->dma.ifragsz <<= 1; + } + if (sm->dma.o16bit) { + SCSTATE->fmt[1] |= 0xc0; + sm->dma.ofragsz <<= 1; + } +#else /* __BIG_ENDIAN */ + if (sm->dma.i16bit) { + SCSTATE->fmt[0] |= 0x40; + sm->dma.ifragsz <<= 1; + } + if (sm->dma.o16bit) { + SCSTATE->fmt[1] |= 0x40; + sm->dma.ofragsz <<= 1; + } +#endif /* __BIG_ENDIAN */ return 0; } } @@ -663,12 +674,8 @@ unsigned long flags; unsigned char oldcodecmode, codecdma; long abrt; - unsigned long dmabufaddr1 = virt_to_bus(SCSTATE->dmabuf); - unsigned long dmabufaddr2 = virt_to_bus(SCSTATE->dmabuf2); - - if (((dmabufaddr1 & 0xffffu) + SCSTATE->dmabuflen > 0x10000) || - ((dmabufaddr2 & 0xffffu) + SCSTATE->dmabuflen > 0x10000)) - panic("%s: DMA buffer violates DMA boundary!", sm_drvname); + unsigned int osamps, isamps; + save_flags(flags); cli(); /* @@ -678,39 +685,19 @@ write_codec(dev, 9, 0); /* disable codec DMA */ wss_ack_int(dev); if ((codecdma = read_codec(dev, 11)) & 0x10) { - disable_dma(dev->dma); - disable_dma(sm->hdrv.ptt_out.dma2); - clear_dma_ff(dev->dma); - set_dma_mode(dev->dma, DMA_MODE_WRITE | DMA_MODE_AUTOINIT); - set_dma_addr(dev->dma, dmabufaddr1); - set_dma_count(dev->dma, SCSTATE->dmabuflen); - clear_dma_ff(sm->hdrv.ptt_out.dma2); - set_dma_mode(sm->hdrv.ptt_out.dma2, DMA_MODE_READ | DMA_MODE_AUTOINIT); - set_dma_addr(sm->hdrv.ptt_out.dma2, dmabufaddr2); - set_dma_count(sm->hdrv.ptt_out.dma2, SCSTATE->dmabuflen); - enable_dma(dev->dma); - enable_dma(sm->hdrv.ptt_out.dma2); + dma_setup(sm, 1, dev->dma); + dma_setup(sm, 0, sm->hdrv.ptt_out.dma2); abrt = 0; - while (((codecdma = read_codec(dev, 11)) & 0x10) || - ((++abrt) >= 0x10000)); + while (((codecdma = read_codec(dev, 11)) & 0x10) || ((++abrt) >= 0x10000)); } - disable_dma(dev->dma); - disable_dma(sm->hdrv.ptt_out.dma2); - clear_dma_ff(dev->dma); - set_dma_mode(dev->dma, DMA_MODE_WRITE | DMA_MODE_AUTOINIT); - set_dma_addr(dev->dma, dmabufaddr1); - set_dma_count(dev->dma, SCSTATE->dmabuflen); - clear_dma_ff(sm->hdrv.ptt_out.dma2); - set_dma_mode(sm->hdrv.ptt_out.dma2, DMA_MODE_READ | DMA_MODE_AUTOINIT); - set_dma_addr(sm->hdrv.ptt_out.dma2, dmabufaddr2); - set_dma_count(sm->hdrv.ptt_out.dma2, SCSTATE->dmabuflen); - enable_dma(dev->dma); - enable_dma(sm->hdrv.ptt_out.dma2); - write_codec(dev, 15, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff); - write_codec(dev, 14, ((SCSTATE->dmabuflen >> 1) - 1) >> 8); + wss_set_codec_fmt(dev, sm, SCSTATE->fmt[1], SCSTATE->fmt[0], 1, 1); + osamps = dma_setup(sm, 1, dev->dma) - 1; + isamps = dma_setup(sm, 0, sm->hdrv.ptt_out.dma2) - 1; + write_codec(dev, 15, osamps & 0xff); + write_codec(dev, 14, osamps >> 8); if (SCSTATE->crystal) { - write_codec(dev, 31, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff); - write_codec(dev, 30, ((SCSTATE->dmabuflen >> 1) - 1) >> 8); + write_codec(dev, 31, isamps & 0xff); + write_codec(dev, 30, isamps >> 8); } write_codec(dev, 9, 3); restore_flags(flags); @@ -722,68 +709,74 @@ { struct device *dev = (struct device *)dev_id; struct sm_state *sm = (struct sm_state *)dev->priv; - unsigned char *buf1; - unsigned char *buf2; unsigned long flags; - int dmares1, dmares2; + unsigned char cry_int_src; + unsigned icfrag, ocfrag, isamps, osamps; if (!dev || !sm || !sm->mode_rx || !sm->mode_tx || sm->hdrv.magic != HDLCDRV_MAGIC) return; save_flags(flags); cli(); - if (SCSTATE->crystal && (!(read_codec(dev, 0x18) & 0x20))) { - /* only regard Crystal Playback interrupts! */ + if (SCSTATE->crystal) { + /* Crystal has an essentially different interrupt handler! */ + cry_int_src = read_codec(dev, 0x18); wss_ack_int(dev); + if (cry_int_src & 0x10) { /* playback interrupt */ + disable_dma(dev->dma); + clear_dma_ff(dev->dma); + osamps = dma_ptr(sm, 1, dev->dma, &ocfrag)-1; + write_codec(dev, 15, osamps & 0xff); + write_codec(dev, 14, osamps >> 8); + enable_dma(dev->dma); + } + if (cry_int_src & 0x20) { /* capture interrupt */ + disable_dma(sm->hdrv.ptt_out.dma2); + clear_dma_ff(sm->hdrv.ptt_out.dma2); + isamps = dma_ptr(sm, 0, sm->hdrv.ptt_out.dma2, &icfrag)-1; + write_codec(dev, 31, isamps & 0xff); + write_codec(dev, 30, isamps >> 8); + enable_dma(sm->hdrv.ptt_out.dma2); + } + restore_flags(flags); + sm_int_freq(sm); + sti(); + if (cry_int_src & 0x10) { + if (dma_end_transmit(sm, ocfrag)) + dma_clear_transmit(sm); + dma_transmit(sm); + } + if (cry_int_src & 0x20) { + dma_receive(sm, icfrag); + hdlcdrv_arbitrate(dev, &sm->hdrv); + } + sm_output_status(sm); + hdlcdrv_transmitter(dev, &sm->hdrv); + hdlcdrv_receiver(dev, &sm->hdrv); return; } wss_ack_int(dev); disable_dma(dev->dma); disable_dma(sm->hdrv.ptt_out.dma2); clear_dma_ff(dev->dma); - dmares1 = get_dma_residue(dev->dma); clear_dma_ff(sm->hdrv.ptt_out.dma2); - dmares2 = get_dma_residue(sm->hdrv.ptt_out.dma2); - if (dmares1 <= 0) - dmares1 = SCSTATE->dmabuflen; - buf1 = SCSTATE->dmabuf; - if (dmares1 > SCSTATE->dmabuflen/2) { - buf1 += SCSTATE->dmabuflen/2; - dmares1 -= SCSTATE->dmabuflen/2; - } - if (dmares2 <= 0) - dmares2 = SCSTATE->dmabuflen; - buf2 = SCSTATE->dmabuf2; - if (dmares2 > SCSTATE->dmabuflen/2) { - buf2 += SCSTATE->dmabuflen/2; - dmares2 -= SCSTATE->dmabuflen/2; - } -#ifdef SM_DEBUG - if (!sm->debug_vals.dma_residue || - dmares1 < sm->debug_vals.dma_residue) - sm->debug_vals.dma_residue = dmares1; -#endif /* SM_DEBUG */ - dmares1--; - dmares2--; - write_codec(dev, 15, dmares1 & 0xff); - write_codec(dev, 14, dmares1 >> 8); + osamps = dma_ptr(sm, 1, dev->dma, &ocfrag)-1; + isamps = dma_ptr(sm, 0, sm->hdrv.ptt_out.dma2, &icfrag)-1; + write_codec(dev, 15, osamps & 0xff); + write_codec(dev, 14, osamps >> 8); if (SCSTATE->crystal) { - write_codec(dev, 31, dmares2 & 0xff); - write_codec(dev, 30, dmares2 >> 8); + write_codec(dev, 31, isamps & 0xff); + write_codec(dev, 30, isamps >> 8); } enable_dma(dev->dma); enable_dma(sm->hdrv.ptt_out.dma2); restore_flags(flags); sm_int_freq(sm); sti(); - if ((SCSTATE->ptt = hdlcdrv_ptt(&sm->hdrv))) - time_exec(sm->debug_vals.mod_cyc, - sm->mode_tx->modulator(sm, buf1, SCSTATE->dmabuflen/2)); - else - time_exec(sm->debug_vals.mod_cyc, - memset(buf1, 0x80, SCSTATE->dmabuflen/2)); - time_exec(sm->debug_vals.demod_cyc, - sm->mode_rx->demodulator(sm, buf2, SCSTATE->dmabuflen/2)); + if (dma_end_transmit(sm, ocfrag)) + dma_clear_transmit(sm); + dma_transmit(sm); + dma_receive(sm, icfrag); hdlcdrv_arbitrate(dev, &sm->hdrv); sm_output_status(sm); hdlcdrv_transmitter(dev, &sm->hdrv); @@ -809,13 +802,14 @@ /* * initialize some variables */ - if (!(SCSTATE->dmabuf = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA))) + if (!(sm->dma.ibuf = kmalloc(sm->dma.ifragsz * (NUM_FRAGMENTS+1), GFP_KERNEL | GFP_DMA))) return -ENOMEM; - if (!(SCSTATE->dmabuf2 = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA))) { - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); + if (!(sm->dma.obuf = kmalloc(sm->dma.ofragsz * NUM_FRAGMENTS, GFP_KERNEL | GFP_DMA))) { + kfree(sm->dma.ibuf); return -ENOMEM; } - SCSTATE->dmabufidx = SCSTATE->ptt = 0; + dma_init_transmit(sm); + dma_init_receive(sm); memset(&sm->m, 0, sizeof(sm->m)); memset(&sm->d, 0, sizeof(sm->d)); @@ -825,20 +819,20 @@ sm->mode_rx->init(sm); if (request_dma(dev->dma, sm->hwdrv->hw_name)) { - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); - kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen); + kfree(sm->dma.ibuf); + kfree(sm->dma.obuf); return -EBUSY; } if (request_dma(sm->hdrv.ptt_out.dma2, sm->hwdrv->hw_name)) { - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); - kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen); + kfree(sm->dma.ibuf); + kfree(sm->dma.obuf); free_dma(dev->dma); return -EBUSY; } if (request_irq(dev->irq, wssfdx_interrupt, SA_INTERRUPT, sm->hwdrv->hw_name, dev)) { - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); - kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen); + kfree(sm->dma.ibuf); + kfree(sm->dma.obuf); free_dma(dev->dma); free_dma(sm->hdrv.ptt_out.dma2); return -EBUSY; @@ -858,13 +852,14 @@ * disable interrupts */ disable_dma(dev->dma); + disable_dma(sm->hdrv.ptt_out.dma2); write_codec(dev, 9, 0xc); /* disable codec */ free_irq(dev->irq, dev); free_dma(dev->dma); free_dma(sm->hdrv.ptt_out.dma2); release_region(dev->base_addr, WSS_EXTENT); - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); - kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen); + kfree(sm->dma.ibuf); + kfree(sm->dma.obuf); return 0; } @@ -875,7 +870,7 @@ char *cp = strchr(mode, '.'); const struct modem_tx_info **mtp = sm_modem_tx_table; const struct modem_rx_info **mrp; - int i, dv; + int i; if (!strcmp(mode, "off")) { sm->mode_tx = NULL; @@ -907,11 +902,37 @@ sm->mode_tx = *mtp; sm->mode_rx = *mrp; SCSTATE->fmt[0] = SCSTATE->fmt[1] = i; - dv = lcm(sm->mode_tx->dmabuflenmodulo, - sm->mode_rx->dmabuflenmodulo); - SCSTATE->dmabuflen = sm->mode_rx->srate/100+dv-1; - SCSTATE->dmabuflen /= dv; - SCSTATE->dmabuflen *= 2*dv; /* make sure DMA buf is even */ + sm->dma.ifragsz = sm->dma.ofragsz = (sm->mode_rx->srate + 50)/100; + if (sm->dma.ifragsz < sm->mode_rx->overlap) + sm->dma.ifragsz = sm->mode_rx->overlap; + sm->dma.i16bit = sm->dma.o16bit = 2; + if (sm->mode_rx->demodulator_s16) { + sm->dma.i16bit = 1; + sm->dma.ifragsz <<= 1; +#ifdef __BIG_ENDIAN /* big endian 16bit only works on crystal cards... */ + SCSTATE->fmt[0] |= 0xc0; +#else /* __BIG_ENDIAN */ + SCSTATE->fmt[0] |= 0x40; +#endif /* __BIG_ENDIAN */ + } else if (sm->mode_rx->demodulator_u8) + sm->dma.i16bit = 0; + if (sm->mode_tx->modulator_s16) { + sm->dma.o16bit = 1; + sm->dma.ofragsz <<= 1; +#ifdef __BIG_ENDIAN /* big endian 16bit only works on crystal cards... */ + SCSTATE->fmt[1] |= 0xc0; +#else /* __BIG_ENDIAN */ + SCSTATE->fmt[1] |= 0x40; +#endif /* __BIG_ENDIAN */ + } else if (sm->mode_tx->modulator_u8) + sm->dma.o16bit = 0; + if (sm->dma.i16bit == 2 || sm->dma.o16bit == 2) { + printk(KERN_INFO "%s: mode %s or %s unusable\n", sm_drvname, + sm->mode_rx->name, sm->mode_tx->name); + sm->mode_tx = NULL; + sm->mode_rx = NULL; + return -EINVAL; + } return 0; } } diff -u --recursive --new-file v2.1.42/linux/drivers/net/soundmodem/smdma.h linux/drivers/net/soundmodem/smdma.h --- v2.1.42/linux/drivers/net/soundmodem/smdma.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/soundmodem/smdma.h Thu Jun 12 16:22:07 1997 @@ -0,0 +1,210 @@ +/*****************************************************************************/ + +/* + * smdma.h -- soundcard radio modem driver dma buffer routines. + * + * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + */ + +#ifndef _SMDMA_H +#define _SMDMA_H + +/* ---------------------------------------------------------------------- */ + +#include "sm.h" + +/* ---------------------------------------------------------------------- */ + +#define DMA_MODE_AUTOINIT 0x10 +#define NUM_FRAGMENTS 4 + +/* --------------------------------------------------------------------- */ +/* + * ===================== DMA buffer management =========================== + */ + +/* + * returns the number of samples per fragment + */ +extern __inline__ unsigned int dma_setup(struct sm_state *sm, int send, unsigned int dmanr) +{ + if (send) { + disable_dma(dmanr); + clear_dma_ff(dmanr); + set_dma_mode(dmanr, DMA_MODE_WRITE | DMA_MODE_AUTOINIT); + set_dma_addr(dmanr, virt_to_bus(sm->dma.obuf)); + set_dma_count(dmanr, sm->dma.ofragsz * NUM_FRAGMENTS); + enable_dma(dmanr); + if (sm->dma.o16bit) + return sm->dma.ofragsz/2; + return sm->dma.ofragsz; + } else { + disable_dma(dmanr); + clear_dma_ff(dmanr); + set_dma_mode(dmanr, DMA_MODE_READ | DMA_MODE_AUTOINIT); + set_dma_addr(dmanr, virt_to_bus(sm->dma.ibuf)); + set_dma_count(dmanr, sm->dma.ifragsz * NUM_FRAGMENTS); + enable_dma(dmanr); + if (sm->dma.i16bit) + return sm->dma.ifragsz/2; + return sm->dma.ifragsz; + } +} + +/* --------------------------------------------------------------------- */ + +extern __inline__ unsigned int dma_ptr(struct sm_state *sm, int send, unsigned int dmanr, + unsigned int *curfrag) +{ + unsigned int dmaptr, sz, frg, offs; + + dmaptr = get_dma_residue(dmanr); + if (send) { + sz = sm->dma.ofragsz * NUM_FRAGMENTS; + if (dmaptr == 0 || dmaptr > sz) + dmaptr = sz; + dmaptr--; + frg = dmaptr / sm->dma.ofragsz; + offs = (dmaptr % sm->dma.ofragsz) + 1; + *curfrag = NUM_FRAGMENTS - 1 - frg; +#ifdef SM_DEBUG + if (!sm->debug_vals.dma_residue || offs < sm->debug_vals.dma_residue) + sm->debug_vals.dma_residue = offs; +#endif /* SM_DEBUG */ + if (sm->dma.o16bit) + return offs/2; + return offs; + } else { + sz = sm->dma.ifragsz * NUM_FRAGMENTS; + if (dmaptr == 0 || dmaptr > sz) + dmaptr = sz; + dmaptr--; + frg = dmaptr / sm->dma.ifragsz; + offs = (dmaptr % sm->dma.ifragsz) + 1; + *curfrag = NUM_FRAGMENTS - 1 - frg; +#ifdef SM_DEBUG + if (!sm->debug_vals.dma_residue || offs < sm->debug_vals.dma_residue) + sm->debug_vals.dma_residue = offs; +#endif /* SM_DEBUG */ + if (sm->dma.i16bit) + return offs/2; + return offs; + } +} + +/* --------------------------------------------------------------------- */ + +extern __inline__ int dma_end_transmit(struct sm_state *sm, unsigned int curfrag) +{ + unsigned int diff = (NUM_FRAGMENTS + curfrag - sm->dma.ofragptr) % NUM_FRAGMENTS; + + sm->dma.ofragptr = curfrag; + if (sm->dma.ptt_cnt <= 0) { + sm->dma.ptt_cnt = 0; + return 0; + } + sm->dma.ptt_cnt -= diff; + if (sm->dma.ptt_cnt <= 0) { + sm->dma.ptt_cnt = 0; + return -1; + } + return 0; +} + +extern __inline__ void dma_transmit(struct sm_state *sm) +{ + void *p; + + while (sm->dma.ptt_cnt < NUM_FRAGMENTS && hdlcdrv_ptt(&sm->hdrv)) { + p = (unsigned char *)sm->dma.obuf + sm->dma.ofragsz * + ((sm->dma.ofragptr + sm->dma.ptt_cnt) % NUM_FRAGMENTS); + if (sm->dma.o16bit) { + time_exec(sm->debug_vals.mod_cyc, + sm->mode_tx->modulator_s16(sm, p, sm->dma.ofragsz/2)); + } else { + time_exec(sm->debug_vals.mod_cyc, + sm->mode_tx->modulator_u8(sm, p, sm->dma.ofragsz)); + } + sm->dma.ptt_cnt++; + } +} + +extern __inline__ void dma_init_transmit(struct sm_state *sm) +{ + sm->dma.ofragptr = 0; + sm->dma.ptt_cnt = 0; +} + +extern __inline__ void dma_start_transmit(struct sm_state *sm) +{ + sm->dma.ofragptr = 0; + if (sm->dma.o16bit) { + time_exec(sm->debug_vals.mod_cyc, + sm->mode_tx->modulator_s16(sm, sm->dma.obuf, sm->dma.ofragsz/2)); + } else { + time_exec(sm->debug_vals.mod_cyc, + sm->mode_tx->modulator_u8(sm, sm->dma.obuf, sm->dma.ofragsz)); + } + sm->dma.ptt_cnt = 1; +} + +extern __inline__ void dma_clear_transmit(struct sm_state *sm) +{ + sm->dma.ptt_cnt = 0; + memset(sm->dma.obuf, (sm->dma.o16bit) ? 0 : 0x80, sm->dma.ofragsz * NUM_FRAGMENTS); +} + +/* --------------------------------------------------------------------- */ + +extern __inline__ void dma_receive(struct sm_state *sm, unsigned int curfrag) +{ + void *p; + + while (sm->dma.ifragptr != curfrag) { + if (sm->dma.ifragptr) + p = (unsigned char *)sm->dma.ibuf + + sm->dma.ifragsz * sm->dma.ifragptr; + else { + p = (unsigned char *)sm->dma.ibuf + NUM_FRAGMENTS * sm->dma.ifragsz; + memcpy(p, sm->dma.ibuf, sm->dma.ifragsz); + } + if (sm->dma.o16bit) { + time_exec(sm->debug_vals.demod_cyc, + sm->mode_rx->demodulator_s16(sm, p, sm->dma.ifragsz/2)); + } else { + time_exec(sm->debug_vals.demod_cyc, + sm->mode_rx->demodulator_u8(sm, p, sm->dma.ifragsz)); + } + sm->dma.ifragptr = (sm->dma.ifragptr + 1) % NUM_FRAGMENTS; + } +} + +extern __inline__ void dma_init_receive(struct sm_state *sm) +{ + sm->dma.ifragptr = 0; +} + +/* --------------------------------------------------------------------- */ +#endif /* _SMDMA_H */ + + + diff -u --recursive --new-file v2.1.42/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v2.1.42/linux/drivers/pci/pci.c Sat May 24 09:10:24 1997 +++ linux/drivers/pci/pci.c Thu Jun 12 16:22:07 1997 @@ -56,7 +56,9 @@ DEVICE( ATI, ATI_68800, "68800AX"), DEVICE( ATI, ATI_215CT222, "215CT222"), DEVICE( ATI, ATI_210888CX, "210888CX"), + DEVICE( ATI, ATI_215GT, "Mach64 GT (Rage II)"), DEVICE( ATI, ATI_210888GX, "210888GX"), + DEVICE( ATI, ATI_264VT, "Mach64 VT"), DEVICE( VLSI, VLSI_82C592, "82C592-FC1"), DEVICE( VLSI, VLSI_82C593, "82C593-FC1"), DEVICE( VLSI, VLSI_82C594, "82C594-AFC2"), @@ -76,6 +78,7 @@ DEVICE( DEC, DEC_TULIP_FAST, "DC21140"), DEVICE( DEC, DEC_FDDI, "DEFPA"), DEVICE( DEC, DEC_TULIP_PLUS, "DC21041"), + DEVICE( DEC, DEC_21142, "DC21142"), DEVICE( DEC, DEC_21052, "DC21052"), DEVICE( DEC, DEC_21152, "DC21152"), DEVICE( CIRRUS, CIRRUS_7548, "GD 7548"), @@ -83,10 +86,14 @@ DEVICE( CIRRUS, CIRRUS_5434_4, "GD 5434"), DEVICE( CIRRUS, CIRRUS_5434_8, "GD 5434"), DEVICE( CIRRUS, CIRRUS_5436, "GD 5436"), + DEVICE( CIRRUS, CIRRUS_5446, "GD 5446"), + DEVICE( CIRRUS, CIRRUS_5464, "GD 5464"), DEVICE( CIRRUS, CIRRUS_6729, "CL 6729"), DEVICE( CIRRUS, CIRRUS_7542, "CL 7542"), DEVICE( CIRRUS, CIRRUS_7543, "CL 7543"), + DEVICE( CIRRUS, CIRRUS_7541, "CL 7541"), DEVICE( IBM, IBM_82G2675, "82G2675"), + DEVICE( IBM, IBM_82351, "82351"), DEVICE( WD, WD_7197, "WD 7197"), DEVICE( AMD, AMD_LANCE, "79C970"), DEVICE( AMD, AMD_SCSI, "53C974"), @@ -101,6 +108,7 @@ DEVICE( CT, CT_65545, "65545"), DEVICE( CT, CT_65548, "65548"), DEVICE( CT, CT_65550, "65550"), + DEVICE( CT, CT_65554, "65554"), DEVICE( MIRO, MIRO_36050, "ZR36050"), DEVICE( FD, FD_36C70, "TMC-18C30"), DEVICE( SI, SI_6201, "6201"), @@ -112,7 +120,10 @@ DEVICE( SI, SI_601, "85C601"), DEVICE( SI, SI_5511, "85C5511"), DEVICE( SI, SI_5513, "85C5513"), + DEVICE( SI, SI_5571, "5571"), + DEVICE( SI, SI_7001, "7001"), DEVICE( HP, HP_J2585A, "J2585A"), + DEVICE( HP, HP_J2585B, "J2585B"), DEVICE( PCTECH, PCTECH_RZ1000, "RZ1000 (buggy)"), DEVICE( PCTECH, PCTECH_RZ1001, "RZ1001 (buggy?)"), DEVICE( DPT, DPT, "SmartCache/Raid"), @@ -128,6 +139,9 @@ DEVICE( BUSLOGIC, BUSLOGIC_FLASHPOINT, "FlashPoint"), DEVICE( OAK, OAK_OTI107, "OTI107"), DEVICE( WINBOND2, WINBOND2_89C940,"NE2000-PCI"), + DEVICE( MOTOROLA, MOTOROLA_MPC105,"MPC105 Eagle"), + DEVICE( MOTOROLA, MOTOROLA_MPC106,"MPC106 Grackle"), + DEVICE( MOTOROLA, MOTOROLA_RAVEN, "Raven"), DEVICE( PROMISE, PROMISE_5300, "DC5030"), DEVICE( N9, N9_I128, "Imagine 128"), DEVICE( N9, N9_I128_2, "Imagine 128v2"), @@ -155,11 +169,13 @@ DEVICE( ACC, ACC_2056, "2056"), DEVICE( WINBOND, WINBOND_83769, "W83769F"), DEVICE( WINBOND, WINBOND_82C105, "SL82C105"), + DEVICE( WINBOND, WINBOND_83C553, "W83C553"), DEVICE( 3COM, 3COM_3C590, "3C590 10bT"), DEVICE( 3COM, 3COM_3C595TX, "3C595 100bTX"), DEVICE( 3COM, 3COM_3C595T4, "3C595 100bT4"), DEVICE( 3COM, 3COM_3C595MII, "3C595 100b-MII"), DEVICE( 3COM, 3COM_3C900TPO, "3C900 10bTPO"), + DEVICE( 3COM, 3COM_3C900COMBO,"3C900 10b Combo"), DEVICE( 3COM, 3COM_3C905TX, "3C905 100bTX"), DEVICE( AL, AL_M1445, "M1445"), DEVICE( AL, AL_M1449, "M1449"), @@ -171,18 +187,24 @@ DEVICE( AL, AL_M4803, "M4803"), DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_NM2070, "Magicgraph NM2070"), DEVICE( ASP, ASP_ABP940, "ABP940"), + DEVICE( ASP, ASP_ABP940U, "ABP940U"), DEVICE( CERN, CERN_SPSB_PMC, "STAR/RD24 SCI-PCI (PMC)"), DEVICE( CERN, CERN_SPSB_PCI, "STAR/RD24 SCI-PCI (PMC)"), DEVICE( IMS, IMS_8849, "8849"), DEVICE( TEKRAM2, TEKRAM2_690c, "DC690c"), + DEVICE( TUNDRA, TUNDRA_CA91C042,"CA91C042 Universe"), DEVICE( AMCC, AMCC_MYRINET, "Myrinet PCI (M2-PCI-32)"), + DEVICE( AMCC, AMCC_S5933, "S5933"), DEVICE( INTERG, INTERG_1680, "IGA-1680"), DEVICE( INTERG, INTERG_1682, "IGA-1682"), DEVICE( REALTEK, REALTEK_8029, "8029"), DEVICE( INIT, INIT_320P, "320 P"), DEVICE( VIA, VIA_82C505, "VT 82C505"), DEVICE( VIA, VIA_82C561, "VT 82C561"), + DEVICE( VIA, VIA_82C586_1, "VT 82C586 Apollo VP-1"), DEVICE( VIA, VIA_82C576, "VT 82C576 3V"), + DEVICE( VIA, VIA_82C585, "VT 82C585VP Apollo VP-1"), + DEVICE( VIA, VIA_82C586_0, "VT 82C586 Apollo VP-1"), DEVICE( VIA, VIA_82C416, "VT 82C416MV"), DEVICE( VORTEX, VORTEX_GDT60x0, "GDT 60x0"), DEVICE( VORTEX, VORTEX_GDT6000B,"GDT 6000b"), @@ -200,19 +222,22 @@ DEVICE( VORTEX, VORTEX_GDT6555, "GDT 6555"), DEVICE( EF, EF_ATM_FPGA, "155P-MF1 (FPGA)"), DEVICE( EF, EF_ATM_ASIC, "155P-MF1 (ASIC)"), - DEVICE( IMAGINGTECH, IMAGINGTECH_ICPCI, "MVC IC-PCI"), DEVICE( FORE, FORE_PCA200PC, "PCA-200PC"), DEVICE( FORE, FORE_PCA200E, "PCA-200E"), + DEVICE( IMAGINGTECH, IMAGINGTECH_ICPCI, "MVC IC-PCI"), DEVICE( PLX, PLX_9060, "PCI9060 i960 bridge"), DEVICE( ALLIANCE, ALLIANCE_PROMOTIO, "Promotion-6410"), DEVICE( ALLIANCE, ALLIANCE_PROVIDEO, "Provideo"), DEVICE( VMIC, VMIC_VME, "VMIVME-7587"), DEVICE( DIGI, DIGI_RIGHTSWITCH, "RightSwitch SE-6"), DEVICE( MUTECH, MUTECH_MV1000, "MV-1000"), + DEVICE( TOSHIBA, TOSHIBA_601, "Laptop"), DEVICE( ZEITNET, ZEITNET_1221, "1221"), DEVICE( ZEITNET, ZEITNET_1225, "1225"), + DEVICE( OMEGA, OMEGA_PCMCIA, "PCMCIA"), DEVICE( SPECIALIX, SPECIALIX_XIO, "XIO/SIO host"), DEVICE( SPECIALIX, SPECIALIX_RIO, "RIO host"), + DEVICE( ZORAN, ZORAN_36120, "ZR36120"), DEVICE( COMPEX, COMPEX_RL2000, "ReadyLink 2000"), DEVICE( RP, RP8OCTA, "RocketPort 8 Oct"), DEVICE( RP, RP8INTF, "RocketPort 8 Intf"), @@ -222,6 +247,8 @@ DEVICE( CYCLADES, CYCLOM_Y_Hi, "Cyclom-Y above 1Mbyte"), DEVICE( CYCLADES, CYCLOM_Z_Lo, "Cyclom-Z below 1Mbyte"), DEVICE( CYCLADES, CYCLOM_Z_Hi, "Cyclom-Z above 1Mbyte"), + DEVICE( 3DFX, 3DFX_VOODOO, "Voodoo"), + DEVICE( SIGMADES, SIGMADES_6425, "REALmagic64/GX"), DEVICE( OPTIBASE, OPTIBASE_FORGE, "MPEG Forge"), DEVICE( OPTIBASE, OPTIBASE_FUSION,"MPEG Fusion"), DEVICE( OPTIBASE, OPTIBASE_VPLEX, "VideoPlex"), @@ -230,6 +257,9 @@ DEVICE( SYMPHONY, SYMPHONY_101, "82C101"), DEVICE( TEKRAM, TEKRAM_DC290, "DC-290"), DEVICE( 3DLABS, 3DLABS_300SX, "GLINT 300SX"), + DEVICE( 3DLABS, 3DLABS_DELTA, "GLINT Delta"), + DEVICE( 3DLABS, 3DLABS_PERMEDIA,"PERMEDIA"), + DEVICE( AVANCE, AVANCE_ALG2064, "ALG2064i"), DEVICE( AVANCE, AVANCE_2302, "ALG-2302"), DEVICE( S3, S3_ViRGE, "ViRGE"), DEVICE( S3, S3_TRIO, "Trio32/Trio64"), @@ -248,6 +278,8 @@ DEVICE( INTEL, INTEL_82378, "82378IB"), DEVICE( INTEL, INTEL_82430, "82430ZX Aries"), BRIDGE( INTEL, INTEL_82434, "82434LX Mercury/Neptune", 0x00), + DEVICE( INTEL, INTEL_82092AA_0,"82092AA PCMCIA bridge"), + DEVICE( INTEL, INTEL_82092AA_1,"82092AA EIDE"), DEVICE( INTEL, INTEL_7116, "SAA7116"), DEVICE( INTEL, INTEL_82596, "82596"), DEVICE( INTEL, INTEL_82865, "82865"), @@ -255,15 +287,19 @@ DEVICE( INTEL, INTEL_82437, "82437"), DEVICE( INTEL, INTEL_82371_0, "82371 Triton PIIX"), DEVICE( INTEL, INTEL_82371_1, "82371 Triton PIIX"), - DEVICE( INTEL, INTEL_430MX_0, "Triton I"), - DEVICE( INTEL, INTEL_430MX_1, "Triton I"), + DEVICE( INTEL, INTEL_82371MX, "430MX - 82371MX MPIIX"), + DEVICE( INTEL, INTEL_82437MX, "430MX - 82437MX MTSC"), DEVICE( INTEL, INTEL_82441, "82441FX Natoma"), DEVICE( INTEL, INTEL_82439, "82439HX Triton II"), DEVICE( INTEL, INTEL_82371SB_0,"82371SB Natoma/Triton II PIIX3"), DEVICE( INTEL, INTEL_82371SB_1,"82371SB Natoma/Triton II PIIX3"), DEVICE( INTEL, INTEL_82371SB_2,"82371SB Natoma/Triton II PIIX3"), DEVICE( INTEL, INTEL_82437VX, "82437VX Triton II"), + DEVICE( INTEL, INTEL_82439TX, "82439TX"), + DEVICE( INTEL, INTEL_82371AB_0,"82371AB PIIX4"), DEVICE( INTEL, INTEL_82371AB, "82371AB 430TX PIIX4"), + DEVICE( INTEL, INTEL_82371AB_2,"82371AB PIIX4"), + DEVICE( INTEL, INTEL_82371AB_3,"82371AB PIIX4 Power Management"), DEVICE( INTEL, INTEL_P6, "Orion P6"), DEVICE( INTEL, INTEL_P6_2, "82450GX Orion P6"), DEVICE( KTI, KTI_ET32P2, "ET32P2"), @@ -508,6 +544,7 @@ case PCI_VENDOR_ID_BUSLOGIC: return "BusLogic"; case PCI_VENDOR_ID_OAK: return "OAK"; case PCI_VENDOR_ID_WINBOND2: return "Winbond"; + case PCI_VENDOR_ID_MOTOROLA: return "Motorola"; case PCI_VENDOR_ID_PROMISE: return "Promise Technology"; case PCI_VENDOR_ID_N9: return "Number Nine"; case PCI_VENDOR_ID_UMC: return "UMC"; @@ -531,6 +568,7 @@ case PCI_VENDOR_ID_CERN: return "CERN"; case PCI_VENDOR_ID_IMS: return "IMS"; case PCI_VENDOR_ID_TEKRAM2: return "Tekram"; + case PCI_VENDOR_ID_TUNDRA: return "Tundra"; case PCI_VENDOR_ID_AMCC: return "AMCC"; case PCI_VENDOR_ID_INTERG: return "Intergraphics"; case PCI_VENDOR_ID_REALTEK: return "Realtek"; @@ -547,10 +585,14 @@ case PCI_VENDOR_ID_MUTECH: return "Mutech"; case PCI_VENDOR_ID_TOSHIBA: return "Toshiba"; case PCI_VENDOR_ID_ZEITNET: return "ZeitNet"; + case PCI_VENDOR_ID_OMEGA: return "Omega Micro"; case PCI_VENDOR_ID_SPECIALIX: return "Specialix"; + case PCI_VENDOR_ID_ZORAN: return "Zoran"; case PCI_VENDOR_ID_COMPEX: return "Compex"; case PCI_VENDOR_ID_RP: return "Comtrol"; case PCI_VENDOR_ID_CYCLADES: return "Cyclades"; + case PCI_VENDOR_ID_3DFX: return "3Dfx"; + case PCI_VENDOR_ID_SIGMADES: return "Sigma Designs"; case PCI_VENDOR_ID_OPTIBASE: return "Optibase"; case PCI_VENDOR_ID_SYMPHONY: return "Symphony"; case PCI_VENDOR_ID_TEKRAM: return "Tekram"; diff -u --recursive --new-file v2.1.42/linux/drivers/sbus/char/bwtwo.c linux/drivers/sbus/char/bwtwo.c --- v2.1.42/linux/drivers/sbus/char/bwtwo.c Wed Apr 23 19:01:21 1997 +++ linux/drivers/sbus/char/bwtwo.c Thu Jun 12 16:22:07 1997 @@ -1,4 +1,4 @@ -/* $Id: bwtwo.c,v 1.13 1997/04/14 17:04:55 jj Exp $ +/* $Id: bwtwo.c,v 1.16 1997/06/04 08:27:26 davem Exp $ * bwtwo.c: bwtwo console driver * * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -15,9 +15,11 @@ #include #include -#include "../../char/vt_kern.h" -#include "../../char/selection.h" -#include "../../char/console_struct.h" +/* These must be included after asm/fbio.h */ +#include +#include +#include + #include "fb.h" #include "cg_common.h" @@ -91,7 +93,7 @@ vma->vm_page_prot, fb->space); if (r) return -EAGAIN; vma->vm_inode = inode; - inode->i_count++; + atomic_inc(&inode->i_count); return 0; } diff -u --recursive --new-file v2.1.42/linux/drivers/sbus/char/cgfourteen.c linux/drivers/sbus/char/cgfourteen.c --- v2.1.42/linux/drivers/sbus/char/cgfourteen.c Wed Apr 23 19:01:21 1997 +++ linux/drivers/sbus/char/cgfourteen.c Thu Jun 12 16:22:07 1997 @@ -1,4 +1,4 @@ -/* $Id: cgfourteen.c,v 1.19 1997/04/14 17:04:57 jj Exp $ +/* $Id: cgfourteen.c,v 1.22 1997/06/04 08:27:27 davem Exp $ * cgfourteen.c: Sun SparcStation console support. * * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -23,9 +23,10 @@ #include #include -#include "../../char/vt_kern.h" -#include "../../char/selection.h" -#include "../../char/console_struct.h" +/* These must be included after asm/fbio.h */ +#include +#include +#include #include "fb.h" #define CG14_MCR_INTENABLE_SHIFT 7 @@ -272,7 +273,7 @@ page += map_size; } vma->vm_inode = inode; - inode->i_count++; + atomic_inc(&inode->i_count); return 0; } diff -u --recursive --new-file v2.1.42/linux/drivers/sbus/char/cgsix.c linux/drivers/sbus/char/cgsix.c --- v2.1.42/linux/drivers/sbus/char/cgsix.c Wed Apr 23 19:01:21 1997 +++ linux/drivers/sbus/char/cgsix.c Thu Jun 12 16:22:07 1997 @@ -1,4 +1,4 @@ -/* $Id: cgsix.c,v 1.27 1997/04/14 17:04:55 jj Exp $ +/* $Id: cgsix.c,v 1.30 1997/06/04 08:27:28 davem Exp $ * cgsix.c: cgsix frame buffer driver * * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -15,9 +15,10 @@ #include #include -#include "../../char/vt_kern.h" -#include "../../char/selection.h" -#include "../../char/console_struct.h" +/* These must be included after asm/fbio.h */ +#include +#include +#include #include "fb.h" #include "cg_common.h" @@ -296,7 +297,7 @@ page += map_size; } vma->vm_inode = inode; - inode->i_count++; + atomic_inc(&inode->i_count); return 0; } diff -u --recursive --new-file v2.1.42/linux/drivers/sbus/char/cgthree.c linux/drivers/sbus/char/cgthree.c --- v2.1.42/linux/drivers/sbus/char/cgthree.c Wed Apr 23 19:01:21 1997 +++ linux/drivers/sbus/char/cgthree.c Thu Jun 12 16:22:07 1997 @@ -1,4 +1,4 @@ -/* $Id: cgthree.c,v 1.18 1997/04/16 17:51:09 jj Exp $ +/* $Id: cgthree.c,v 1.21 1997/06/04 08:27:29 davem Exp $ * cgtree.c: cg3 frame buffer driver * * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -18,9 +18,10 @@ #include #include -#include "../../char/vt_kern.h" -#include "../../char/selection.h" -#include "../../char/console_struct.h" +/* These must be included after asm/fbio.h */ +#include +#include +#include #include "fb.h" #include "cg_common.h" @@ -131,7 +132,7 @@ page += map_size; } vma->vm_inode = inode; - inode->i_count++; + atomic_inc(&inode->i_count); return 0; } diff -u --recursive --new-file v2.1.42/linux/drivers/sbus/char/creator.c linux/drivers/sbus/char/creator.c --- v2.1.42/linux/drivers/sbus/char/creator.c Tue May 13 22:41:12 1997 +++ linux/drivers/sbus/char/creator.c Thu Jun 12 16:22:07 1997 @@ -15,9 +15,10 @@ #include #include -#include "../../char/vt_kern.h" -#include "../../char/selection.h" -#include "../../char/console_struct.h" +/* These must be included after asm/fbio.h */ +#include +#include +#include #include "fb.h" __initfunc(void creator_setup (fbinfo_t *fb, int slot, int con_node, unsigned long creator, int creator_io)) diff -u --recursive --new-file v2.1.42/linux/drivers/sbus/char/leo.c linux/drivers/sbus/char/leo.c --- v2.1.42/linux/drivers/sbus/char/leo.c Wed Apr 23 19:01:21 1997 +++ linux/drivers/sbus/char/leo.c Thu Jun 12 16:22:07 1997 @@ -1,4 +1,4 @@ -/* $Id: leo.c,v 1.15 1997/04/14 17:04:54 jj Exp $ +/* $Id: leo.c,v 1.18 1997/06/04 08:27:30 davem Exp $ * leo.c: SUNW,leo 24/8bit frame buffer driver * * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -17,9 +17,10 @@ #include #include -#include "../../char/vt_kern.h" -#include "../../char/selection.h" -#include "../../char/console_struct.h" +/* These must be included after asm/fbio.h */ +#include +#include +#include #include "fb.h" #include "cg_common.h" @@ -221,7 +222,7 @@ page += map_size; } vma->vm_inode = inode; - inode->i_count++; + atomic_inc(&inode->i_count); return 0; } diff -u --recursive --new-file v2.1.42/linux/drivers/sbus/char/suncons.c linux/drivers/sbus/char/suncons.c --- v2.1.42/linux/drivers/sbus/char/suncons.c Thu May 15 16:48:03 1997 +++ linux/drivers/sbus/char/suncons.c Thu Jun 12 16:22:07 1997 @@ -1,4 +1,4 @@ -/* $Id: suncons.c,v 1.62 1997/05/02 22:32:32 davem Exp $ +/* $Id: suncons.c,v 1.63 1997/05/31 18:33:25 mj Exp $ * * suncons.c: Sun SparcStation console support. * @@ -76,11 +76,11 @@ #include #include -#include "../../char/kbd_kern.h" -#include "../../char/vt_kern.h" -#include "../../char/consolemap.h" -#include "../../char/selection.h" -#include "../../char/console_struct.h" +#include +#include +#include +#include +#include #include "fb.h" diff -u --recursive --new-file v2.1.42/linux/drivers/sbus/char/sunfb.c linux/drivers/sbus/char/sunfb.c --- v2.1.42/linux/drivers/sbus/char/sunfb.c Mon Apr 14 16:28:13 1997 +++ linux/drivers/sbus/char/sunfb.c Thu Jun 12 16:22:07 1997 @@ -1,4 +1,4 @@ -/* $Id: sunfb.c,v 1.22 1997/04/03 08:47:56 davem Exp $ +/* $Id: sunfb.c,v 1.23 1997/05/31 18:33:26 mj Exp $ * sunfb.c: Sun generic frame buffer support. * * Copyright (C) 1995, 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -33,11 +33,11 @@ #include #include -#include "../../char/kbd_kern.h" -#include "../../char/vt_kern.h" -#include "../../char/consolemap.h" -#include "../../char/selection.h" -#include "../../char/console_struct.h" +#include +#include +#include +#include +#include #include "fb.h" diff -u --recursive --new-file v2.1.42/linux/drivers/sbus/char/sunkbd.c linux/drivers/sbus/char/sunkbd.c --- v2.1.42/linux/drivers/sbus/char/sunkbd.c Tue May 13 22:41:12 1997 +++ linux/drivers/sbus/char/sunkbd.c Thu Jun 12 16:22:07 1997 @@ -25,9 +25,9 @@ #include #include -#include "../../char/kbd_kern.h" -#include "../../char/diacr.h" -#include "../../char/vt_kern.h" +#include +#include +#include #define SIZE(x) (sizeof(x)/sizeof((x)[0])) diff -u --recursive --new-file v2.1.42/linux/drivers/sbus/char/tcx.c linux/drivers/sbus/char/tcx.c --- v2.1.42/linux/drivers/sbus/char/tcx.c Wed Apr 23 19:01:21 1997 +++ linux/drivers/sbus/char/tcx.c Thu Jun 12 16:22:07 1997 @@ -1,4 +1,4 @@ -/* $Id: tcx.c,v 1.12 1997/04/14 17:04:51 jj Exp $ +/* $Id: tcx.c,v 1.15 1997/06/04 08:27:32 davem Exp $ * tcx.c: SUNW,tcx 24/8bit frame buffer driver * * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -16,9 +16,10 @@ #include #include -#include "../../char/vt_kern.h" -#include "../../char/selection.h" -#include "../../char/console_struct.h" +/* These must be included after asm/fbio.h */ +#include +#include +#include #include "fb.h" #include "cg_common.h" @@ -171,7 +172,7 @@ page += map_size; } vma->vm_inode = inode; - inode->i_count++; + atomic_inc(&inode->i_count); return 0; } diff -u --recursive --new-file v2.1.42/linux/drivers/sbus/char/vfc_dev.c linux/drivers/sbus/char/vfc_dev.c --- v2.1.42/linux/drivers/sbus/char/vfc_dev.c Tue May 13 22:41:12 1997 +++ linux/drivers/sbus/char/vfc_dev.c Thu Jun 12 16:22:07 1997 @@ -581,7 +581,7 @@ vma->vm_page_prot, dev->which_io); if(ret) return -EAGAIN; vma->vm_inode=inode; - inode->i_count++; + atomic_inc(&inode->i_count); return 0; } diff -u --recursive --new-file v2.1.42/linux/drivers/sbus/char/weitek.c linux/drivers/sbus/char/weitek.c --- v2.1.42/linux/drivers/sbus/char/weitek.c Wed Apr 23 19:01:21 1997 +++ linux/drivers/sbus/char/weitek.c Thu Jun 12 16:22:07 1997 @@ -1,4 +1,4 @@ -/* $Id: weitek.c,v 1.9 1997/04/14 17:04:57 jj Exp $ +/* $Id: weitek.c,v 1.12 1997/06/04 08:27:34 davem Exp $ * weitek.c: Tadpole P9100/P9000 console driver * * Copyright (C) 1996 David Redman (djhr@tadpole.co.uk) @@ -15,9 +15,10 @@ #include #include -#include "../../char/vt_kern.h" -#include "../../char/selection.h" -#include "../../char/console_struct.h" +/* These must be included after asm/fbio.h */ +#include +#include +#include #include "fb.h" #include "cg_common.h" @@ -82,7 +83,7 @@ page += map_size; } vma->vm_inode = inode; - inode->i_count++; + atomic_inc(&inode->i_count); return 0; } #endif diff -u --recursive --new-file v2.1.42/linux/drivers/scsi/amiga7xx.c linux/drivers/scsi/amiga7xx.c --- v2.1.42/linux/drivers/scsi/amiga7xx.c Sat May 24 09:10:24 1997 +++ linux/drivers/scsi/amiga7xx.c Thu Jun 12 16:22:07 1997 @@ -50,20 +50,20 @@ #ifdef CONFIG_WARPENGINE_SCSI if ((key = zorro_find(MANUF_MACROSYSTEMS, PROD_WARP_ENGINE, 0, 0))) { - cd = zorro_get_board(key); - address = (unsigned long)kernel_map((unsigned long)cd->cd_BoardAddr, + cd = zorro_get_board(key); + address = (unsigned long)kernel_map((unsigned long)cd->cd_BoardAddr, cd->cd_BoardSize, KERNELMAP_NOCACHE_SER, NULL); - options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT; + options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT; clock = 50000000; /* 50MHz SCSI Clock */ - ncr53c7xx_init(tpnt, 0, 710, (u32)(unsigned char *)(address + 0x40000), - 0, IRQ_AMIGA_PORTS & ~IRQ_MACHSPEC, DMA_NONE, + ncr53c7xx_init(tpnt, 0, 710, (u32)(unsigned char *)(address + 0x40000), + 0, IRQ_AMIGA_PORTS, DMA_NONE, options, clock); - zorro_config_board(key, 0); - num++; + zorro_config_board(key, 0); + num++; } #endif @@ -94,7 +94,7 @@ clock = 50000000; /* 50MHz SCSI Clock */ ncr53c7xx_init(tpnt, 0, 710, (u32)(unsigned char *)(address+0x800000), - 0, IRQ_AMIGA_PORTS & ~IRQ_MACHSPEC, DMA_NONE, + 0, IRQ_AMIGA_PORTS, DMA_NONE, options, clock); zorro_config_board(key, 0); diff -u --recursive --new-file v2.1.42/linux/drivers/scsi/g_NCR5380.c linux/drivers/scsi/g_NCR5380.c --- v2.1.42/linux/drivers/scsi/g_NCR5380.c Thu May 29 21:53:08 1997 +++ linux/drivers/scsi/g_NCR5380.c Thu Jun 12 16:22:07 1997 @@ -619,7 +619,10 @@ struct Scsi_Host *scsi_ptr; Scsi_Cmnd *ptr; struct NCR5380_hostdata *hostdata; - +#ifdef NCR5380_STATS + Scsi_Device *dev; + extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; +#endif cli(); for (scsi_ptr = first_instance; scsi_ptr; scsi_ptr=scsi_ptr->next) diff -u --recursive --new-file v2.1.42/linux/drivers/scsi/script_asm.pl linux/drivers/scsi/script_asm.pl --- v2.1.42/linux/drivers/scsi/script_asm.pl Sat Nov 4 19:25:10 1995 +++ linux/drivers/scsi/script_asm.pl Thu Jun 12 16:22:07 1997 @@ -1,4 +1,4 @@ -#! /usr/local/bin/perl +#!/usr/bin/perl -s # NCR 53c810 script assembler # Sponsored by @@ -10,6 +10,9 @@ # drew@Colorado.EDU # +1 (303) 786-7975 # +# Support for 53c710 (via -ncr7x0_family switch) added by Richard +# Hirst - 15th March 1997 +# # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or @@ -74,7 +77,15 @@ # and = 0x04_00_00_00 # add = 0x06_00_00_00 -%operators_810 = ( +if ($ncr7x0_family) { + %operators = ( + '|', 0x02_00_00_00, 'OR', 0x02_00_00_00, + '&', 0x04_00_00_00, 'AND', 0x04_00_00_00, + '+', 0x06_00_00_00 + ); +} +else { + %operators = ( 'SHL', 0x01_00_00_00, '|', 0x02_00_00_00, 'OR', 0x02_00_00_00, 'XOR', 0x03_00_00_00, @@ -83,11 +94,33 @@ # Note : low bit of the operator bit should be set for add with # carry. '+', 0x06_00_00_00 -); - + ); +} # Table of register addresses -%registers_810 = ( + +if ($ncr7x0_family) { + %registers = ( + 'SCNTL0', 0, 'SCNTL1', 1, 'SDID', 2, 'SIEN', 3, + 'SCID', 4, 'SXFER', 5, 'SODL', 6, 'SOCL', 7, + 'SFBR', 8, 'SIDL', 9, 'SBDL', 10, 'SBCL', 11, + 'DSTAT', 12, 'SSTAT0', 13, 'SSTAT1', 14, 'SSTAT2', 15, + 'DSA0', 16, 'DSA1', 17, 'DSA2', 18, 'DSA3', 19, + 'CTEST0', 20, 'CTEST1', 21, 'CTEST2', 22, 'CTEST3', 23, + 'CTEST4', 24, 'CTEST5', 25, 'CTEST6', 26, 'CTEST7', 27, + 'TEMP0', 28, 'TEMP1', 29, 'TEMP2', 30, 'TEMP3', 31, + 'DFIFO', 32, 'ISTAT', 33, 'CTEST8', 34, 'LCRC', 35, + 'DBC0', 36, 'DBC1', 37, 'DBC2', 38, 'DCMD', 39, + 'DNAD0', 40, 'DNAD1', 41, 'DNAD2', 42, 'DNAD3', 43, + 'DSP0', 44, 'DSP1', 45, 'DSP2', 46, 'DSP3', 47, + 'DSPS0', 48, 'DSPS1', 49, 'DSPS2', 50, 'DSPS3', 51, + 'SCRATCH0', 52, 'SCRATCH1', 53, 'SCRATCH2', 54, 'SCRATCH3', 55, + 'DMODE', 56, 'DIEN', 57, 'DWT', 58, 'DCNTL', 59, + 'ADDER0', 60, 'ADDER1', 61, 'ADDER2', 62, 'ADDER3', 63, + ); +} +else { + %registers = ( 'SCNTL0', 0, 'SCNTL1', 1, 'SCNTL2', 2, 'SCNTL3', 3, 'SCID', 4, 'SXFER', 5, 'SDID', 6, 'GPREG', 7, 'SFBR', 8, 'SOCL', 9, 'SSID', 10, 'SBCL', 11, @@ -113,7 +146,8 @@ 'SODL', 84, 'SBDL', 88, 'SCRATCHB0', 92, 'SCRATCHB1', 93, 'SCRATCHB2', 94, 'SCRATCHB3', 95 -); + ); +} # Parsing regular expressions $identifier = '[A-Za-z_][A-Za-z_0-9]*'; @@ -131,17 +165,22 @@ $phase = join ('|', keys %scsi_phases); print STDERR "phase regex = $phase\n" if ($debug); -$register = join ('|', keys %registers_810); +$register = join ('|', keys %registers); -# yucky - since %operators_810 includes meta-characters which must +# yucky - since %operators includes meta-characters which must # be escaped, I can't use the join() trick I used for the register # regex -$operator = '\||OR|AND|XOR|\&|\+'; +if ($ncr7x0_family) { + $operator = '\||OR|AND|\&|\+'; +} +else { + $operator = '\||OR|AND|XOR|\&|\+'; +} # Global variables -%symbol_values = (%registers_810) ; # Traditional symbol table +%symbol_values = (%registers) ; # Traditional symbol table %symbol_references = () ; # Table of symbol references, where # the index is the symbol name, @@ -421,6 +460,7 @@ if ($1 =~ /^($identifier)\s*$/) { push (@entry, $1); } else { + die "$0 : syntax error in line $lineno : $_ expected ENTRY "; @@ -558,13 +598,13 @@ # instruction. if (($src_reg eq undef) || ($src_reg eq $dst_reg)) { $code[$address] |= 0x38_00_00_00 | - ($registers_810{$dst_reg} << 16); + ($registers{$dst_reg} << 16); } elsif ($dst_reg =~ /SFBR/i) { $code[$address] |= 0x30_00_00_00 | - ($registers_810{$src_reg} << 16); + ($registers{$src_reg} << 16); } elsif ($src_reg =~ /SFBR/i) { $code[$address] |= 0x28_00_00_00 | - ($registers_810{$dst_reg} << 16); + ($registers{$dst_reg} << 16); } else { die "$0 : Illegal combination of registers in line $lineno : $_ @@ -573,10 +613,10 @@ "; } - $code[$address] |= $operators_810{$op}; + $code[$address] |= $operators{$op}; &parse_value ($data8, 0, 1, 1); - $code[$address] |= $operators_810{$op}; + $code[$address] |= $operators{$op}; $code[$address + 1] = 0x00_00_00_00;# Reserved $address += 2; } else { diff -u --recursive --new-file v2.1.42/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c --- v2.1.42/linux/drivers/sound/dmabuf.c Wed May 28 10:51:32 1997 +++ linux/drivers/sound/dmabuf.c Mon Jun 16 14:23:51 1997 @@ -802,6 +802,8 @@ */ max = dmap->max_fragments; + if (max > dmap->nbufs) + max = dmap->nbufs; len = dmap->qlen; if (audio_devs[dev]->d->local_qlen) diff -u --recursive --new-file v2.1.42/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c --- v2.1.42/linux/drivers/sound/soundcard.c Wed May 28 10:51:33 1997 +++ linux/drivers/sound/soundcard.c Thu Jun 12 16:22:07 1997 @@ -327,7 +327,7 @@ return -EAGAIN; vma->vm_inode = inode; - inode->i_count++; + atomic_inc(&inode->i_count); dmap->mapping_flags |= DMA_MAP_MAPPED; diff -u --recursive --new-file v2.1.42/linux/fs/Config.in linux/fs/Config.in --- v2.1.42/linux/fs/Config.in Sun Apr 13 10:18:21 1997 +++ linux/fs/Config.in Thu Jun 12 16:22:07 1997 @@ -5,6 +5,27 @@ comment 'Filesystems' bool 'Quota support' CONFIG_QUOTA +bool 'Preload dcache entries in readdir() [ALPHA, currently dangerous!]' CONFIG_DCACHE_PRELOAD +bool 'Include support for omirr online mirror' CONFIG_OMIRR +bool 'Translate filename suffixes' CONFIG_TRANS_NAMES +if [ "$CONFIG_TRANS_NAMES" = "y" ]; then + bool ' Restrict translation to specific gid' CONFIG_TRANS_RESTRICT + if [ "$CONFIG_TRANS_RESTRICT" = "y" ]; then + int ' Enter gid to compile in' CONFIG_TRANS_GID 4 + fi + bool ' Translate nodename' CONFIG_TR_NODENAME + bool ' Translate compiled-in kernelname' CONFIG_TR_KERNNAME + if [ "$CONFIG_TR_KERNNAME" = "y" ]; then + string ' Enter kernelname string to compile in' CONFIG_KERNNAME banana + fi + bool ' Translate compiled-in kerneltype' CONFIG_TR_KERNTYPE + if [ "$CONFIG_TR_KERNTYPE" = "y" ]; then + string ' Enter kerneltype string to compile in' CONFIG_KERNTYPE default + fi + bool ' Translate machine type' CONFIG_TR_MACHINE + bool ' Translate sysname' CONFIG_TR_SYSNAME +fi + tristate 'Minix fs support' CONFIG_MINIX_FS tristate 'Second extended fs support' CONFIG_EXT2_FS diff -u --recursive --new-file v2.1.42/linux/fs/Makefile linux/fs/Makefile --- v2.1.42/linux/fs/Makefile Mon Apr 7 11:35:30 1997 +++ linux/fs/Makefile Thu Jun 12 16:22:07 1997 @@ -10,10 +10,10 @@ L_TARGET := filesystems.a L_OBJS = $(join $(SUB_DIRS),$(SUB_DIRS:%=/%.o)) O_TARGET := fs.o -O_OBJS = open.o read_write.o inode.o devices.o file_table.o buffer.o \ +O_OBJS = open.o read_write.o devices.o file_table.o buffer.o \ super.o block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ ioctl.o readdir.o select.o fifo.o locks.o filesystems.o \ - dcache.o $(BINFMTS) + inode.o dcache.o attr.o $(BINFMTS) MOD_LIST_NAME := FS_MODULES ALL_SUB_DIRS = minix ext2 fat msdos vfat proc isofs nfs umsdos \ @@ -25,6 +25,10 @@ O_OBJS += noquot.o endif +ifeq ($(CONFIG_TRANS_NAMES),y) +O_OBJS += nametrans.o +endif + ifeq ($(CONFIG_MINIX_FS),y) SUB_DIRS += minix else @@ -210,6 +214,14 @@ endif endif + +ifeq ($(CONFIG_BINFMT_MISC),y) +BINFMTS += binfmt_misc.o +else + ifeq ($(CONFIG_BINFMT_MISC),m) + M_OBJS += binfmt_misc.o + endif +endif # binfmt_script is always there BINFMTS += binfmt_script.o diff -u --recursive --new-file v2.1.42/linux/fs/affs/dir.c linux/fs/affs/dir.c --- v2.1.42/linux/fs/affs/dir.c Tue May 13 22:41:13 1997 +++ linux/fs/affs/dir.c Thu Jun 12 16:22:08 1997 @@ -55,7 +55,6 @@ NULL, /* mknod */ affs_rename, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/affs/file.c linux/fs/affs/file.c --- v2.1.42/linux/fs/affs/file.c Tue May 13 22:41:13 1997 +++ linux/fs/affs/file.c Thu Jun 12 16:22:08 1997 @@ -71,7 +71,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ generic_readpage, /* readpage */ NULL, /* writepage */ affs_bmap, /* bmap */ @@ -105,7 +104,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/affs/inode.c linux/fs/affs/inode.c --- v2.1.42/linux/fs/affs/inode.c Tue May 13 22:41:14 1997 +++ linux/fs/affs/inode.c Thu Jun 12 16:22:08 1997 @@ -899,7 +899,7 @@ return NULL; } - inode->i_count = 1; + atomic_set(&inode->i_count, 1); inode->i_nlink = 1; inode->i_dev = sb->s_dev; inode->i_uid = current->fsuid; @@ -1031,9 +1031,9 @@ } static struct file_system_type affs_fs_type = { - affs_read_super, "affs", - 1, + FS_REQUIRES_DEV, + affs_read_super, NULL }; diff -u --recursive --new-file v2.1.42/linux/fs/affs/namei.c linux/fs/affs/namei.c --- v2.1.42/linux/fs/affs/namei.c Tue May 13 22:41:14 1997 +++ linux/fs/affs/namei.c Thu Jun 12 16:22:08 1997 @@ -343,7 +343,7 @@ retval = -ENOTEMPTY; goto rmdir_done; } - if (inode->i_count > 1) { + if (atomic_read(&inode->i_count) > 1) { retval = -EBUSY; goto rmdir_done; } @@ -512,7 +512,7 @@ int ino; int result; - new_inode->i_count++; + atomic_inc(&new_inode->i_count); result = 0; for (;;) { if (new_inode == old_inode) { @@ -535,8 +535,7 @@ int affs_rename(struct inode *old_dir, const char *old_name, int old_len, - struct inode *new_dir, const char *new_name, int new_len, - int must_be_dir) + struct inode *new_dir, const char *new_name, int new_len) { struct inode *old_inode; struct inode *new_inode; @@ -570,8 +569,6 @@ old_inode = __iget(old_dir->i_sb,old_ino,0); if (!old_inode) goto end_rename; - if (must_be_dir && !S_ISDIR(old_inode->i_mode)) - goto end_rename; new_bh = affs_find_entry(new_dir,new_name,new_len,&new_ino); if (new_bh) { new_inode = __iget(new_dir->i_sb,new_ino,0); @@ -595,7 +592,7 @@ if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode))) goto end_rename; retval = -EBUSY; - if (new_inode->i_count > 1) + if (atomic_read(&new_inode->i_count) > 1) goto end_rename; } if (S_ISDIR(old_inode->i_mode)) { diff -u --recursive --new-file v2.1.42/linux/fs/affs/symlink.c linux/fs/affs/symlink.c --- v2.1.42/linux/fs/affs/symlink.c Tue May 13 22:41:14 1997 +++ linux/fs/affs/symlink.c Thu Jun 12 16:22:08 1997 @@ -20,7 +20,6 @@ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) static int affs_readlink(struct inode *, char *, int); -static int affs_follow_link(struct inode *, struct inode *, int, int, struct inode **); struct inode_operations affs_symlink_inode_operations = { NULL, /* no file-operations */ @@ -34,92 +33,12 @@ NULL, /* mknod */ NULL, /* rename */ affs_readlink, /* readlink */ - affs_follow_link, /* follow_link */ NULL, /* bmap */ NULL, /* truncate */ NULL /* permission */ }; static int -affs_follow_link(struct inode *dir, struct inode *inode, int flag, int mode, - struct inode **res_inode) -{ - struct buffer_head *bh; - struct slink_front *lf; - char *buffer; - int error; - int i, j; - char c; - char lc; - - pr_debug("AFFS: follow_link(ino=%lu)\n",inode->i_ino); - - *res_inode = NULL; - if (!dir) { - dir = current->fs->root; - dir->i_count++; - } - if (!inode) { - iput(dir); - return -ENOENT; - } - if (!S_ISLNK(inode->i_mode)) { - iput(dir); - *res_inode = inode; - return 0; - } - if (current->link_count > 5) { - iput(inode); - iput(dir); - return -ELOOP; - } - if (!(buffer = kmalloc(1024,GFP_KERNEL))) { - iput(inode); - iput(dir); - return -ENOSPC; - } - bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)); - i = 0; - j = 0; - if (!bh) { - affs_error(inode->i_sb,"follow_link","Cannot read block %lu\n",inode->i_ino); - kfree(buffer); - iput(inode); - iput(dir); - return -EIO; - } - lf = (struct slink_front *)bh->b_data; - lc = 0; - if (strchr(lf->symname,':')) { /* Handle assign or volume name */ - while (i < 1023 && (c = inode->i_sb->u.affs_sb.s_prefix[i])) - buffer[i++] = c; - while (i < 1023 && lf->symname[j] != ':') - buffer[i++] = lf->symname[j++]; - if (i < 1023) - buffer[i++] = '/'; - j++; - lc = '/'; - } - while (i < 1023 && (c = lf->symname[j])) { - if (c == '/' && lc == '/' && i < 1020) { /* parent dir */ - buffer[i++] = '.'; - buffer[i++] = '.'; - } - buffer[i++] = c; - lc = c; - j++; - } - buffer[i] = '\0'; - affs_brelse(bh); - iput(inode); - current->link_count++; - error = open_namei(buffer,flag,mode,res_inode,dir); - current->link_count--; - kfree(buffer); - return error; -} - -static int affs_readlink(struct inode *inode, char *buffer, int buflen) { struct buffer_head *bh; @@ -130,10 +49,6 @@ pr_debug("AFFS: readlink(ino=%lu,buflen=%d)\n",inode->i_ino,buflen); - if (!S_ISLNK(inode->i_mode)) { - iput(inode); - return -EINVAL; - } bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)); i = 0; j = 0; diff -u --recursive --new-file v2.1.42/linux/fs/attr.c linux/fs/attr.c --- v2.1.42/linux/fs/attr.c Wed Dec 31 16:00:00 1969 +++ linux/fs/attr.c Thu Jun 12 16:22:08 1997 @@ -0,0 +1,99 @@ +/* + * linux/fs/attr.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * changes by Thomas Schoebel-Theuer + */ + +#include +#include +#include +#include +#include +#include + +/* Taken over from the old code... */ + +/* POSIX UID/GID verification for setting inode attributes. */ +int inode_change_ok(struct inode *inode, struct iattr *attr) +{ + /* If force is set do it anyway. */ + if (attr->ia_valid & ATTR_FORCE) + return 0; + + /* Make sure a caller can chown. */ + if ((attr->ia_valid & ATTR_UID) && + (current->fsuid != inode->i_uid || + attr->ia_uid != inode->i_uid) && !fsuser()) + return -EPERM; + + /* Make sure caller can chgrp. */ + if ((attr->ia_valid & ATTR_GID) && + (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid) && + !fsuser()) + return -EPERM; + + /* Make sure a caller can chmod. */ + if (attr->ia_valid & ATTR_MODE) { + if ((current->fsuid != inode->i_uid) && !fsuser()) + return -EPERM; + /* Also check the setgid bit! */ + if (!fsuser() && !in_group_p((attr->ia_valid & ATTR_GID) ? attr->ia_gid : + inode->i_gid)) + attr->ia_mode &= ~S_ISGID; + } + + /* Check for setting the inode time. */ + if ((attr->ia_valid & ATTR_ATIME_SET) && + ((current->fsuid != inode->i_uid) && !fsuser())) + return -EPERM; + if ((attr->ia_valid & ATTR_MTIME_SET) && + ((current->fsuid != inode->i_uid) && !fsuser())) + return -EPERM; + return 0; +} + +void inode_setattr(struct inode * inode, struct iattr * attr) +{ + if(attr->ia_valid & + (ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_MTIME|ATTR_CTIME|ATTR_MODE)) { + if (attr->ia_valid & ATTR_UID) + inode->i_uid = attr->ia_uid; + if (attr->ia_valid & ATTR_GID) + inode->i_gid = attr->ia_gid; + if (attr->ia_valid & ATTR_SIZE) + inode->i_size = attr->ia_size; + if (attr->ia_valid & ATTR_ATIME) + inode->i_atime = attr->ia_atime; + if (attr->ia_valid & ATTR_MTIME) + inode->i_mtime = attr->ia_mtime; + if (attr->ia_valid & ATTR_CTIME) + inode->i_ctime = attr->ia_ctime; + if (attr->ia_valid & ATTR_MODE) { + inode->i_mode = attr->ia_mode; + if (!fsuser() && !in_group_p(inode->i_gid)) + inode->i_mode &= ~S_ISGID; + } + inode->i_dirt = 1; + } +} + +int notify_change(struct inode * inode, struct iattr * attr) +{ + int error; + time_t now = CURRENT_TIME; + + attr->ia_ctime = now; + if ((attr->ia_valid & (ATTR_ATIME | ATTR_ATIME_SET)) == ATTR_ATIME) + attr->ia_atime = now; + if ((attr->ia_valid & (ATTR_MTIME | ATTR_MTIME_SET)) == ATTR_MTIME) + attr->ia_mtime = now; + attr->ia_valid &= ~(ATTR_CTIME); + if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->notify_change) + return inode->i_sb->s_op->notify_change(inode, attr); + error = inode_change_ok(inode, attr); + if(!error) + inode_setattr(inode, attr); + return error; +} + diff -u --recursive --new-file v2.1.42/linux/fs/autofs/dir.c linux/fs/autofs/dir.c --- v2.1.42/linux/fs/autofs/dir.c Tue May 13 22:41:14 1997 +++ linux/fs/autofs/dir.c Thu Jun 12 16:22:08 1997 @@ -80,7 +80,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* read_page */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/autofs/init.c linux/fs/autofs/init.c --- v2.1.42/linux/fs/autofs/init.c Thu May 15 16:48:03 1997 +++ linux/fs/autofs/init.c Thu Jun 12 16:22:08 1997 @@ -20,7 +20,10 @@ #endif static struct file_system_type autofs_fs_type = { - autofs_read_super, "autofs", 0, NULL + "autofs", + FS_NO_DCACHE, + autofs_read_super, + NULL }; #ifdef MODULE diff -u --recursive --new-file v2.1.42/linux/fs/autofs/root.c linux/fs/autofs/root.c --- v2.1.42/linux/fs/autofs/root.c Wed May 28 10:51:33 1997 +++ linux/fs/autofs/root.c Thu Jun 12 16:22:08 1997 @@ -48,7 +48,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/autofs/symlink.c linux/fs/autofs/symlink.c --- v2.1.42/linux/fs/autofs/symlink.c Tue May 13 22:41:14 1997 +++ linux/fs/autofs/symlink.c Thu Jun 12 16:22:08 1997 @@ -14,39 +14,6 @@ #include #include "autofs_i.h" -static int autofs_follow_link(struct inode *dir, struct inode *inode, - int flag, int mode, struct inode **res_inode) -{ - int error; - char *link; - - *res_inode = NULL; - if (!dir) { - dir = current->fs->root; - dir->i_count++; - } - if (!inode) { - iput(dir); - return -ENOENT; - } - if (!S_ISLNK(inode->i_mode)) { - iput(dir); - *res_inode = inode; - return 0; - } - if (current->link_count > 5) { - iput(dir); - iput(inode); - return -ELOOP; - } - link = ((struct autofs_symlink *)inode->u.generic_ip)->data; - current->link_count++; - error = open_namei(link,flag,mode,res_inode,dir); - current->link_count--; - iput(inode); - return error; -} - static int autofs_readlink(struct inode *inode, char *buffer, int buflen) { struct autofs_symlink *sl; @@ -76,7 +43,6 @@ NULL, /* mknod */ NULL, /* rename */ autofs_readlink, /* readlink */ - autofs_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c --- v2.1.42/linux/fs/binfmt_aout.c Wed Apr 23 19:01:22 1997 +++ linux/fs/binfmt_aout.c Thu Jun 12 16:22:08 1997 @@ -214,6 +214,7 @@ /* Finally dump the task struct. Not be used by gdb, but could be useful */ set_fs(KERNEL_DS); DUMP_WRITE(current,sizeof(*current)); + inode->i_status |= ST_MODIFIED; close_coredump: if (file.f_op->release) file.f_op->release(inode,&file); diff -u --recursive --new-file v2.1.42/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c --- v2.1.42/linux/fs/binfmt_elf.c Sat May 24 09:10:24 1997 +++ linux/fs/binfmt_elf.c Thu Jun 12 16:22:08 1997 @@ -681,7 +681,7 @@ #ifndef VM_STACK_FLAGS current->executable = bprm->inode; - bprm->inode->i_count++; + atomic_inc(&bprm->inode->i_count); #endif #ifdef LOW_ELF_STACK current->start_stack = bprm->p = elf_stack - 4; @@ -887,6 +887,7 @@ */ static int dump_write(struct file *file, const void *addr, int nr) { + file->f_inode->i_status |= ST_MODIFIED; return file->f_op->write(file->f_inode, file, addr, nr) == nr; } diff -u --recursive --new-file v2.1.42/linux/fs/binfmt_misc.c linux/fs/binfmt_misc.c --- v2.1.42/linux/fs/binfmt_misc.c Wed Dec 31 16:00:00 1969 +++ linux/fs/binfmt_misc.c Thu Jun 12 16:22:08 1997 @@ -0,0 +1,505 @@ +/* + * binfmt_misc.c + * + * Copyright (C) 1997 Richard Günther + * + * binfmt_misc detects binaries via a magic or filename extension and invokes + * a specified wrapper. This should obsolete binfmt_java, binfmt_em86 and + * binfmt_mz. + * + * 25.4.97 first version + * [...] + * 19.5.97 cleanup + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define VERBOSE_STATUS /* undef this to save 400 bytes kernel memory */ + +#ifndef MIN +#define MIN(x,y) (((x)<(y))?(x):(y)) +#endif + +struct binfmt_entry { + struct binfmt_entry *next; + int id; + int flags; /* type, status, etc. */ + int offset; /* offset of magic */ + int size; /* size of magic/mask */ + char *magic; /* magic or filename extension */ + char *mask; /* mask, NULL for exact match */ + char *interpreter; /* filename of interpreter */ + char *proc_name; + struct proc_dir_entry *proc_dir; +}; + +#define ENTRY_ENABLED 1 /* the old binfmt_entry.enabled */ +#define ENTRY_MAGIC 8 /* not filename detection */ +#define ENTRY_STRIP_EXT 32 /* strip of last filename extension */ + +static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs); +static void entry_proc_cleanup(struct binfmt_entry *e); +static int entry_proc_setup(struct binfmt_entry *e); + +static struct linux_binfmt misc_format = { +#ifndef MODULE + NULL, 0, load_misc_binary, NULL, NULL +#else + NULL, &__this_module, load_misc_binary, NULL, NULL +#endif +}; + +static struct proc_dir_entry *bm_dir = NULL; + +static struct binfmt_entry *entries = NULL; +static int free_id = 1; +static int enabled = 1; +static rwlock_t entries_lock = RW_LOCK_UNLOCKED; + + +/* + * Unregister one entry + */ +static void clear_entry(int id) +{ + struct binfmt_entry **ep, *e; + + write_lock(&entries_lock); + ep = &entries; + while (*ep && ((*ep)->id != id)) + ep = &((*ep)->next); + if ((e = *ep)) { + *ep = e->next; + entry_proc_cleanup(e); + kfree(e); + MOD_DEC_USE_COUNT; + } + write_unlock(&entries_lock); +} + +/* + * Clear all registered binary formats + */ +static void clear_entries(void) +{ + struct binfmt_entry *e; + + write_lock(&entries_lock); + while ((e = entries)) { + entries = entries->next; + entry_proc_cleanup(e); + kfree(e); + MOD_DEC_USE_COUNT; + } + write_unlock(&entries_lock); +} + +/* + * Find entry through id - caller has to do locking + */ +static struct binfmt_entry *get_entry(int id) +{ + struct binfmt_entry *e = entries; + + while (e && (e->id != id)) + e = e->next; + return e; +} + + +/* + * Check if we support the binfmt + * if we do, return the binfmt_entry, else NULL + * locking is done in load_misc_binary + */ +static struct binfmt_entry *check_file(struct linux_binprm *bprm) +{ + struct binfmt_entry *e = entries; + char *p = strrchr(bprm->filename, '.'); + int j; + + while (e) { + if (e->flags & ENTRY_ENABLED) { + if (!(e->flags & ENTRY_MAGIC)) { + if (p && !strcmp(e->magic, p + 1)) + return e; + } else { + j = 0; + while ((j < e->size) && + !((bprm->buf[e->offset + j] ^ e->magic[j]) + & (e->mask ? e->mask[j] : 0xff))) + j++; + if (j == e->size) + return e; + } + } + e = e->next; + }; + return NULL; +} + +/* + * the loader itself + */ +static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) +{ + struct binfmt_entry *fmt; + char iname[128]; + char *iname_addr = iname, *p; + int retval, fmt_flags = 0; + + MOD_INC_USE_COUNT; + if (!enabled) { + retval = -ENOEXEC; + goto _ret; + } + + /* to keep locking time low, we copy the interpreter string */ + read_lock(&entries_lock); + if ((fmt = check_file(bprm))) { + strncpy(iname, fmt->interpreter, 127); + iname[127] = '\0'; + fmt_flags = fmt->flags; + } + read_unlock(&entries_lock); + if (!fmt) { + retval = -ENOEXEC; + goto _ret; + } + + iput(bprm->inode); + bprm->dont_iput = 1; + + /* Build args for interpreter */ + if ((fmt_flags & ENTRY_STRIP_EXT) && + (p = strrchr(bprm->filename, '.'))) { + *p = '\0'; + remove_arg_zero(bprm); + bprm->p = copy_strings(1, &bprm->filename, bprm->page, bprm->p, 2); + bprm->argc++; + } + bprm->p = copy_strings(1, &iname_addr, bprm->page, bprm->p, 2); + bprm->argc++; + if (!bprm->p) { + retval = -E2BIG; + goto _ret; + } + bprm->filename = iname; /* for binfmt_script */ + + if ((retval = open_namei(iname, 0, 0, &bprm->inode, NULL))) + goto _ret; + bprm->dont_iput = 0; + + if ((retval = prepare_binprm(bprm)) >= 0) + retval = search_binary_handler(bprm, regs); +_ret: + MOD_DEC_USE_COUNT; + return retval; +} + + + +/* + * /proc handling routines + */ + +/* + * parses and copies one argument enclosed in del from *sp to *dp, + * recognising the \x special. + * returns pointer to the copied argument or NULL in case of an + * error (and sets err) or null argument length. + */ +static char *copyarg(char **dp, const char **sp, int *count, + char del, int special, int *err) +{ + char c, *res = *dp; + + while (!*err && ((c = *((*sp)++)), (*count)--) && (c != del)) { + switch (c) { + case '\\': + if (special && (**sp == 'x')) { + if (!isxdigit(c = toupper(*(++*sp)))) + *err = -EINVAL; + **dp = (c - (isdigit(c) ? '0' : 'A' - 10)) * 16; + if (!isxdigit(c = toupper(*(++*sp)))) + *err = -EINVAL; + *((*dp)++) += c - (isdigit(c) ? '0' : 'A' - 10); + ++*sp; + *count -= 3; + break; + } + default: + *((*dp)++) = c; + } + } + if (*err || (c != del) || (res == *dp)) + res = NULL; + else if (!special) + *((*dp)++) = '\0'; + return res; +} + +/* + * This registers a new binary format, it recognises the syntax + * ':name:type:offset:magic:mask:interpreter:' + * where the ':' is the IFS, that can be chosen with the first char + */ +static int proc_write_register(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + const char *sp; + char del, *dp; + struct binfmt_entry *e; + int memsize, cnt = count - 1, err = 0; + + MOD_INC_USE_COUNT; + /* some sanity checks */ + if ((count < 11) || (count > 256)) { + err = -EINVAL; + goto _err; + } + + memsize = sizeof(struct binfmt_entry) + count; + if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER))) { + err = -ENOMEM; + goto _err; + } + + sp = buffer + 1; + del = buffer[0]; + dp = (char *)e + sizeof(struct binfmt_entry); + + e->proc_name = copyarg(&dp, &sp, &cnt, del, 0, &err); + + /* we can use bit 3 and 5 of type for ext/magic and ext-strip + flag due to the nice encoding of E, M, e and m */ + if ((*sp & 0x92) || (sp[1] != del)) + err = -EINVAL; + else + e->flags = (*sp++ & (ENTRY_MAGIC | ENTRY_STRIP_EXT)) + | ENTRY_ENABLED; + cnt -= 2; sp++; + + e->offset = 0; + while (cnt-- && isdigit(*sp)) + e->offset = e->offset * 10 + *sp++ - '0'; + if (*sp++ != del) + err = -EINVAL; + + e->magic = copyarg(&dp, &sp, &cnt, del, (e->flags & ENTRY_MAGIC), &err); + e->size = dp - e->magic; + e->mask = copyarg(&dp, &sp, &cnt, del, 1, &err); + if (e->mask && ((dp - e->mask) != e->size)) + err = -EINVAL; + e->interpreter = copyarg(&dp, &sp, &cnt, del, 0, &err); + e->id = free_id++; + + /* more sanity checks */ + if (err || !(!cnt || (!(--cnt) && (*sp == '\n'))) || + (e->size < 1) || ((e->size + e->offset) > 127) || + !(e->proc_name) || !(e->interpreter) || + entry_proc_setup(e)) { + kfree(e); + err = -EINVAL; + goto _err; + } + + write_lock(&entries_lock); + e->next = entries; + entries = e; + write_unlock(&entries_lock); + + return count; +_err: + MOD_DEC_USE_COUNT; + return err; +} + +/* + * Get status of entry/binfmt_misc + * FIXME? should an entry be marked disabled if binfmt_misc is disabled though + * entry is enabled? + */ +static int proc_read_status(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct binfmt_entry *e; + char *dp; + int elen, i; + + MOD_INC_USE_COUNT; +#ifndef VERBOSE_STATUS + if (data) { + read_lock(&entries_lock); + if (!(e = get_entry((int) data))) + i = 0; + else + i = e->flags & ENTRY_ENABLED; + read_unlock(&entries_lock); + } else { + i = enabled; + } + sprintf(page, "%s\n", (i ? "enabled" : "disabled")); +#else + if (!data) + sprintf(page, "%s\n", (enabled ? "enabled" : "disabled")); + else { + read_lock(&entries_lock); + if (!(e = get_entry((int) data))) { + *page = '\0'; + goto _out; + } + sprintf(page, "%s\ninterpreter %s\n", + (e->flags & ENTRY_ENABLED ? "enabled" : "disabled"), + e->interpreter); + dp = page + strlen(page); + if (!(e->flags & ENTRY_MAGIC)) { + sprintf(dp, "extension .%s\n", e->magic); + dp = page + strlen(page); + } else { + sprintf(dp, "offset %i\nmagic ", e->offset); + dp = page + strlen(page); + for (i = 0; i < e->size; i++) { + sprintf(dp, "%02x", 0xff & (int) (e->magic[i])); + dp += 2; + } + if (e->mask) { + sprintf(dp, "\nmask "); + dp += 6; + for (i = 0; i < e->size; i++) { + sprintf(dp, "%02x", 0xff & (int) (e->mask[i])); + dp += 2; + } + } + *dp++ = '\n'; + *dp = '\0'; + } + if (e->flags & ENTRY_STRIP_EXT) + sprintf(dp, "extension stripped\n"); +_out: + read_unlock(&entries_lock); + } +#endif + + elen = strlen(page) - off; + if (elen < 0) + elen = 0; + *eof = (elen <= count) ? 1 : 0; + *start = page + off; + + MOD_DEC_USE_COUNT; + return elen; +} + +/* + * Set status of entry/binfmt_misc: + * '1' enables, '0' disables and '-1' clears entry/binfmt_misc + */ +static int proc_write_status(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + struct binfmt_entry *e; + int res = count; + + MOD_INC_USE_COUNT; + if (((buffer[0] == '1') || (buffer[0] == '0')) && + ((count == 1) || ((count == 2) && (buffer[1] == '\n')))) { + if (data) { + read_lock(&entries_lock); + if ((e = get_entry((int) data))) + e->flags = (e->flags & -2) | (int) (buffer[0] - '0'); + read_unlock(&entries_lock); + } else { + enabled = buffer[0] - '0'; + } + } else if ((buffer[0] == '-') && (buffer[1] == '1') && + ((count == 2) || ((count == 3) && (buffer[2] == '\n')))) { + if (data) + clear_entry((int) data); + else + clear_entries(); + } else { + res = -EINVAL; + } + MOD_DEC_USE_COUNT; + return res; +} + +/* + * Remove the /proc-dir entries of one binfmt + */ +static void entry_proc_cleanup(struct binfmt_entry *e) +{ + remove_proc_entry(e->proc_name, bm_dir); +} + +/* + * Create the /proc-dir entry for binfmt + */ +static int entry_proc_setup(struct binfmt_entry *e) +{ + if (!(e->proc_dir = create_proc_entry(e->proc_name, + S_IFREG | S_IRUGO | S_IWUSR, bm_dir))) + return -ENOMEM; + + e->proc_dir->data = (void *) (e->id); + e->proc_dir->read_proc = proc_read_status; + e->proc_dir->write_proc = proc_write_status; + + return 0; +} + + +__initfunc(int init_misc_binfmt(void)) +{ + struct proc_dir_entry *status = NULL, *reg; + + if (!(bm_dir = create_proc_entry("sys/fs/binfmt_misc", S_IFDIR, + NULL)) || + !(status = create_proc_entry("status", S_IFREG | S_IRUGO | S_IWUSR, + bm_dir)) || + !(reg = create_proc_entry("register", S_IFREG | S_IWUSR, + bm_dir))) { + if (status) + remove_proc_entry("status", bm_dir); + if (bm_dir) + remove_proc_entry("sys/fs/binfmt_misc", NULL); + return -ENOMEM; + } + status->read_proc = proc_read_status; + status->write_proc = proc_write_status; + + reg->write_proc = proc_write_register; + + return register_binfmt(&misc_format); +} + +#ifdef MODULE +EXPORT_NO_SYMBOLS; +int init_module(void) +{ + return init_misc_binfmt(); +} + +void cleanup_module(void) +{ + unregister_binfmt(&misc_format); + remove_proc_entry("register", bm_dir); + remove_proc_entry("status", bm_dir); + remove_proc_entry("sys/fs/binfmt_misc", NULL); +} +#endif +#undef VERBOSE_STATUS diff -u --recursive --new-file v2.1.42/linux/fs/buffer.c linux/fs/buffer.c --- v2.1.42/linux/fs/buffer.c Thu May 29 21:53:08 1997 +++ linux/fs/buffer.c Mon Jun 16 08:46:23 1997 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -81,8 +82,6 @@ * remove any of the parameters, make sure to update kernel/sysctl.c. */ -static void wakeup_bdflush(int); - #define N_PARAM 9 /* The dummy values in this structure are left in there for compatibility @@ -113,6 +112,8 @@ int bdflush_min[N_PARAM] = { 0, 10, 5, 25, 0, 100, 100, 1, 1}; int bdflush_max[N_PARAM] = {100,5000, 2000, 2000,100, 60000, 60000, 2047, 5}; +void wakeup_bdflush(int); + /* * Rewrote the wait-routines to use the "new" wait-queue functionality, * and getting rid of the cli-sti pairs. The wait-queue routines still @@ -1109,10 +1110,10 @@ { if (test_and_clear_bit(PG_decr_after, &page->flags)) atomic_dec(&nr_async_pages); + if (test_and_clear_bit(PG_swap_unlock_after, &page->flags)) + swap_after_unlock_page(page->pg_swap_entry); if (test_and_clear_bit(PG_free_after, &page->flags)) __free_page(page); - if (test_and_clear_bit(PG_swap_unlock_after, &page->flags)) - swap_after_unlock_page(page->swap_unlock_entry); } /* @@ -1533,7 +1534,7 @@ struct wait_queue * bdflush_done = NULL; struct task_struct *bdflush_tsk = 0; -static void wakeup_bdflush(int wait) +void wakeup_bdflush(int wait) { if (current == bdflush_tsk) return; @@ -1707,7 +1708,9 @@ #ifdef DEBUG printk("bdflush() activated..."); #endif - + + CHECK_EMERGENCY_SYNC + ncount = 0; #ifdef DEBUG for(nlist = 0; nlist < NR_LIST; nlist++) diff -u --recursive --new-file v2.1.42/linux/fs/dcache.c linux/fs/dcache.c --- v2.1.42/linux/fs/dcache.c Tue May 13 22:41:14 1997 +++ linux/fs/dcache.c Thu Jun 12 21:53:45 1997 @@ -1,283 +1,1039 @@ /* - * linux/fs/dcache.c + * fs/dcache.c * - * (C) Copyright 1994 Linus Torvalds + * Complete reimplementation + * (C) 1997 Thomas Schoebel-Theuer */ -/* Speeded up searches a bit and threaded the mess. -DaveM */ +/* The new dcache is exclusively called from the VFS, not from + * the specific fs'es any more. Despite having the same name as in the + * old code, it has less to do with it. + * + * It serves many purposes: + * + * 1) Any inode that has been retrieved with lookup() and is in use + * (i_count>0), has access to its full absolute path name, by going + * to inode->i_dentry and then recursively following the entry->d_parent + * chain. Use d_path() as predefined method for that. + * You may find out the corresponding inode belonging to + * a dentry by calling d_inode(). This can be used as an easy way for + * determining .. and its absolute pathname, an old UNIX problem that + * deserved a solution for a long time. + * Note that hardlinked inodes may have multiple dentries assigned to + * (via the d_next chain), reflecting multiple alias pathnames. + * + * 2) If not disabled by filesystem types specifying FS_NO_DCACHE, + * the dentries of unused (aged) inodes are retained for speeding up + * lookup()s, by allowing hashed inquiry starting from the dentry of + * the parent directory. + * + * 3) It can remeber so-called "negative entries", that is dentries for + * pathnames that are known to *not* exist, so unneccessary repeated + * lookup()s for non-existant names can be saved. + * + * 4) It provides a means for keeping deleted files (inode->i_nlink==0) + * accessible in the so-called *basket*. Inodes in the basket have been + * removed with unlink() while being in use (i_count>0), so they would + * normally use up space on the disk and be accessile through their + * filedescriptor, but would not be accessible for lookup() any more. + * The basket simply keeps such files in the dcache (for potential + * dcache lookup) until they are either eventually removed completely, + * or transferred to the second-level basket, the so-called *ibasket*. + * The ibasket is implemented in the new inode code, on request of + * filesystem types that have the flag FS_IBASKET set, and proliferates + * the unlinked files when i_count has gone to zero, at least as long + * as there is space on the disk and enough inodes remain available + * and no umount() has started. + * + * 5) Preliminary dentries can be added by readdir(). While normal dentries + * directly point to the inode via u.d_inode only the inode number is + * known from readdir(), but not more. They can be converted to + * normal dentries by using d_inode(). + */ /* - * The directory cache is a "two-level" cache, each level doing LRU on - * its entries. Adding new entries puts them at the end of the LRU - * queue on the first-level cache, while the second-level cache is - * fed by any cache hits. - * - * The idea is that new additions (from readdir(), for example) will not - * flush the cache of entries that have really been used. + * Notes on the allocation strategy: * - * There is a global hash-table over both caches that hashes the entries - * based on the directory inode number and device as well as on a - * string-hash computed over the name. + * The dcache is a full slave cache of the inodes. Whenever an inode + * is cleared, all the dentries associated with it will recursively + * disappear. dentries have no own reference counting; this has to + * be obeyed for SMP. + * If directories could go out of inode cache while + * successors are alive, this would interrupt the d_parent chain of + * the live successors. To prevent this without using zombies, all + * directories are thus prevented from __iput() as long as successors + * are alive. */ -#include +#include #include +#include +#include +#include +#include -#include -#include - -spinlock_t dcache_lock = SPIN_LOCK_UNLOCKED; +/* this should be removed after the beta phase */ +/* #define DEBUG */ +/*#undef DEBUG*/ +/* #define DEBUG_DDIR_COUNT */ + +#define D_HASHSIZE 64 + +/* local flags for d_flag */ +#define D_DIR 32 +#define D_HASHED 64 +#define D_ZOMBIE 128 +#define D_PRELIMINARY 256 +#define D_INC_DDIR 512 + +/* local flags for d_del() */ +#define D_RECURSIVE 4 +#define D_NO_FREE 8 + +/* adjust these constants if you know a probability distribution ... */ +#define D_SMALL 16 +#define D_MEDIUM 64 +#define D_LARGE 256 +#define D_HUGE D_MAXLEN + +#define BASE_DHEADER(x) (struct dheader*)((unsigned long)(x) & ~(PAGE_SIZE-1)) +#define BYTE_ADD(x,n) (void*)((char*)(x) + (n)) +#define BYTE_SUB(x,n) (void*)((char*)(x) - (n)) -/* - * Don't bother caching long names.. They just take up space in the cache, and - * for a name cache you just want to cache the "normal" names anyway which tend - * to be short. +/* This is for global allocation of dentries. Remove this when + * converting to SLAB. */ -#define DCACHE_NAME_LEN 15 -#define DCACHE_SIZE 1024 -#define DCACHE_HASH_QUEUES 256 /* keep this a pow2 */ +struct dheader { + struct dentry * emptylist; + short free, maxfree; + struct dheader * next; + struct dheader * prev; +}; -/* - * The dir_cache_entry must be in this order: we do ugly things with the pointers +struct anchors { + struct dheader * free; /* each contains at least 1 empty dentry */ + struct dheader * full; /* all the used up ones */ + struct dheader * dir_free; + struct dheader * dir_full; +}; + +/* This is only used for directory dentries. Think of it as an extension + * of the dentry. + * It is defined as separate struct, so it uses up space only + * where necessary. */ -struct dir_cache_entry { - struct dir_cache_entry *next; - struct dir_cache_entry **pprev; - kdev_t dc_dev; - unsigned long dir; - unsigned long version; - unsigned long ino; - unsigned char name_len; - char name[DCACHE_NAME_LEN]; - struct dir_cache_entry ** lru_head; - struct dir_cache_entry * next_lru, * prev_lru; +struct ddir { + struct dentry * dd_hashtable[D_HASHSIZE]; + struct dentry * dd_neglist; + struct dentry * dd_basketlist; + struct dentry * dd_zombielist; + unsigned short dd_alloced; /* # d_alloc()ed, but not yet d_add()ed */ + unsigned short dd_hashed; /* # of entries in hashtable */ + unsigned short dd_true_hashed; /* # non-preliminaries in hashtable */ + unsigned short dd_negs; /* # of negative entries */ }; -#define dcache_offset(x) ((unsigned long)&((struct dir_cache_entry*)0)->x) -#define dcache_datalen (dcache_offset(lru_head) - dcache_offset(dc_dev)) +DEF_INSERT(header,struct dheader,next,prev) +DEF_REMOVE(header,struct dheader,next,prev) -#define COPYDATA(de, newde) \ -memcpy((void *) &newde->dc_dev, (void *) &de->dc_dev, dcache_datalen) +DEF_INSERT(alias,struct dentry,d_next,d_prev) +DEF_REMOVE(alias,struct dentry,d_next,d_prev) -static struct dir_cache_entry level1_cache[DCACHE_SIZE]; -static struct dir_cache_entry level2_cache[DCACHE_SIZE]; +DEF_INSERT(hash,struct dentry,d_hash_next,d_hash_prev) +DEF_REMOVE(hash,struct dentry,d_hash_next,d_hash_prev) -/* - * The LRU-lists are doubly-linked circular lists, and do not change in size - * so these pointers always have something to point to (after _init) - */ -static struct dir_cache_entry * level1_head; -static struct dir_cache_entry * level2_head; +DEF_INSERT(basket,struct dentry,d_basket_next,d_basket_prev) +DEF_REMOVE(basket,struct dentry,d_basket_next,d_basket_prev) -/* The hash queues are layed out in a slightly different manner. */ -static struct dir_cache_entry *hash_table[DCACHE_HASH_QUEUES]; +static struct anchors anchors[4]; -#define hash_fn(dev,dir,namehash) \ - ((HASHDEV(dev) ^ (dir) ^ (namehash)) & (DCACHE_HASH_QUEUES - 1)) +struct dentry * the_root = NULL; -/* - * Stupid name"hash" algorithm. Write something better if you want to, - * but I doubt it matters that much. +unsigned long name_cache_init(unsigned long mem_start, unsigned long mem_end) +{ + memset(anchors, 0, sizeof(anchors)); + return mem_start; +} + +#ifdef DEBUG +/* throw this away after the beta phase */ +/*************************************************************************/ +extern void xcheck(char * txt, struct inode * p); + +static int x_alloc = 0; +static int x_freed = 0; +static int x_free = 0; + +static void * tst[20000]; +static int cnt = 0; + +static void ins(void* ptr) +{ + extern int inodes_stat; + tst[cnt++] = ptr; + if(cnt % 1000 == 0) + printk("------%d allocated: %d: %d %d %d\n", inodes_stat, cnt, + x_alloc, x_freed, x_free); + if(cnt>=20000) panic("stop"); +} + +#if 0 +static inline int search(void* ptr) +{ + int i; + for(i = cnt-1; i>=0; i--) + if(tst[i] == ptr) + return i; + return -1; +} + +#define TST(n,x) if(search(x)<0) printk("%s bad ptr %p line %d\n", n, x, __LINE__) +#else +#define TST(n,x) /*nothing*/ +#endif + +void LOG(char * txt, struct dentry * entry) +{ + static int count = 0; + if(entry) { + TST(txt,entry); + } + if(count) { + count--; + printk("%s: entry=%p\n", txt, entry); + } +} + +#ifdef DEBUG_DDIR_COUNT +static struct ddir * d_dir(struct dentry * entry); +void recursive_test(struct dentry * entry) +{ + int i; + struct ddir * ddir = d_dir(entry); + int sons = 0; + + if(ddir->dd_zombielist) + sons++; + for(i=0; i < D_HASHSIZE; i++) { + struct dentry ** base = &ddir->dd_hashtable[i]; + struct dentry * tmp = *base; + if(tmp) do { + TST("__clear",tmp); + if(!(tmp->d_flag & D_HASHED)) { + printk("VFS: dcache entry not hashed!\n"); + printpath(*base); printk("\n"); + printpath(tmp); + } + if(!(tmp->d_flag & D_PRELIMINARY)) + sons++; + if(tmp->d_flag & D_DIR) + recursive_test(tmp); + tmp = tmp->d_hash_next; + } while(tmp && tmp != *base); + } + if(!sons && !(entry->d_flag & D_PRELIMINARY) && entry->u.d_inode) { + struct inode * inode = entry->u.d_inode; + if(!atomic_read(&inode->i_count)) { + if(!(inode->i_status & 1/*ST_AGED*/)) { + printpath(entry); + printk(" is not aged!\n"); + } + if(inode->i_ddir_count) { + printpath(entry); + printk(" has ddir_count blockage!\n"); + } + } + } +} +#else +#define recursive_test(e) /*nothing*/ +#endif +#else +#define TST(n,x) /*nothing*/ +#define LOG(n,x) /*nothing*/ +#define xcheck(t,i) /*nothing*/ +#define recursive_test(e) /*nothing*/ +/*****************************************************************************/ +#endif + +void printpath(struct dentry * entry) +{ + if(!IS_ROOT(entry)) + printpath(entry->d_parent); + printk("/%s", entry->d_name); +} + +static inline long has_sons(struct ddir * ddir) +{ + return ((ddir->dd_alloced | ddir->dd_hashed) || + ddir->dd_neglist || + ddir->dd_basketlist || + ddir->dd_zombielist); +} + +static inline int has_true_sons(struct ddir * ddir) +{ + return (ddir->dd_alloced | ddir->dd_true_hashed); +} + +/* Only hold the i_ddir_count pseudo refcount when neccessary (i.e. when + * they have true_sons), to prevent keeping too much dir inodes in use. */ -static unsigned long namehash(const char * name, int len) +static inline void inc_ddir(struct dentry * entry, struct inode * inode) { - unsigned long hash = 0; + if(!(entry->d_flag & D_INC_DDIR)) { + entry->d_flag |= D_INC_DDIR; +#ifdef DEBUG + if(inode->i_ddir_count) { + printpath(entry); + printk(" ddir_count=%d\n", inode->i_ddir_count); + } +#endif + inode->i_ddir_count++; + _get_inode(inode); + } +} - while ((len -= sizeof(unsigned long)) > 0) { - hash += get_unaligned((unsigned long *)name); - name += sizeof(unsigned long); +static inline blocking void dec_ddir(struct dentry * entry, struct inode * inode) +{ + if(entry->d_flag & D_INC_DDIR) { + entry->d_flag &= ~D_INC_DDIR; + inode->i_ddir_count--; + if(!inode->i_ddir_count) + __iput(inode); } - return hash + - (get_unaligned((unsigned long *)name) & - ~(~0UL << ((len + sizeof(unsigned long)) << 3))); } -static inline struct dir_cache_entry **get_hlist(struct inode *dir, - const char *name, int len) +/* Do not inline this many times. */ +static void d_panic(void) { - return hash_table + hash_fn(dir->i_dev, dir->i_ino, namehash(name, len)); + panic("VFS: dcache directory corruption"); } -static inline void remove_lru(struct dir_cache_entry * de) +static inline struct ddir * d_dir(struct dentry * entry) { - struct dir_cache_entry * next = de->next_lru; - struct dir_cache_entry * prev = de->prev_lru; + struct ddir * res = BYTE_SUB(entry, sizeof(struct ddir)); - next->prev_lru = prev; - prev->next_lru = next; + if(!(entry->d_flag & D_DIR)) + d_panic(); +#ifdef DEBUG + if(!entry) + panic("entry NULL!"); + if(BASE_DHEADER(res) != BASE_DHEADER(entry)) + printk("Scheisse!!!\n"); +#endif + return res; } -static inline void add_lru(struct dir_cache_entry * de, struct dir_cache_entry *head) +static /*inline*/ struct dheader * dinit(int isdir, int size) { - struct dir_cache_entry * prev = head->prev_lru; + struct dheader * res = (struct dheader*)__get_free_page(GFP_KERNEL); + int restlen = PAGE_SIZE - sizeof(struct dheader); + struct dentry * ptr = BYTE_ADD(res, sizeof(struct dheader)); + + if(!res) + return NULL; + memset(res, 0, sizeof(struct dheader)); + if(isdir) { + ptr = BYTE_ADD(ptr, sizeof(struct ddir)); + size += sizeof(struct ddir); + } + if(BASE_DHEADER(ptr) != res) + panic("Bad kernel page alignment"); + size += sizeof(struct dentry) - D_MAXLEN; + res->emptylist = NULL; + res->free = 0; + while(restlen >= size) { +#ifdef DEBUG + ins(ptr); + if(BASE_DHEADER(ptr) != res) + panic("Wrong dinit!"); +#endif + ptr->d_next = res->emptylist; + res->emptylist = ptr; + ptr = BYTE_ADD(ptr, size); + res->free++; + restlen -= size; + } + res->maxfree = res->free; + return res; +} - de->next_lru = head; - de->prev_lru = prev; - prev->next_lru = de; - head->prev_lru = de; +static /*inline*/ struct dentry * __dalloc(struct anchors * anchor, + struct dentry * parent, int isdir, + int len, int size) +{ + struct dheader ** free = isdir ? &anchor->dir_free : &anchor->free; + struct dheader ** full = isdir ? &anchor->dir_full : &anchor->full; + struct dheader * base = *free; + struct dentry * res; + + if(!base) { + base = dinit(isdir, size); + if(!base) + return NULL; + insert_header(free, base); + } + base->free--; + res = base->emptylist; + if(!(base->emptylist = res->d_next)) { + remove_header(free, base); + insert_header(full, base); + } + memset(res, 0, sizeof(struct dentry) - D_MAXLEN); + if(isdir) { + res->d_flag = D_DIR; + memset(d_dir(res), 0, sizeof(struct ddir)); + } + res->d_len = len; + res->d_parent = parent; + if(parent) { + struct ddir * pdir = d_dir(parent); +#ifdef DEBUG + if(pdir->dd_alloced > 1 && !IS_ROOT(parent)) { + printpath(parent); + printk(" dd_alloced=%d\n", pdir->dd_alloced); + } +#endif + pdir->dd_alloced++; + } +#ifdef DEBUG + x_alloc++; +#endif + return res; } -static inline void update_lru(struct dir_cache_entry * de) +struct dentry * d_alloc(struct dentry * parent, int len, int isdir) { - if (de == *de->lru_head) - *de->lru_head = de->next_lru; - else { - remove_lru(de); - add_lru(de,*de->lru_head); + int i, size; + +#ifdef DEBUG + if(the_root) + recursive_test(the_root); + LOG("d_alloc", parent); +#endif + if(len >= D_MEDIUM) { + if(len >= D_LARGE) { + i = 3; + size = D_HUGE; + } else { + i = 2; + size = D_LARGE; + } + } else if(len >= D_SMALL) { + i = 1; + size = D_MEDIUM; + } else { + i = 0; + size = D_SMALL; } + return __dalloc(&anchors[i], parent, isdir, len, size); } -/* - * Hash queue manipulation. Look out for the casts.. - * - * What casts? 8-) -DaveM - */ -static inline void remove_hash(struct dir_cache_entry * de) +extern blocking struct dentry * d_alloc_root(struct inode * root_inode) { - if(de->pprev) { - if(de->next) - de->next->pprev = de->pprev; - *de->pprev = de->next; - de->pprev = NULL; + struct dentry * res = the_root; + + if(res) { + d_del(res, D_NO_CLEAR_INODE); /* invalidate everything beyond */ + } else { + struct ddir * ddir; + + the_root = res = d_alloc(NULL, 0, 1); + LOG("d_alloc_root", res); + res->d_parent = res; + res->d_name[0]='\0'; + ddir = d_dir(res); + ddir->dd_alloced = 999; /* protect from deletion */ } + insert_alias(&root_inode->i_dentry, res); + root_inode->i_dent_count++; + root_inode->i_ddir_count++; + res->u.d_inode = root_inode; + return res; } -static inline void add_hash(struct dir_cache_entry * de, struct dir_cache_entry ** hash) +static inline unsigned long d_hash(char first, char last) { - if((de->next = *hash) != NULL) - (*hash)->pprev = &de->next; - *hash = de; - de->pprev = hash; + return ((unsigned long)first ^ ((unsigned long)last << 4)) & (D_HASHSIZE-1); } -/* - * Find a directory cache entry given all the necessary info. - */ -static inline struct dir_cache_entry * find_entry(struct inode * dir, const char * name, unsigned char len, struct dir_cache_entry ** hash) +static inline struct dentry ** d_base_entry(struct ddir * pdir, struct dentry * entry) { - struct dir_cache_entry *de; + return &pdir->dd_hashtable[d_hash(entry->d_name[0], + entry->d_name[entry->d_len-1])]; +} - de = *hash; - goto inside; - for (;;) { - de = de->next; -inside: - if (!de) - break; - if((de->name_len == (unsigned char) len) && - (de->dc_dev == dir->i_dev) && - (de->dir == dir->i_ino) && - (de->version == dir->i_version) && - (!memcmp(de->name, name, len))) - break; +static inline struct dentry ** d_base_qstr(struct ddir * pdir, + struct qstr * s1, + struct qstr * s2) +{ + unsigned long hash; + + if(s2 && s2->len) { + hash = d_hash(s1->name[0], s2->name[s2->len-1]); + } else { + hash = d_hash(s1->name[0], s1->name[s1->len-1]); } - return de; + return &pdir->dd_hashtable[hash]; } -/* - * Move a successfully used entry to level2. If already at level2, - * move it to the end of the LRU queue.. + +static /*inline*/ blocking void _d_remove_from_parent(struct dentry * entry, + struct ddir * pdir, + struct inode * inode, + int flags) +{ + if(entry->d_flag & D_HASHED) { + struct dentry ** base = d_base_entry(pdir, entry); + + remove_hash(base, entry); + entry->d_flag &= ~D_HASHED; + pdir->dd_hashed--; + if(!(entry->d_flag & D_PRELIMINARY)) { + pdir->dd_true_hashed--; + if(!inode) { +#ifdef DEBUG + if(!entry->d_next || !entry->d_prev) { + printpath(entry); + printk(" flags=%x d_flag=%x negs=%d " + "hashed=%d\n", flags, entry->d_flag, + pdir->dd_negs, pdir->dd_hashed); + } +#endif + remove_alias(&pdir->dd_neglist, entry); + pdir->dd_negs--; + } + } + } else if(!(entry->d_flag & D_ZOMBIE)) { +#ifdef DEBUG + if(!pdir->dd_alloced) printk("dd_alloced is 0!\n"); +#endif + pdir->dd_alloced--; + } + if(entry->d_flag & D_BASKET) { + remove_basket(&pdir->dd_basketlist, entry); + entry->d_flag &= ~D_BASKET; + } +} + +/* Theoretically, zombies should never or extremely seldom appear, + * so this code is nearly superfluous. + * A way to get zombies is while using inodes (i_count>0), unlink() + * them as well as rmdir() the parent dir => the parent dir becomes a zombie. + * Zombies are *not* in the hashtable, because somebody could re-creat() + * that filename in it's parent dir again. + * Besides coding errors during beta phase, when forcing an umount() + * (e.g. at shutdown time), inodes could be in use such that the parent + * dir is cleared, resulting also in zombies. */ -static inline void move_to_level2(struct dir_cache_entry * old_de, struct dir_cache_entry ** hash) +static /*inline*/ void _d_handle_zombie(struct dentry * entry, + struct ddir * ddir, + struct ddir * pdir) { - struct dir_cache_entry * de; + if(entry->d_flag & D_DIR) { + if(entry->d_flag & D_ZOMBIE) { + if(!has_sons(ddir)) { + entry->d_flag &= ~D_ZOMBIE; + remove_hash(&pdir->dd_zombielist, entry); + if(!pdir->dd_zombielist && + (entry->d_parent->d_flag & D_ZOMBIE)) { + d_del(entry->d_parent, D_NORMAL); + } + } + } else if(has_sons(ddir)) { + entry->d_flag |= D_ZOMBIE; + insert_hash(&pdir->dd_zombielist, entry); + + /* This condition is no longer a bug, with the removal + * of recursive_clear() this happens naturally during + * an unmount attempt of a filesystem which is busy. + */ +#if 0 + /* Not sure when this message should show up... */ + if(!IS_ROOT(entry)) { + printk("VFS: clearing dcache directory " + "with successors\n"); +#ifdef DEBUG + printpath(entry); + printk(" d_flag=%x alloced=%d negs=%d hashed=%d " + "basket=%p zombies=%p\n", + entry->d_flag, ddir->dd_alloced, + ddir->dd_negs, ddir->dd_hashed, + ddir->dd_basketlist, ddir->dd_zombielist); +#endif + } +#endif + } + } +} + +static /*inline*/ blocking void _d_del(struct dentry * entry, + struct anchors * anchor, + int flags) +{ + struct dheader ** free; + struct dheader ** full; + struct dheader * base = BASE_DHEADER(entry); + struct ddir * ddir = NULL; + struct ddir * pdir; + struct inode * inode = entry->d_flag & D_PRELIMINARY ? NULL : entry->u.d_inode; + +#ifdef DEBUG + if(inode) + xcheck("_d_del", inode); +#endif + if(!entry->d_parent) { + printk("VFS: dcache parent is NULL\n"); + return; + } + if(entry->d_flag & D_DIR) { + free = &anchor->dir_free; + full = &anchor->dir_full; + } else { + free = &anchor->free; + full = &anchor->full; + } + pdir = d_dir(entry->d_parent); + if(!IS_ROOT(entry)) + _d_remove_from_parent(entry, pdir, inode, flags); - if (old_de->lru_head == &level2_head) { - update_lru(old_de); + /* This may block, be careful! _d_remove_from_parent() is + * thus called before. + */ + if(entry->d_flag & D_DIR) + ddir = d_dir(entry); + if(IS_ROOT(entry)) return; - } - de = level2_head; - level2_head = de->next_lru; - remove_hash(de); - COPYDATA(old_de, de); - add_hash(de, hash); + + if(flags & D_NO_FREE) { + /* Make it re-d_add()able */ + pdir->dd_alloced++; + entry->d_flag &= D_DIR; + } else + _d_handle_zombie(entry, ddir, pdir); + + /* This dec_ddir() must occur after zombie handling. */ + if(!has_true_sons(pdir)) + dec_ddir(entry->d_parent, entry->d_parent->u.d_inode); + + entry->u.d_inode = NULL; + if(inode) { + remove_alias(&inode->i_dentry, entry); + inode->i_dent_count--; + if (entry->d_flag & D_DIR) + dec_ddir(entry, inode); + + if(!(flags & D_NO_CLEAR_INODE) && + !(atomic_read(&inode->i_count) + + inode->i_ddir_count + + inode->i_dent_count)) { +#ifdef DEBUG + printk("#"); +#endif + /* This may block also. */ + _clear_inode(inode, 0, 0); + } + } + if(!(flags & D_NO_FREE) && !(entry->d_flag & D_ZOMBIE)) { + base->free++; + if(base->free == base->maxfree) { +#ifndef DEBUG + remove_header(free, base); + free_page((unsigned long)base); + goto done; +#endif + } + entry->d_next = base->emptylist; + base->emptylist = entry; + if(!entry->d_next) { + remove_header(full, base); + insert_header(free, base); + } +#ifdef DEBUG + x_freed++; +#endif + } +#ifndef DEBUG +done: +#else + x_free++; +#endif } -int dcache_lookup(struct inode * dir, const char * name, int len, unsigned long * ino) +blocking void d_del(struct dentry * entry, int flags) { - int ret = 0; + int i; + + if(!entry) + return; + LOG("d_clear", entry); + if(entry->d_len >= D_MEDIUM) { + if(entry->d_len >= D_LARGE) { + i = 3; + } else { + i = 2; + } + } else if(entry->d_len >= D_SMALL) { + i = 1; + } else { + i = 0; + } + _d_del(entry, &anchors[i], flags); +} + +static inline struct dentry * __dlookup(struct dentry ** base, + struct qstr * name, + struct qstr * appendix) +{ + struct dentry * tmp = *base; + + if(tmp && name->len) { + int totallen = name->len; + + if(appendix) + totallen += appendix->len; + do { + if(tmp->d_len == totallen && + !(tmp->d_flag & D_DUPLICATE) && + !strncmp(tmp->d_name, name->name, name->len) && + (!appendix || !strncmp(tmp->d_name+name->len, + appendix->name, appendix->len))) + return tmp; + tmp = tmp->d_hash_next; + } while(tmp != *base); + } + return NULL; +} + +struct dentry * d_lookup(struct inode * dir, + struct qstr * name, + struct qstr * appendix) +{ + if(dir->i_dentry) { + struct ddir * ddir = d_dir(dir->i_dentry); + struct dentry ** base = d_base_qstr(ddir, name, appendix); + + return __dlookup(base, name, appendix); + } + return NULL; +} + +static /*inline*/ blocking void _d_insert_to_parent(struct dentry * entry, + struct ddir * pdir, + struct inode * inode, + struct qstr * ininame, + int flags) +{ + struct dentry ** base; + struct dentry * parent = entry->d_parent; + +#ifdef DEBUG + if(!pdir->dd_alloced) + printk("dd_alloced is 0!\n"); +#endif + base = d_base_qstr(pdir, ininame, NULL); + if(!(flags & (D_NOCHECKDUP|D_DUPLICATE)) && + __dlookup(base, ininame, NULL)) { + d_del(entry, D_NO_CLEAR_INODE); + return; + } + if(entry->d_flag & D_HASHED) { + printk("VFS: dcache entry is already hashed\n"); + return; + } + if(!(flags & D_PRELIMINARY)) + pdir->dd_true_hashed++; + pdir->dd_hashed++; + insert_hash(base, entry); + entry->d_flag |= D_HASHED; + pdir->dd_alloced--; + if(flags & D_BASKET) + insert_basket(&pdir->dd_basketlist, entry); + +#ifdef DEBUG + if(inode && inode->i_dentry && (entry->d_flag & D_DIR)) { + struct dentry * tmp = inode->i_dentry; + printk("Auweia inode=%p entry=%p (%p %p %s)\n", + inode, entry, parent->u.d_inode, parent, parent->d_name); + printk("entry path="); printpath(entry); printk("\n"); + do { + TST("auweia",tmp); + printk("alias path="); printpath(tmp); printk("\n"); + tmp = tmp->d_next; + } while(tmp != inode->i_dentry); + printk("\n"); + } +#endif + if(has_true_sons(pdir)) + inc_ddir(parent, parent->u.d_inode); + if(!inode && !(flags & D_PRELIMINARY)) { + insert_alias(&pdir->dd_neglist, entry); + pdir->dd_negs++; + + /* Don't allow the negative list to grow too much ... */ + while(pdir->dd_negs > (pdir->dd_true_hashed >> 1) + 5) + d_del(pdir->dd_neglist->d_prev, D_REMOVE); + } +} - if(len <= DCACHE_NAME_LEN) { - struct dir_cache_entry **hash = get_hlist(dir, name, len); - struct dir_cache_entry *de; +blocking void d_add(struct dentry * entry, struct inode * inode, + struct qstr * ininame, int flags) +{ + struct dentry * parent = entry->d_parent; + struct qstr dummy; + struct ddir * pdir; + +#ifdef DEBUG + if(inode) + xcheck("d_add", inode); + if(IS_ROOT(entry)) { + printk("VFS: d_add for root dentry "); + printpath(entry); + printk(" -> "); + if(ininame) + printk("%s", ininame->name); + printk("\n"); + return; + } + if(!parent) + panic("d_add with parent==NULL"); + LOG("d_add", entry); +#endif + if(ininame) { + if(ininame->len != entry->d_len) { + printk("VFS: d_add with wrong string length"); + entry->d_len = ininame->len; /* kludge */ + } + memcpy(entry->d_name, ininame->name, ininame->len); + entry->d_name[ininame->len] = '\0'; + } else { + dummy.name = entry->d_name; + dummy.len = entry->d_len; + ininame = &dummy; + } + if(entry->d_flag & D_HASHED) + printk("VFS: d_add of already added dcache entry\n"); - spin_lock(&dcache_lock); - de = find_entry(dir, name, (unsigned char) len, hash); - if(de) { - *ino = de->ino; - move_to_level2(de, hash); - ret = 1; + pdir = d_dir(parent); + _d_insert_to_parent(entry, pdir, inode, ininame, flags); + entry->d_flag |= flags; + if(inode && !(flags & D_PRELIMINARY)) { + if(entry->d_flag & D_DIR) { + if(inode->i_dentry) { + printk("VFS: creating dcache directory alias\n"); + return; + } } - spin_unlock(&dcache_lock); + insert_alias(&inode->i_dentry, entry); + inode->i_dent_count++; } - return ret; + entry->u.d_inode = inode; } -void dcache_add(struct inode * dir, const char * name, int len, unsigned long ino) +blocking struct dentry * d_entry(struct dentry * parent, + struct qstr * name, + struct inode * inode) { - if (len <= DCACHE_NAME_LEN) { - struct dir_cache_entry **hash = get_hlist(dir, name, len); - struct dir_cache_entry *de; + struct ddir * pdir = d_dir(parent); + struct dentry ** base = d_base_qstr(pdir, name, NULL); + struct dentry * found = __dlookup(base, name, NULL); + + if(!found) { + int isdir = (inode && S_ISDIR(inode->i_mode)); + + found = d_alloc(parent, name->len, isdir); + if(found) { + d_add(found, inode, name, + isdir ? (D_DIR|D_NOCHECKDUP) : D_NOCHECKDUP); + } else + printk("VFS: problem with d_alloc\n"); + } + return found; +} - spin_lock(&dcache_lock); - de = find_entry(dir, name, (unsigned char) len, hash); - if (de) { - de->ino = ino; - update_lru(de); - } else { - de = level1_head; - level1_head = de->next_lru; - remove_hash(de); - de->dc_dev = dir->i_dev; - de->dir = dir->i_ino; - de->version = dir->i_version; - de->ino = ino; - de->name_len = len; - memcpy(de->name, name, len); - add_hash(de, hash); +blocking void d_entry_preliminary(struct dentry * parent, + struct qstr * name, + unsigned long ino) +{ + struct ddir * pdir = d_dir(parent); + struct dentry ** base = d_base_qstr(pdir, name, NULL); + struct dentry * found = __dlookup(base, name, NULL); + + if(!found && ino) { + struct dentry * new = d_alloc(parent, name->len, 0); + + if(new) { + d_add(new, NULL, name, D_PRELIMINARY|D_NOCHECKDUP); + new->u.d_ino = ino; + } else + printk("VFS: problem with d_alloc\n"); + } +} + +blocking void d_move(struct dentry * entry, struct inode * newdir, + struct qstr * newname, struct qstr * newapp) +{ + struct ddir tmp; + struct dentry * new; + struct inode * inode; + int len; + int flags; + + if(!entry) + return; + inode = entry->u.d_inode; + flags = entry->d_flag; + if((flags & D_PRELIMINARY) || !inode) { + if(!(flags & D_PRELIMINARY)) + printk("VFS: trying to move negative dcache entry\n"); + d_del(entry, D_NO_CLEAR_INODE); + return; + } +#if 0 +printk("d_move %p '%s' -> '%s%s' dent_count=%d\n", inode, entry->d_name, + newname->name, newapp ? newapp->name : "", inode->i_dent_count); +#endif + if(flags & D_ZOMBIE) { + printk("VFS: moving zombie entry\n"); + } + if(flags & D_DIR) { + struct ddir * ddir = d_dir(entry); + + memcpy(&tmp, ddir, sizeof(struct ddir)); + + /* Simulate empty dir for d_del(). */ + memset(ddir, 0, sizeof(struct ddir)); + } + len = newname->len; + if(newapp) { + len += newapp->len; + flags |= D_BASKET; + } else + flags &= ~D_BASKET; + new = d_alloc(newdir->i_dentry, len, flags & D_DIR); + memcpy(new->d_name, newname->name, newname->len); + if(newapp) + memcpy(new->d_name+newname->len, newapp->name, newapp->len); + new->d_name[len] = '\0'; + d_del(entry, D_NO_CLEAR_INODE); + d_add(new, inode, NULL, flags & (D_DIR|D_BASKET)); + if(flags & D_DIR) { + struct ddir * ddir = d_dir(new); + + memcpy(ddir, &tmp, sizeof(struct ddir)); + } +} + +int d_path(struct dentry * entry, struct inode * chroot, char * buf) +{ + if(IS_ROOT(entry) || (chroot && entry->u.d_inode == chroot && + !(entry->d_flag & D_PRELIMINARY))) { + *buf = '/'; + return 1; + } else { + int len = d_path(entry->d_parent, chroot, buf); + + buf += len; + if(len > 1) { + *buf++ = '/'; + len++; } - spin_unlock(&dcache_lock); + memcpy(buf, entry->d_name, entry->d_len); + return len + entry->d_len; } } -unsigned long name_cache_init(unsigned long mem_start, unsigned long mem_end) +struct dentry * d_basket(struct dentry * dir_entry) { - int i; - struct dir_cache_entry * p; + if(dir_entry && (dir_entry->d_flag & D_DIR)) { + struct ddir * ddir = d_dir(dir_entry); - /* - * Init level1 LRU lists.. - */ - p = level1_cache; - do { - p[1].prev_lru = p; - p[0].next_lru = p+1; - p[0].lru_head = &level1_head; - } while (++p < level1_cache + DCACHE_SIZE-1); - level1_cache[0].prev_lru = p; - p[0].next_lru = &level1_cache[0]; - p[0].lru_head = &level1_head; - level1_head = level1_cache; + return ddir->dd_basketlist; + } else + return NULL; +} - /* - * Init level2 LRU lists.. - */ - p = level2_cache; - do { - p[1].prev_lru = p; - p[0].next_lru = p+1; - p[0].lru_head = &level2_head; - } while (++p < level2_cache + DCACHE_SIZE-1); - level2_cache[0].prev_lru = p; - p[0].next_lru = &level2_cache[0]; - p[0].lru_head = &level2_head; - level2_head = level2_cache; +int d_isbasket(struct dentry * entry) +{ + return entry->d_flag & D_BASKET; +} - /* - * Empty hash queues.. - */ - for (i = 0 ; i < DCACHE_HASH_QUEUES ; i++) - hash_table[i] = NULL; +blocking struct inode * d_inode(struct dentry ** changing_entry) +{ + struct dentry * entry = *changing_entry; + struct inode * inode; - return mem_start; +#ifdef CONFIG_DCACHE_PRELOAD + if(entry->d_flag & D_PRELIMINARY) { + struct qstr name = { entry->d_name, entry->d_len }; + struct ddir * pdir = d_dir(entry->d_parent); + struct dentry ** base = d_base_qstr(pdir, &name, NULL); + struct dentry * found; + unsigned long ino; + struct inode * dir = entry->d_parent->u.d_inode; + TST("d_inode",entry); + ino = entry->u.d_ino; + if(!dir) + d_panic(); + + /* Prevent concurrent d_lookup()s or d_inode()s before + * giving up vfs_lock. This just removes from the parent, + * but does not deallocate it. + */ + + /* !!!!!!! Aiee, here is an unresolved race if somebody + * unlink()s the inode during the iget(). The problem is + * that we need to synchronize externally. Proposed solution: + * put a rw_lock (read-mode) on the parent dir for each + * iget(), lookup() and so on, and a write-mode lock for + * everything that changes the dir (e.g. unlink()), and do + * this consistently everywhere in the generic VFS (not in + * the concrete filesystems). This should kill similar + * races everywhere, with a single clean concept. + * Later, the synchronization stuff can be cleaned out + * of the concrete fs'es. + */ + d_del(entry, D_NO_CLEAR_INODE|D_NO_FREE); + vfs_unlock(); + + /* This circumvents the normal lookup() of pathnames. + * Therefore, preliminary entries must not be used + * (see FS_NO_DCACHE and FS_NO_PRELIM) if the fs does not + * permit fetching *valid* inodes with plain iget(). + */ + inode = __iget(dir->i_sb, ino, 0); + vfs_lock(); + if(!inode) { + printk("VFS: preliminary dcache entry was invalid\n"); + *changing_entry = NULL; + return NULL; + } + xcheck("d_inode iget()", inode); + if((found = __dlookup(base, &name, NULL))) { + d_del(entry, D_NO_CLEAR_INODE); + *changing_entry = found; + } else if(S_ISDIR(inode->i_mode)) { + struct dentry * new = d_alloc(entry->d_parent, entry->d_len, 1); + if(new) + d_add(new, inode, &name, D_DIR); + *changing_entry = new; + + /* Finally deallocate old entry. */ + d_del(entry, D_NO_CLEAR_INODE); + } else { + /* Re-insert to the parent, but now as normal dentry. */ + d_add(entry, inode, NULL, 0); + } + return inode; + } +#endif + inode = entry->u.d_inode; + if(inode) { +#ifdef DEBUG + xcheck("d_inode", inode); +#endif + iinc_zero(inode); + } + return inode; } diff -u --recursive --new-file v2.1.42/linux/fs/devices.c linux/fs/devices.c --- v2.1.42/linux/fs/devices.c Fri Apr 4 08:52:24 1997 +++ linux/fs/devices.c Thu Jun 12 16:22:08 1997 @@ -273,7 +273,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -326,7 +325,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/dquot.c linux/fs/dquot.c --- v2.1.42/linux/fs/dquot.c Tue May 13 22:41:14 1997 +++ linux/fs/dquot.c Thu Jun 12 16:22:08 1997 @@ -237,9 +237,12 @@ filp->f_pos = dqoff(dquot->dq_id); fs = get_fs(); set_fs(KERNEL_DS); + if (filp->f_op->write(filp->f_inode, filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk)) == sizeof(struct dqblk)) dquot->dq_flags &= ~DQ_MOD; + /* inode->i_status |= ST_MODIFIED is willingly *not* done here */ + up(&dquot->dq_mnt->mnt_sem); set_fs(fs); unlock_dquot(dquot); @@ -1035,7 +1038,8 @@ if (special == (char *)NULL && (cmds == Q_SYNC || cmds == Q_GETSTATS)) dev = 0; else { - if (namei(special, &ino)) + int error = namei(NAM_FOLLOW_LINK, special, &ino); + if(error) goto out; dev = ino->i_rdev; ret = -ENOTBLK; diff -u --recursive --new-file v2.1.42/linux/fs/exec.c linux/fs/exec.c --- v2.1.42/linux/fs/exec.c Thu May 15 16:48:04 1997 +++ linux/fs/exec.c Thu Jun 12 16:22:08 1997 @@ -68,6 +68,10 @@ __initfunc(void binfmt_setup(void)) { +#ifdef CONFIG_BINFMT_MISC + init_misc_binfmt(); +#endif + #ifdef CONFIG_BINFMT_ELF init_elf_binfmt(); #endif @@ -154,7 +158,7 @@ } } current->files->fd[fd] = f; - inode->i_count++; + atomic_inc(&inode->i_count); } return fd; } diff -u --recursive --new-file v2.1.42/linux/fs/ext2/balloc.c linux/fs/ext2/balloc.c --- v2.1.42/linux/fs/ext2/balloc.c Tue May 13 22:41:14 1997 +++ linux/fs/ext2/balloc.c Thu Jun 12 16:22:08 1997 @@ -291,6 +291,7 @@ printk ("ext2_new_block: nonexistent device"); return 0; } +retry: lock_super (sb); es = sb->u.ext2_sb.s_es; if (le32_to_cpu(es->s_free_blocks_count) <= le32_to_cpu(es->s_r_blocks_count) && @@ -298,6 +299,8 @@ (sb->u.ext2_sb.s_resgid == 0 || !in_group_p (sb->u.ext2_sb.s_resgid)))) { unlock_super (sb); + if(sb->s_ibasket && free_ibasket(sb)) + goto retry; return 0; } @@ -389,6 +392,8 @@ } if (k >= sb->u.ext2_sb.s_groups_count) { unlock_super (sb); + if(sb->s_ibasket && free_ibasket(sb)) + goto retry; return 0; } bitmap_nr = load_block_bitmap (sb, i); diff -u --recursive --new-file v2.1.42/linux/fs/ext2/dir.c linux/fs/ext2/dir.c --- v2.1.42/linux/fs/ext2/dir.c Sun Jan 26 02:07:43 1997 +++ linux/fs/ext2/dir.c Thu Jun 12 16:22:08 1997 @@ -65,7 +65,6 @@ ext2_mknod, /* mknod */ ext2_rename, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -194,12 +193,13 @@ * currently swapped out. So, use a * version stamp to detect whether or * not the directory has been modified - * during the copy operation. */ - unsigned long version; - dcache_add(inode, de->name, le16_to_cpu(de->name_len), - le32_to_cpu(de->inode)); - version = inode->i_version; - error = filldir(dirent, de->name, le16_to_cpu(de->name_len), filp->f_pos, le32_to_cpu(de->inode)); + * during the copy operation. + */ + unsigned long version = inode->i_version; + + error = filldir(dirent, de->name, + le16_to_cpu(de->name_len), + filp->f_pos, le32_to_cpu(de->inode)); if (error) break; if (version != inode->i_version) diff -u --recursive --new-file v2.1.42/linux/fs/ext2/file.c linux/fs/ext2/file.c --- v2.1.42/linux/fs/ext2/file.c Fri Apr 4 08:52:24 1997 +++ linux/fs/ext2/file.c Thu Jun 12 16:22:08 1997 @@ -72,7 +72,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ generic_readpage, /* readpage */ NULL, /* writepage */ ext2_bmap, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c --- v2.1.42/linux/fs/ext2/ialloc.c Sat Nov 30 02:24:01 1996 +++ linux/fs/ext2/ialloc.c Thu Jun 12 16:22:08 1997 @@ -171,9 +171,9 @@ printk ("ext2_free_inode: inode has no device\n"); return; } - if (inode->i_count > 1) { + if (atomic_read(&inode->i_count) > 1) { printk ("ext2_free_inode: inode has count=%d\n", - inode->i_count); + atomic_read(&inode->i_count)); return; } if (inode->i_nlink) { @@ -404,7 +404,7 @@ sb->s_dirt = 1; inode->i_mode = mode; inode->i_sb = sb; - inode->i_count = 1; + atomic_set(&inode->i_count, 1); inode->i_nlink = 1; inode->i_dev = sb->s_dev; inode->i_uid = current->fsuid; diff -u --recursive --new-file v2.1.42/linux/fs/ext2/namei.c linux/fs/ext2/namei.c --- v2.1.42/linux/fs/ext2/namei.c Tue May 13 22:41:14 1997 +++ linux/fs/ext2/namei.c Thu Jun 12 16:22:08 1997 @@ -172,27 +172,12 @@ iput (dir); return -ENAMETOOLONG; } - if (dcache_lookup(dir, name, len, &ino)) { - if (!ino) { - iput(dir); - return -ENOENT; - } - if (!(*result = iget (dir->i_sb, ino))) { - iput (dir); - return -EACCES; - } - iput (dir); - return 0; - } ino = dir->i_version; if (!(bh = ext2_find_entry (dir, name, len, &de))) { - if (ino == dir->i_version) - dcache_add(dir, name, len, 0); iput (dir); return -ENOENT; } ino = le32_to_cpu(de->inode); - dcache_add(dir, name, len, ino); brelse (bh); if (!(*result = iget (dir->i_sb, ino))) { iput (dir); @@ -391,7 +376,6 @@ } de->inode = cpu_to_le32(inode->i_ino); dir->i_version = ++event; - dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode)); mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); @@ -460,7 +444,6 @@ } de->inode = cpu_to_le32(inode->i_ino); dir->i_version = ++event; - dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode)); mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); @@ -538,7 +521,6 @@ } de->inode = cpu_to_le32(inode->i_ino); dir->i_version = ++event; - dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode)); mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); @@ -662,7 +644,7 @@ else if (le32_to_cpu(de->inode) != inode->i_ino) retval = -ENOENT; else { - if (inode->i_count > 1) { + if (atomic_read(&inode->i_count) > 1) { /* * Are we deleting the last instance of a busy directory? * Better clean up if so. @@ -836,7 +818,6 @@ } de->inode = cpu_to_le32(inode->i_ino); dir->i_version = ++event; - dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode)); mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); @@ -885,7 +866,6 @@ } de->inode = cpu_to_le32(oldinode->i_ino); dir->i_version = ++event; - dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode)); mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); @@ -905,7 +885,7 @@ int ino; int result; - new_inode->i_count++; + atomic_inc(&new_inode->i_count); result = 0; for (;;) { if (new_inode == old_inode) { @@ -945,8 +925,7 @@ */ static int do_ext2_rename (struct inode * old_dir, const char * old_name, int old_len, struct inode * new_dir, - const char * new_name, int new_len, - int must_be_dir) + const char * new_name, int new_len) { struct inode * old_inode, * new_inode; struct buffer_head * old_bh, * new_bh, * dir_bh; @@ -981,8 +960,6 @@ old_inode = __iget (old_dir->i_sb, le32_to_cpu(old_de->inode), 0); /* don't cross mnt-points */ if (!old_inode) goto end_rename; - if (must_be_dir && !S_ISDIR(old_inode->i_mode)) - goto end_rename; retval = -EPERM; if ((old_dir->i_mode & S_ISVTX) && current->fsuid != old_inode->i_uid && @@ -1016,7 +993,7 @@ if (!empty_dir (new_inode)) goto end_rename; retval = -EBUSY; - if (new_inode->i_count > 1) + if (atomic_read(&new_inode->i_count) > 1) goto end_rename; } retval = -EPERM; @@ -1059,7 +1036,6 @@ * ok, that's it */ new_de->inode = le32_to_cpu(old_inode->i_ino); - dcache_add(new_dir, new_de->name, le16_to_cpu(new_de->name_len), le32_to_cpu(new_de->inode)); retval = ext2_delete_entry (old_de, old_bh); if (retval == -ENOENT) goto try_again; @@ -1075,7 +1051,6 @@ old_dir->i_dirt = 1; if (dir_bh) { PARENT_INO(dir_bh->b_data) = le32_to_cpu(new_dir->i_ino); - dcache_add(old_inode, "..", 2, new_dir->i_ino); mark_buffer_dirty(dir_bh, 1); old_dir->i_nlink--; old_dir->i_dirt = 1; @@ -1123,8 +1098,7 @@ * on the same file system */ int ext2_rename (struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len, - int must_be_dir) + struct inode * new_dir, const char * new_name, int new_len) { int result; @@ -1132,7 +1106,7 @@ sleep_on (&old_dir->i_sb->u.ext2_sb.s_rename_wait); old_dir->i_sb->u.ext2_sb.s_rename_lock = 1; result = do_ext2_rename (old_dir, old_name, old_len, new_dir, - new_name, new_len, must_be_dir); + new_name, new_len); old_dir->i_sb->u.ext2_sb.s_rename_lock = 0; wake_up (&old_dir->i_sb->u.ext2_sb.s_rename_wait); return result; diff -u --recursive --new-file v2.1.42/linux/fs/ext2/super.c linux/fs/ext2/super.c --- v2.1.42/linux/fs/ext2/super.c Tue May 13 22:41:14 1997 +++ linux/fs/ext2/super.c Thu Jun 12 16:22:08 1997 @@ -319,6 +319,13 @@ ext2_check_inodes_bitmap (sb); } } +#if 0 /* ibasket's still have unresolved bugs... -DaveM */ + + /* [T. Schoebel-Theuer] This limit should be maintained on disk. + * This is just provisionary. + */ + sb->s_ibasket_max = 100; +#endif } static int ext2_check_descriptors (struct super_block * sb) @@ -728,7 +735,10 @@ } static struct file_system_type ext2_fs_type = { - ext2_read_super, "ext2", 1, NULL + "ext2", + FS_REQUIRES_DEV /* | FS_IBASKET */, /* ibaskets have unresolved bugs */ + ext2_read_super, + NULL }; __initfunc(int init_ext2_fs(void)) diff -u --recursive --new-file v2.1.42/linux/fs/ext2/symlink.c linux/fs/ext2/symlink.c --- v2.1.42/linux/fs/ext2/symlink.c Sat Jan 25 03:02:44 1997 +++ linux/fs/ext2/symlink.c Thu Jun 12 16:22:08 1997 @@ -25,8 +25,6 @@ #include static int ext2_readlink (struct inode *, char *, int); -static int ext2_follow_link (struct inode *, struct inode *, int, int, - struct inode **); /* * symlinks can't do much... @@ -43,7 +41,6 @@ NULL, /* mknod */ NULL, /* rename */ ext2_readlink, /* readlink */ - ext2_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -52,70 +49,20 @@ NULL /* smap */ }; -static int ext2_follow_link(struct inode * dir, struct inode * inode, - int flag, int mode, struct inode ** res_inode) -{ - int error; - struct buffer_head * bh = NULL; - char * link; - - *res_inode = NULL; - if (!dir) { - dir = current->fs->root; - dir->i_count++; - } - if (!inode) { - iput (dir); - return -ENOENT; - } - if (!S_ISLNK(inode->i_mode)) { - iput (dir); - *res_inode = inode; - return 0; - } - if (current->link_count > 5) { - iput (dir); - iput (inode); - return -ELOOP; - } - if (inode->i_blocks) { - if (!(bh = ext2_bread (inode, 0, 0, &error))) { - iput (dir); - iput (inode); - return -EIO; - } - link = bh->b_data; - } else - link = (char *) inode->u.ext2_i.i_data; - if (DO_UPDATE_ATIME(inode)) { - inode->i_atime = CURRENT_TIME; - inode->i_dirt = 1; - } - current->link_count++; - error = open_namei (link, flag, mode, res_inode, dir); - current->link_count--; - iput (inode); - if (bh) - brelse (bh); - return error; -} - static int ext2_readlink (struct inode * inode, char * buffer, int buflen) { struct buffer_head * bh = NULL; char * link; int i, err; - if (!S_ISLNK(inode->i_mode)) { - iput (inode); - return -EINVAL; - } if (buflen > inode->i_sb->s_blocksize - 1) buflen = inode->i_sb->s_blocksize - 1; if (inode->i_blocks) { bh = ext2_bread (inode, 0, 0, &err); if (!bh) { iput (inode); + if(err < 0) /* indicate type of error */ + return err; return 0; } link = bh->b_data; diff -u --recursive --new-file v2.1.42/linux/fs/fat/dir.c linux/fs/fat/dir.c --- v2.1.42/linux/fs/fat/dir.c Sun Jan 26 02:07:43 1997 +++ linux/fs/fat/dir.c Thu Jun 12 16:22:08 1997 @@ -260,10 +260,8 @@ ino = fat_parent_ino(inode,0); if (shortnames || !is_long) { - dcache_add(inode, bufname, i+dotoffset, ino); - if (both) { + if (both) bufname[i+dotoffset] = '\0'; - } spos = oldpos; if (is_long) { spos = filp->f_pos - sizeof(struct msdos_dir_entry); @@ -276,7 +274,6 @@ } } if (is_long && longnames) { - dcache_add(inode, longname, long_len, ino); if (both) { memcpy(&longname[long_len+1], bufname, i+dotoffset); long_len += i+dotoffset; diff -u --recursive --new-file v2.1.42/linux/fs/fat/file.c linux/fs/fat/file.c --- v2.1.42/linux/fs/fat/file.c Sun Jan 26 02:07:44 1997 +++ linux/fs/fat/file.c Thu Jun 12 16:22:08 1997 @@ -52,7 +52,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ generic_readpage, /* readpage */ NULL, /* writepage */ fat_bmap, /* bmap */ @@ -100,7 +99,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/fat/mmap.c linux/fs/fat/mmap.c --- v2.1.42/linux/fs/fat/mmap.c Mon Oct 28 04:29:25 1996 +++ linux/fs/fat/mmap.c Thu Jun 12 16:22:08 1997 @@ -105,7 +105,7 @@ } vma->vm_inode = inode; - inode->i_count++; + atomic_inc(&inode->i_count); vma->vm_ops = &fat_file_mmap; return 0; } diff -u --recursive --new-file v2.1.42/linux/fs/fifo.c linux/fs/fifo.c --- v2.1.42/linux/fs/fifo.c Mon Mar 11 01:23:22 1996 +++ linux/fs/fifo.c Thu Jun 12 16:22:08 1997 @@ -143,7 +143,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/filesystems.c linux/fs/filesystems.c --- v2.1.42/linux/fs/filesystems.c Thu May 29 21:53:08 1997 +++ linux/fs/filesystems.c Thu Jun 12 16:22:08 1997 @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -43,6 +44,10 @@ device_setup(); binfmt_setup(); + +#ifdef CONFIG_TRANS_NAMES + init_nametrans(); +#endif #ifdef CONFIG_EXT2_FS init_ext2_fs(); diff -u --recursive --new-file v2.1.42/linux/fs/hpfs/hpfs_fs.c linux/fs/hpfs/hpfs_fs.c --- v2.1.42/linux/fs/hpfs/hpfs_fs.c Wed Apr 23 19:01:23 1997 +++ linux/fs/hpfs/hpfs_fs.c Thu Jun 12 16:22:08 1997 @@ -175,7 +175,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ generic_readpage, /* readpage */ NULL, /* writepage */ (int (*)(struct inode *, int)) @@ -219,7 +218,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -1746,7 +1744,10 @@ } static struct file_system_type hpfs_fs_type = { - hpfs_read_super, "hpfs", 1, NULL + "hpfs", + FS_REQUIRES_DEV, + hpfs_read_super, + NULL }; __initfunc(int init_hpfs_fs(void)) diff -u --recursive --new-file v2.1.42/linux/fs/inode.c linux/fs/inode.c --- v2.1.42/linux/fs/inode.c Thu May 15 16:48:04 1997 +++ linux/fs/inode.c Thu Jun 12 21:53:45 1997 @@ -1,657 +1,708 @@ /* - * linux/fs/inode.c: Keeping track of inodes. + * fs/inode.c * - * Copyright (C) 1991, 1992 Linus Torvalds - * Copyright (C) 1997 David S. Miller + * Complete reimplementation + * (C) 1997 Thomas Schoebel-Theuer */ -#include -#include -#include -#include +/* Everything here is intended to be MP-safe. However, other parts + * of the kernel are not yet MP-safe, in particular the inode->i_count++ + * that are spread over everywhere. These should be replaced by + * iinc() as soon as possible. Since I have no MP machine, I could + * not test it. + */ +#include +#include +#include #include +#include +#include +#include +#include +#include + +/* #define DEBUG */ + +#define HASH_SIZE 1024 /* must be a power of 2 */ +#define NR_LEVELS 4 + +#define ST_AGED 1 +#define ST_HASHED 2 +#define ST_EMPTY 4 +#define ST_TO_READ 8 +#define ST_TO_WRITE 16 +#define ST_TO_PUT 32 +#define ST_TO_DROP 64 +#define ST_IO (ST_TO_READ|ST_TO_WRITE|ST_TO_PUT|ST_TO_DROP) +#define ST_WAITING 128 +#define ST_FREEING 256 +#define ST_IBASKET 512 + +/* The idea is to keep empty inodes in a separate list, so no search + * is required as long as empty inodes exit. + * All reusable inodes occurring in the hash table with i_count==0 + * are also registered in the ringlist aged_i[level], but in LRU order. + * Used inodes with i_count>0 are kept solely in the hashtable and in + * all_i, but in no other list. + * The level is used for multilevel aging to avoid thrashing; each + * time i_count decreases to 0, the inode is inserted into the next level + * ringlist. Cache reusage is simply by taking the _last_ element from the + * lowest-level ringlist that contains inodes. + * In contrast to the old code, there isn't any O(n) search overhead now + * in iget/iput (if you make HASH_SIZE large enough). + */ +static struct inode * hashtable[HASH_SIZE];/* linked with i_hash_{next,prev} */ +static struct inode * all_i = NULL; /* linked with i_{next,prev} */ +static struct inode * empty_i = NULL; /* linked with i_{next,prev} */ +static struct inode * aged_i[NR_LEVELS+1]; /* linked with i_lru_{next,prev} */ +static int aged_reused[NR_LEVELS+1]; /* # removals from aged_i[level] */ +static int age_table[NR_LEVELS+1] = { /* You may tune this. */ + 1, 4, 10, 100, 1000 +}; /* after which # of uses to increase to the next level */ + +/* This is for kernel/sysctl.c */ + +/* Just aligning plain ints and arrays thereof doesn't work reliably.. */ +struct { + int nr_inodes; + int nr_free_inodes; + int aged_count[NR_LEVELS+1]; /* # in each level */ +} inodes_stat; -int nr_inodes = 0, nr_free_inodes = 0; int max_inodes = NR_INODE; +unsigned long last_inode = 0; -#define INODE_HASHSZ 1024 - -static struct inode *inode_hash[INODE_HASHSZ]; - -/* All the details of hashing and lookup. */ -#define hashfn(dev, i) ((HASHDEV(dev) + ((i) ^ ((i) >> 10))) & (INODE_HASHSZ - 1)) - -__inline__ void insert_inode_hash(struct inode *inode) -{ - struct inode **htable = &inode_hash[hashfn(inode->i_dev, inode->i_ino)]; - if((inode->i_hash_next = *htable) != NULL) - (*htable)->i_hash_pprev = &inode->i_hash_next; - *htable = inode; - inode->i_hash_pprev = htable; -} - -#define hash_inode(inode) insert_inode_hash(inode) - -static inline void unhash_inode(struct inode *inode) -{ - if(inode->i_hash_pprev) { - if(inode->i_hash_next) - inode->i_hash_next->i_hash_pprev = inode->i_hash_pprev; - *(inode->i_hash_pprev) = inode->i_hash_next; - inode->i_hash_pprev = NULL; - } -} - -static inline struct inode *find_inode(unsigned int hashent, - kdev_t dev, unsigned long ino) +void inode_init(void) { - struct inode *inode; - - for(inode = inode_hash[hashent]; inode; inode = inode->i_hash_next) - if(inode->i_dev == dev && inode->i_ino == ino) - break; - return inode; + memset(hashtable, 0, sizeof(hashtable)); + memset(aged_i, 0, sizeof(aged_i)); + memset(aged_reused, 0, sizeof(aged_reused)); + memset(&inodes_stat, 0, sizeof(inodes_stat)); } -/* Free list queue and management. */ -static struct free_inode_queue { - struct inode *head; - struct inode **last; -} free_inodes = { NULL, &free_inodes.head }; - -static inline void put_inode_head(struct inode *inode) -{ - if((inode->i_next = free_inodes.head) != NULL) - free_inodes.head->i_pprev = &inode->i_next; - else - free_inodes.last = &inode->i_next; - free_inodes.head = inode; - inode->i_pprev = &free_inodes.head; - nr_free_inodes++; -} +/* Intended for short locks of the above global data structures. + * Could be replaced with spinlocks completely, since there is + * no blocking during manipulation of the static data; however the + * lock in invalidate_inodes() may last relatively long. + */ +#ifdef __SMP__ +struct semaphore vfs_sem = MUTEX; +#endif + +DEF_INSERT(all,struct inode,i_next,i_prev) +DEF_REMOVE(all,struct inode,i_next,i_prev) + +DEF_INSERT(lru,struct inode,i_lru_next,i_lru_prev) +DEF_REMOVE(lru,struct inode,i_lru_next,i_lru_prev) + +DEF_INSERT(hash,struct inode,i_hash_next,i_hash_prev) +DEF_REMOVE(hash,struct inode,i_hash_next,i_hash_prev) + +DEF_INSERT(ibasket,struct inode,i_basket_next,i_basket_prev) +DEF_REMOVE(ibasket,struct inode,i_basket_next,i_basket_prev) + +#ifdef DEBUG +extern void printpath(struct dentry * entry); +struct inode * xtst[15000]; +int xcnt = 0; -static inline void put_inode_last(struct inode *inode) +void xcheck(char * txt, struct inode * p) { - inode->i_next = NULL; - inode->i_pprev = free_inodes.last; - *free_inodes.last = inode; - free_inodes.last = &inode->i_next; - nr_free_inodes++; + int i; + for(i=xcnt-1; i>=0; i--) + if(xtst[i] == p) + return; + printk("Bogus inode %p in %s\n", p, txt); } +#else +#define xcheck(t,p) /*nothing*/ +#endif -static inline void remove_free_inode(struct inode *inode) +static inline struct inode * grow_inodes(void) { - if(inode->i_pprev) { - if(inode->i_next) - inode->i_next->i_pprev = inode->i_pprev; - else - free_inodes.last = inode->i_pprev; - *inode->i_pprev = inode->i_next; - inode->i_pprev = NULL; - nr_free_inodes--; + struct inode * res; + struct inode * inode = res = (struct inode*)__get_free_page(GFP_KERNEL); + int size = PAGE_SIZE; + if(!inode) + return NULL; + + size -= sizeof(struct inode); + inode++; + inodes_stat.nr_inodes++; +#ifdef DEBUG +xtst[xcnt++]=res; +#endif + while(size >= sizeof(struct inode)) { +#ifdef DEBUG +xtst[xcnt++]=inode; +#endif + inodes_stat.nr_inodes++; + inodes_stat.nr_free_inodes++; + insert_all(&empty_i, inode); + inode->i_status = ST_EMPTY; + inode++; + size -= sizeof(struct inode); } + return res; } -/* This is the in-use queue, if i_count > 0 (as far as we can tell) - * the sucker is here. - */ -static struct inode *inuse_list = NULL; - -static inline void put_inuse(struct inode *inode) +static inline int hash(dev_t i_dev, unsigned long i_ino) { - if((inode->i_next = inuse_list) != NULL) - inuse_list->i_pprev = &inode->i_next; - inuse_list = inode; - inode->i_pprev = &inuse_list; + return ((int)i_ino ^ ((int)i_dev << 6)) & (HASH_SIZE-1); } -static inline void remove_inuse(struct inode *inode) +static inline blocking void wait_io(struct inode * inode, unsigned short flags) { - if(inode->i_pprev) { - if(inode->i_next) - inode->i_next->i_pprev = inode->i_pprev; - *inode->i_pprev = inode->i_next; - inode->i_pprev = NULL; + while(inode->i_status & flags) { + struct wait_queue wait = {current, NULL}; + inode->i_status |= ST_WAITING; + vfs_unlock(); + add_wait_queue(&inode->i_wait, &wait); + sleep_on(&inode->i_wait); + remove_wait_queue(&inode->i_wait, &wait); + vfs_lock(); } } -/* Locking and unlocking inodes, plus waiting for locks to clear. */ -static void __wait_on_inode(struct inode *); - -static inline void wait_on_inode(struct inode *inode) +static inline blocking void set_io(struct inode * inode, + unsigned short waitflags, + unsigned short setflags) { - if(inode->i_lock) - __wait_on_inode(inode); + wait_io(inode, waitflags); + inode->i_status |= setflags; + vfs_unlock(); } -static inline void lock_inode(struct inode *inode) +static inline blocking int release_io(struct inode * inode, unsigned short flags) { - if(inode->i_lock) - __wait_on_inode(inode); - inode->i_lock = 1; -} - -static inline void unlock_inode(struct inode *inode) -{ - inode->i_lock = 0; - wake_up(&inode->i_wait); + int res = 0; + vfs_lock(); + inode->i_status &= ~flags; + if(inode->i_status & ST_WAITING) { + inode->i_status &= ~ST_WAITING; + vfs_unlock(); + wake_up(&inode->i_wait); + res = 1; + } + return res; } -static void __wait_on_inode(struct inode * inode) +static inline blocking void _io(void (*op)(struct inode*), struct inode * inode, + unsigned short waitflags, unsigned short setflags) { - struct wait_queue wait = { current, NULL }; - - add_wait_queue(&inode->i_wait, &wait); -repeat: - current->state = TASK_UNINTERRUPTIBLE; - if (inode->i_lock) { - schedule(); - goto repeat; + /* Do nothing if the same op is already in progress. */ + if(op && !(inode->i_status & setflags)) { + set_io(inode, waitflags, setflags); + op(inode); + if(release_io(inode, setflags)) { + /* Somebody grabbed my inode from under me. */ +#ifdef DEBUG + printk("_io grab!\n"); +#endif + vfs_lock(); + } } - remove_wait_queue(&inode->i_wait, &wait); - current->state = TASK_RUNNING; } -/* Clear an inode of all it's identity, this is exported to the world. */ -void clear_inode(struct inode *inode) +blocking int _free_ibasket(struct super_block * sb) { - struct wait_queue *wait; - - /* So we don't disappear. */ - inode->i_count++; - - truncate_inode_pages(inode, 0); - wait_on_inode(inode); - if(IS_WRITABLE(inode) && inode->i_sb && inode->i_sb->dq_op) - inode->i_sb->dq_op->drop(inode); - - if(--inode->i_count > 0) - remove_inuse(inode); - else - remove_free_inode(inode); - unhash_inode(inode); - wait = inode->i_wait; - memset(inode, 0, sizeof(*inode)); barrier(); - inode->i_wait = wait; - put_inode_head(inode); /* Pages zapped, put at the front. */ + if(sb->s_ibasket) { + struct inode * delinquish = sb->s_ibasket->i_basket_prev; +#if 0 +printpath(delinquish->i_dentry); +printk(" delinquish\n"); +#endif + _clear_inode(delinquish, 0, 1); + return 1; + } + return 0; } -/* These check the validity of a mount/umount type operation, we essentially - * check if there are any inodes hanging around which prevent this operation - * from occurring. We also clear out clean inodes referencing this device. - */ -int fs_may_mount(kdev_t dev) +static /*inline*/ void _put_ibasket(struct inode * inode) { - struct inode *inode; - int pass = 0; - - inode = free_inodes.head; -repeat: - while(inode) { - struct inode *next = inode->i_next; - if(inode->i_dev != dev) - goto next; - if(inode->i_count || inode->i_dirt || inode->i_lock) - return 0; - clear_inode(inode); - next: - inode = next; + struct super_block * sb = inode->i_sb; + if(!(inode->i_status & ST_IBASKET)) { + inode->i_status |= ST_IBASKET; + insert_ibasket(&sb->s_ibasket, inode); + sb->s_ibasket_count++; + if(sb->s_ibasket_count > sb->s_ibasket_max) + (void)_free_ibasket(sb); } - if(pass == 0) { - inode = inuse_list; - pass = 1; - goto repeat; - } - return 1; /* Tis' cool bro. */ } -int fs_may_umount(kdev_t dev, struct inode *iroot) -{ - struct inode *inode; - int pass = 0; - - inode = free_inodes.head; -repeat: - for(; inode; inode = inode->i_next) { - if(inode->i_dev != dev || !inode->i_count) - continue; - if(inode == iroot && - (inode->i_count == (inode->i_mount == inode ? 2 : 1))) - continue; - return 0; - } - if(pass == 0) { - inode = inuse_list; - pass = 1; - goto repeat; +blocking void _clear_inode(struct inode * inode, int external, int verbose) +{ +xcheck("_clear_inode",inode); + if(inode->i_status & ST_IBASKET) { + struct super_block * sb = inode->i_sb; + remove_ibasket(&sb->s_ibasket, inode); + sb->s_ibasket_count--; + inode->i_status &= ~ST_IBASKET; +#if 0 +printpath(inode->i_dentry); +printk(" put_inode\n"); +#endif + _io(sb->s_op->put_inode, inode, ST_TO_PUT|ST_TO_WRITE, ST_TO_PUT); + if(inode->i_status & ST_EMPTY) + return; } - return 1; /* Tis' cool bro. */ + if(inode->i_status & ST_HASHED) + remove_hash(&hashtable[hash(inode->i_dev, inode->i_ino)], inode); + if(inode->i_status & ST_AGED) { + /* "cannot happen" when called from an fs because at least + * the caller must use it. Can happen when called from + * invalidate_inodes(). */ + if(verbose) + printk("VFS: clearing aged inode\n"); + if(atomic_read(&inode->i_count)) + printk("VFS: aged inode is in use\n"); + remove_lru(&aged_i[inode->i_level], inode); + inodes_stat.aged_count[inode->i_level]--; + } + if(!external && inode->i_status & ST_IO) { + printk("VFS: clearing inode during IO operation\n"); + } + if(!(inode->i_status & ST_EMPTY)) { + remove_all(&all_i, inode); + inode->i_status = ST_EMPTY; + while(inode->i_dentry) { + d_del(inode->i_dentry, D_NO_CLEAR_INODE); + } + if(inode->i_pages) { + vfs_unlock(); /* may block, can that be revised? */ + truncate_inode_pages(inode, 0); + vfs_lock(); + } + insert_all(&empty_i, inode); + inodes_stat.nr_free_inodes++; + } else if(external) + printk("VFS: empty inode is unnecessarily cleared multiple " + "times by an fs\n"); + else + printk("VFS: clearing empty inode\n"); + inode->i_status = ST_EMPTY; + /* The inode is not really cleared any more here, but only once + * when taken from empty_i. This saves instructions and processor + * cache pollution. + */ +} + +void insert_inode_hash(struct inode * inode) +{ +xcheck("insert_inode_hash",inode); + vfs_lock(); + if(!(inode->i_status & ST_HASHED)) { + insert_hash(&hashtable[hash(inode->i_dev, inode->i_ino)], inode); + inode->i_status |= ST_HASHED; + } else + printk("VFS: trying to hash an inode again\n"); + vfs_unlock(); } -/* This belongs in file_table.c, not here... */ -int fs_may_remount_ro(kdev_t dev) +blocking struct inode * _get_empty_inode(void) { - struct file * file; + struct inode * inode; + int retry = 0; - /* Check that no files are currently opened for writing. */ - for (file = inuse_filps; file; file = file->f_next) { - if (!file->f_inode || file->f_inode->i_dev != dev) - continue; - if (S_ISREG(file->f_inode->i_mode) && (file->f_mode & 2)) - return 0; - } - return 1; /* Tis' cool bro. */ -} - -/* Reading/writing inodes. */ -static void write_inode(struct inode *inode) -{ - if(inode->i_dirt) { - wait_on_inode(inode); - if(inode->i_dirt) { - if(inode->i_sb && - inode->i_sb->s_op && - inode->i_sb->s_op->write_inode) { - inode->i_lock = 1; - inode->i_sb->s_op->write_inode(inode); - unlock_inode(inode); - } else { - inode->i_dirt = 0; +retry: + inode = empty_i; + if(inode) { + remove_all(&empty_i, inode); + inodes_stat.nr_free_inodes--; + } else if(inodes_stat.nr_inodes < max_inodes || retry > 2) { + inode = grow_inodes(); + } + if(!inode) { + int level; + int usable = 0; + for(level = 0; level <= NR_LEVELS; level++) + if(aged_i[level]) { + inode = aged_i[level]->i_lru_prev; + /* Here is the picking strategy, tune this */ + if(aged_reused[level] < (usable++ ? + inodes_stat.aged_count[level] : + 2)) + break; + aged_reused[level] = 0; } + if(inode) { + if(!(inode->i_status & ST_AGED)) + printk("VFS: inode aging inconsistency\n"); + if(atomic_read(&inode->i_count) + inode->i_ddir_count) + printk("VFS: i_count of aged inode is not zero\n"); + if(inode->i_dirt) + printk("VFS: Hey, somebody made my aged inode dirty\n"); + _clear_inode(inode, 0, 0); + goto retry; } } + if(!inode) { + vfs_unlock(); + schedule(); + if(retry > 10) + panic("VFS: cannot repair inode shortage"); + if(retry > 2) + printk("VFS: no free inodes\n"); + retry++; + vfs_lock(); + goto retry; + } +xcheck("get_empty_inode",inode); + memset(inode, 0, sizeof(struct inode)); + atomic_set(&inode->i_count, 1); + inode->i_nlink = 1; + sema_init(&inode->i_sem, 1); + inode->i_ino = ++last_inode; + inode->i_version = ++event; + insert_all(&all_i, inode); + return inode; } -static inline void read_inode(struct inode *inode) +static inline blocking struct inode * _get_empty_inode_hashed(dev_t i_dev, + unsigned long i_ino) { - if(inode->i_sb && - inode->i_sb->s_op && - inode->i_sb->s_op->read_inode) { - lock_inode(inode); - inode->i_sb->s_op->read_inode(inode); - unlock_inode(inode); - } -} - -int inode_change_ok(struct inode *inode, struct iattr *attr) -{ - if(!(attr->ia_valid & ATTR_FORCE)) { - unsigned short fsuid = current->fsuid; - uid_t iuid = inode->i_uid; - int not_fsuser = !fsuser(); - - if(((attr->ia_valid & ATTR_UID) && - ((fsuid != iuid) || - (attr->ia_uid != iuid)) && not_fsuser) || - - ((attr->ia_valid & ATTR_GID) && - (!in_group_p(attr->ia_gid) && - (attr->ia_gid != inode->i_gid)) && not_fsuser) || - - ((attr->ia_valid & (ATTR_ATIME_SET | ATTR_MTIME_SET)) && - (fsuid != iuid) && not_fsuser)) - return -EPERM; - - if(attr->ia_valid & ATTR_MODE) { - gid_t grp; - if(fsuid != iuid && not_fsuser) - return -EPERM; - grp = attr->ia_valid & ATTR_GID ? attr->ia_gid : inode->i_gid; - if(not_fsuser && !in_group_p(grp)) - attr->ia_mode &= ~S_ISGID; - } - } - return 0; + struct inode ** base = &hashtable[hash(i_dev, i_ino)]; + struct inode * inode = *base; + if(inode) do { + if(inode->i_ino == i_ino && inode->i_dev == i_dev) { + atomic_inc(&inode->i_count); + printk("VFS: inode %lx is already in use\n", i_ino); + return inode; + } + inode = inode->i_hash_next; + } while(inode != *base); + inode = _get_empty_inode(); + inode->i_dev = i_dev; + inode->i_ino = i_ino; + insert_hash(base, inode); + inode->i_status |= ST_HASHED; + return inode; } -void inode_setattr(struct inode *inode, struct iattr *attr) +blocking struct inode * get_empty_inode_hashed(dev_t i_dev, unsigned long i_ino) { - if (attr->ia_valid & ATTR_UID) - inode->i_uid = attr->ia_uid; - if (attr->ia_valid & ATTR_GID) - inode->i_gid = attr->ia_gid; - if (attr->ia_valid & ATTR_SIZE) - inode->i_size = attr->ia_size; - if (attr->ia_valid & ATTR_ATIME) - inode->i_atime = attr->ia_atime; - if (attr->ia_valid & ATTR_MTIME) - inode->i_mtime = attr->ia_mtime; - if (attr->ia_valid & ATTR_CTIME) - inode->i_ctime = attr->ia_ctime; - if (attr->ia_valid & ATTR_MODE) { - inode->i_mode = attr->ia_mode; - if (!fsuser() && !in_group_p(inode->i_gid)) - inode->i_mode &= ~S_ISGID; - } - if (attr->ia_valid & ATTR_ATTR_FLAG) - inode->i_attr_flags = attr->ia_attr_flags; - inode->i_dirt = 1; -} - -int notify_change(struct inode *inode, struct iattr *attr) -{ - attr->ia_ctime = CURRENT_TIME; - if (attr->ia_valid & (ATTR_ATIME | ATTR_MTIME)) { - if (!(attr->ia_valid & ATTR_ATIME_SET)) - attr->ia_atime = attr->ia_ctime; - if (!(attr->ia_valid & ATTR_MTIME_SET)) - attr->ia_mtime = attr->ia_ctime; - } - - if (inode->i_sb && - inode->i_sb->s_op && - inode->i_sb->s_op->notify_change) - return inode->i_sb->s_op->notify_change(inode, attr); + struct inode * inode; - if(inode_change_ok(inode, attr) != 0) - return -EPERM; - - inode_setattr(inode, attr); - return 0; -} - -int bmap(struct inode *inode, int block) -{ - if(inode->i_op && inode->i_op->bmap) - return inode->i_op->bmap(inode, block); - return 0; + vfs_lock(); + inode = _get_empty_inode_hashed(i_dev, i_ino); + vfs_unlock(); + return inode; } -void invalidate_inodes(kdev_t dev) +void _get_inode(struct inode * inode) { - struct inode *inode; - int pass = 0; - - inode = free_inodes.head; -repeat: - while(inode) { - struct inode *next = inode->i_next; - if(inode->i_dev != dev) - goto next; - clear_inode(inode); - next: - inode = next; - } - if(pass == 0) { - inode = inuse_list; - pass = 1; - goto repeat; - } -} - -void sync_inodes(kdev_t dev) -{ - struct inode *inode; - int pass = 0; - - inode = free_inodes.head; -repeat: - while(inode) { - struct inode *next = inode->i_next; - if(dev && inode->i_dev != dev) - goto next; - wait_on_inode(inode); - write_inode(inode); - next: - inode = next; - } - if(pass == 0) { - inode = inuse_list; - pass = 1; - goto repeat; + if(inode->i_status & ST_IBASKET) { + inode->i_status &= ~ST_IBASKET; + remove_ibasket(&inode->i_sb->s_ibasket, inode); + inode->i_sb->s_ibasket_count--; + } + if(inode->i_status & ST_AGED) { + inode->i_status &= ~ST_AGED; + remove_lru(&aged_i[inode->i_level], inode); + inodes_stat.aged_count[inode->i_level]--; + aged_reused[inode->i_level]++; + if(S_ISDIR(inode->i_mode)) + /* make dirs less thrashable */ + inode->i_level = NR_LEVELS-1; + else if(inode->i_nlink > 1) + /* keep hardlinks totally separate */ + inode->i_level = NR_LEVELS; + else if(++inode->i_reuse_count >= age_table[inode->i_level] + && inode->i_level < NR_LEVELS-1) + inode->i_level++; + if(atomic_read(&inode->i_count) != 1) + printk("VFS: inode count was not zero\n"); + } else if(inode->i_status & ST_EMPTY) + printk("VFS: invalid reuse of empty inode\n"); +} + +blocking struct inode * __iget(struct super_block * sb, + unsigned long i_ino, + int crossmntp) +{ + struct inode ** base; + struct inode * inode; + dev_t i_dev; + + if(!sb) + panic("VFS: iget with sb == NULL"); + i_dev = sb->s_dev; + if(!i_dev) + panic("VFS: sb->s_dev is NULL\n"); + base = &hashtable[hash(i_dev, i_ino)]; + vfs_lock(); + inode = *base; + if(inode) do { + if(inode->i_ino == i_ino && inode->i_dev == i_dev) { + atomic_inc(&inode->i_count); + _get_inode(inode); + + /* Allow concurrent writes/puts. This is in particular + * useful e.g. when syncing large chunks. + * I hope the i_dirty flag is everywhere set as soon + * as _any_ modifcation is made and _before_ + * giving up control, so no harm should occur if data + * is modified during writes, because it will be + * rewritten again (does a short inconsistency on the + * disk harm?) + */ + wait_io(inode, ST_TO_READ); + vfs_unlock(); + goto done; + } + inode = inode->i_hash_next; + } while(inode != *base); + inode = _get_empty_inode_hashed(i_dev, i_ino); + inode->i_sb = sb; + inode->i_flags = sb->s_flags; + if(sb->s_op && sb->s_op->read_inode) { + set_io(inode, 0, ST_TO_READ); /* do not wait at all */ + sb->s_op->read_inode(inode); + if(release_io(inode, ST_TO_READ)) + goto done; + } + vfs_unlock(); +done: + while(crossmntp && inode->i_mount) { + struct inode * tmp = inode->i_mount; + iinc(tmp); + iput(inode); + inode = tmp; } +xcheck("_iget",inode); + return inode; } -static struct wait_queue *inode_wait, *update_wait; - -void iput(struct inode *inode) +blocking void __iput(struct inode * inode) { - if(!inode) - return; - wait_on_inode(inode); - if(!inode->i_count) { - printk("VFS: Freeing free inode, tell DaveM\n"); + struct super_block * sb; +xcheck("_iput",inode); + if(atomic_read(&inode->i_count) + inode->i_ddir_count < 0) + printk("VFS: i_count is negative\n"); + if((atomic_read(&inode->i_count) + inode->i_ddir_count) || + (inode->i_status & ST_FREEING)) { return; } - if(inode->i_pipe) - wake_up_interruptible(&PIPE_WAIT(*inode)); -we_slept: - if(inode->i_count > 1) { - inode->i_count--; - } else { - wake_up(&inode_wait); - if(inode->i_pipe) { - free_page((unsigned long)PIPE_BASE(*inode)); - PIPE_BASE(*inode) = NULL; - } - if(inode->i_sb && - inode->i_sb->s_op && - inode->i_sb->s_op->put_inode) { - inode->i_sb->s_op->put_inode(inode); - if(!inode->i_nlink) - return; - } - if(inode->i_dirt) { - write_inode(inode); - wait_on_inode(inode); - goto we_slept; - } - if(IS_WRITABLE(inode) && - inode->i_sb && - inode->i_sb->dq_op) { - inode->i_lock = 1; - inode->i_sb->dq_op->drop(inode); - unlock_inode(inode); - goto we_slept; - } - /* There is a serious race leading to here, watch out. */ - if(--inode->i_count == 0) { - remove_inuse(inode); - put_inode_last(inode); /* Place at end of LRU free queue */ + inode->i_status |= ST_FREEING; +#ifdef CONFIG_OMIRR + if(inode->i_status & ST_MODIFIED) { + inode->i_status &= ~ST_MODIFIED; + omirr_printall(inode, " W %ld ", CURRENT_TIME); + } +#endif + if(inode->i_pipe) { + free_page((unsigned long)PIPE_BASE(*inode)); + PIPE_BASE(*inode)= NULL; + } + if((sb = inode->i_sb)) { + if(sb->s_type && (sb->s_type->fs_flags & FS_NO_DCACHE)) { + while(inode->i_dentry) + d_del(inode->i_dentry, D_NO_CLEAR_INODE); + if(atomic_read(&inode->i_count) + inode->i_ddir_count) + goto done; + } + if(sb->s_op) { + if(inode->i_nlink <= 0 && inode->i_dent_count && + !(inode->i_status & (ST_EMPTY|ST_IBASKET)) && + (sb->s_type->fs_flags & FS_IBASKET)) { + _put_ibasket(inode); + goto done; + } + if(!inode->i_dent_count || + (sb->s_type->fs_flags & FS_NO_DCACHE)) { + _io(sb->s_op->put_inode, inode, + ST_TO_PUT|ST_TO_WRITE, ST_TO_PUT); + if(atomic_read(&inode->i_count) + inode->i_ddir_count) + goto done; + if(inode->i_nlink <= 0) { + if(!(inode->i_status & ST_EMPTY)) { + _clear_inode(inode, 0, 1); + } + goto done; + } + } + if(inode->i_dirt) { + inode->i_dirt = 0; + _io(sb->s_op->write_inode, inode, + ST_TO_PUT|ST_TO_WRITE, ST_TO_WRITE); + if(atomic_read(&inode->i_count) + inode->i_ddir_count) + goto done; + } } - } -} - -static kmem_cache_t *inode_cachep; - -static void grow_inodes(void) -{ - int i = 16; - - while(i--) { - struct inode *inode; - - inode = kmem_cache_alloc(inode_cachep, SLAB_KERNEL); - if(!inode) - return; - memset(inode, 0, sizeof(*inode)); - put_inode_head(inode); - nr_inodes++; - } -} - -/* We have to be really careful, it's really easy to run yourself into - * inefficient sequences of events. The first problem is that when you - * steal a non-referenced inode you run the risk of zaping a considerable - * number of page cache entries, which might get refernced once again. - * But if you are growing the inode set to quickly, you suck up ram - * and cause other problems. - * - * We approach the problem in the following way, we take two things into - * consideration. Firstly we take a look at how much we have "committed" - * to this inode already (i_nrpages), this accounts for the cost of getting - * those pages back if someone should reference that inode soon. We also - * attempt to factor in i_blocks, which says "how much of a problem could - * this potentially be". It still needs some tuning though. -DaveM - */ -#define BLOCK_FACTOR_SHIFT 5 /* It is not factored in as much. */ -static struct inode *find_best_candidate_weighted(struct inode *inode) -{ - struct inode *best = NULL; + if(IS_WRITABLE(inode) && sb->dq_op) { + /* can operate in parallel to other ops ? */ + _io(sb->dq_op->drop, inode, 0, ST_TO_DROP); + if(atomic_read(&inode->i_count) + inode->i_ddir_count) + goto done; + } + } + if(inode->i_mmap) + printk("VFS: inode has mappings\n"); + if(inode->i_status & ST_AGED) { + printk("VFS: reaging inode\n"); +#if defined(DEBUG) +printpath(inode->i_dentry); +printk("\n"); +#endif + goto done; + } + if(!(inode->i_status & (ST_HASHED|ST_EMPTY))) { + _clear_inode(inode, 0, 1); + goto done; + } + if(inode->i_status & ST_EMPTY) { + printk("VFS: aging an empty inode\n"); + goto done; + } + insert_lru(&aged_i[inode->i_level], inode); + inodes_stat.aged_count[inode->i_level]++; + inode->i_status |= ST_AGED; +done: + inode->i_status &= ~ST_FREEING; +} + +blocking void _iput(struct inode * inode) +{ + vfs_lock(); + __iput(inode); + vfs_unlock(); +} + +blocking void sync_inodes(kdev_t dev) +{ + struct inode * inode; + vfs_lock(); + inode = all_i; + if(inode) do { +xcheck("sync_inodes",inode); + if(inode->i_dirt && (inode->i_dev == dev || !dev)) { + if(inode->i_sb && inode->i_sb->s_op && + !(inode->i_status & ST_FREEING)) { + inode->i_dirt = 0; + _io(inode->i_sb->s_op->write_inode, inode, + ST_IO, ST_TO_WRITE); + } + } + inode = inode->i_next; + } while(inode != all_i); + vfs_unlock(); +} + +blocking int _check_inodes(kdev_t dev, int complain) +{ + struct inode * inode; + int bad = 0; + + vfs_lock(); +startover: + inode = all_i; + if(inode) do { + struct inode * next; +xcheck("_check_inodes",inode); + next = inode->i_next; + if(inode->i_dev == dev) { + if(inode->i_dirt || atomic_read(&inode->i_count)) { + bad++; + } else { + _clear_inode(inode, 0, 0); - if(inode) { - unsigned long bestscore = 1000; - int limit = nr_free_inodes >> 2; - do { - if(!(inode->i_lock | inode->i_dirt)) { - int myscore = inode->i_nrpages; - - myscore += (inode->i_blocks >> BLOCK_FACTOR_SHIFT); - if(myscore < bestscore) { - bestscore = myscore; - best = inode; - } + /* _clear_inode() may recursively clear other + * inodes, probably also the next one. + */ + if(next->i_status & ST_EMPTY) + goto startover; } - inode = inode->i_next; - } while(inode && --limit); - } - return best; + } + inode = next; + } while(inode != all_i); + vfs_unlock(); + if(complain && bad) + printk("VFS: %d inode(s) busy on removed device `%s'\n", + bad, kdevname(dev)); + return (bad == 0); } -static inline struct inode *find_best_free(struct inode *inode) +/*inline*/ void invalidate_inodes(kdev_t dev) { - if(inode) { - int limit = nr_free_inodes >> 5; - do { - if(!inode->i_nrpages) - return inode; - inode = inode->i_next; - } while(inode && --limit); - } - return NULL; + /* Requires two passes, because of the new dcache holding + * directories with i_count > 1. + */ + (void)_check_inodes(dev, 0); + (void)_check_inodes(dev, 1); } -struct inode *get_empty_inode(void) +/*inline*/ int fs_may_mount(kdev_t dev) { - static int ino = 0; - struct inode *inode; - -repeat: - inode = find_best_free(free_inodes.head); - if(!inode) - goto pressure; -got_it: - inode->i_count++; - truncate_inode_pages(inode, 0); - wait_on_inode(inode); - if(IS_WRITABLE(inode) && inode->i_sb && inode->i_sb->dq_op) - inode->i_sb->dq_op->drop(inode); - unhash_inode(inode); - remove_free_inode(inode); - - memset(inode, 0, sizeof(*inode)); - inode->i_count = 1; - inode->i_nlink = 1; - inode->i_version = ++event; - sema_init(&inode->i_sem, 1); - inode->i_ino = ++ino; - inode->i_dev = 0; - put_inuse(inode); - return inode; -pressure: - if(nr_inodes < max_inodes) { - grow_inodes(); - goto repeat; - } - inode = find_best_candidate_weighted(free_inodes.head); - if(!inode) { - printk("VFS: No free inodes, contact DaveM\n"); - sleep_on(&inode_wait); - goto repeat; - } - if(inode->i_lock) { - wait_on_inode(inode); - goto repeat; - } else if(inode->i_dirt) { - write_inode(inode); - goto repeat; - } - goto got_it; + return _check_inodes(dev, 0); } -struct inode *get_pipe_inode(void) +int fs_may_remount_ro(kdev_t dev) { - extern struct inode_operations pipe_inode_operations; - struct inode *inode = get_empty_inode(); - - if(inode) { - unsigned long page = __get_free_page(GFP_USER); - if(!page) { - iput(inode); - inode = NULL; - } else { - PIPE_BASE(*inode) = (char *) page; - inode->i_op = &pipe_inode_operations; - inode->i_count = 2; - PIPE_WAIT(*inode) = NULL; - PIPE_START(*inode) = PIPE_LEN(*inode) = 0; - PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0; - PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1; - PIPE_LOCK(*inode) = 0; - inode->i_pipe = 1; - inode->i_mode |= S_IFIFO | S_IRUSR | S_IWUSR; - inode->i_uid = current->fsuid; - inode->i_gid = current->fsgid; - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - inode->i_blksize = PAGE_SIZE; - } - } - return inode; + (void)dev; + return 1; /* not checked any more */ } -static int inode_updating[INODE_HASHSZ]; - -struct inode *__iget(struct super_block *sb, int nr, int crossmntp) +int fs_may_umount(kdev_t dev, struct inode * mount_root) { - unsigned int hashent = hashfn(sb->s_dev, nr); - struct inode *inode, *empty = NULL; - -we_slept: - if((inode = find_inode(hashent, sb->s_dev, nr)) == NULL) { - if(empty == NULL) { - inode_updating[hashent]++; - empty = get_empty_inode(); - if(!--inode_updating[hashent]) - wake_up(&update_wait); - goto we_slept; - } - inode = empty; - inode->i_sb = sb; - inode->i_dev = sb->s_dev; - inode->i_ino = nr; - inode->i_flags = sb->s_flags; - hash_inode(inode); - read_inode(inode); - } else { - if(!inode->i_count++) { - remove_free_inode(inode); - put_inuse(inode); - } - wait_on_inode(inode); - if(crossmntp && inode->i_mount) { - struct inode *mp = inode->i_mount; - mp->i_count++; - iput(inode); - wait_on_inode(inode = mp); - } - if(empty) - iput(empty); + struct inode * inode; + vfs_lock(); + inode = all_i; + if(inode) do { +xcheck("fs_may_umount",inode); + if(inode->i_dev == dev && atomic_read(&inode->i_count)) + if(inode != mount_root || atomic_read(&inode->i_count) > + (inode->i_mount == inode ? 2 : 1)) { + vfs_unlock(); + return 0; + } + inode = inode->i_next; + } while(inode != all_i); + vfs_unlock(); + return 1; +} + +extern struct inode_operations pipe_inode_operations; + +blocking struct inode * get_pipe_inode(void) +{ + struct inode * inode = get_empty_inode(); + + PIPE_BASE(*inode) = (char*)__get_free_page(GFP_USER); + if(!(PIPE_BASE(*inode))) { + iput(inode); + return NULL; + } + inode->i_blksize = PAGE_SIZE; + inode->i_pipe = 1; + inode->i_mode = S_IFIFO | S_IRUSR | S_IWUSR; + atomic_inc(&inode->i_count); + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_op = &pipe_inode_operations; + PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1; + + /* I hope this does not introduce security problems. + * Please check and give me response. + */ + { + char dummyname[32]; + struct qstr dummy = { dummyname, 0 }; + struct dentry * new; + sprintf(dummyname, ".anonymous-pipe-%06lud", inode->i_ino); + dummy.len = strlen(dummyname); + vfs_lock(); + new = d_alloc(the_root, dummy.len, 0); + if(new) + d_add(new, inode, &dummy, D_BASKET); + vfs_unlock(); } - while(inode_updating[hashent]) - sleep_on(&update_wait); return inode; } -void inode_init(void) +int bmap(struct inode * inode, int block) { - int i; - - inode_cachep = kmem_cache_create("inode", sizeof(struct inode), - 0, - SLAB_HWCACHE_ALIGN, NULL, NULL); - if(!inode_cachep) - panic("Cannot create inode SLAB cache\n"); - - for(i = 0; i < INODE_HASHSZ; i++) - inode_hash[i] = NULL; + if (inode->i_op && inode->i_op->bmap) + return inode->i_op->bmap(inode, block); + return 0; } diff -u --recursive --new-file v2.1.42/linux/fs/isofs/dir.c linux/fs/isofs/dir.c --- v2.1.42/linux/fs/isofs/dir.c Mon May 19 12:57:39 1997 +++ linux/fs/isofs/dir.c Thu Jun 12 16:22:08 1997 @@ -54,7 +54,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ isofs_bmap, /* bmap */ @@ -226,7 +225,6 @@ /* rrflag == 1 means that we have a new name (kmalloced) */ if (rrflag == 1) { rrflag = filldir(dirent, name, len, filp->f_pos, inode_number); - dcache_add(inode, name, len, inode_number); kfree(name); /* this was allocated in get_r_r_filename.. */ if (rrflag < 0) break; @@ -239,7 +237,6 @@ len = isofs_name_translate(name, len, tmpname); if (filldir(dirent, tmpname, len, filp->f_pos, inode_number) < 0) break; - dcache_add(inode, tmpname, len, inode_number); filp->f_pos += de_len; continue; } @@ -247,7 +244,6 @@ if (filldir(dirent, name, len, filp->f_pos, inode_number) < 0) break; - dcache_add(inode, name, len, inode_number); filp->f_pos += de_len; continue; } diff -u --recursive --new-file v2.1.42/linux/fs/isofs/file.c linux/fs/isofs/file.c --- v2.1.42/linux/fs/isofs/file.c Sun Jan 26 02:07:44 1997 +++ linux/fs/isofs/file.c Thu Jun 12 16:22:08 1997 @@ -47,7 +47,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ generic_readpage, /* readpage */ NULL, /* writepage */ isofs_bmap, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/isofs/inode.c linux/fs/isofs/inode.c --- v2.1.42/linux/fs/isofs/inode.c Tue May 13 22:41:14 1997 +++ linux/fs/isofs/inode.c Thu Jun 12 16:22:08 1997 @@ -912,7 +912,10 @@ #endif static struct file_system_type iso9660_fs_type = { - isofs_read_super, "iso9660", 1, NULL + "iso9660", + FS_REQUIRES_DEV, + isofs_read_super, + NULL }; __initfunc(int init_iso9660_fs(void)) diff -u --recursive --new-file v2.1.42/linux/fs/isofs/namei.c linux/fs/isofs/namei.c --- v2.1.42/linux/fs/isofs/namei.c Mon May 19 12:57:39 1997 +++ linux/fs/isofs/namei.c Thu Jun 12 16:22:08 1997 @@ -206,6 +206,7 @@ { unsigned long ino, ino_back; struct buffer_head * bh; + char *lcname; #ifdef DEBUG printk("lookup: %x %d\n",dir->i_ino, len); @@ -219,38 +220,29 @@ return -ENOENT; } - ino = 0; - - if (dcache_lookup(dir, name, len, &ino)) ino_back = dir->i_ino; - - if (!ino) { - char *lcname; - - /* If mounted with check=relaxed (and most likely norock), - then first convert this name to lower case. */ - if (dir->i_sb->u.isofs_sb.s_name_check == 'r' - && (lcname = kmalloc(len, GFP_KERNEL)) != NULL) { - int i; - char c; - - for (i=0; i= 'A' && c <= 'Z') c |= 0x20; - lcname[i] = c; - } - bh = isofs_find_entry(dir,lcname,len, &ino, &ino_back); - kfree(lcname); - } else - bh = isofs_find_entry(dir,name,len, &ino, &ino_back); - - if (!bh) { - iput(dir); - return -ENOENT; + /* If mounted with check=relaxed (and most likely norock), + * then first convert this name to lower case. + */ + if (dir->i_sb->u.isofs_sb.s_name_check == 'r' && + (lcname = kmalloc(len, GFP_KERNEL)) != NULL) { + int i; + char c; + + for (i=0; i= 'A' && c <= 'Z') c |= 0x20; + lcname[i] = c; } - if (ino_back == dir->i_ino) - dcache_add(dir, name, len, ino); - brelse(bh); + bh = isofs_find_entry(dir,lcname,len, &ino, &ino_back); + kfree(lcname); + } else + bh = isofs_find_entry(dir,name,len, &ino, &ino_back); + + if (!bh) { + iput(dir); + return -ENOENT; } + brelse(bh); if (!(*result = iget(dir->i_sb,ino))) { iput(dir); @@ -258,14 +250,12 @@ } /* We need this backlink for the ".." entry unless the name that we - are looking up traversed a mount point (in which case the inode - may not even be on an iso9660 filesystem, and writing to - u.isofs_i would only cause memory corruption). - */ - - if (ino_back && !(*result)->i_pipe && (*result)->i_sb == dir->i_sb) { - (*result)->u.isofs_i.i_backlink = ino_back; - } + * are looking up traversed a mount point (in which case the inode + * may not even be on an iso9660 filesystem, and writing to + * u.isofs_i would only cause memory corruption). + */ + if (ino_back && !(*result)->i_pipe && (*result)->i_sb == dir->i_sb) + (*result)->u.isofs_i.i_backlink = ino_back; iput(dir); return 0; diff -u --recursive --new-file v2.1.42/linux/fs/isofs/symlink.c linux/fs/isofs/symlink.c --- v2.1.42/linux/fs/isofs/symlink.c Wed Jan 1 06:56:07 1997 +++ linux/fs/isofs/symlink.c Thu Jun 12 16:22:08 1997 @@ -19,7 +19,6 @@ #include static int isofs_readlink(struct inode *, char *, int); -static int isofs_follow_link(struct inode *, struct inode *, int, int, struct inode **); /* * symlinks can't do much... @@ -36,7 +35,6 @@ NULL, /* mknod */ NULL, /* rename */ isofs_readlink, /* readlink */ - isofs_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -44,50 +42,10 @@ NULL /* permission */ }; -static int isofs_follow_link(struct inode * dir, struct inode * inode, - int flag, int mode, struct inode ** res_inode) -{ - int error; - char * pnt; - - if (!dir) { - dir = current->fs->root; - dir->i_count++; - } - if (!inode) { - iput(dir); - *res_inode = NULL; - return -ENOENT; - } - if (!S_ISLNK(inode->i_mode)) { - iput(dir); - *res_inode = inode; - return 0; - } - if ((current->link_count > 5) || - !(pnt = get_rock_ridge_symlink(inode))) { - iput(dir); - iput(inode); - *res_inode = NULL; - return -ELOOP; - } - iput(inode); - current->link_count++; - error = open_namei(pnt,flag,mode,res_inode,dir); - current->link_count--; - kfree(pnt); - return error; -} - static int isofs_readlink(struct inode * inode, char * buffer, int buflen) { char * pnt; int i; - - if (!S_ISLNK(inode->i_mode)) { - iput(inode); - return -EINVAL; - } if (buflen > 1023) buflen = 1023; diff -u --recursive --new-file v2.1.42/linux/fs/minix/bitmap.c linux/fs/minix/bitmap.c --- v2.1.42/linux/fs/minix/bitmap.c Fri Dec 20 01:24:38 1996 +++ linux/fs/minix/bitmap.c Thu Jun 12 16:22:08 1997 @@ -191,8 +191,8 @@ printk("free_inode: inode has no device\n"); return; } - if (inode->i_count != 1) { - printk("free_inode: inode has count=%d\n",inode->i_count); + if (atomic_read(&inode->i_count) != 1) { + printk("free_inode: inode has count=%d\n",atomic_read(&inode->i_count)); return; } if (inode->i_nlink) { @@ -251,7 +251,7 @@ iput(inode); return NULL; } - inode->i_count = 1; + atomic_set(&inode->i_count, 1); inode->i_nlink = 1; inode->i_dev = sb->s_dev; inode->i_uid = current->fsuid; diff -u --recursive --new-file v2.1.42/linux/fs/minix/dir.c linux/fs/minix/dir.c --- v2.1.42/linux/fs/minix/dir.c Sun Jan 26 02:07:44 1997 +++ linux/fs/minix/dir.c Thu Jun 12 16:22:08 1997 @@ -50,7 +50,6 @@ minix_mknod, /* mknod */ minix_rename, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/minix/file.c linux/fs/minix/file.c --- v2.1.42/linux/fs/minix/file.c Sun Jan 26 02:07:44 1997 +++ linux/fs/minix/file.c Thu Jun 12 16:22:08 1997 @@ -58,7 +58,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ generic_readpage, /* readpage */ NULL, /* writepage */ minix_bmap, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/minix/inode.c linux/fs/minix/inode.c --- v2.1.42/linux/fs/minix/inode.c Wed Apr 23 19:01:26 1997 +++ linux/fs/minix/inode.c Thu Jun 12 16:22:08 1997 @@ -944,7 +944,10 @@ } static struct file_system_type minix_fs_type = { - minix_read_super, "minix", 1, NULL + "minix", + FS_REQUIRES_DEV, + minix_read_super, + NULL }; __initfunc(int init_minix_fs(void)) diff -u --recursive --new-file v2.1.42/linux/fs/minix/namei.c linux/fs/minix/namei.c --- v2.1.42/linux/fs/minix/namei.c Sat Nov 30 02:24:01 1996 +++ linux/fs/minix/namei.c Thu Jun 12 16:22:08 1997 @@ -462,7 +462,7 @@ retval = -ENOENT; goto end_rmdir; } - if (inode->i_count > 1) { + if (atomic_read(&inode->i_count) > 1) { retval = -EBUSY; goto end_rmdir; } @@ -639,7 +639,7 @@ int ino; int result; - new_inode->i_count++; + atomic_inc(&new_inode->i_count); result = 0; for (;;) { if (new_inode == old_inode) { @@ -672,7 +672,7 @@ * higher-level routines. */ static int do_minix_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len, int must_be_dir) + struct inode * new_dir, const char * new_name, int new_len) { struct inode * old_inode, * new_inode; struct buffer_head * old_bh, * new_bh, * dir_bh; @@ -700,8 +700,6 @@ old_inode = __iget(old_dir->i_sb, old_de->inode,0); /* don't cross mnt-points */ if (!old_inode) goto end_rename; - if (must_be_dir && !S_ISDIR(old_inode->i_mode)) - goto end_rename; retval = -EPERM; if ((old_dir->i_mode & S_ISVTX) && current->fsuid != old_inode->i_uid && @@ -730,7 +728,7 @@ if (!empty_dir(new_inode)) goto end_rename; retval = -EBUSY; - if (new_inode->i_count > 1) + if (atomic_read(&new_inode->i_count) > 1) goto end_rename; } retval = -EPERM; @@ -818,8 +816,7 @@ * as they are on different partitions. */ int minix_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len, - int must_be_dir) + struct inode * new_dir, const char * new_name, int new_len) { static struct wait_queue * wait = NULL; static int lock = 0; @@ -829,7 +826,7 @@ sleep_on(&wait); lock = 1; result = do_minix_rename(old_dir, old_name, old_len, - new_dir, new_name, new_len, must_be_dir); + new_dir, new_name, new_len); lock = 0; wake_up(&wait); return result; diff -u --recursive --new-file v2.1.42/linux/fs/minix/symlink.c linux/fs/minix/symlink.c --- v2.1.42/linux/fs/minix/symlink.c Mon Oct 28 04:29:26 1996 +++ linux/fs/minix/symlink.c Thu Jun 12 16:22:08 1997 @@ -15,7 +15,6 @@ #include static int minix_readlink(struct inode *, char *, int); -static int minix_follow_link(struct inode *, struct inode *, int, int, struct inode **); /* * symlinks can't do much... @@ -32,7 +31,6 @@ NULL, /* mknod */ NULL, /* rename */ minix_readlink, /* readlink */ - minix_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -40,54 +38,12 @@ NULL /* permission */ }; -static int minix_follow_link(struct inode * dir, struct inode * inode, - int flag, int mode, struct inode ** res_inode) -{ - int error; - struct buffer_head * bh; - - *res_inode = NULL; - if (!dir) { - dir = current->fs->root; - dir->i_count++; - } - if (!inode) { - iput(dir); - return -ENOENT; - } - if (!S_ISLNK(inode->i_mode)) { - iput(dir); - *res_inode = inode; - return 0; - } - if (current->link_count > 5) { - iput(inode); - iput(dir); - return -ELOOP; - } - if (!(bh = minix_bread(inode, 0, 0))) { - iput(inode); - iput(dir); - return -EIO; - } - iput(inode); - current->link_count++; - error = open_namei(bh->b_data,flag,mode,res_inode,dir); - current->link_count--; - brelse(bh); - return error; -} - static int minix_readlink(struct inode * inode, char * buffer, int buflen) { struct buffer_head * bh; int i; char c; - if (!S_ISLNK(inode->i_mode)) { - iput(inode); - return -EINVAL; - } if (buflen > 1023) buflen = 1023; bh = minix_bread(inode, 0, 0); diff -u --recursive --new-file v2.1.42/linux/fs/msdos/msdosfs_syms.c linux/fs/msdos/msdosfs_syms.c --- v2.1.42/linux/fs/msdos/msdosfs_syms.c Tue May 13 22:41:14 1997 +++ linux/fs/msdos/msdosfs_syms.c Thu Jun 12 16:22:08 1997 @@ -31,7 +31,10 @@ struct file_system_type msdos_fs_type = { - msdos_read_super, "msdos", 1, NULL + "msdos", + FS_REQUIRES_DEV, + msdos_read_super, + NULL }; __initfunc(int init_msdos_fs(void)) diff -u --recursive --new-file v2.1.42/linux/fs/msdos/namei.c linux/fs/msdos/namei.c --- v2.1.42/linux/fs/msdos/namei.c Sat Dec 21 04:24:02 1996 +++ linux/fs/msdos/namei.c Thu Jun 12 16:22:08 1997 @@ -219,14 +219,6 @@ if (!(*result = iget(dir->i_sb,ino))) return -EACCES; return 0; } -#if 0 - if (dcache_lookup(dir, name, len, (unsigned long *) &ino)) { - iput(dir); - if (!(*result = iget(dir->i_sb, ino))) - return -EACCES; - return 0; - } -#endif PRINTK (("msdos_lookup 3\n")); if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) { iput(dir); @@ -304,7 +296,6 @@ (*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime = CURRENT_TIME; (*result)->i_dirt = 1; - dcache_add(dir, name, len, ino); return 0; } @@ -378,7 +369,7 @@ struct buffer_head *bh; struct msdos_dir_entry *de; - if (dir->i_count > 1) + if (atomic_read(&dir->i_count) > 1) return -EBUSY; if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */ pos = 0; @@ -596,7 +587,6 @@ new_inode->i_dirt = 1; new_de->name[0] = DELETED_FLAG; fat_mark_buffer_dirty(sb, new_bh, 1); - dcache_add(new_dir, new_name, new_len, new_ino); iput(new_inode); fat_brelse(sb, new_bh); } @@ -721,10 +711,9 @@ MSDOS_I(new_inode)->i_depend = free_inode; MSDOS_I(free_inode)->i_old = new_inode; /* Two references now exist to free_inode so increase count */ - free_inode->i_count++; + atomic_inc(&free_inode->i_count); /* free_inode is put after putting new_inode and old_inode */ iput(new_inode); - dcache_add(new_dir, new_name, new_len, new_ino); fat_brelse(sb, new_bh); } if (S_ISDIR(old_inode->i_mode)) { @@ -755,8 +744,7 @@ /***** Rename, a wrapper for rename_same_dir & rename_diff_dir */ int msdos_rename(struct inode *old_dir,const char *old_name,int old_len, - struct inode *new_dir,const char *new_name,int new_len, - int must_be_dir) + struct inode *new_dir,const char *new_name,int new_len) { struct super_block *sb = old_dir->i_sb; char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME]; @@ -805,7 +793,6 @@ NULL, /* mknod */ msdos_rename, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ fat_bmap, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/namei.c linux/fs/namei.c --- v2.1.42/linux/fs/namei.c Tue May 13 22:41:14 1997 +++ linux/fs/namei.c Sun Jun 15 15:09:10 1997 @@ -8,6 +8,11 @@ * Some corrections by tytso. */ +/* [Feb 1997 T. Schoebel-Theuer] Complete rewrite of the pathname + * lookup logic. + */ + +#include #include #include #include @@ -15,18 +20,114 @@ #include #include #include +#include +#include +#include +#include #include #include #include #include +#include #include +/* This can be removed after the beta phase. */ +#define CACHE_SUPERVISE /* debug the correctness of dcache entries */ +#undef DEBUG /* some other debugging */ + + +/* local flags for __namei() */ +#define NAM_SEMLOCK 8 /* set a semlock on the last dir */ +#define NAM_TRANSCREATE 16 /* last component may be created, try "=CREATE#" suffix*/ +#define NAM_NO_TRAILSLASH 32 /* disallow trailing slashes by returning EISDIR */ #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) +/* [Feb-1997 T. Schoebel-Theuer] + * Fundamental changes in the pathname lookup mechanisms (namei) + * were necessary because of omirr. The reason is that omirr needs + * to know the _real_ pathname, not the user-supplied one, in case + * of symlinks (and also when transname replacements occur). + * + * The new code replaces the old recursive symlink resolution with + * an iterative one (in case of non-nested symlink chains). It does + * this by looking up the symlink name from the particular filesystem, + * and then follows this name as if it were a user-supplied one. This + * is done solely in the VFS level, such that _follow_link() is not + * used any more and could be removed in future. As a side effect, + * dir_namei(), _namei() and follow_link() are now replaced with a single + * function __namei() that can handle all the special cases of the former + * code. + * + * With the new dcache, the pathname is stored at each inode, at least as + * long as the refcount of the inode is positive. As a side effect, the + * size of the dcache depends on the inode cache and thus is dynamic. + */ -/* - * In order to reduce some races, while at the same time doing additional +/* [24-Feb-97 T. Schoebel-Theuer] Side effects caused by new implementation: + * New symlink semantics: when open() is called with flags O_CREAT | O_EXCL + * and the name already exists in form of a symlink, try to create the new + * name indicated by the symlink. The old code always complained that the + * name already exists, due to not following the symlink even if its target + * is non-existant. The new semantics affects also mknod() and link() when + * the name is a symlink pointing to a non-existant name. + * + * I don't know which semantics is the right one, since I have no access + * to standards. But I found by trial that HP-UX 9.0 has the full "new" + * semantics implemented, while SunOS 4.1.1 and Solaris (SunOS 5.4) have the + * "old" one. Personally, I think the new semantics is much more logical. + * Note that "ln old new" where "new" is a symlink pointing to a non-existing + * file does succeed in both HP-UX and SunOs, but not in Solaris + * and in the old Linux semantics. + */ + +static char * quicklist = NULL; +static int quickcount = 0; +struct semaphore quicklock = MUTEX; + +/* Tuning: increase locality by reusing same pages again... + * if quicklist becomes too long on low memory machines, either a limit + * should be added or after a number of cycles some pages should + * be released again ... + */ +static inline char * get_page(void) +{ + char * res; + down(&quicklock); + res = quicklist; + if(res) { +#ifdef DEBUG + char * tmp = res; + int i; + for(i=0; ii_writecount--; } -/* - * lookup() looks up one part of a pathname, using the fs-dependent - * routines (currently minix_lookup) for it. It also checks for - * fathers (pseudo-roots, mount-points) +static /*inline */ int concat(struct qstr * name, struct qstr * appendix, char * buf) +{ + int totallen = name->len; + if(name->len > MAX_TRANS_FILELEN || + appendix->len > MAX_TRANS_SUFFIX) { + return -ENAMETOOLONG; + } + memcpy(buf, name->name, name->len); + memcpy(buf + name->len, appendix->name, appendix->len); + totallen += appendix->len; + buf[totallen] = '\0'; + return totallen; +} + +/* Internal lookup() using the new generic dcache. + * buf must only be supplied if appendix!=NULL. */ -int lookup(struct inode * dir,const char * name, int len, - struct inode ** result) +static int cached_lookup(struct inode * dir, struct qstr * name, + struct qstr * appendix, char * buf, + struct qstr * res_name, struct dentry ** res_entry, + struct inode ** result) { - struct super_block * sb; - int perm; + struct qstr tmp = { name->name, name->len }; + int error; + struct dentry * cached; *result = NULL; - if (!dir) - return -ENOENT; -/* check permissions before traversing mount-points */ - perm = permission(dir,MAY_EXEC); - if (len==2 && get_unaligned((u16 *) name) == 0x2e2e) { - if (dir == current->fs->root) { - *result = dir; - return 0; - } else if ((sb = dir->i_sb) && (dir == sb->s_mounted)) { - iput(dir); - dir = sb->s_covered; - if (!dir) - return -ENOENT; - dir->i_count++; - } - } - if (!dir->i_op || !dir->i_op->lookup) { - iput(dir); - return -ENOTDIR; - } - if (perm != 0) { - iput(dir); - return perm; - } - if (!len) { - *result = dir; - return 0; + if(name->len >= D_MAXLEN) + return -ENAMETOOLONG; + vfs_lock(); + cached = d_lookup(dir, name, appendix); + if(cached) { + struct inode *inode = NULL; + + if(cached->u.d_inode && (inode = d_inode(&cached))) { + error = 0; + if(appendix && res_name) { + tmp.len = error = concat(name, appendix, buf); + tmp.name = buf; + if(error > 0) + error = 0; + } + } else { + error = -ENOENT; + } + vfs_unlock(); + if(res_entry) + *res_entry = cached; + + /* Since we are bypassing the iget() mechanism, we have to + * fabricate the act of crossing any mount points. + */ + if(!error && inode && inode->i_mount) { + do { + struct inode *mnti = inode->i_mount; + iinc(mnti); + iput(inode); + inode = mnti; + } while(inode->i_mount); + } + *result = inode; + goto done; + } else + vfs_unlock(); + + if(appendix) { + tmp.len = error = concat(name, appendix, buf); + tmp.name = buf; + if(error < 0) + goto done; + } + atomic_inc(&dir->i_count); + error = dir->i_op->lookup(dir, tmp.name, tmp.len, result); + if(dir->i_dentry && tmp.len && + (!error || (error == -ENOENT && (!dir->i_sb || !dir->i_sb->s_type || + !(dir->i_sb->s_type->fs_flags & FS_NO_DCACHE))))) { + struct dentry * res; + vfs_lock(); + res = d_entry(dir->i_dentry, &tmp, error ? NULL : *result); + vfs_unlock(); + if(res_entry) + *res_entry = res; + } +done: + if(res_name) { + if(error) { + res_name->name = name->name; + res_name->len = name->len; + } else { + res_name->name = tmp.name; + res_name->len = tmp.len; + } } - return dir->i_op->lookup(dir, name, len, result); + return error; } -int follow_link(struct inode * dir, struct inode * inode, - int flag, int mode, struct inode ** res_inode) -{ - if (!dir || !inode) { - iput(dir); - iput(inode); - *res_inode = NULL; - return -ENOENT; +#ifdef CONFIG_TRANS_NAMES +/* If a normal filename is seen, try to determine whether a + * "#keyword=context#" file exists and return the new filename. + * If the name is to be created (create_mode), check whether a + * "#keyword=CREATE" name exists and optionally return the corresponding + * context name even if it didn't exist before. + */ +static int check_suffixes(struct inode * dir, struct qstr * name, + int create_mode, char * buf, + struct qstr * res_name, struct dentry ** res_entry, + struct inode ** result) +{ + struct translations * trans; + char * env; + struct qstr * suffixes; + int i; + int error = -ENOENT; + + if(!buf) + panic("buf==NULL"); + env = env_transl(); +#ifdef CONFIG_TRANS_RESTRICT + if(!env && dir->i_gid != CONFIG_TRANS_GID) { + return error; + } +#endif + trans = get_translations(env); + suffixes = create_mode ? trans->c_name : trans->name; + for(i = 0; i < trans->count; i++) { + error = cached_lookup(dir, name, &suffixes[i], + buf, res_name, res_entry, result); + if(!error) { + if(res_name && create_mode) { + /* buf == res_name->name, but is writable */ + memcpy(buf + name->len, + trans->name[i].name, + trans->name[i].len); + res_name->len = name->len + trans->name[i].len; + buf[res_name->len] = '\0'; + } + break; + } } - if (!inode->i_op || !inode->i_op->follow_link) { - iput(dir); - *res_inode = inode; - return 0; + if(env) + free_page((unsigned long)trans); + return error; +} + +#endif + +/* Any operations involving reserved names at the VFS level should go here. */ +static /*inline*/ int reserved_lookup(struct inode * dir, struct qstr * name, + int create_mode, char * buf, + struct inode ** result) +{ + int error = -ENOENT; + if(name->name[0] == '.') { + if(name->len == 1) { + *result = dir; + error = 0; + } else if (name->len==2 && name->name[1] == '.') { + if (dir == current->fs->root) { + *result = dir; + error = 0; + } + else if(dir->i_dentry) { + error = 0; + *result = dir->i_dentry->d_parent->u.d_inode; + if(!*result) { + printk("dcache parent directory is lost"); + error = -ESTALE; /* random error */ + } + } + } + if(!error) + atomic_inc(&(*result)->i_count); } - return inode->i_op->follow_link(dir,inode,flag,mode,res_inode); + return error; } -/* - * dir_namei() - * - * dir_namei() returns the inode of the directory of the - * specified name, and the name within that directory. +/* In difference to the former version, lookup() no longer eats the dir. */ +static /*inline*/ int lookup(struct inode * dir, struct qstr * name, int create_mode, + char * buf, struct qstr * res_name, + struct dentry ** res_entry, struct inode ** result) +{ + int perm; + + *result = NULL; + perm = -ENOENT; + if (!dir) + goto done; + + /* Check permissions before traversing mount-points. */ + perm = permission(dir,MAY_EXEC); + if (perm) + goto done; + perm = reserved_lookup(dir, name, create_mode, buf, result); + if(!perm) { + if(res_name) { + res_name->name = name->name; + res_name->len = name->len; + } + goto done; + } + perm = -ENOTDIR; + if (!dir->i_op || !dir->i_op->lookup) + goto done; +#ifdef CONFIG_TRANS_NAMES /* try suffixes */ + perm = check_suffixes(dir, name, 0, buf, res_name, res_entry, result); + if(perm) /* try original name */ +#endif + perm = cached_lookup(dir, name, NULL, buf, res_name, res_entry, result); +#ifdef CONFIG_TRANS_NAMES + if(perm == -ENOENT && create_mode) { /* try the =CREATE# suffix */ + struct inode * dummy; + if(!check_suffixes(dir, name, 1, buf, res_name, NULL, &dummy)) { + iput(dummy); + } + } +#endif +done: + return perm; +} + +/* [8-Feb-97 T. Schoebel-Theuer] follow_link() modified for generic operation + * on the VFS layer: first call _readlink() and then open_namei(). + * All _follow_link() are not used any more and may be eliminated + * (by Linus; I refrained in order to not break other patches). + * Single exeption is procfs, where proc_follow_link() is used + * internally (and perhaps should be rewritten). + * Note: [partly obsolete] I removed parameters flag and mode, since now + * __namei() is called instead of open_namei(). In the old semantics, + * the _last_ instance of open_namei() did the real create() if O_CREAT was + * set and the name existed already in form of a symlink. This has been + * simplified now, and also the semantics when combined with O_EXCL has changed. + **************************************************************************** + * [13-Feb-97] Complete rewrite -> functionality of reading symlinks factored + * out into _read_link(). The above notes remain valid in principle. */ -static int dir_namei(const char *pathname, int *namelen, const char **name, - struct inode * base, struct inode **res_inode) +static /*inline*/ int _read_link(struct inode * inode, char ** linkname, int loopcount) { - unsigned char c; - const char * thisname; - int len,error; - struct inode * inode; + unsigned long old_fs; + int error; - *res_inode = NULL; - if (!base) { - base = current->fs->pwd; - base->i_count++; + error = -ENOSYS; + if (!inode->i_op || !inode->i_op->readlink) + goto done; + error = -ELOOP; + if (current->link_count + loopcount > 10) + goto done; + error = -ENOMEM; + if(!*linkname && !(*linkname = get_page())) + goto done; + if (DO_UPDATE_ATIME(inode)) { + inode->i_atime = CURRENT_TIME; + inode->i_dirt = 1; + } + atomic_inc(&inode->i_count); + old_fs = get_fs(); + set_fs(KERNEL_DS); + error = inode->i_op->readlink(inode, *linkname, PAGE_SIZE); + set_fs(old_fs); + if(!error) { + error = -ENOENT; /* ? or other error code ? */ + } else if(error > 0) { + (*linkname)[error] = '\0'; + error = 0; } - if ((c = *pathname) == '/') { - iput(base); +done: + iput(inode); + return error; +} + +/* [13-Feb-97 T. Schoebel-Theuer] complete rewrite: + * merged dir_name(), _namei() and follow_link() into one new routine + * that obeys all the special cases hidden in the old routines in a + * (hopefully) systematic way: + * parameter retrieve_mode is bitwise or'ed of the ST_* flags. + * if res_inode is a NULL pointer, dont try to retrieve the last component + * at all. Parameters with prefix last_ are used only if res_inode is + * non-NULL and refer to the last component of the path only. + */ +int __namei(int retrieve_mode, const char * name, struct inode * base, + char * buf, struct inode ** res_dir, struct inode ** res_inode, + struct qstr * last_name, struct dentry ** last_entry, + int * last_error) +{ + char c; + struct qstr this; + char * linkname = NULL; + char * oldlinkname = NULL; + int trail_flag = 0; + int loopcount = 0; + int error; +#ifdef DEBUG + if(last_name) { + last_name->name = "(Uninitialized)"; + last_name->len = 15; + } +#endif +again: + error = -ENOENT; + this.name = name; + if (this.name[0] == '/') { + if(base) + iput(base); + if (__prefix_namei(retrieve_mode, this.name, base, buf, + res_dir, res_inode, + last_name, last_entry, last_error) == 0) + return 0; base = current->fs->root; - pathname++; - base->i_count++; + atomic_inc(&base->i_count); + this.name++; + } else if (!base) { + base = current->fs->pwd; + atomic_inc(&base->i_count); } - while (1) { - thisname = pathname; - for(len=0;(c = *(pathname++))&&(c != '/');len++) - /* nothing */ ; - if (!c) + for(;;) { + struct inode * inode; + const char * tmp = this.name; + int len; + + for(len = 0; (c = *tmp++) && (c != '/'); len++) ; + this.len = len; + if(!c) break; - base->i_count++; - error = lookup(base, thisname, len, &inode); - if (error) { - iput(base); - return error; + while((c = *tmp) == '/') /* remove embedded/trailing slashes */ + tmp++; + if(!c) { + trail_flag = 1; + if(retrieve_mode & NAM_NO_TRAILSLASH) { + error = -EISDIR; + goto alldone; + } + break; } - error = follow_link(base,inode,0,0,&base); +#if 0 + if(atomic_read(&base->i_count) == 0) + printk("vor lookup this=%s tmp=%s\n", this.name, tmp); +#endif + error = lookup(base, &this, 0, buf, NULL, NULL, &inode); +#if 0 + if(atomic_read(&base->i_count) == 0) + printk("nach lookup this=%s tmp=%s\n", this.name, tmp); +#endif if (error) - return error; - } - if (!base->i_op || !base->i_op->lookup) { + goto alldone; + if(S_ISLNK(inode->i_mode)) { + error = _read_link(inode, &linkname, loopcount); + if(error) + goto alldone; + current->link_count++; + error = __namei((retrieve_mode & + ~(NAM_SEMLOCK|NAM_TRANSCREATE|NAM_NO_TRAILSLASH)) + | NAM_FOLLOW_LINK, + linkname, base, buf, + &base, &inode, NULL, NULL, NULL); + current->link_count--; + if(error) + goto alldone; + } +#if 0 + if(atomic_read(&base->i_count) == 0) + printk("this=%s tmp=%s\n", this.name, tmp); +#endif + this.name = tmp; iput(base); - return -ENOTDIR; + base = inode; } - *name = thisname; - *namelen = len; - *res_inode = base; - return 0; -} - -static int _namei(const char * pathname, struct inode * base, - int follow_links, struct inode ** res_inode) -{ - const char *basename; - int namelen,error; - struct inode * inode; - - translate_namei(pathname, base, follow_links, res_inode); - *res_inode = NULL; - error = dir_namei(pathname, &namelen, &basename, base, &base); - if (error) - return error; - base->i_count++; /* lookup uses up base */ - error = lookup(base, basename, namelen, &inode); - if (error) { - iput(base); - return error; + if(res_inode) { + if(retrieve_mode & NAM_SEMLOCK) + down(&base->i_sem); + error = lookup(base, &this, retrieve_mode & NAM_TRANSCREATE, + buf, last_name, last_entry, res_inode); + if(!error && S_ISLNK((*res_inode)->i_mode) && + ((retrieve_mode & NAM_FOLLOW_LINK) || + (trail_flag && (retrieve_mode & NAM_FOLLOW_TRAILSLASH)))) { + char * tmp; + + error = _read_link(*res_inode, &linkname, loopcount); + if(error) + goto lastdone; + if(retrieve_mode & NAM_SEMLOCK) + up(&base->i_sem); + /* exchange pages */ + name = tmp = linkname; + linkname = oldlinkname; oldlinkname = tmp; + loopcount++; + goto again; /* Tail recursion elimination "by hand", + * uses less dynamic memory. + */ + + /* Note that trail_flag is not reset, so it + * does not matter in a symlink chain where a + * trailing slash indicates a directory endpoint. + */ + } + if(!error && trail_flag && !S_ISDIR((*res_inode)->i_mode)) { + iput(*res_inode); + error = -ENOTDIR; + } + lastdone: + if(last_error) { + *last_error = error; + error = 0; + } } - if (follow_links) { - error = follow_link(base, inode, 0, 0, &inode); - if (error) - return error; - } else +alldone: + if(!error && res_dir) + *res_dir = base; + else iput(base); - *res_inode = inode; - return 0; -} - -int lnamei(const char *pathname, struct inode **res_inode) -{ - int error; - char * tmp; - - error = getname(pathname, &tmp); - if (!error) { - error = _namei(tmp, NULL, 0, res_inode); - putname(tmp); - } + putname(linkname); + putname(oldlinkname); return error; } @@ -302,14 +642,20 @@ * Open, link etc use their own routines, but this is enough for things * like 'chmod' etc. */ -int namei(const char *pathname, struct inode **res_inode) + +/* [Feb 1997 T.Schoebel-Theuer] lnamei() completely removed; can be + * simulated when calling with retrieve_mode==NAM_FOLLOW_TRAILSLASH. + */ +int namei(int retrieve_mode, const char *pathname, struct inode **res_inode) { int error; char * tmp; error = getname(pathname, &tmp); if (!error) { - error = _namei(tmp, NULL, 1, res_inode); + char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2]; + error = __namei(retrieve_mode, tmp, NULL, + buf, NULL, res_inode, NULL, NULL, NULL); putname(tmp); } return error; @@ -328,40 +674,30 @@ * which is a lot more logical, and also allows the "no perm" needed * for symlinks (where the permissions are checked later). */ -int -open_namei(const char * pathname, int flag, int mode, +int open_namei(const char * pathname, int flag, int mode, struct inode ** res_inode, struct inode * base) { - const char * basename; - int namelen,error; - struct inode * dir, *inode; + char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2]; + struct qstr last; + int error; + int lasterror; + struct inode * dir, * inode; + int namei_mode; - translate_open_namei(pathname, flag, mode, res_inode, base); mode &= S_IALLUGO & ~current->fs->umask; mode |= S_IFREG; - error = dir_namei(pathname, &namelen, &basename, base, &dir); + + namei_mode = NAM_FOLLOW_LINK; + if(flag & O_CREAT) + namei_mode |= NAM_SEMLOCK|NAM_TRANSCREATE|NAM_NO_TRAILSLASH; + error = __namei(namei_mode, pathname, base, buf, + &dir, &inode, &last, NULL, &lasterror); if (error) - return error; - if (!namelen) { /* special case: '/usr/' etc */ - if (flag & 2) { - iput(dir); - return -EISDIR; - } - /* thanks to Paul Pluzhnikov for noticing this was missing.. */ - if ((error = permission(dir,ACC_MODE(flag))) != 0) { - iput(dir); - return error; - } - *res_inode=dir; - return 0; - } - dir->i_count++; /* lookup eats the dir */ + goto exit; + error = lasterror; if (flag & O_CREAT) { - down(&dir->i_sem); - error = lookup(dir, basename, namelen, &inode); if (!error) { if (flag & O_EXCL) { - iput(inode); error = -EEXIST; } } else if (IS_RDONLY(dir)) @@ -371,31 +707,31 @@ else if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) ; /* error is already set! */ else { - dir->i_count++; /* create eats the dir */ + d_del(d_lookup(dir, &last, NULL), D_REMOVE); + atomic_inc(&dir->i_count); /* create eats the dir */ if (dir->i_sb && dir->i_sb->dq_op) dir->i_sb->dq_op->initialize(dir, -1); - error = dir->i_op->create(dir, basename, namelen, mode, res_inode); + error = dir->i_op->create(dir, last.name, last.len, + mode, res_inode); +#ifdef CONFIG_OMIRR + if(!error) + omirr_print(dir->i_dentry, NULL, &last, + " c %ld %d ", CURRENT_TIME, mode); +#endif up(&dir->i_sem); - iput(dir); - return error; + goto exit_dir; } up(&dir->i_sem); - } else - error = lookup(dir, basename, namelen, &inode); - if (error) { - iput(dir); - return error; } - error = follow_link(dir,inode,flag,mode,&inode); if (error) - return error; + goto exit_inode; + if (S_ISDIR(inode->i_mode) && (flag & 2)) { - iput(inode); - return -EISDIR; + error = -EISDIR; + goto exit_inode; } if ((error = permission(inode,ACC_MODE(flag))) != 0) { - iput(inode); - return error; + goto exit_inode; } if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { /* @@ -410,86 +746,102 @@ } else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) { if (IS_NODEV(inode)) { - iput(inode); - return -EACCES; + error = -EACCES; + goto exit_inode; } flag &= ~O_TRUNC; } else { if (IS_RDONLY(inode) && (flag & 2)) { - iput(inode); - return -EROFS; + error = -EROFS; + goto exit_inode; } } /* - * An append-only file must be opened in append mode for writing + * An append-only file must be opened in append mode for writing. */ if (IS_APPEND(inode) && ((flag & FMODE_WRITE) && !(flag & O_APPEND))) { - iput(inode); - return -EPERM; + error = -EPERM; + goto exit_inode; } if (flag & O_TRUNC) { - if ((error = get_write_access(inode))) { - iput(inode); - return error; - } + if ((error = get_write_access(inode))) + goto exit_inode; /* - * Refuse to truncate files with mandatory locks held on them + * Refuse to truncate files with mandatory locks held on them. */ error = locks_verify_locked(inode); - if (error) { - iput(inode); - return error; - } + if (error) + goto exit_inode; if (inode->i_sb && inode->i_sb->dq_op) inode->i_sb->dq_op->initialize(inode, -1); error = do_truncate(inode, 0); put_write_access(inode); - if (error) { - iput(inode); - return error; - } } else if (flag & FMODE_WRITE) if (inode->i_sb && inode->i_sb->dq_op) inode->i_sb->dq_op->initialize(inode, -1); - *res_inode = inode; - return 0; +exit_inode: + if(error) { + if(!lasterror) + iput(inode); + } else + *res_inode = inode; +exit_dir: + iput(dir); +exit: + return error; } int do_mknod(const char * filename, int mode, dev_t dev) { - const char * basename; - int namelen, error; + char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2]; + struct qstr last; + int error, lasterror; struct inode * dir; + struct inode * inode; mode &= ~current->fs->umask; - error = dir_namei(filename, &namelen, &basename, NULL, &dir); + error = __namei(NAM_FOLLOW_LINK|NAM_TRANSCREATE|NAM_NO_TRAILSLASH, + filename, NULL, buf, + &dir, &inode, &last, NULL, &lasterror); if (error) - return error; - if (!namelen) { - iput(dir); - return -ENOENT; + goto exit; + if(!lasterror) { + error = -EEXIST; + goto exit_inode; + } + if (!last.len) { + error = -ENOENT; + goto exit_inode; } if (IS_RDONLY(dir)) { - iput(dir); - return -EROFS; - } - if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) { - iput(dir); - return error; + error = -EROFS; + goto exit_inode; } + if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) + goto exit_inode; if (!dir->i_op || !dir->i_op->mknod) { - iput(dir); - return -EPERM; + error = -ENOSYS; /* instead of EPERM, what does Posix say? */ + goto exit_inode; } - dir->i_count++; + atomic_inc(&dir->i_count); if (dir->i_sb && dir->i_sb->dq_op) dir->i_sb->dq_op->initialize(dir, -1); down(&dir->i_sem); - error = dir->i_op->mknod(dir,basename,namelen,mode,dev); + d_del(d_lookup(dir, &last, NULL), D_REMOVE); + error = dir->i_op->mknod(dir, last.name, last.len, mode, dev); +#ifdef CONFIG_OMIRR + if(!error) + omirr_print(dir->i_dentry, NULL, &last, " n %ld %d %d ", + CURRENT_TIME, mode, dev); +#endif up(&dir->i_sem); +exit_inode: + if(!lasterror) + iput(inode); iput(dir); +exit: return error; } @@ -522,75 +874,59 @@ return error; } -/* - * Some operations need to remove trailing slashes for POSIX.1 - * conformance. For rename we also need to change the behaviour - * depending on whether we had a trailing slash or not.. (we - * cannot rename normal files with trailing slashes, only dirs) - * - * "dummy" is used to make sure we don't do "/" -> "". +/* [Feb-97 T. Schoebel-Theuer] remove_trailing_slashes() is now obsolete, + * its functionality is handled by observing trailing slashes in __namei(). */ -static int remove_trailing_slashes(char * name) +static inline int do_mkdir(const char * pathname, int mode) { - int result; - char dummy[1]; - char *remove = dummy+1; - - for (;;) { - char c = *name; - name++; - if (!c) - break; - if (c != '/') { - remove = NULL; - continue; - } - if (remove) - continue; - remove = name; - } - - result = 0; - if (remove) { - remove[-1] = 0; - result = 1; - } - - return result; -} - -static int do_mkdir(const char * pathname, int mode) -{ - const char * basename; - int namelen, error; + char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2]; + struct qstr last; + int error, lasterror; struct inode * dir; + struct inode * inode; - error = dir_namei(pathname, &namelen, &basename, NULL, &dir); + mode &= 0777 & ~current->fs->umask; + + error = __namei(NAM_FOLLOW_LINK|NAM_TRANSCREATE, pathname, NULL, buf, + &dir, &inode, &last, NULL, &lasterror); if (error) - return error; - if (!namelen) { - iput(dir); - return -ENOENT; + goto exit; + if(!lasterror) { + error = -EEXIST; + goto exit_inode; + } + if (!last.len) { + error = -ENOENT; + goto exit_inode; } if (IS_RDONLY(dir)) { - iput(dir); - return -EROFS; - } - if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) { - iput(dir); - return error; + error = -EROFS; + goto exit_inode; } + if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) + goto exit_inode; if (!dir->i_op || !dir->i_op->mkdir) { - iput(dir); - return -EPERM; + error = -ENOSYS; /* instead of EPERM, what does Posix say? */ + goto exit_inode; } - dir->i_count++; + atomic_inc(&dir->i_count); if (dir->i_sb && dir->i_sb->dq_op) dir->i_sb->dq_op->initialize(dir, -1); down(&dir->i_sem); - error = dir->i_op->mkdir(dir, basename, namelen, mode & 01777 & ~current->fs->umask); + d_del(d_lookup(dir, &last, NULL), D_REMOVE); + mode &= 01777 & ~current->fs->umask; + error = dir->i_op->mkdir(dir, last.name, last.len, mode); +#ifdef CONFIG_OMIRR + if(!error) + omirr_print(dir->i_dentry, NULL, &last, " d %ld %d ", + CURRENT_TIME, mode); +#endif up(&dir->i_sem); +exit_inode: + if(!lasterror) + iput(inode); iput(dir); +exit: return error; } @@ -602,7 +938,6 @@ lock_kernel(); error = getname(pathname,&tmp); if (!error) { - remove_trailing_slashes(tmp); error = do_mkdir(tmp,mode); putname(tmp); } @@ -610,43 +945,125 @@ return error; } -static int do_rmdir(const char * name) -{ - const char * basename; - int namelen, error; +#if 0 /* We need a "deletefs", someone please write it. -DaveM */ +/* Perhaps this could be moved out into a new file. */ +static void basket_name(struct inode * dir, struct dentry * entry) +{ + char prefix[32]; + struct qstr prename = { prefix, 14 }; + struct qstr entname = { entry->d_name, entry->d_len }; + struct inode * inode; + struct dentry * old = entry; /* dummy */ + int i; + if(!entry || !(inode = d_inode(&entry))) + return; +#if 0 + if(atomic_read(&inode->i_count) > 2) { + extern void printpath(struct dentry *entry); + + printk("Caution: in use "); + if(inode->i_dentry) + printpath(inode->i_dentry); + printk(" i_nlink=%d i_count=%d i_ddir_count=%d i_dent_count=%d\n", + inode->i_nlink, atomic_read(&inode->i_count), + inode->i_ddir_count, inode->i_dent_count); + } +#endif + vfs_lock(); + for(i = 1; old; i++) { + sprintf(prefix, ".deleted-%04d.", i); + old = d_lookup(dir, &prename, &entname); + } + d_move(entry, dir, &prename, &entname); + vfs_unlock(); + iput(inode); +} +#endif + +static inline int do_rmdir(const char * name) +{ + char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2]; + struct qstr last; + struct dentry * lastent = NULL; + int error; struct inode * dir; + struct inode * inode; - error = dir_namei(name, &namelen, &basename, NULL, &dir); + /* [T.Schoebel-Theuer] I'm not sure which flags to use here. + * Try the following on different platforms: + * [0] rm -rf test test2 + * [1] ln -s test2 test + * [2] mkdir test || mkdir test2 + * [3] rmdir test && mkdir test2 + * [4] rmdir test/ + * Now the rusults: + * cmd | HP-UX | SunOS | Solaris | Old Linux | New Linux | + * ---------------------------------------------------------------- + * [2] | (OK) | EEXIST | EEXIST | EEXIST | (OK) + * [3] | ENOTDIR | ENOTDIR | ENOTDIR | ENOTDIR | ENOTDIR + * [4] | (OK) | EINVAL | ENOTDIR | ENOTDIR | (OK) + * So I implemented the HP-UX semantics. If this is not right + * for Posix compliancy, change the flags accordingly. If Posix + * let the question open, I'd suggest to stay at the new semantics. + * I'd even make case [3] work by adding 2 to the flags parameter + * if Posix tolerates that. + */ + error = __namei(NAM_FOLLOW_TRAILSLASH, name, NULL, buf, + &dir, &inode, &last, &lastent, NULL); if (error) - return error; - if (!namelen) { - iput(dir); - return -ENOENT; - } + goto exit; if (IS_RDONLY(dir)) { - iput(dir); - return -EROFS; - } - if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) { - iput(dir); - return error; + error = -EROFS; + goto exit_dir; } + if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) + goto exit_dir; /* - * A subdirectory cannot be removed from an append-only directory + * A subdirectory cannot be removed from an append-only directory. */ if (IS_APPEND(dir)) { - iput(dir); - return -EPERM; + error = -EPERM; + goto exit_dir; } if (!dir->i_op || !dir->i_op->rmdir) { - iput(dir); - return -EPERM; + error = -ENOSYS; /* was EPERM */ + goto exit_dir; + } + /* Disallow removals of mountpoints. */ + if(inode->i_mount) { + error = -EBUSY; + goto exit_dir; } if (dir->i_sb && dir->i_sb->dq_op) dir->i_sb->dq_op->initialize(dir, -1); - down(&dir->i_sem); - error = dir->i_op->rmdir(dir,basename,namelen); - up(&dir->i_sem); + + down(&dir->i_sem); +#if 0 + if(lastent && d_isbasket(lastent)) { + d_del(lastent, D_REMOVE); + error = 0; + goto exit_lock; + } +#endif + atomic_inc(&dir->i_count); + error = dir->i_op->rmdir(dir, last.name, last.len); +#ifdef CONFIG_OMIRR + if(!error) + omirr_print(lastent, NULL, NULL, " r %ld ", CURRENT_TIME); +#endif +#if 0 + if(!error && lastent) + basket_name(dir, lastent); +exit_lock: +#else + if(!error && lastent) + d_del(lastent, D_REMOVE); +#endif + up(&dir->i_sem); +exit_dir: + iput(inode); + iput(dir); +exit: return error; } @@ -658,7 +1075,6 @@ lock_kernel(); error = getname(pathname,&tmp); if (!error) { - remove_trailing_slashes(tmp); error = do_rmdir(tmp); putname(tmp); } @@ -666,43 +1082,93 @@ return error; } -static int do_unlink(const char * name) +static inline int do_unlink(const char * name) { - const char * basename; - int namelen, error; + char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2]; + struct qstr last; + struct dentry * lastent = NULL; + int error; struct inode * dir; + struct inode * inode; - error = dir_namei(name, &namelen, &basename, NULL, &dir); + /* HP-UX shows a strange behaviour: + * touch y; ln -s y x; rm x/ + * this succeeds and removes the file y, not the symlink x! + * Solaris and old Linux remove the symlink instead, and + * old SunOS complains ENOTDIR. + * I chose the SunOS behaviour (by not using NAM_FOLLOW_TRAILSLASH), + * but I'm not shure whether I should. + * The current code generally prohibits using trailing slashes with + * non-directories if the name already exists, but not if + * it is to be newly created. + * Perhaps this should be further strengthened (by introducing + * an additional flag bit indicating whether trailing slashes are + * allowed) to get it as consistant as possible, but I don't know + * what Posix says. + */ + error = __namei(NAM_NO_TRAILSLASH, name, NULL, buf, + &dir, &inode, &last, &lastent, NULL); if (error) - return error; - if (!namelen) { - iput(dir); - return -EPERM; - } + goto exit; if (IS_RDONLY(dir)) { - iput(dir); - return -EROFS; - } - if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) { - iput(dir); - return error; + error = -EROFS; + goto exit_dir; } + if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) + goto exit_dir; /* - * A file cannot be removed from an append-only directory + * A file cannot be removed from an append-only directory. */ if (IS_APPEND(dir)) { - iput(dir); - return -EPERM; + error = -EPERM; + goto exit_dir; } if (!dir->i_op || !dir->i_op->unlink) { - iput(dir); - return -EPERM; + error = -ENOSYS; /* was EPERM */ + goto exit_dir; } if (dir->i_sb && dir->i_sb->dq_op) dir->i_sb->dq_op->initialize(dir, -1); - down(&dir->i_sem); - error = dir->i_op->unlink(dir,basename,namelen); - up(&dir->i_sem); + + down(&dir->i_sem); +#if 0 + if(atomic_read(&inode->i_count) > 1) { + extern void printpath(struct dentry *entry); + + printk("Fire "); + if(lastent) + printpath(lastent); + printk(" i_nlink=%d i_count=%d i_ddir_count=%d i_dent_count=%d\n", + inode->i_nlink, atomic_read(&inode->i_count), + inode->i_ddir_count, inode->i_dent_count); + } +#endif +#if 0 + if(lastent && d_isbasket(lastent)) { + d_del(lastent, D_REMOVE); + error = 0; + goto exit_lock; + } +#endif + atomic_inc(&dir->i_count); + error = dir->i_op->unlink(dir, last.name, last.len); +#ifdef CONFIG_OMIRR + if(!error) + omirr_print(lastent, NULL, NULL, " u %ld ", CURRENT_TIME); +#endif +#if 0 + if(!error && lastent) + basket_name(dir, lastent); +exit_lock: +#else + if(!error && lastent) + d_del(lastent, D_REMOVE); +#endif + up(&dir->i_sem); +exit_dir: + iput(inode); + iput(dir); +exit: return error; } @@ -721,38 +1187,65 @@ return error; } -static int do_symlink(const char * oldname, const char * newname) +static inline int do_symlink(const char * oldname, const char * newname) { + char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2]; + struct qstr last; + int error, lasterror; struct inode * dir; - const char * basename; - int namelen, error; + struct inode * inode; - error = dir_namei(newname, &namelen, &basename, NULL, &dir); + /* The following works on HP-UX and Solaris, by producing + * a symlink chain: + * rm -rf ? ; mkdir z ; ln -s z y ; ln -s y x/ + * Under old SunOS, the following occurs: + * ln: x/: No such file or directory + * Under old Linux, very strange things occur: + * ln: cannot create symbolic link `x//y' to `y': No such file or directory + * This is very probably a bug, but may be caused by the ln program + * when checking for a directory target. + * + * I'm not shure whether to add NAM_NO_TRAILSLASH to inhibit trailing + * slashes in the target generally. + */ + error = __namei(NAM_TRANSCREATE, newname, NULL, buf, + &dir, &inode, &last, NULL, &lasterror); if (error) - return error; - if (!namelen) { - iput(dir); - return -ENOENT; + goto exit; + if(!lasterror) { + iput(inode); + error = -EEXIST; + goto exit_dir; } - if (IS_RDONLY(dir)) { - iput(dir); - return -EROFS; + if (!last.len) { + error = -ENOENT; + goto exit_dir; } - if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) { - iput(dir); - return error; + if (IS_RDONLY(dir)) { + error = -EROFS; + goto exit_dir; } + if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) + goto exit_dir; if (!dir->i_op || !dir->i_op->symlink) { - iput(dir); - return -EPERM; + error = -ENOSYS; /* was EPERM */ + goto exit_dir; } - dir->i_count++; + atomic_inc(&dir->i_count); if (dir->i_sb && dir->i_sb->dq_op) dir->i_sb->dq_op->initialize(dir, -1); down(&dir->i_sem); - error = dir->i_op->symlink(dir,basename,namelen,oldname); + d_del(d_lookup(dir, &last, NULL), D_REMOVE); + error = dir->i_op->symlink(dir, last.name, last.len, oldname); +#ifdef CONFIG_OMIRR + if(!error) + omirr_print(dir->i_dentry, NULL, &last, + " s %ld %s\0", CURRENT_TIME, oldname); +#endif up(&dir->i_sem); +exit_dir: iput(dir); +exit: return error; } @@ -775,149 +1268,198 @@ return error; } -static int do_link(struct inode * oldinode, const char * newname) +static inline int do_link(const char * oldname, const char * newname) { - struct inode * dir; - const char * basename; - int namelen, error; + char oldbuf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2]; + char newbuf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2]; + struct qstr oldlast; + struct qstr newlast; + struct dentry * oldent = NULL; + struct inode * oldinode; + struct inode * newinode; + struct inode * newdir; + int error, lasterror; + + error = __namei(NAM_FOLLOW_LINK|NAM_NO_TRAILSLASH, + oldname, NULL, oldbuf, + NULL, &oldinode, &oldlast, &oldent, NULL); + if (error) + goto exit; - error = dir_namei(newname, &namelen, &basename, NULL, &dir); - if (error) { - iput(oldinode); - return error; - } - if (!namelen) { - iput(oldinode); - iput(dir); - return -EPERM; - } - if (IS_RDONLY(dir)) { - iput(oldinode); - iput(dir); - return -EROFS; - } - if (dir->i_dev != oldinode->i_dev) { - iput(dir); - iput(oldinode); - return -EXDEV; - } - if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) { - iput(dir); - iput(oldinode); - return error; + error = __namei(NAM_FOLLOW_LINK|NAM_TRANSCREATE, newname, NULL, newbuf, + &newdir, &newinode, &newlast, NULL, &lasterror); + if (error) + goto old_exit; + if(!lasterror) { + iput(newinode); + error = -EEXIST; + goto new_exit; + } + if (!newlast.len) { + error = -EPERM; + goto new_exit; + } + if (IS_RDONLY(newdir)) { + error = -EROFS; + goto new_exit; + } + if (newdir->i_dev != oldinode->i_dev) { + error = -EXDEV; + goto new_exit; } + if ((error = permission(newdir,MAY_WRITE | MAY_EXEC)) != 0) + goto new_exit; /* - * A link to an append-only or immutable file cannot be created + * A link to an append-only or immutable file cannot be created. */ if (IS_APPEND(oldinode) || IS_IMMUTABLE(oldinode)) { - iput(dir); - iput(oldinode); - return -EPERM; - } - if (!dir->i_op || !dir->i_op->link) { - iput(dir); - iput(oldinode); - return -EPERM; + error = -EPERM; + goto new_exit; } - dir->i_count++; - if (dir->i_sb && dir->i_sb->dq_op) - dir->i_sb->dq_op->initialize(dir, -1); - down(&dir->i_sem); - error = dir->i_op->link(oldinode, dir, basename, namelen); - up(&dir->i_sem); - iput(dir); + if (!newdir->i_op || !newdir->i_op->link) { + error = -ENOSYS; /* was EPERM */ + goto new_exit; + } + atomic_inc(&oldinode->i_count); + atomic_inc(&newdir->i_count); + if (newdir->i_sb && newdir->i_sb->dq_op) + newdir->i_sb->dq_op->initialize(newdir, -1); + down(&newdir->i_sem); + d_del(d_lookup(newdir, &newlast, NULL), D_REMOVE); + error = newdir->i_op->link(oldinode, newdir, newlast.name, newlast.len); +#ifdef CONFIG_OMIRR + if(!error) + omirr_print(oldent, newdir->i_dentry, &newlast, + " l %ld ", CURRENT_TIME); +#endif + up(&newdir->i_sem); +new_exit: + iput(newdir); +old_exit: + iput(oldinode); +exit: return error; } asmlinkage int sys_link(const char * oldname, const char * newname) { int error; - char * to; - struct inode * oldinode; + char * from, * to; lock_kernel(); - error = lnamei(oldname, &oldinode); - if (error) - goto out; - error = getname(newname,&to); - if (error) { - iput(oldinode); - goto out; + error = getname(oldname,&from); + if (!error) { + error = getname(newname,&to); + if (!error) { + error = do_link(from,to); + putname(to); + } + putname(from); } - error = do_link(oldinode,to); - putname(to); -out: unlock_kernel(); return error; } -static int do_rename(const char * oldname, const char * newname, int must_be_dir) +static inline int do_rename(const char * oldname, const char * newname) { - struct inode * old_dir, * new_dir; - const char * old_base, * new_base; - int old_len, new_len, error; + char oldbuf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2]; + struct qstr oldlast; + char newbuf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2]; + struct qstr newlast; + struct dentry * oldent = NULL; + struct inode * olddir, * newdir; + struct inode * oldinode, * newinode; + int error, newlasterror; - error = dir_namei(oldname, &old_len, &old_base, NULL, &old_dir); + error = __namei(NAM_FOLLOW_TRAILSLASH, oldname, NULL, oldbuf, + &olddir, &oldinode, &oldlast, &oldent, NULL); if (error) - return error; - if ((error = permission(old_dir,MAY_WRITE | MAY_EXEC)) != 0) { - iput(old_dir); - return error; + goto exit; + if ((error = permission(olddir,MAY_WRITE | MAY_EXEC)) != 0) + goto old_exit; + if (!oldlast.len || (oldlast.name[0] == '.' && + (oldlast.len == 1 || (oldlast.name[1] == '.' && + oldlast.len == 2)))) { + error = -EPERM; + goto old_exit; + } + /* Disallow moves of mountpoints. */ + if(oldinode->i_mount) { + error = -EBUSY; + goto old_exit; } - if (!old_len || (old_base[0] == '.' && - (old_len == 1 || (old_base[1] == '.' && - old_len == 2)))) { - iput(old_dir); - return -EPERM; - } - error = dir_namei(newname, &new_len, &new_base, NULL, &new_dir); - if (error) { - iput(old_dir); - return error; - } - if ((error = permission(new_dir,MAY_WRITE | MAY_EXEC)) != 0){ - iput(old_dir); - iput(new_dir); - return error; - } - if (!new_len || (new_base[0] == '.' && - (new_len == 1 || (new_base[1] == '.' && - new_len == 2)))) { - iput(old_dir); - iput(new_dir); - return -EPERM; - } - if (new_dir->i_dev != old_dir->i_dev) { - iput(old_dir); - iput(new_dir); - return -EXDEV; - } - if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir)) { - iput(old_dir); - iput(new_dir); - return -EROFS; + + error = __namei(NAM_FOLLOW_LINK|NAM_TRANSCREATE, newname, NULL, newbuf, + &newdir, &newinode, &newlast, NULL, &newlasterror); + if (error) + goto old_exit; + if ((error = permission(newdir,MAY_WRITE | MAY_EXEC)) != 0) + goto new_exit; + if (!newlast.len || (newlast.name[0] == '.' && + (newlast.len == 1 || (newlast.name[1] == '.' && + newlast.len == 2)))) { + error = -EPERM; + goto new_exit; + } + if (newdir->i_dev != olddir->i_dev) { + error = -EXDEV; + goto new_exit; + } + if (IS_RDONLY(newdir) || IS_RDONLY(olddir)) { + error = -EROFS; + goto new_exit; } /* - * A file cannot be removed from an append-only directory + * A file cannot be removed from an append-only directory. + */ + if (IS_APPEND(olddir)) { + error = -EPERM; + goto new_exit; + } + if (!olddir->i_op || !olddir->i_op->rename) { + error = -ENOSYS; /* was EPERM */ + goto new_exit; + } +#ifdef CONFIG_TRANS_NAMES + /* if oldname has been translated, but newname not (and + * has not already a suffix), take over the suffix from oldname. */ - if (IS_APPEND(old_dir)) { - iput(old_dir); - iput(new_dir); - return -EPERM; - } - if (!old_dir->i_op || !old_dir->i_op->rename) { - iput(old_dir); - iput(new_dir); - return -EPERM; - } - new_dir->i_count++; - if (new_dir->i_sb && new_dir->i_sb->dq_op) - new_dir->i_sb->dq_op->initialize(new_dir, -1); - down(&new_dir->i_sem); - error = old_dir->i_op->rename(old_dir, old_base, old_len, - new_dir, new_base, new_len, must_be_dir); - up(&new_dir->i_sem); - iput(new_dir); + if(oldlast.name == oldbuf && newlast.name != newbuf && + newlast.name[newlast.len-1] != '#') { + int i = oldlast.len - 2; + while (i > 0 && oldlast.name[i] != '#') + i--; + memcpy(newbuf, newlast.name, newlast.len); + memcpy(newbuf+newlast.len, oldlast.name+i, oldlast.len - i); + newlast.len += oldlast.len - i; + newlast.name = newbuf; + } +#endif + atomic_inc(&olddir->i_count); + atomic_inc(&newdir->i_count); + if (newdir->i_sb && newdir->i_sb->dq_op) + newdir->i_sb->dq_op->initialize(newdir, -1); + down(&newdir->i_sem); + error = olddir->i_op->rename(olddir, oldlast.name, oldlast.len, + newdir, newlast.name, newlast.len); +#ifdef CONFIG_OMIRR + if(!error) + omirr_print(oldent, newdir->i_dentry, &newlast, + " m %ld ", CURRENT_TIME); +#endif + if(!error) { + d_del(d_lookup(newdir, &newlast, NULL), D_REMOVE); + d_move(d_lookup(olddir, &oldlast, NULL), newdir, &newlast, NULL); + } + up(&newdir->i_sem); +new_exit: + if(!newlasterror) + iput(newinode); + iput(newdir); +old_exit: + iput(oldinode); + iput(olddir); +exit: return error; } @@ -931,9 +1473,7 @@ if (!error) { error = getname(newname,&to); if (!error) { - error = do_rename(from,to, - remove_trailing_slashes(from) | - remove_trailing_slashes(to)); + error = do_rename(from,to); putname(to); } putname(from); diff -u --recursive --new-file v2.1.42/linux/fs/nametrans.c linux/fs/nametrans.c --- v2.1.42/linux/fs/nametrans.c Wed Dec 31 16:00:00 1969 +++ linux/fs/nametrans.c Thu Jun 12 16:22:08 1997 @@ -0,0 +1,310 @@ +/* + * $Id: nametrans.c,v 1.2 1997/06/04 23:45:44 davem Exp $ + * + * linux/fs/nametrans.c - context-dependend filename suffixes. + * Copyright (C) 1997, Thomas Schoebel-Theuer, + * . + * + * translates names of the form "filename#host=myhost#" to "filename" + * as if both names were hardlinked to the same file. + * benefit: diskless clients can mount the / filesystem of the + * server if /etc/fstab (and other config files) are organized using + * context suffixes. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +char nametrans_txt[MAX_DEFAULT_TRANSLEN] = ""; +static struct translations * global_trans = NULL; +static int default_trans = 1; +static const char version[] = "revision: 2.3 "; +int translations_dirty = 1; +static char * transl_names[] = { +#ifdef CONFIG_TR_NODENAME + "host=", system_utsname.nodename, +#endif +#ifdef CONFIG_TR_KERNNAME + "kname=", CONFIG_KERNNAME, +#endif +#ifdef CONFIG_TR_KERNTYPE + "ktype=", CONFIG_KERNTYPE, +#endif +#ifdef CONFIG_TR_MACHINE + "machine=", system_utsname.machine, +#endif +#ifdef CONFIG_TR_SYSNAME + "system=", system_utsname.sysname, +#endif + 0, 0 +}; + +/* Convert and do syntax checking. */ +static void convert(char * txt, struct translations * res) +{ + char * tmp = txt; + char * space = (char*)res + sizeof(struct translations); + + res->count = 0; + while(*tmp) { + struct qstr * name = &res->name[res->count]; + struct qstr * c_name = &res->c_name[res->count]; + int len; + char * p = tmp; + + if(*p++ != '#') + goto next; + while(*p && *p != '=' && *p != ':') + p++; + if(*p != '=') + goto next; + p++; + len = (unsigned long)p - (unsigned long)tmp; + c_name->name = space; + memcpy(space, tmp, len); + memcpy(space + len, "CREATE#", 8); + c_name->len = len + 7; + if(c_name->len >= MAX_TRANS_SUFFIX) + goto next; + while(*p && *p != '#' && *p != ':') + p++; + if(*p != '#') + goto next; + p++; + if(*p != ':' && *p) + goto next; + space += len + 8; + name->len = len = (unsigned long)p - (unsigned long)tmp; + if(len >= MAX_TRANS_SUFFIX) + goto next; + name->name = space; + memcpy(space, tmp, len); + space[len] = '\0'; + space += len + 1; + res->count++; + if(res->count >= MAX_TRANSLATIONS || + (unsigned long)space - (unsigned long)res >= PAGE_SIZE-2*MAX_TRANS_SUFFIX) + return; + next: + while(*p && *p++ != ':') ; + tmp = p; + } +} + +static inline void trans_to_string(struct translations * trans, char * buf, int maxlen) +{ + int i; + + for(i = 0; i < trans->count; i++) { + int len = trans->name[i].len; + if(len < maxlen) { + memcpy(buf, trans->name[i].name, len); + buf += len; + maxlen -= len; + *buf++ = ':'; + maxlen--; + } + } + buf--; + *buf = '\0'; +} + +static inline void default_nametrans(char * buf) +{ + char * res = buf; + char ** entry; + char * ptr; + + for (entry = transl_names; *entry; entry++) { + *res++ = '#'; + for(ptr = *entry; *ptr; ptr++) + *res++ = *ptr; + entry++; + for(ptr = *entry; *ptr; ptr++) + *res++ = *ptr; + *res++ = '#'; + *res++ = ':'; + } + res--; + *res = '\0'; +} + +void nametrans_setup(char * line) +{ + if(line) { + default_trans = (!line[0]); + if(!global_trans) { + /* This can happen at boot time, and there is no chance + * to allocate memory at this early stage. + */ + strncpy(nametrans_txt, line, MAX_DEFAULT_TRANSLEN); + } else { + if(default_trans) { + default_nametrans(nametrans_txt); + line = nametrans_txt; + } + convert(line, global_trans); + + /* Show what really was recognized after parsing... */ + trans_to_string(global_trans, nametrans_txt, MAX_DEFAULT_TRANSLEN); + } + } +} + +/* If the _first_ environment variable is "NAMETRANS", return + * a pointer to the list of appendices. + * You can set the first environment variable using + * 'env - NAMETRANS=... "`env`" command ...' + */ +char* env_transl(void) +{ + char* env; + int i; + + if(current && current->mm && (env = (char*)current->mm->env_start) + && get_ds() != get_fs() + && current->mm->env_end>=current->mm->env_start+10 + && !verify_area(VERIFY_READ,env,10)) { + for(i=0; i<10; i++) { + char c; + + get_user(c, env++); + if(c != "NAMETRANS="[i]) + return 0; + } + return env; + } + return 0; +} + +/* If name has the correct suffix "#keyword=correct_context#", + * return position of the suffix, else 0. + */ +char *testname(int restricted, char* name) +{ + char * ptr = name; + char * cut; + char * env; + struct translations * trans; + int i, len; + char c, tmp; + + env = env_transl(); +#ifdef CONFIG_TRANS_RESTRICT + if(!env && restricted) + goto done; +#else + (void)restricted; /* inhibit parameter usage warning */ +#endif + if(get_user(c, ptr)) + goto done; + while(c && c != '#') { + ptr++; + __get_user(c, ptr); + } + if(!c) + goto done; + cut = ptr++; + if(get_user(c, ptr)) + goto done; + while (c && c != '#') { + ptr++; + get_user(c, ptr); + } + if(!c) + goto done; + get_user(tmp, ptr); + if(tmp) + goto done; + trans = get_translations(env); + len = (unsigned long)ptr - (unsigned long)cut; + for(i = 0; i < trans->count; i++) + if(trans->name[i].len == len) { + const char * p1 = cut; + const char * p2 = trans->name[i].name; + get_user(c, p1); + while(c && c == *p2++) { + p1++; + get_user(c, p1); + } + if(!c) + return cut; + } +done: + return NULL; +} + +static inline void check_dirty(void) +{ + if(translations_dirty && default_trans) { + nametrans_setup(""); + translations_dirty = 0; + } +} + +struct translations * get_translations(char * env) +{ + struct translations * res; + + if(env) { + char * env_txt = (char*)__get_free_page(GFP_KERNEL); + + strncpy_from_user(env_txt, env, PAGE_SIZE); + res = (struct translations *)__get_free_page(GFP_KERNEL); + convert(env_txt, res); + free_page((unsigned long)env_txt); + } else { + check_dirty(); + res = global_trans; + } + return res; +} + +int nametrans_dostring(ctl_table * table, int write, struct file * filp, + void * buffer, size_t * lenp) +{ + int res; + check_dirty(); + res = proc_dostring(table, write, filp, buffer, lenp); + if(!res && write) + nametrans_setup(nametrans_txt); + + return res; +} + +int nametrans_string(ctl_table * table, int * name, int nlen, + void * oldval, size_t * oldlenp, + void * newval, size_t newlen, void ** context) +{ + int res; + check_dirty(); + res = sysctl_string(table, name, nlen, oldval, oldlenp, newval, newlen, context); + if(!res && newval && newlen) + nametrans_setup(nametrans_txt); + + return res; +} + +void init_nametrans(void) +{ + if(!global_trans) + global_trans = (struct translations*)__get_free_page(GFP_KERNEL); + if(!global_trans) { + printk("NAMETRANS: No free memory\n"); + return; + } + nametrans_setup(nametrans_txt); + + /* Notify user for the default/supplied translations. + * Extremely useful for finding translation problems. + */ + printk("Nametrans %s\nNametrans %s: %s\n", version, + default_trans ? "default translations" : "external parameter", + nametrans_txt); +} diff -u --recursive --new-file v2.1.42/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c --- v2.1.42/linux/fs/ncpfs/dir.c Fri Apr 4 08:52:24 1997 +++ linux/fs/ncpfs/dir.c Thu Jun 12 16:22:08 1997 @@ -67,8 +67,7 @@ static int ncp_rename(struct inode *old_dir, const char *old_name, int old_len, - struct inode *new_dir, const char *new_name, int new_len, - int must_be_dir); + struct inode *new_dir, const char *new_name, int new_len); static inline void str_upper(char *name) { @@ -129,7 +128,6 @@ NULL, /* mknod */ ncp_rename, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* bmap */ NULL, /* truncate */ NULL, /* permission */ @@ -965,8 +963,7 @@ } static int ncp_rename(struct inode *old_dir, const char *old_name, int old_len, - struct inode *new_dir, const char *new_name, int new_len, - int must_be_dir) + struct inode *new_dir, const char *new_name, int new_len) { int res; char _old_name[old_len + 1]; diff -u --recursive --new-file v2.1.42/linux/fs/ncpfs/file.c linux/fs/ncpfs/file.c --- v2.1.42/linux/fs/ncpfs/file.c Fri Apr 4 08:52:24 1997 +++ linux/fs/ncpfs/file.c Thu Jun 12 16:22:08 1997 @@ -232,7 +232,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* bmap */ NULL /* truncate */ }; diff -u --recursive --new-file v2.1.42/linux/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c --- v2.1.42/linux/fs/ncpfs/inode.c Tue May 13 22:41:15 1997 +++ linux/fs/ncpfs/inode.c Thu Jun 12 16:22:08 1997 @@ -406,9 +406,11 @@ int ncp_current_malloced; #endif -static struct file_system_type ncp_fs_type = -{ - ncp_read_super, "ncpfs", 0, NULL +static struct file_system_type ncp_fs_type = { + "ncpfs", + FS_NO_DCACHE, + ncp_read_super, + NULL }; __initfunc(int init_ncp_fs(void)) diff -u --recursive --new-file v2.1.42/linux/fs/ncpfs/mmap.c linux/fs/ncpfs/mmap.c --- v2.1.42/linux/fs/ncpfs/mmap.c Fri Apr 4 08:52:24 1997 +++ linux/fs/ncpfs/mmap.c Thu Jun 12 16:22:08 1997 @@ -133,7 +133,7 @@ inode->i_dirt = 1; } vma->vm_inode = inode; - inode->i_count++; + atomic_inc(&inode->i_count); vma->vm_ops = &ncp_file_mmap; return 0; } diff -u --recursive --new-file v2.1.42/linux/fs/nfs/dir.c linux/fs/nfs/dir.c --- v2.1.42/linux/fs/nfs/dir.c Wed Apr 23 19:01:26 1997 +++ linux/fs/nfs/dir.c Thu Jun 12 16:22:08 1997 @@ -51,7 +51,7 @@ static int nfs_link(struct inode *, struct inode *, const char *, int); static int nfs_mknod(struct inode *, const char *, int, int, int); static int nfs_rename(struct inode *, const char *, int, - struct inode *, const char *, int, int); + struct inode *, const char *, int); static struct file_operations nfs_dir_operations = { NULL, /* lseek - default */ @@ -78,7 +78,6 @@ nfs_mknod, /* mknod */ nfs_rename, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -351,7 +350,7 @@ char filename[NFS_MAXNAMLEN + 1]; struct nfs_fh fhandle; struct nfs_fattr fattr; - int expiration_date; + unsigned long expiration_date; } nfs_lookup_cache[NFS_LOOKUP_CACHE_SIZE]; static struct nfs_lookup_cache_entry *nfs_lookup_cache_index(struct inode *dir, @@ -492,7 +491,7 @@ } memcpy(name,__name,len); name[len] = '\0'; - if (len == 1 && name[0] == '.') { /* cheat for "." */ + if (len == 0 || (len == 1 && name[0] == '.')) { /* cheat for "" and "." */ *result = dir; return 0; } @@ -649,11 +648,11 @@ char silly[16]; int slen, ret; - dir->i_count++; + atomic_inc(&dir->i_count); if (nfs_lookup(dir, name, len, &inode) < 0) return -EIO; /* arbitrary */ - if (inode->i_count == 1) { + if (atomic_read(&inode->i_count) == 1) { iput(inode); return -EIO; } @@ -679,7 +678,7 @@ nfs_lookup_cache_remove(dir, NULL, name); nfs_lookup_cache_remove(dir, NULL, silly); NFS_RENAMED_DIR(inode) = dir; - dir->i_count++; + atomic_inc(&dir->i_count); } nfs_invalidate_dircache(dir); iput(inode); @@ -823,8 +822,7 @@ * file in old_dir will go away when the last process iput()s the inode. */ static int nfs_rename(struct inode *old_dir, const char *old_name, int old_len, - struct inode *new_dir, const char *new_name, int new_len, - int must_be_dir) + struct inode *new_dir, const char *new_name, int new_len) { int error; @@ -850,10 +848,6 @@ return -ENAMETOOLONG; } - /* We don't do rename() with trailing slashes over NFS now. Hmm. */ - if (must_be_dir) - return -EINVAL; - error = nfs_proc_rename(NFS_SERVER(old_dir), NFS_FH(old_dir), old_name, NFS_FH(new_dir), new_name); @@ -879,7 +873,8 @@ int was_empty; dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d)\n", - inode->i_dev, inode->i_ino, inode->i_count); + inode->i_dev, inode->i_ino, + atomic_read(&inode->i_count)); if (!inode || !fattr) { printk("nfs_refresh_inode: inode or fattr is NULL\n"); diff -u --recursive --new-file v2.1.42/linux/fs/nfs/file.c linux/fs/nfs/file.c --- v2.1.42/linux/fs/nfs/file.c Mon Apr 7 11:35:30 1997 +++ linux/fs/nfs/file.c Thu Jun 12 16:22:08 1997 @@ -69,7 +69,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ nfs_readpage, /* readpage */ nfs_writepage, /* writepage */ NULL, /* bmap */ @@ -143,7 +142,7 @@ int result; dfprintk(VFS, "nfs: write(%x/%ld (%d), %lu@%lu)\n", - inode->i_dev, inode->i_ino, inode->i_count, + inode->i_dev, inode->i_ino, atomic_read(&inode->i_count), count, (unsigned long) file->f_pos); if (!inode) { diff -u --recursive --new-file v2.1.42/linux/fs/nfs/inode.c linux/fs/nfs/inode.c --- v2.1.42/linux/fs/nfs/inode.c Mon Apr 14 16:28:17 1997 +++ linux/fs/nfs/inode.c Thu Jun 12 16:22:08 1997 @@ -316,7 +316,8 @@ nfs_refresh_inode(inode, fattr); } dprintk("NFS: fhget(%x/%ld ct=%d)\n", - inode->i_dev, inode->i_ino, inode->i_count); + inode->i_dev, inode->i_ino, + atomic_read(&inode->i_count)); return inode; } @@ -433,7 +434,10 @@ * File system information */ static struct file_system_type nfs_fs_type = { - nfs_read_super, "nfs", 0, NULL + "nfs", + FS_NO_DCACHE, + nfs_read_super, + NULL }; /* diff -u --recursive --new-file v2.1.42/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c --- v2.1.42/linux/fs/nfs/nfsroot.c Thu May 29 21:53:08 1997 +++ linux/fs/nfs/nfsroot.c Thu Jun 12 16:22:08 1997 @@ -1,5 +1,5 @@ /* - * $Id: nfsroot.c,v 1.36 1997/05/27 15:57:47 mj Exp $ + * $Id: nfsroot.c,v 1.37 1997/06/04 08:28:10 davem Exp $ * * Copyright (C) 1995, 1996 Gero Kuhlmann * @@ -78,6 +78,7 @@ #include #include +#include #include #include #include @@ -832,6 +833,9 @@ root_bootp_string(nfs_path, ext+1, *ext, NFS_MAXPATHLEN); break; } +#ifdef CONFIG_TRANS_NAMES + translations_dirty = 1; +#endif } @@ -1254,6 +1258,9 @@ system_utsname.domainname[0] = '\0'; user_dev_name[0] = '\0'; bootp_flag = rarp_flag = 1; +#ifdef CONFIG_TRANS_NAMES + translations_dirty = 1; +#endif /* The following is just a shortcut for automatic IP configuration */ if (!strcmp(addrs, "bootp")) { @@ -1299,6 +1306,9 @@ } strncpy(system_utsname.nodename, ip, __NEW_UTS_LEN); system_utsname.nodename[__NEW_UTS_LEN] = '\0'; +#ifdef CONFIG_TRANS_NAMES + translations_dirty = 1; +#endif break; case 5: strncpy(user_dev_name, ip, IFNAMSIZ); @@ -1332,6 +1342,9 @@ if (!system_utsname.nodename[0]) { strncpy(system_utsname.nodename, in_ntoa(myaddr), __NEW_UTS_LEN); system_utsname.nodename[__NEW_UTS_LEN] = '\0'; +#ifdef CONFIG_TRANS_NAMES + translations_dirty = 1; +#endif } /* Set the correct netmask */ diff -u --recursive --new-file v2.1.42/linux/fs/nfs/proc.c linux/fs/nfs/proc.c --- v2.1.42/linux/fs/nfs/proc.c Mon Apr 7 11:35:31 1997 +++ linux/fs/nfs/proc.c Thu Jun 12 16:22:08 1997 @@ -177,8 +177,8 @@ int nfs_proc_rename(struct nfs_server *server, - struct nfs_fh *old_dir, const char *old_name, - struct nfs_fh *new_dir, const char *new_name) + struct nfs_fh *old_dir, const char *old_name, + struct nfs_fh *new_dir, const char *new_name) { struct nfs_renameargs arg = { old_dir, old_name, new_dir, new_name }; int status; diff -u --recursive --new-file v2.1.42/linux/fs/nfs/read.c linux/fs/nfs/read.c --- v2.1.42/linux/fs/nfs/read.c Mon Apr 14 16:28:17 1997 +++ linux/fs/nfs/read.c Thu Jun 12 16:22:08 1997 @@ -188,7 +188,7 @@ nfs_readpage_result, req); if (result >= 0) { - inode->i_count++; + atomic_inc(&inode->i_count); atomic_inc(&page->count); return 0; } diff -u --recursive --new-file v2.1.42/linux/fs/nfs/symlink.c linux/fs/nfs/symlink.c --- v2.1.42/linux/fs/nfs/symlink.c Mon Apr 7 11:35:31 1997 +++ linux/fs/nfs/symlink.c Thu Jun 12 16:22:08 1997 @@ -19,8 +19,6 @@ #include static int nfs_readlink(struct inode *, char *, int); -static int nfs_follow_link(struct inode *, struct inode *, int, int, - struct inode **); /* * symlinks can't do much... @@ -37,7 +35,6 @@ NULL, /* mknod */ NULL, /* rename */ nfs_readlink, /* readlink */ - nfs_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -45,55 +42,6 @@ NULL /* permission */ }; -static int nfs_follow_link(struct inode *dir, struct inode *inode, - int flag, int mode, struct inode **res_inode) -{ - int error; - unsigned int len; - char *res, *res2; - void *mem; - - *res_inode = NULL; - if (!dir) { - dir = current->fs->root; - dir->i_count++; - } - if (!inode) { - iput(dir); - return -ENOENT; - } - if (!S_ISLNK(inode->i_mode)) { - iput(dir); - *res_inode = inode; - return 0; - } - if (current->link_count > 5) { - iput(inode); - iput(dir); - return -ELOOP; - } - error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), &mem, - &res, &len, NFS_MAXPATHLEN); - if (error) { - iput(inode); - iput(dir); - kfree(mem); - return error; - } - while ((res2 = (char *) kmalloc(NFS_MAXPATHLEN + 1, GFP_NFS)) == NULL) { - schedule(); - } - memcpy(res2, res, len); - res2[len] = '\0'; - kfree(mem); - iput(inode); - current->link_count++; - error = open_namei(res2, flag, mode, res_inode, dir); - current->link_count--; - kfree_s(res2, NFS_MAXPATHLEN + 1); - return error; -} - static int nfs_readlink(struct inode *inode, char *buffer, int buflen) { int error; @@ -103,10 +51,6 @@ dfprintk(VFS, "nfs: readlink(%x/%ld)\n", inode->i_dev, inode->i_ino); - if (!S_ISLNK(inode->i_mode)) { - iput(inode); - return -EINVAL; - } if (buflen > NFS_MAXPATHLEN) buflen = NFS_MAXPATHLEN; error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), &mem, diff -u --recursive --new-file v2.1.42/linux/fs/nfs/write.c linux/fs/nfs/write.c --- v2.1.42/linux/fs/nfs/write.c Wed May 28 10:51:33 1997 +++ linux/fs/nfs/write.c Mon Jun 16 08:46:24 1997 @@ -133,7 +133,7 @@ if (test_and_clear_bit(PG_decr_after, &page->flags)) atomic_dec(&page->count); if (test_and_clear_bit(PG_swap_unlock_after, &page->flags)) - swap_after_unlock_page(page->swap_unlock_entry); + swap_after_unlock_page(page->pg_swap_entry); #endif } @@ -338,7 +338,7 @@ wreq->wb_page = page; wreq->wb_offset = offset; wreq->wb_bytes = bytes; - inode->i_count++; + atomic_inc(&inode->i_count); atomic_inc(&page->count); append_write_request(&NFS_WRITEBACK(inode), wreq); @@ -788,7 +788,7 @@ dprintk("NFS: %4d saving write failure code\n", task->tk_pid); append_write_request(&nfs_failed_requests, req); - inode->i_count++; + atomic_inc(&inode->i_count); } clear_bit(PG_uptodate, &page->flags); } else if (!WB_CANCELLED(req)) { diff -u --recursive --new-file v2.1.42/linux/fs/nfsd/export.c linux/fs/nfsd/export.c --- v2.1.42/linux/fs/nfsd/export.c Mon Apr 7 11:35:31 1997 +++ linux/fs/nfsd/export.c Thu Jun 12 16:22:09 1997 @@ -331,7 +331,7 @@ if (!(exp = exp_get(clp, dev, ino))) return -EPERM; - exp->ex_inode->i_count++; + atomic_inc(&exp->ex_inode->i_count); fh_compose(&fh, exp, exp->ex_inode); memcpy(f, &fh.fh_handle, sizeof(struct knfs_fh)); fh_put(&fh); diff -u --recursive --new-file v2.1.42/linux/fs/nfsd/nfsctl.c linux/fs/nfsd/nfsctl.c --- v2.1.42/linux/fs/nfsd/nfsctl.c Wed Apr 23 19:01:27 1997 +++ linux/fs/nfsd/nfsctl.c Thu Jun 12 16:22:09 1997 @@ -35,8 +35,8 @@ # define copy_to_user memcpy_tofs # define access_ok !verify_area #endif -#include -#include +#include +#include extern long sys_call_table[]; @@ -213,8 +213,6 @@ EXPORT_NO_SYMBOLS; MODULE_AUTHOR("Olaf Kirch "); #endif - -static unsigned long old_syscallvec; extern int (*do_nfsservctl)(int, void *, void *); diff -u --recursive --new-file v2.1.42/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c --- v2.1.42/linux/fs/nfsd/vfs.c Tue May 13 22:41:15 1997 +++ linux/fs/nfsd/vfs.c Thu Jun 12 16:22:09 1997 @@ -39,9 +39,6 @@ #define NFSDDBG_FACILITY NFSDDBG_FILEOP -/* Symbol not exported */ -static struct super_block *get_super(dev_t dev); - /* Open mode for nfsd_open */ #define OPEN_READ 0 #define OPEN_WRITE 1 @@ -123,13 +120,13 @@ dotdot = (len == 2 && name[0] == '.' && name[1] == '.'); if (dotdot) { if (dirp == current->fs->root) { - dirp->i_count++; + atomic_inc(&dirp->i_count); *resfh = *fhp; return 0; } if (dirp->i_dev == exp->ex_dev && dirp->i_ino == exp->ex_ino) { - dirp->i_count++; + atomic_inc(&dirp->i_count); *resfh = *fhp; return 0; } @@ -147,12 +144,12 @@ if (perm != 0) return perm; if (!len) { - dirp->i_count++; + atomic_inc(&dirp->i_count); *resfh = *fhp; return 0; } - dirp->i_count++; /* lookup eats the dirp inode */ + atomic_inc(&dirp->i_count); /* lookup eats the dirp inode */ err = dirp->i_op->lookup(dirp, name, len, &inode); if (err) @@ -165,7 +162,7 @@ if (!dotdot && (sb = inode->i_sb) && (inode == sb->s_mounted)) { iput(inode); inode = sb->s_covered; - inode->i_count++; + atomic_inc(&inode->i_count); } fh_compose(resfh, exp, inode); @@ -294,7 +291,7 @@ } } - inode->i_count++; + atomic_inc(&inode->i_count); return 0; } @@ -307,7 +304,7 @@ struct inode *inode; inode = filp->f_inode; - if (!inode->i_count) + if (!atomic_read(&inode->i_count)) printk(KERN_WARNING "nfsd: inode count == 0!\n"); if (filp->f_op && filp->f_op->release) filp->f_op->release(inode, filp); @@ -536,7 +533,7 @@ fh_lock(fhp); /* lock directory */ dirp = fhp->fh_inode; - dirp->i_count++; /* dirop eats the inode */ + atomic_inc(&dirp->i_count); /* dirop eats the inode */ switch (type) { case S_IFREG: @@ -571,7 +568,7 @@ * If the VFS call doesn't return the inode, look it up now. */ if (inode == NULL) { - dirp->i_count++; + atomic_inc(&dirp->i_count); err = dirp->i_op->lookup(dirp, fname, flen, &inode); if (err < 0) return -nfserrno(err); /* Huh?! */ @@ -646,7 +643,7 @@ if (!inode->i_op || !inode->i_op->readlink) return nfserr_io; - inode->i_count++; + atomic_inc(&inode->i_count); oldfs = get_fs(); set_fs(KERNEL_DS); err = inode->i_op->readlink(inode, buf, *lenp); set_fs(oldfs); @@ -683,7 +680,7 @@ return nfserr_perm; fh_lock(fhp); /* lock inode */ - dirp->i_count++; + atomic_inc(&dirp->i_count); err = dirp->i_op->symlink(dirp, fname, flen, path); fh_unlock(fhp); /* unlock inode */ @@ -696,7 +693,7 @@ /* * Okay, now look up the inode of the new symlink. */ - dirp->i_count++; /* lookup eats the dirp inode */ + atomic_inc(&dirp->i_count); /* lookup eats the dirp inode */ err = dirp->i_op->lookup(dirp, fname, flen, &inode); if (err) return nfserrno(-err); @@ -733,7 +730,7 @@ return nfserr_perm; fh_lock(ffhp); /* lock directory inode */ - dirp->i_count++; + atomic_inc(&dirp->i_count); err = dirp->i_op->link(dest, dirp, fname, len); fh_unlock(ffhp); /* unlock inode */ @@ -773,9 +770,9 @@ return nfserr_perm; fh_lock(tfhp); /* lock destination directory */ - tdir->i_count++; - fdir->i_count++; - err = fdir->i_op->rename(fdir, fname, flen, tdir, tname, tlen, 0); + atomic_inc(&tdir->i_count); + atomic_inc(&fdir->i_count); + err = fdir->i_op->rename(fdir, fname, flen, tdir, tname, tlen); fh_unlock(tfhp); /* unlock inode */ if (!err && EX_ISSYNC(tfhp->fh_export)) { @@ -808,12 +805,12 @@ if (type == S_IFDIR) { if (!dirp->i_op || !dirp->i_op->rmdir) return nfserr_notdir; - dirp->i_count++; + atomic_inc(&dirp->i_count); err = dirp->i_op->rmdir(dirp, fname, flen); } else { /* other than S_IFDIR */ if (!dirp->i_op || !dirp->i_op->unlink) return nfserr_perm; - dirp->i_count++; + atomic_inc(&dirp->i_count); err = dirp->i_op->unlink(dirp, fname, flen); } @@ -1039,26 +1036,6 @@ return 0; *devp = sb->s_covered->i_dev; return 1; -} - -/* Duplicated here from fs/super.c because it's not exported */ -static struct super_block * -get_super(dev_t dev) -{ - struct super_block *s; - - if (!dev) - return NULL; - s = 0 + super_blocks; - while (s < NR_SUPER + super_blocks) - if (s->s_dev == dev) { - wait_on_super(s); - if (s->s_dev == dev) - return s; - s = 0 + super_blocks; - } else - s++; - return NULL; } /* diff -u --recursive --new-file v2.1.42/linux/fs/open.c linux/fs/open.c --- v2.1.42/linux/fs/open.c Tue May 13 22:41:15 1997 +++ linux/fs/open.c Thu Jun 12 16:22:09 1997 @@ -4,6 +4,7 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ +#include #include #include #include @@ -20,6 +21,7 @@ #include #include #include +#include #include #include @@ -33,7 +35,7 @@ error = verify_area(VERIFY_WRITE, buf, sizeof(struct statfs)); if (error) goto out; - error = namei(path,&inode); + error = namei(NAM_FOLLOW_LINK, path, &inode); if (error) goto out; error = -ENOSYS; @@ -88,6 +90,7 @@ vmtruncate(inode, length); if (inode->i_op && inode->i_op->truncate) inode->i_op->truncate(inode); + inode->i_status |= ST_MODIFIED; } up(&inode->i_sem); return error; @@ -99,7 +102,7 @@ int error; lock_kernel(); - error = namei(path,&inode); + error = namei(NAM_FOLLOW_LINK, path, &inode); if (error) goto out; @@ -185,33 +188,36 @@ struct iattr newattrs; lock_kernel(); - error = namei(filename,&inode); + /* Hmm, should I always follow symlinks or not ? */ + error = namei(NAM_FOLLOW_LINK, filename, &inode); if (error) goto out; error = -EROFS; - if (IS_RDONLY(inode)) { - iput(inode); - goto out; - } + if (IS_RDONLY(inode)) + goto iput_and_out; + /* Don't worry, the checks are done in inode_change_ok() */ newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; if (times) { error = get_user(newattrs.ia_atime, ×->actime); if (!error) error = get_user(newattrs.ia_mtime, ×->modtime); - if (error) { - iput(inode); - goto out; - } + if (error) + goto iput_and_out; + newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET; } else { if (current->fsuid != inode->i_uid && - (error = permission(inode,MAY_WRITE)) != 0) { - iput(inode); - goto out; - } + (error = permission(inode,MAY_WRITE)) != 0) + goto iput_and_out; } error = notify_change(inode, &newattrs); +#ifdef CONFIG_OMIRR + if(!error) + omirr_printall(inode, " U %ld %ld %ld ", CURRENT_TIME, + newattrs.ia_atime, newattrs.ia_mtime); +#endif +iput_and_out: iput(inode); out: unlock_kernel(); @@ -231,7 +237,7 @@ struct iattr newattrs; lock_kernel(); - error = namei(filename,&inode); + error = namei(NAM_FOLLOW_LINK, filename, &inode); if (error) goto out; error = -EROFS; @@ -252,6 +258,11 @@ goto iput_and_out; } error = notify_change(inode, &newattrs); +#ifdef CONFIG_OMIRR + if(!error) + omirr_printall(inode, " U %ld %ld %ld ", CURRENT_TIME, + newattrs.ia_atime, newattrs.ia_mtime); +#endif iput_and_out: iput(inode); out: @@ -276,7 +287,7 @@ old_fsgid = current->fsgid; current->fsuid = current->uid; current->fsgid = current->gid; - res = namei(filename,&inode); + res = namei(NAM_FOLLOW_LINK, filename, &inode); if (!res) { res = permission(inode, mode); iput(inode); @@ -291,24 +302,23 @@ asmlinkage int sys_chdir(const char * filename) { struct inode * inode; + struct inode * tmpi; int error; lock_kernel(); - error = namei(filename,&inode); + error = namei(NAM_FOLLOW_LINK, filename, &inode); if (error) goto out; error = -ENOTDIR; - if (!S_ISDIR(inode->i_mode)) { - iput(inode); - goto out; - } - if ((error = permission(inode,MAY_EXEC)) != 0) { - iput(inode); - goto out; - } - iput(current->fs->pwd); - current->fs->pwd = inode; - error = 0; + if (!S_ISDIR(inode->i_mode)) + goto iput_and_out; + if ((error = permission(inode,MAY_EXEC)) != 0) + goto iput_and_out; + + /* exchange inodes */ + tmpi = current->fs->pwd; current->fs->pwd = inode; inode = tmpi; +iput_and_out: + iput(inode); out: unlock_kernel(); return error; @@ -333,8 +343,7 @@ goto out; iput(current->fs->pwd); current->fs->pwd = inode; - inode->i_count++; - error = 0; + atomic_inc(&inode->i_count); out: unlock_kernel(); return error; @@ -343,25 +352,23 @@ asmlinkage int sys_chroot(const char * filename) { struct inode * inode; + struct inode * tmpi; int error; lock_kernel(); - error = namei(filename,&inode); + error = namei(NAM_FOLLOW_LINK, filename, &inode); if (error) goto out; error = -ENOTDIR; - if (!S_ISDIR(inode->i_mode)) { - iput(inode); - goto out; - } + if (!S_ISDIR(inode->i_mode)) + goto iput_and_out; error = -EPERM; - if (!fsuser()) { - iput(inode); - goto out; - } - iput(current->fs->root); - current->fs->root = inode; + if (!fsuser()) + goto iput_and_out; + tmpi = current->fs->root; current->fs->root = inode; inode = tmpi; error = 0; +iput_and_out: + iput(inode); out: unlock_kernel(); return error; @@ -392,6 +399,10 @@ newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; inode->i_dirt = 1; err = notify_change(inode, &newattrs); +#ifdef CONFIG_OMIRR + if(!err) + omirr_printall(inode, " M %ld %ld ", CURRENT_TIME, newattrs.ia_mode); +#endif out: unlock_kernel(); return err; @@ -404,7 +415,11 @@ struct iattr newattrs; lock_kernel(); - error = namei(filename,&inode); + /* I'm not sure whether to use NAM_FOLLOW_TRAILSLASH instead, + * because permissions on symlinks now can never be changed, + * but on the other hand they are never needed. + */ + error = namei(NAM_FOLLOW_LINK, filename, &inode); if (error) goto out; error = -EROFS; @@ -419,6 +434,10 @@ newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; inode->i_dirt = 1; error = notify_change(inode, &newattrs); +#ifdef CONFIG_OMIRR + if(!error) + omirr_printall(inode, " M %ld %ld ", CURRENT_TIME, newattrs.ia_mode); +#endif iput_and_out: iput(inode); out: @@ -481,6 +500,11 @@ inode->i_sb->dq_op->transfer(inode, &newattrs, 1); } else error = notify_change(inode, &newattrs); +#ifdef CONFIG_OMIRR + if(!error) + omirr_printall(inode, " O %d %d ", CURRENT_TIME, + newattrs.ia_uid, newattrs.ia_gid); +#endif out: unlock_kernel(); return error; @@ -493,7 +517,7 @@ struct iattr newattrs; lock_kernel(); - error = lnamei(filename,&inode); + error = namei(NAM_FOLLOW_TRAILSLASH, filename, &inode); if (error) goto out; error = -EROFS; @@ -532,12 +556,17 @@ inode->i_sb->dq_op->initialize(inode, -1); error = -EDQUOT; if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0)) - goto out; + goto iput_and_out; error = notify_change(inode, &newattrs); if (error) inode->i_sb->dq_op->transfer(inode, &newattrs, 1); } else error = notify_change(inode, &newattrs); +#ifdef CONFIG_OMIRR + if(!error) + omirr_printall(inode, " O %d %d ", CURRENT_TIME, + newattrs.ia_uid, newattrs.ia_gid); +#endif iput_and_out: iput(inode); out: diff -u --recursive --new-file v2.1.42/linux/fs/pipe.c linux/fs/pipe.c --- v2.1.42/linux/fs/pipe.c Tue May 13 22:41:15 1997 +++ linux/fs/pipe.c Thu Jun 12 16:22:09 1997 @@ -385,7 +385,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -442,7 +441,7 @@ close_f12_inode_i: put_unused_fd(i); close_f12_inode: - inode->i_count--; + atomic_dec(&inode->i_count); iput(inode); close_f12: put_filp(f2); diff -u --recursive --new-file v2.1.42/linux/fs/proc/Makefile linux/fs/proc/Makefile --- v2.1.42/linux/fs/proc/Makefile Mon Mar 17 14:54:30 1997 +++ linux/fs/proc/Makefile Thu Jun 12 16:22:09 1997 @@ -8,8 +8,11 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := proc.o -O_OBJS := inode.o root.o base.o generic.o mem.o link.o fd.o array.o \ +O_OBJS := inode.o root.o base.o generic.o mem.o link.o arbitrary.o fd.o array.o \ kmsg.o scsi.o proc_tty.o +ifdef CONFIG_OMIRR +O_OBJS := $(O_OBJS) omirr.o +endif OX_OBJS := procfs_syms.o M_OBJS := diff -u --recursive --new-file v2.1.42/linux/fs/proc/arbitrary.c linux/fs/proc/arbitrary.c --- v2.1.42/linux/fs/proc/arbitrary.c Wed Dec 31 16:00:00 1969 +++ linux/fs/proc/arbitrary.c Thu Jun 12 16:22:09 1997 @@ -0,0 +1,58 @@ +/* + * $Id: arbitrary.c,v 1.2 1997/06/05 01:27:47 davem Exp $ + * + * linux/fs/proc/arbitrary.c - lookup() for arbitrary inodes. + * Copyright (C) 1997, Thomas Schoebel-Theuer, + * . + */ + +#include +#include +#include +#include + +/* Format of dev/inode pairs that can be used as file names: + * [ + * (the same format that is already in use in /proc//exe, + * /proc//cwd and /proc//root). + */ +/* Note that readdir does not supply such names, so they must be used + * either "blind" or must be queried another way, for example + * as result of a virtual symlink (see linux/proc/link.c). + */ +int proc_arbitrary_lookup(struct inode * dir, const char * name, + int len, struct inode ** result) +{ + int dev, ino; + char * ptr = (char*)name; + kdev_t kdev; + int i; + int error = -EINVAL; + + if(*ptr++ != '[') + goto done; + dev = simple_strtoul(ptr, &ptr, 16); + if(*ptr++ != ']') + goto done; + if(*ptr++ != ':') + goto done; + ino = simple_strtoul(ptr, &ptr, 0); + if((long)ptr - (long)name != len) + goto done; + + error = -ENOENT; + kdev = to_kdev_t(dev); + if(!kdev) + goto done; + for(i = 0; i < NR_SUPER; i++) + if(super_blocks[i].s_dev == kdev) + break; + if(i < NR_SUPER) { + *result = iget(&super_blocks[i], ino); + if(*result) + error = 0; + } +done: + iput(dir); + return error; +} diff -u --recursive --new-file v2.1.42/linux/fs/proc/array.c linux/fs/proc/array.c --- v2.1.42/linux/fs/proc/array.c Wed May 28 10:51:33 1997 +++ linux/fs/proc/array.c Thu Jun 12 16:22:09 1997 @@ -154,8 +154,6 @@ return read; } - - /* * Writing to /proc/profile resets the counters * @@ -1021,6 +1019,9 @@ #ifdef CONFIG_ZORRO extern int zorro_get_list(char *); #endif +#if defined (CONFIG_AMIGA) || defined (CONFIG_ATARI) +extern int get_hardware_list(char *); +#endif static long get_root_array(char * page, int type, char **start, off_t offset, unsigned long length) @@ -1105,6 +1106,10 @@ case PROC_ZORRO: return zorro_get_list(page); #endif +#if defined (CONFIG_AMIGA) || defined (CONFIG_ATARI) + case PROC_HARDWARE: + return get_hardware_list(page); +#endif } return -EBADF; } @@ -1211,7 +1216,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -1257,7 +1261,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/proc/base.c linux/fs/proc/base.c --- v2.1.42/linux/fs/proc/base.c Tue May 13 22:41:15 1997 +++ linux/fs/proc/base.c Thu Jun 12 16:22:09 1997 @@ -42,7 +42,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/proc/fd.c linux/fs/proc/fd.c --- v2.1.42/linux/fs/proc/fd.c Tue May 13 22:41:15 1997 +++ linux/fs/proc/fd.c Thu Jun 12 16:22:09 1997 @@ -44,7 +44,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/proc/generic.c linux/fs/proc/generic.c --- v2.1.42/linux/fs/proc/generic.c Thu Mar 27 14:40:06 1997 +++ linux/fs/proc/generic.c Thu Jun 12 16:22:09 1997 @@ -51,7 +51,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -74,7 +73,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/proc/kmsg.c linux/fs/proc/kmsg.c --- v2.1.42/linux/fs/proc/kmsg.c Fri Apr 4 08:52:24 1997 +++ linux/fs/proc/kmsg.c Thu Jun 12 16:22:09 1997 @@ -70,7 +70,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/proc/link.c linux/fs/proc/link.c --- v2.1.42/linux/fs/proc/link.c Tue May 13 22:41:15 1997 +++ linux/fs/proc/link.c Thu Jun 12 16:22:09 1997 @@ -14,10 +14,9 @@ #include #include #include +#include static int proc_readlink(struct inode *, char *, int); -static int proc_follow_link(struct inode *, struct inode *, int, int, - struct inode **); /* * PLAN9_SEMANTICS won't work any more: it used an ugly hack that broke @@ -53,7 +52,6 @@ NULL, /* mknod */ NULL, /* rename */ proc_readlink, /* readlink */ - proc_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -61,7 +59,11 @@ NULL /* permission */ }; - +/* [Feb-1997 T. Schoebel-Theuer] This is no longer called from the + * VFS, but only from proc_readlink(). All the functionality + * should the moved there (without using temporary inodes any more) + * and then it could be eliminated. + */ static int proc_follow_link(struct inode * dir, struct inode * inode, int flag, int mode, struct inode ** res_inode) { @@ -130,33 +132,35 @@ if (!new_inode) return -ENOENT; *res_inode = new_inode; - new_inode->i_count++; + atomic_inc(&new_inode->i_count); return 0; } static int proc_readlink(struct inode * inode, char * buffer, int buflen) { - int i; - unsigned int dev,ino; - char buf[64]; + int error = proc_follow_link(NULL, inode, 0, 0, &inode); - if (!S_ISLNK(inode->i_mode)) { - iput(inode); - return -EINVAL; - } - i = proc_follow_link(NULL, inode, 0, 0, &inode); - if (i) - return i; + if (error) + return error; if (!inode) return -EIO; - dev = kdev_t_to_nr(inode->i_dev); - ino = inode->i_ino; + + /* This will return *one* of the alias names (which is not quite + * correct). I have to rethink the problem, so this is only a + * quick hack... + */ + if(inode->i_dentry) { + char * tmp = (char*)__get_free_page(GFP_KERNEL); + int len = d_path(inode->i_dentry, current->fs->root, tmp); + int min = buflen i) - buflen = i; - i = 0; - while (i < buflen) - put_user(buf[i++],buffer++); - return i; + return error; } diff -u --recursive --new-file v2.1.42/linux/fs/proc/mem.c linux/fs/proc/mem.c --- v2.1.42/linux/fs/proc/mem.c Thu May 15 16:48:04 1997 +++ linux/fs/proc/mem.c Thu Jun 12 16:22:09 1997 @@ -328,7 +328,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/proc/net.c linux/fs/proc/net.c --- v2.1.42/linux/fs/proc/net.c Sun Jan 26 02:07:45 1997 +++ linux/fs/proc/net.c Thu Jun 12 16:22:09 1997 @@ -111,7 +111,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/proc/omirr.c linux/fs/proc/omirr.c --- v2.1.42/linux/fs/proc/omirr.c Wed Dec 31 16:00:00 1969 +++ linux/fs/proc/omirr.c Thu Jun 12 16:22:09 1997 @@ -0,0 +1,297 @@ +/* + * fs/proc/omirr.c - online mirror support + * + * (C) 1997 Thomas Schoebel-Theuer + */ + +#include +#include +#include +#include +#include +#include + +static int nr_omirr_open = 0; +static int cleared_flag = 0; + +static char * buffer = NULL; +static int read_pos, write_pos; +static int clip_pos, max_pos; +static struct wait_queue * read_wait = NULL; +static struct wait_queue * write_wait = NULL; + +static /*inline*/ int reserve_write_space(int len) +{ + int rest = max_pos - write_pos; + + if(rest < len) { + clip_pos = write_pos; + write_pos = 0; + rest = max_pos; + } + while(read_pos > write_pos && read_pos <= write_pos+len) { + if(!nr_omirr_open) + return 0; + interruptible_sleep_on(&write_wait); + } + return 1; +} + +static /*inline*/ void write_space(int len) +{ + write_pos += len; + wake_up_interruptible(&read_wait); +} + +static /*inline*/ int reserve_read_space(int len) +{ + int rest = clip_pos - read_pos; + + if(!rest) { + read_pos = 0; + rest = clip_pos; + clip_pos = max_pos; + } + if(len > rest) + len = rest; + while(read_pos == write_pos) { + interruptible_sleep_on(&read_wait); + } + rest = write_pos - read_pos; + if(rest > 0 && rest < len) + len = rest; + return len; +} + +static /*inline*/ void read_space(int len) +{ + read_pos += len; + if(read_pos >= clip_pos) { + read_pos = 0; + clip_pos = max_pos; + } + wake_up_interruptible(&write_wait); +} + +static /*inline*/ void init_buffer(char * initxt) +{ + int len = initxt ? strlen(initxt) : 0; + + if(!buffer) { + buffer = (char*)__get_free_page(GFP_USER); + max_pos = clip_pos = PAGE_SIZE; + } + read_pos = write_pos = 0; + memcpy(buffer, initxt, len); + write_space(len); +} + +static int omirr_open(struct inode * inode, struct file * file) +{ + if(nr_omirr_open) + return -EAGAIN; + nr_omirr_open++; + if(!buffer) + init_buffer(NULL); + return 0; +} + +static int omirr_release(struct inode * inode, struct file * file) +{ + nr_omirr_open--; + read_space(0); + return 0; +} + +static long omirr_read(struct inode * inode, struct file * file, + char * buf, unsigned long count) +{ + char * tmp; + int len; + int error = 0; + + if(!count) + goto done; + error = -EINVAL; + if(!buf || count < 0) + goto done; + + error = verify_area(VERIFY_WRITE, buf, count); + if(error) + goto done; + + error = -EAGAIN; + if((file->f_flags & O_NONBLOCK) && read_pos == write_pos) + goto done; + + error = len = reserve_read_space(count); + tmp = buffer + read_pos; + while(len) { + put_user(*tmp++, buf++); + len--; + } + read_space(error); +done: + return error; +} + +int compute_name(struct dentry * entry, char * buf) +{ + int len; + + if(IS_ROOT(entry)) { + *buf = '/'; + return 1; + } + len = compute_name(entry->d_parent, buf); + if(len > 1) { + buf[len++] = '/'; + } + memcpy(buf+len, entry->d_name, entry->d_len); + return len + entry->d_len; +} + +int _omirr_print(struct dentry * ent1, struct dentry * ent2, + struct qstr * suffix, const char * fmt, + va_list args1, va_list args2) +{ + int count = strlen(fmt) + 10; /* estimate */ + const char * tmp = fmt; + char lenbuf[8]; + int res; + + if(!buffer) + init_buffer(NULL); + while(*tmp) { + while(*tmp && *tmp++ != '%') ; + if(*tmp) { + if(*tmp == 's') { + char * str = va_arg(args1, char*); + count += strlen(str); + } else { + (void)va_arg(args1, int); + count += 8; /* estimate */ + } + } + } + if(ent1) { + struct dentry * dent = ent1; + while(dent && !IS_ROOT(dent)) { + count += dent->d_len + 1; + dent = dent->d_parent; + } + count++; + if(ent2) { + dent = ent2; + while(dent && !IS_ROOT(dent)) { + count += dent->d_len + 1; + dent = dent->d_parent; + } + count++; + } + if(suffix) + count += suffix->len + 1; + } + + if((nr_omirr_open | cleared_flag) && reserve_write_space(count)) { + cleared_flag = 0; + res = vsprintf(buffer+write_pos+4, fmt, args2) + 4; + if(res > count) + printk("omirr: format estimate was wrong\n"); + if(ent1) { + res += compute_name(ent1, buffer+write_pos+res); + if(ent2) { + buffer[write_pos+res++] = '\0'; + res += compute_name(ent2, buffer+write_pos+res); + } + if(suffix) { + buffer[write_pos+res++] = '/'; + memcpy(buffer+write_pos+res, + suffix->name, suffix->len); + res += suffix->len; + } + buffer[write_pos+res++] = '\0'; + buffer[write_pos+res++] = '\n'; + } + sprintf(lenbuf, "%04d", res); + memcpy(buffer+write_pos, lenbuf, 4); + } else { + if(!cleared_flag) { + cleared_flag = 1; + init_buffer("0007 Z\n"); + } + res = 0; + } + write_space(res); + return res; +} + +int omirr_print(struct dentry * ent1, struct dentry * ent2, + struct qstr * suffix, const char * fmt, ...) +{ + va_list args1, args2; + int res; + + /* I don't know whether I could make a simple copy of the va_list, + * so for the safe way... + */ + va_start(args1, fmt); + va_start(args2, fmt); + res = _omirr_print(ent1, ent2, suffix, fmt, args1, args2); + va_end(args2); + va_end(args1); + return res; +} + +int omirr_printall(struct inode * inode, const char * fmt, ...) +{ + int res = 0; + struct dentry * tmp = inode->i_dentry; + + if(tmp) do { + va_list args1, args2; + va_start(args1, fmt); + va_start(args2, fmt); + res += _omirr_print(tmp, NULL, NULL, fmt, args1, args2); + va_end(args2); + va_end(args1); + tmp = tmp->d_next; + } while(tmp != inode->i_dentry); + return res; +} + +static struct file_operations omirr_operations = { + NULL, /* omirr_lseek */ + omirr_read, + NULL, /* omirr_write */ + NULL, /* omirr_readdir */ + NULL, /* omirr_select */ + NULL, /* omirr_ioctl */ + NULL, /* mmap */ + omirr_open, + omirr_release, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL /* revalidate */ +}; + +struct inode_operations proc_omirr_inode_operations = { + &omirr_operations, + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL, /* permission */ + NULL /* smap */ +}; diff -u --recursive --new-file v2.1.42/linux/fs/proc/openpromfs.c linux/fs/proc/openpromfs.c --- v2.1.42/linux/fs/proc/openpromfs.c Mon Apr 14 16:28:18 1997 +++ linux/fs/proc/openpromfs.c Thu Jun 12 16:22:09 1997 @@ -1,4 +1,4 @@ -/* $Id: openpromfs.c,v 1.13 1997/04/03 08:49:25 davem Exp $ +/* $Id: openpromfs.c,v 1.15 1997/06/05 01:28:11 davem Exp $ * openpromfs.c: /proc/openprom handling routines * * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -484,7 +484,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -517,7 +516,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -550,7 +548,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -1015,7 +1012,7 @@ static int usec = 0; if (inc) { - if (inode->i_count == 1) + if (atomic_read(&inode->i_count) == 1) usec++; else if (root_fresh && inode->i_ino == PROC_OPENPROM_FIRST) { root_fresh = 0; @@ -1028,10 +1025,10 @@ usec--; } printk ("openpromfs_use: %d %d %d %d\n", - inode->i_ino, inc, usec, inode->i_count); + inode->i_ino, inc, usec, atomic_read(&inode->i_count)); #else if (inc) { - if (inode->i_count == 1) + if (atomic_read(&inode->i_count) == 1) MOD_INC_USE_COUNT; else if (root_fresh && inode->i_ino == PROC_OPENPROM_FIRST) { root_fresh = 0; diff -u --recursive --new-file v2.1.42/linux/fs/proc/procfs_syms.c linux/fs/proc/procfs_syms.c --- v2.1.42/linux/fs/proc/procfs_syms.c Sun Apr 13 10:18:22 1997 +++ linux/fs/proc/procfs_syms.c Thu Jun 12 16:22:09 1997 @@ -37,7 +37,10 @@ #endif static struct file_system_type proc_fs_type = { - proc_read_super, "proc", 0, NULL + "proc", + FS_NO_DCACHE, + proc_read_super, + NULL }; int init_proc_fs(void) diff -u --recursive --new-file v2.1.42/linux/fs/proc/root.c linux/fs/proc/root.c --- v2.1.42/linux/fs/proc/root.c Tue May 13 22:41:15 1997 +++ linux/fs/proc/root.c Thu Jun 12 16:22:09 1997 @@ -64,7 +64,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -105,7 +104,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -266,7 +264,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -348,17 +345,6 @@ /* * /proc/self: */ -static int proc_self_followlink(struct inode * dir, struct inode * inode, - int flag, int mode, struct inode ** res_inode) -{ - iput(dir); - *res_inode = proc_get_inode(inode->i_sb, (current->pid << 16) + PROC_PID_INO, &proc_pid); - iput(inode); - if (!*res_inode) - return -ENOENT; - return 0; -} - static int proc_self_readlink(struct inode * inode, char * buffer, int buflen) { int len; @@ -384,7 +370,6 @@ NULL, /* mknod */ NULL, /* rename */ proc_self_readlink, /* readlink */ - proc_self_followlink, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -436,6 +421,13 @@ S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_array_inode_operations }; +#if defined (CONFIG_AMIGA) || defined (CONFIG_ATARI) +static struct proc_dir_entry proc_root_hardware = { + PROC_HARDWARE, 8, "hardware", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_array_inode_operations +}; +#endif static struct proc_dir_entry proc_root_self = { PROC_SELF, 4, "self", S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, 1, 0, 0, @@ -539,6 +531,13 @@ S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_array_inode_operations }; +#ifdef CONFIG_OMIRR +static struct proc_dir_entry proc_root_omirr = { + PROC_OMIRR, 5, "omirr", + S_IFREG | S_IRUSR, 1, 0, 0, + 0, &proc_omirr_inode_operations +}; +#endif void proc_root_init(void) { @@ -599,7 +598,9 @@ #endif proc_register(&proc_root, &proc_openprom); #endif - +#if defined (CONFIG_AMIGA) || defined (CONFIG_ATARI) + proc_register(&proc_root, &proc_root_hardware); +#endif proc_register(&proc_root, &proc_root_slab); if (prof_shift) { @@ -641,6 +642,16 @@ return -EINVAL; } + /* Either remove this as soon as possible due to security problems, + * or uncomment the root-only usage. + */ + + /* Allow generic inode lookups everywhere. + * No other name in /proc must begin with a '['. + */ + if(/*!current->uid &&*/ name[0] == '[') + return proc_arbitrary_lookup(dir,name,len,result); + /* Special case "." and "..": they aren't on the directory list */ *result = dir; if (!len) @@ -686,7 +697,7 @@ int ino, retval; struct task_struct *p; - dir->i_count++; + atomic_inc(&dir->i_count); if (dir->i_ino == PROC_ROOT_INO) { /* check for safety... */ dir->i_nlink = proc_root.nlink; diff -u --recursive --new-file v2.1.42/linux/fs/proc/scsi.c linux/fs/proc/scsi.c --- v2.1.42/linux/fs/proc/scsi.c Sun Jan 26 02:07:45 1997 +++ linux/fs/proc/scsi.c Thu Jun 12 16:22:09 1997 @@ -69,7 +69,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/read_write.c linux/fs/read_write.c --- v2.1.42/linux/fs/read_write.c Sun Jan 26 02:07:45 1997 +++ linux/fs/read_write.c Thu Jun 12 16:22:09 1997 @@ -168,6 +168,7 @@ goto out; down(&inode->i_sem); error = write(inode,file,buf,count); + inode->i_status |= ST_MODIFIED; up(&inode->i_sem); out: fput(file, inode); @@ -248,6 +249,10 @@ len = vector->iov_len; vector++; count--; + + /* Any particular reason why we do not grab the inode semaphore + * when doing writes here? -DaveM + */ nr = fn(inode, file, base, len); if (nr < 0) { if (retval) @@ -259,6 +264,8 @@ if (nr != len) break; } + if(fn == (IO_fn_t) file->f_op->write) + inode->i_status |= ST_MODIFIED; if (iov != iovstack) kfree(iov); return retval; diff -u --recursive --new-file v2.1.42/linux/fs/readdir.c linux/fs/readdir.c --- v2.1.42/linux/fs/readdir.c Sun Jan 26 02:07:45 1997 +++ linux/fs/readdir.c Thu Jun 12 16:22:09 1997 @@ -1,20 +1,35 @@ /* - * linux/fs/readdir.c + * fs/readdir.c * * Copyright (C) 1995 Linus Torvalds */ +#include #include #include #include #include #include #include +#ifdef CONFIG_TRANS_NAMES +#include +#endif +#include #include #include #include +/* [T.Schoebel-Theuer] I am assuming that directories never get too large. + * The problem is that getdents() delivers d_offset's that can be used + * for lseek() by the user, so I must encode the status information for + * name translation and dcache baskets in the offset. + * Note that the linux man page getdents(2) does not mention that + * the d_offset is fs-specific and can be used for lseek(). + */ +#define BASKET_BIT (1<<30) /* 31 is already used by affs */ +#define TRANS_BIT (1<<29) + /* * Traditional linux readdir() handling.. * @@ -35,6 +50,9 @@ struct readdir_callback { struct old_linux_dirent * dirent; + struct file * file; + int translate; + off_t oldoffset; int count; }; @@ -47,11 +65,26 @@ return -EINVAL; buf->count++; dirent = buf->dirent; + copy_to_user(dirent->d_name, name, namlen); + put_user(0, dirent->d_name + namlen); +#ifdef CONFIG_TRANS_NAMES + if(!buf->translate) { + char * cut; +#ifdef CONFIG_TRANS_RESTRICT + struct inode * inode = buf->file->f_inode; + cut = testname(inode && inode->i_gid != CONFIG_TRANS_GID, dirent->d_name); +#else + cut = testname(1, dirent->d_name); +#endif + if(cut) { + put_user(0, cut); + buf->translate = 1; + } + } +#endif put_user(ino, &dirent->d_ino); put_user(offset, &dirent->d_offset); put_user(namlen, &dirent->d_namlen); - copy_to_user(dirent->d_name, name, namlen); - put_user(0, dirent->d_name + namlen); return 0; } @@ -60,6 +93,7 @@ int error = -EBADF; struct file * file; struct readdir_callback buf; + off_t oldpos; lock_kernel(); if (fd >= NR_OPEN || !(file = current->files->fd[fd])) @@ -70,11 +104,21 @@ error = verify_area(VERIFY_WRITE, dirent, sizeof(struct old_linux_dirent)); if (error) goto out; - buf.count = 0; + oldpos = file->f_pos; + buf.file = file; buf.dirent = dirent; + buf.count = 0; + buf.translate = 0; + if(file->f_pos & TRANS_BIT) { + file->f_pos &= ~TRANS_BIT; + buf.translate = 1; + } error = file->f_op->readdir(file->f_inode, file, &buf, fillonedir); if (error < 0) goto out; + if(buf.translate) { + file->f_pos = oldpos | TRANS_BIT; + } error = buf.count; out: unlock_kernel(); @@ -95,8 +139,11 @@ struct getdents_callback { struct linux_dirent * current_dir; struct linux_dirent * previous; + struct file * file; int count; - int error; + int error; + int restricted; + int do_preload; }; static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino) @@ -105,18 +152,51 @@ struct getdents_callback * buf = (struct getdents_callback *) __buf; int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); - buf->error = -EINVAL; /* only used if we fail.. */ + /* Do not touch buf->error any more if everything is ok! */ if (reclen > buf->count) - return -EINVAL; - dirent = buf->previous; - if (dirent) - put_user(offset, &dirent->d_off); + return (buf->error = -EINVAL); +#ifdef CONFIG_DCACHE_PRELOAD + if(buf->do_preload && (name[0] != '.' || namlen > 2)) { + struct qstr qname = { name, namlen }; + struct inode * dir = buf->file->f_inode; + d_entry_preliminary(dir->i_dentry, &qname, ino); + } +#endif dirent = buf->current_dir; - buf->previous = dirent; - put_user(ino, &dirent->d_ino); - put_user(reclen, &dirent->d_reclen); copy_to_user(dirent->d_name, name, namlen); put_user(0, dirent->d_name + namlen); +#ifdef CONFIG_TRANS_NAMES + { + char * cut; +#ifdef CONFIG_TRANS_RESTRICT + cut = testname(buf->restricted, dirent->d_name); +#else + cut = testname(1, dirent->d_name); +#endif + if(cut) { + int newlen = (int)cut - (int)dirent->d_name; + int newreclen = ROUND_UP(NAME_OFFSET(dirent) + newlen + 1); + /* Either both must fit or none. This way we need + * no status information in f_pos */ + if (reclen+newlen > buf->count) + return -EINVAL; + put_user(0, cut); + put_user(ino, &dirent->d_ino); + put_user(newreclen, &dirent->d_reclen); + put_user(offset, &dirent->d_off); + ((char *) dirent) += newreclen; + buf->count -= newreclen; + put_user(offset, &dirent->d_off); + copy_to_user(dirent->d_name, name, namlen); + put_user(0, dirent->d_name + namlen); + } + } +#endif + put_user(ino, &dirent->d_ino); + put_user(reclen, &dirent->d_reclen); + if (buf->previous) + put_user(buf->file->f_pos, &buf->previous->d_off); + buf->previous = dirent; ((char *) dirent) += reclen; buf->current_dir = dirent; buf->count -= reclen; @@ -126,7 +206,6 @@ asmlinkage int sys_getdents(unsigned int fd, void * dirent, unsigned int count) { struct file * file; - struct linux_dirent * lastdirent; struct getdents_callback buf; int error = -EBADF; @@ -139,18 +218,72 @@ error = verify_area(VERIFY_WRITE, dirent, count); if (error) goto out; + buf.file = file; buf.current_dir = (struct linux_dirent *) dirent; buf.previous = NULL; buf.count = count; buf.error = 0; - error = file->f_op->readdir(file->f_inode, file, &buf, filldir); - if (error < 0) - goto out; - lastdirent = buf.previous; - if (!lastdirent) { + buf.restricted = 0; +#ifdef CONFIG_TRANS_RESTRICT + buf.restricted = file->f_inode && file->f_inode->i_gid != CONFIG_TRANS_GID; +#endif + buf.do_preload = 0; +#ifdef CONFIG_DCACHE_PRELOAD + if(file->f_inode && file->f_inode->i_dentry && + !(file->f_inode->i_sb->s_type->fs_flags & (FS_NO_DCACHE|FS_NO_PRELIM)) && + !(file->f_inode->i_dentry->d_flag & D_PRELOADED)) + buf.do_preload = 1; +#endif + + if(!(file->f_pos & BASKET_BIT)) { + int oldcount; + do { + oldcount = buf.count; + error = file->f_op->readdir(file->f_inode, file, &buf, filldir); + if (error < 0) + goto out; + } while(!buf.error && buf.count != oldcount); + } + if(!buf.error) { + int nr = 0; + struct dentry * list = file->f_inode ? + d_basket(file->f_inode->i_dentry) : NULL; + struct dentry * ptr = list; +#ifdef CONFIG_DCACHE_PRELOAD + if(buf.do_preload) { + buf.do_preload = 0; + file->f_inode->i_dentry->d_flag |= D_PRELOADED; + } +#endif + if(ptr) { + if(!(file->f_pos & BASKET_BIT)) + file->f_pos = BASKET_BIT; + do { + struct dentry * next = ptr->d_basket_next; + struct inode * inode; + /* vfs_locks() are missing here */ + inode = d_inode(&ptr); + if(inode) { + nr++; + if(nr > (file->f_pos & ~BASKET_BIT)) { + int err = filldir(&buf, ptr->d_name, + ptr->d_len, + file->f_pos, + inode->i_ino); + if(err) + break; + file->f_pos++; + } + iput(inode); + } + ptr = next; + } while(ptr != list); + } + } + if (!buf.previous) { error = buf.error; } else { - put_user(file->f_pos, &lastdirent->d_off); + put_user(file->f_pos, &buf.previous->d_off); error = count - buf.count; } out: diff -u --recursive --new-file v2.1.42/linux/fs/romfs/inode.c linux/fs/romfs/inode.c --- v2.1.42/linux/fs/romfs/inode.c Wed Apr 23 19:01:27 1997 +++ linux/fs/romfs/inode.c Thu Jun 12 16:22:09 1997 @@ -417,59 +417,6 @@ return mylen; } -static int -romfs_follow_link(struct inode *dir, struct inode *inode, - int flag, int mode, struct inode **res_inode) -{ - int error, len; - char *buf; - - *res_inode = NULL; - if (!dir) { - dir = current->fs->root; - dir->i_count++; - } - - if (!inode) { - iput(dir); - return -ENOENT; - } - if (!S_ISLNK(inode->i_mode)) { - *res_inode = inode; - iput(dir); - return 0; - } - if (current->link_count > 5) { - iput(inode); - iput(dir); - return -ELOOP; - } - - /* Eek. Short enough. */ - len = inode->i_size; - if (!(buf = kmalloc(len+1, GFP_KERNEL))) { - iput(inode); - iput(dir); - /* correct? spin? */ - return -EAGAIN; - } - error = romfs_copyfrom(inode, buf, inode->u.romfs_i.i_dataoffset, len); - if (error != len) { - iput(inode); - iput(dir); - error = -EIO; - } else { - iput(inode); - buf[len] = 0; - current->link_count++; - error = open_namei(buf, flag, mode, res_inode, dir); - current->link_count--; - } - - kfree(buf); - return error; -} - /* Mapping from our types to the kernel */ static struct file_operations romfs_file_operations = { @@ -500,7 +447,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ romfs_readpage, /* readpage */ NULL, /* writepage */ NULL, /* bmap -- not really */ @@ -525,7 +471,7 @@ NULL /* revalidate */ }; -/* Merged dir/symlink op table. readdir/lookup/readlink/follow_link +/* Merged dir/symlink op table. readdir/lookup/readlink * will protect from type mismatch. */ @@ -541,7 +487,6 @@ NULL, /* mknod */ NULL, /* rename */ romfs_readlink, /* readlink */ - romfs_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -638,7 +583,10 @@ }; static struct file_system_type romfs_fs_type = { - romfs_read_super, "romfs", 1, NULL + "romfs", + (FS_REQUIRES_DEV | FS_NO_DCACHE), /* Can dcache be used? */ + romfs_read_super, + NULL }; __initfunc(int init_romfs_fs(void)) diff -u --recursive --new-file v2.1.42/linux/fs/select.c linux/fs/select.c --- v2.1.42/linux/fs/select.c Thu Feb 6 02:51:45 1997 +++ linux/fs/select.c Thu Jun 12 16:22:09 1997 @@ -208,17 +208,18 @@ * We do a VERIFY_WRITE here even though we are only reading this time: * we'll write to it eventually.. * - * Use "int" accesses to let user-mode fd_set's be int-aligned. + * Use "unsigned long" accesses to let user-mode fd_set's be long-aligned. */ -static int __get_fd_set(unsigned long nr, int * fs_pointer, int * fdset) +static int __get_fd_set(unsigned long nr, unsigned long * fs_pointer, unsigned long * fdset) { - /* round up nr to nearest "int" */ - nr = (nr + 8*sizeof(int)-1) / (8*sizeof(int)); + /* round up nr to nearest "unsigned long" */ + nr = (nr + 8*sizeof(unsigned long)-1) / (8*sizeof(unsigned long)); if (fs_pointer) { - int error = verify_area(VERIFY_WRITE,fs_pointer,nr*sizeof(int)); + int error = verify_area(VERIFY_WRITE,fs_pointer, + nr*sizeof(unsigned long)); if (!error) { while (nr) { - get_user(*fdset, fs_pointer); + __get_user(*fdset, fs_pointer); nr--; fs_pointer++; fdset++; @@ -234,13 +235,13 @@ return 0; } -static void __set_fd_set(long nr, int * fs_pointer, int * fdset) +static void __set_fd_set(long nr, unsigned long * fs_pointer, unsigned long * fdset) { if (!fs_pointer) return; while (nr >= 0) { - put_user(*fdset, fs_pointer); - nr -= 8 * sizeof(int); + __put_user(*fdset, fs_pointer); + nr -= 8 * sizeof(unsigned long); fdset++; fs_pointer++; } @@ -261,13 +262,16 @@ * subtract by 1 on the nr of file descriptors. The former is better for * machines with long > int, and the latter allows us to test the bit count * against "zero or positive", which can mostly be just a sign bit test.. + * + * Unfortunately this scheme falls apart on big endian machines where + * sizeof(long) > sizeof(int) (ie. V9 Sparc). -DaveM */ #define get_fd_set(nr,fsp,fdp) \ -__get_fd_set(nr, (int *) (fsp), (int *) (fdp)) +__get_fd_set(nr, (unsigned long *) (fsp), (unsigned long *) (fdp)) #define set_fd_set(nr,fsp,fdp) \ -__set_fd_set((nr)-1, (int *) (fsp), (int *) (fdp)) +__set_fd_set((nr)-1, (unsigned long *) (fsp), (unsigned long *) (fdp)) #define zero_fd_set(nr,fdp) \ __zero_fd_set((nr)-1, (unsigned long *) (fdp)) @@ -302,11 +306,11 @@ error = verify_area(VERIFY_WRITE, tvp, sizeof(*tvp)); if (error) goto out; - get_user(timeout, &tvp->tv_usec); + __get_user(timeout, &tvp->tv_usec); timeout = ROUND_UP(timeout,(1000000/HZ)); { unsigned long tmp; - get_user(tmp, &tvp->tv_sec); + __get_user(tmp, &tvp->tv_sec); timeout += tmp * (unsigned long) HZ; } if (timeout) @@ -322,10 +326,10 @@ if ((long) timeout < 0) timeout = 0; if (tvp && !(current->personality & STICKY_TIMEOUTS)) { - put_user(timeout/HZ, &tvp->tv_sec); + __put_user(timeout/HZ, &tvp->tv_sec); timeout %= HZ; timeout *= (1000000/HZ); - put_user(timeout, &tvp->tv_usec); + __put_user(timeout, &tvp->tv_usec); } if (error < 0) goto out; diff -u --recursive --new-file v2.1.42/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c --- v2.1.42/linux/fs/smbfs/dir.c Sun Jan 26 02:07:45 1997 +++ linux/fs/smbfs/dir.c Thu Jun 12 16:22:09 1997 @@ -47,8 +47,7 @@ static int smb_rename(struct inode *old_dir, const char *old_name, int old_len, - struct inode *new_dir, const char *new_name, int new_len, - int must_be_dir); + struct inode *new_dir, const char *new_name, int new_len); static struct file_operations smb_dir_operations = { @@ -77,7 +76,6 @@ NULL, /* mknod */ smb_rename, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -798,8 +796,7 @@ static int smb_rename(struct inode *old_dir, const char *old_name, int old_len, - struct inode *new_dir, const char *new_name, int new_len, - int must_be_dir) + struct inode *new_dir, const char *new_name, int new_len) { int res; diff -u --recursive --new-file v2.1.42/linux/fs/smbfs/file.c linux/fs/smbfs/file.c --- v2.1.42/linux/fs/smbfs/file.c Sun Jan 26 02:07:45 1997 +++ linux/fs/smbfs/file.c Thu Jun 12 16:22:09 1997 @@ -236,7 +236,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c --- v2.1.42/linux/fs/smbfs/inode.c Tue May 13 22:41:15 1997 +++ linux/fs/smbfs/inode.c Thu Jun 12 16:22:09 1997 @@ -429,9 +429,11 @@ int smb_current_vmalloced; #endif -static struct file_system_type smb_fs_type = -{ - smb_read_super, "smbfs", 0, NULL +static struct file_system_type smb_fs_type = { + "smbfs", + FS_NO_DCACHE, + smb_read_super, + NULL }; __initfunc(int init_smb_fs(void)) diff -u --recursive --new-file v2.1.42/linux/fs/smbfs/mmap.c linux/fs/smbfs/mmap.c --- v2.1.42/linux/fs/smbfs/mmap.c Sun Dec 1 08:26:22 1996 +++ linux/fs/smbfs/mmap.c Thu Jun 12 16:22:09 1997 @@ -120,7 +120,7 @@ inode->i_dirt = 1; } vma->vm_inode = inode; - inode->i_count++; + atomic_inc(&inode->i_count); vma->vm_ops = &smb_file_mmap; return 0; } diff -u --recursive --new-file v2.1.42/linux/fs/stat.c linux/fs/stat.c --- v2.1.42/linux/fs/stat.c Fri Apr 4 08:52:24 1997 +++ linux/fs/stat.c Thu Jun 12 16:22:09 1997 @@ -127,7 +127,7 @@ int error; lock_kernel(); - error = namei(filename,&inode); + error = namei(NAM_FOLLOW_LINK, filename, &inode); if (error) goto out; if ((error = do_revalidate(inode)) == 0) @@ -145,7 +145,7 @@ int error; lock_kernel(); - error = namei(filename,&inode); + error = namei(NAM_FOLLOW_LINK, filename, &inode); if (error) goto out; if ((error = do_revalidate(inode)) == 0) @@ -168,7 +168,7 @@ int error; lock_kernel(); - error = lnamei(filename,&inode); + error = namei(NAM_FOLLOW_TRAILSLASH, filename, &inode); if (error) goto out; if ((error = do_revalidate(inode)) == 0) @@ -187,7 +187,7 @@ int error; lock_kernel(); - error = lnamei(filename,&inode); + error = namei(NAM_FOLLOW_TRAILSLASH, filename, &inode); if (error) goto out; if ((error = do_revalidate(inode)) == 0) @@ -249,14 +249,18 @@ error = verify_area(VERIFY_WRITE,buf,bufsiz); if (error) goto out; - error = lnamei(path,&inode); + error = namei(NAM_FOLLOW_TRAILSLASH, path, &inode); if (error) goto out; error = -EINVAL; - if (!inode->i_op || !inode->i_op->readlink - || (error = do_revalidate(inode)) < 0) { + if (!inode->i_op || !inode->i_op->readlink || + !S_ISLNK(inode->i_mode) || (error = do_revalidate(inode)) < 0) { iput(inode); goto out; + } + if (!IS_RDONLY(inode)) { + inode->i_atime = CURRENT_TIME; + inode->i_dirt = 1; } error = inode->i_op->readlink(inode,buf,bufsiz); out: diff -u --recursive --new-file v2.1.42/linux/fs/super.c linux/fs/super.c --- v2.1.42/linux/fs/super.c Thu May 29 21:53:08 1997 +++ linux/fs/super.c Thu Jun 12 16:22:09 1997 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -59,8 +60,8 @@ struct super_block super_blocks[NR_SUPER]; static struct file_system_type *file_systems = (struct file_system_type *) NULL; -static struct vfsmount *vfsmntlist = (struct vfsmount *) NULL, - *vfsmnttail = (struct vfsmount *) NULL, +struct vfsmount *vfsmntlist = (struct vfsmount *) NULL; +static struct vfsmount *vfsmnttail = (struct vfsmount *) NULL, *mru_vfsmnt = (struct vfsmount *) NULL; /* @@ -376,7 +377,7 @@ tmp = file_systems; while (tmp && len < PAGE_SIZE - 80) { len += sprintf(buf+len, "%s\t%s\n", - tmp->requires_dev ? "" : "nodev", + (tmp->fs_flags & FS_REQUIRES_DEV) ? "" : "nodev", tmp->name); tmp = tmp->next; } @@ -435,7 +436,7 @@ } } -static struct super_block * get_super(kdev_t dev) +struct super_block * get_super(kdev_t dev) { struct super_block * s; @@ -601,6 +602,10 @@ if (!sb->s_covered->i_mount) printk("VFS: umount(%s): mounted inode has i_mount=NULL\n", kdevname(dev)); + while(sb->s_ibasket) + free_ibasket(sb); + if(sb->s_mounted->i_dentry) + d_del(sb->s_mounted->i_dentry, D_NO_CLEAR_INODE); /* * Before checking if the filesystem is still busy make sure the kernel * doesn't hold any quotafiles open on that device. If the umount fails @@ -636,15 +641,15 @@ { struct inode * inode; kdev_t dev; + struct inode * dummy_inode = NULL; int retval = -EPERM; - struct inode dummy_inode; lock_kernel(); if (!suser()) goto out; - retval = namei(name, &inode); + retval = namei(NAM_FOLLOW_LINK, name, &inode); if (retval) { - retval = lnamei(name, &inode); + retval = namei(NAM_FOLLOW_TRAILSLASH, name, &inode); if (retval) goto out; } @@ -663,9 +668,8 @@ } dev = inode->i_sb->s_dev; iput(inode); - memset(&dummy_inode, 0, sizeof(dummy_inode)); - dummy_inode.i_rdev = dev; - inode = &dummy_inode; + inode = dummy_inode = get_empty_inode(); + inode->i_rdev = dev; } retval = -ENXIO; if (MAJOR(dev) >= MAX_BLKDEV) { @@ -680,8 +684,7 @@ put_unnamed_dev(dev); } } - if (inode != &dummy_inode) - iput(inode); + iput(inode); if (!retval) fsync_dev(dev); out: @@ -697,22 +700,42 @@ * We cannot mount a filesystem if it has active, used, or dirty inodes. * We also have to flush all inode-data for this device, as the new mount * might need new info. + * + * [21-Mar-97] T.Schoebel-Theuer: Now this can be overridden when + * supplying a leading "!" before the dir_name, allowing "stacks" of + * mounted filesystems. The stacking will only influence any pathname lookups + * _after_ the mount, but open filedescriptors or working directories that + * are now covered remain valid. For example, when you overmount /home, any + * process with old cwd /home/joe will continue to use the old versions, + * as long as relative paths are used, but absolute paths like /home/joe/xxx + * will go to the new "top of stack" version. In general, crossing a + * mountpoint will always go to the top of stack element. + * Anyone using this new feature must know what he/she is doing. */ int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const char * type, int flags, void * data) { - struct inode * dir_i; + struct inode * dir_i = NULL; struct super_block * sb; struct vfsmount *vfsmnt; int error; + int override = 0; + if(dir_name) { + char c; + + get_user(c, dir_name); + override = (c == '!'); + } if (!(flags & MS_RDONLY) && dev && is_read_only(dev)) return -EACCES; /*flags |= MS_RDONLY;*/ - error = namei(dir_name, &dir_i); + if(override) + dir_name++; + error = namei(NAM_FOLLOW_LINK, dir_name, &dir_i); if (error) return error; - if (dir_i->i_count != 1 || dir_i->i_mount) { + if (!override && (atomic_read(&dir_i->i_count) != 1 || dir_i->i_mount)) { iput(dir_i); return -EBUSY; } @@ -720,7 +743,7 @@ iput(dir_i); return -ENOTDIR; } - if (!fs_may_mount(dev)) { + if (!fs_may_mount(dev) && !override) { iput(dir_i); return -EBUSY; } @@ -738,6 +761,22 @@ vfsmnt->mnt_sb = sb; vfsmnt->mnt_flags = flags; } + { + struct dentry * old = dir_i->i_dentry; + struct dentry * new; + vfs_lock(); + new = d_alloc(old->d_parent, old->d_len, 1); + if(new) { + struct qstr copy = { old->d_name, old->d_len }; + d_add(new, sb->s_mounted, ©, D_DUPLICATE); + vfs_unlock(); + } else { + printk("VFS: cannot setup dentry for mount\n"); + iput(dir_i); + return -ENOMEM; + } + vfs_unlock(); + } sb->s_covered = dir_i; dir_i->i_mount = sb->s_mounted; return 0; /* we don't iput(dir_i) - see umount */ @@ -781,7 +820,7 @@ struct inode *dir_i; int retval; - retval = namei(dir, &dir_i); + retval = namei(NAM_FOLLOW_LINK, dir, &dir_i); if (retval) return retval; if (dir_i != dir_i->i_sb->s_mounted) { @@ -872,8 +911,8 @@ goto out; t = fstype->name; fops = NULL; - if (fstype->requires_dev) { - retval = namei(dev_name, &inode); + if ((fstype->fs_flags & FS_REQUIRES_DEV)) { + retval = namei(NAM_FOLLOW_LINK, dev_name, &inode); if (retval) goto out; retval = -ENOTBLK; @@ -943,7 +982,7 @@ struct file_system_type * fs_type; struct super_block * sb; struct vfsmount *vfsmnt; - struct inode * inode, d_inode; + struct inode * inode, * d_inode = NULL; struct file filp; int retval; @@ -963,13 +1002,14 @@ sb->s_flags = root_mountflags & ~MS_RDONLY; if (nfs_root_mount(sb) >= 0) { inode = sb->s_mounted; - inode->i_count += 3 ; + atomic_add(3, &inode->i_count); sb->s_covered = inode; sb->s_rd_only = 0; sb->s_dirt = 0; sb->s_type = fs_type; current->fs->pwd = inode; current->fs->root = inode; + (void)d_alloc_root(inode); ROOT_DEV = sb->s_dev; printk (KERN_NOTICE "VFS: Mounted root (nfs filesystem).\n"); vfsmnt = add_vfsmnt(ROOT_DEV, "/dev/root", "/"); @@ -1000,19 +1040,20 @@ #endif memset(&filp, 0, sizeof(filp)); - memset(&d_inode, 0, sizeof(d_inode)); - d_inode.i_rdev = ROOT_DEV; - filp.f_inode = &d_inode; + d_inode = get_empty_inode(); + d_inode->i_rdev = ROOT_DEV; + filp.f_inode = d_inode; if ( root_mountflags & MS_RDONLY) filp.f_mode = 1; /* read only */ else filp.f_mode = 3; /* read write */ - retval = blkdev_open(&d_inode, &filp); + retval = blkdev_open(d_inode, &filp); if (retval == -EROFS) { root_mountflags |= MS_RDONLY; filp.f_mode = 1; - retval = blkdev_open(&d_inode, &filp); + retval = blkdev_open(d_inode, &filp); } + iput(d_inode); if (retval) /* * Allow the user to distinguish between failed open @@ -1021,16 +1062,19 @@ printk("VFS: Cannot open root device %s\n", kdevname(ROOT_DEV)); else for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) { - if (!fs_type->requires_dev) + if (!(fs_type->fs_flags & FS_REQUIRES_DEV)) continue; sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1); if (sb) { inode = sb->s_mounted; - inode->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */ + + /* NOTE! it is logically used 4 times, not 1 */ + atomic_add(3, &inode->i_count); sb->s_covered = inode; sb->s_flags = root_mountflags; current->fs->pwd = inode; current->fs->root = inode; + (void)d_alloc_root(inode); printk ("VFS: Mounted root (%s filesystem)%s.\n", fs_type->name, (sb->s_flags & MS_RDONLY) ? " readonly" : ""); @@ -1077,11 +1121,13 @@ do_mount_root(); old_fs = get_fs(); set_fs(get_ds()); - error = namei(put_old,&inode); + error = namei(NAM_FOLLOW_LINK, put_old, &inode); if (error) inode = NULL; set_fs(old_fs); - if (!error && (inode->i_count != 1 || inode->i_mount)) error = -EBUSY; - if (!error && !S_ISDIR(inode->i_mode)) error = -ENOTDIR; + if (!error && (atomic_read(&inode->i_count) != 1 || inode->i_mount)) + error = -EBUSY; + if (!error && !S_ISDIR(inode->i_mode)) + error = -ENOTDIR; iput(old_root); /* current->fs->root */ iput(old_pwd); /* current->fs->pwd */ if (error) { diff -u --recursive --new-file v2.1.42/linux/fs/sysv/dir.c linux/fs/sysv/dir.c --- v2.1.42/linux/fs/sysv/dir.c Sun Jan 26 02:07:45 1997 +++ linux/fs/sysv/dir.c Thu Jun 12 16:22:09 1997 @@ -57,7 +57,6 @@ sysv_mknod, /* mknod */ sysv_rename, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/sysv/file.c linux/fs/sysv/file.c --- v2.1.42/linux/fs/sysv/file.c Sun Jan 26 02:07:45 1997 +++ linux/fs/sysv/file.c Thu Jun 12 16:22:09 1997 @@ -64,7 +64,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ generic_readpage, /* readpage */ NULL, /* writepage */ sysv_bmap, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/sysv/ialloc.c linux/fs/sysv/ialloc.c --- v2.1.42/linux/fs/sysv/ialloc.c Sat Nov 30 02:24:01 1996 +++ linux/fs/sysv/ialloc.c Thu Jun 12 16:22:09 1997 @@ -62,8 +62,9 @@ printk("sysv_free_inode: inode has no device\n"); return; } - if (inode->i_count != 1) { - printk("sysv_free_inode: inode has count=%d\n", inode->i_count); + if (atomic_read(&inode->i_count) != 1) { + printk("sysv_free_inode: inode has count=%d\n", + atomic_read(&inode->i_count)); return; } if (inode->i_nlink) { @@ -149,7 +150,7 @@ mark_buffer_dirty(sb->sv_bh1, 1); /* super-block has been modified */ if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2, 1); sb->s_dirt = 1; /* and needs time stamp */ - inode->i_count = 1; + atomic_set(&inode->i_count, 1); inode->i_nlink = 1; inode->i_dev = sb->s_dev; inode->i_uid = current->fsuid; diff -u --recursive --new-file v2.1.42/linux/fs/sysv/inode.c linux/fs/sysv/inode.c --- v2.1.42/linux/fs/sysv/inode.c Wed Apr 23 19:01:27 1997 +++ linux/fs/sysv/inode.c Thu Jun 12 16:22:09 1997 @@ -975,9 +975,9 @@ /* Every kernel module contains stuff like this. */ static struct file_system_type sysv_fs_type[3] = { - {sysv_read_super, "xenix", 1, NULL}, - {sysv_read_super, "sysv", 1, NULL}, - {sysv_read_super, "coherent", 1, NULL} + {"xenix", FS_REQUIRES_DEV, sysv_read_super, NULL}, + {"sysv", FS_REQUIRES_DEV, sysv_read_super, NULL}, + {"coherent", FS_REQUIRES_DEV, sysv_read_super, NULL} }; __initfunc(int init_sysv_fs(void)) diff -u --recursive --new-file v2.1.42/linux/fs/sysv/namei.c linux/fs/sysv/namei.c --- v2.1.42/linux/fs/sysv/namei.c Sat Nov 30 02:24:01 1996 +++ linux/fs/sysv/namei.c Thu Jun 12 16:22:09 1997 @@ -454,7 +454,7 @@ retval = -ENOENT; goto end_rmdir; } - if (inode->i_count > 1) { + if (atomic_read(&inode->i_count) > 1) { retval = -EBUSY; goto end_rmdir; } @@ -635,7 +635,7 @@ int ino; int result; - new_inode->i_count++; + atomic_inc(&new_inode->i_count); result = 0; for (;;) { if (new_inode == old_inode) { @@ -668,7 +668,7 @@ * higher-level routines. */ static int do_sysv_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len, int must_be_dir) + struct inode * new_dir, const char * new_name, int new_len) { struct inode * old_inode, * new_inode; struct buffer_head * old_bh, * new_bh, * dir_bh; @@ -694,8 +694,6 @@ old_inode = __iget(old_dir->i_sb, old_de->inode, 0); /* don't cross mnt-points */ if (!old_inode) goto end_rename; - if (must_be_dir && !S_ISDIR(old_inode->i_mode)) - goto end_rename; retval = -EPERM; if ((old_dir->i_mode & S_ISVTX) && current->fsuid != old_inode->i_uid && @@ -724,7 +722,7 @@ if (!empty_dir(new_inode)) goto end_rename; retval = -EBUSY; - if (new_inode->i_count > 1) + if (atomic_read(&new_inode->i_count) > 1) goto end_rename; } retval = -EPERM; @@ -810,8 +808,7 @@ * as they are on different partitions. */ int sysv_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len, - int must_be_dir) + struct inode * new_dir, const char * new_name, int new_len) { static struct wait_queue * wait = NULL; static int lock = 0; @@ -821,7 +818,7 @@ sleep_on(&wait); lock = 1; result = do_sysv_rename(old_dir, old_name, old_len, - new_dir, new_name, new_len, must_be_dir); + new_dir, new_name, new_len); lock = 0; wake_up(&wait); return result; diff -u --recursive --new-file v2.1.42/linux/fs/sysv/symlink.c linux/fs/sysv/symlink.c --- v2.1.42/linux/fs/sysv/symlink.c Mon Oct 28 04:29:27 1996 +++ linux/fs/sysv/symlink.c Thu Jun 12 16:22:09 1997 @@ -21,7 +21,6 @@ #include static int sysv_readlink(struct inode *, char *, int); -static int sysv_follow_link(struct inode *, struct inode *, int, int, struct inode **); /* * symlinks can't do much... @@ -38,7 +37,6 @@ NULL, /* mknod */ NULL, /* rename */ sysv_readlink, /* readlink */ - sysv_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -46,44 +44,6 @@ NULL /* permission */ }; -static int sysv_follow_link(struct inode * dir, struct inode * inode, - int flag, int mode, struct inode ** res_inode) -{ - int error; - struct buffer_head * bh; - - *res_inode = NULL; - if (!dir) { - dir = current->fs->root; - dir->i_count++; - } - if (!inode) { - iput(dir); - return -ENOENT; - } - if (!S_ISLNK(inode->i_mode)) { - iput(dir); - *res_inode = inode; - return 0; - } - if (current->link_count > 5) { - iput(inode); - iput(dir); - return -ELOOP; - } - if (!(bh = sysv_file_bread(inode, 0, 0))) { /* is reading 1 block enough ?? */ - iput(inode); - iput(dir); - return -EIO; - } - iput(inode); - current->link_count++; - error = open_namei(bh->b_data,flag,mode,res_inode,dir); - current->link_count--; - brelse(bh); - return error; -} - static int sysv_readlink(struct inode * inode, char * buffer, int buflen) { struct buffer_head * bh; @@ -91,10 +51,6 @@ int i; char c; - if (!S_ISLNK(inode->i_mode)) { - iput(inode); - return -EINVAL; - } if (buflen > inode->i_sb->sv_block_size_1) buflen = inode->i_sb->sv_block_size_1; bh = sysv_file_bread(inode, 0, 0); diff -u --recursive --new-file v2.1.42/linux/fs/ufs/ufs_dir.c linux/fs/ufs/ufs_dir.c --- v2.1.42/linux/fs/ufs/ufs_dir.c Sun Jan 26 02:07:45 1997 +++ linux/fs/ufs/ufs_dir.c Thu Jun 12 16:22:09 1997 @@ -6,7 +6,7 @@ * Laboratory for Computer Science Research Computing Facility * Rutgers, The State University of New Jersey * - * $Id: ufs_dir.c,v 1.8 1997/01/26 07:14:28 davem Exp $ + * $Id: ufs_dir.c,v 1.10 1997/06/05 01:29:06 davem Exp $ * */ @@ -108,11 +108,8 @@ * version stamp to detect whether or * not the directory has been modified * during the copy operation. */ - unsigned long version; - dcache_add(inode, de->d_name, - ufs_swab16(de->d_namlen), - ufs_swab32(de->d_ino)); - version = inode->i_version; + unsigned long version = inode->i_version; + if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { printk("ufs_readdir: filldir(%s,%u)\n", de->d_name, ufs_swab32(de->d_ino)); @@ -166,7 +163,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -174,13 +170,3 @@ NULL, /* permission */ NULL, /* smap */ }; - -/* - * Local Variables: *** - * c-indent-level: 8 *** - * c-continued-statement-offset: 8 *** - * c-brace-offset: -8 *** - * c-argdecl-indent: 0 *** - * c-label-offset: -8 *** - * End: *** - */ diff -u --recursive --new-file v2.1.42/linux/fs/ufs/ufs_file.c linux/fs/ufs/ufs_file.c --- v2.1.42/linux/fs/ufs/ufs_file.c Sun Jan 26 02:07:45 1997 +++ linux/fs/ufs/ufs_file.c Thu Jun 12 16:22:09 1997 @@ -6,7 +6,7 @@ * Laboratory for Computer Science Research Computing Facility * Rutgers, The State University of New Jersey * - * $Id: ufs_file.c,v 1.7 1997/01/26 07:14:28 davem Exp $ + * $Id: ufs_file.c,v 1.8 1997/06/05 01:29:09 davem Exp $ * */ @@ -41,7 +41,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ generic_readpage, /* readpage */ NULL, /* writepage */ ufs_bmap, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/ufs/ufs_inode.c linux/fs/ufs/ufs_inode.c --- v2.1.42/linux/fs/ufs/ufs_inode.c Sat Nov 30 03:22:19 1996 +++ linux/fs/ufs/ufs_inode.c Thu Jun 12 16:22:09 1997 @@ -6,7 +6,7 @@ * Laboratory for Computer Science Research Computing Facility * Rutgers, The State University of New Jersey * - * $Id: ufs_inode.c,v 1.7 1996/06/01 14:56:46 ecd Exp $ + * $Id: ufs_inode.c,v 1.8 1997/06/04 08:28:28 davem Exp $ * */ @@ -18,8 +18,9 @@ { printk("ino %lu mode 0%6.6o lk %d uid %d gid %d" " sz %lu blks %lu cnt %u\n", - inode->i_ino, inode->i_mode, inode->i_nlink, inode->i_uid, - inode->i_gid, inode->i_size, inode->i_blocks, inode->i_count); + inode->i_ino, inode->i_mode, inode->i_nlink, inode->i_uid, + inode->i_gid, inode->i_size, inode->i_blocks, + atomic_read(&inode->i_count)); printk(" db <0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x" " 0x%x 0x%x 0x%x 0x%x>\n", inode->u.ufs_i.i_data[0], inode->u.ufs_i.i_data[1], diff -u --recursive --new-file v2.1.42/linux/fs/ufs/ufs_super.c linux/fs/ufs/ufs_super.c --- v2.1.42/linux/fs/ufs/ufs_super.c Wed Apr 23 19:01:27 1997 +++ linux/fs/ufs/ufs_super.c Thu Jun 12 16:22:09 1997 @@ -8,7 +8,7 @@ * * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) * - * $Id: ufs_super.c,v 1.23 1997/04/16 04:53:39 tdyas Exp $ + * $Id: ufs_super.c,v 1.24 1997/06/04 08:28:29 davem Exp $ * */ @@ -49,7 +49,10 @@ }; static struct file_system_type ufs_fs_type = { - ufs_read_super, "ufs", 1, NULL + "ufs", + FS_REQUIRES_DEV, + ufs_read_super, + NULL }; __initfunc(int init_ufs_fs(void)) diff -u --recursive --new-file v2.1.42/linux/fs/ufs/ufs_symlink.c linux/fs/ufs/ufs_symlink.c --- v2.1.42/linux/fs/ufs/ufs_symlink.c Sun Jan 26 02:07:46 1997 +++ linux/fs/ufs/ufs_symlink.c Thu Jun 12 16:22:09 1997 @@ -6,7 +6,7 @@ * Laboratory for Computer Science Research Computing Facility * Rutgers, The State University of New Jersey * - * $Id: ufs_symlink.c,v 1.7 1997/01/26 07:14:29 davem Exp $ + * $Id: ufs_symlink.c,v 1.9 1997/06/05 01:29:11 davem Exp $ * */ @@ -30,10 +30,6 @@ inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev)); } - if (!S_ISLNK(inode->i_mode)) { - iput (inode); - return -EINVAL; - } if (buflen > inode->i_sb->s_blocksize - 1) buflen = inode->i_sb->s_blocksize - 1; if (inode->i_blocks) { @@ -67,73 +63,6 @@ return i; } -/* - * XXX - blatantly stolen from ext2fs - */ -static int -ufs_follow_link(struct inode * dir, struct inode * inode, - int flag, int mode, struct inode ** res_inode) -{ - unsigned long int block; - int error; - struct buffer_head * bh; - char * link; - - bh = NULL; - - if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) { - printk("ufs_follow_link: called on ino %lu dev %u/%u\n", - dir->i_ino, MAJOR(dir->i_dev), MINOR(dir->i_dev)); - } - - *res_inode = NULL; - if (!dir) { - dir = current->fs->root; - dir->i_count++; - } - if (!inode) { - iput (dir); - return -ENOENT; - } - if (!S_ISLNK(inode->i_mode)) { - iput (dir); - *res_inode = inode; - return 0; - } - if (current->link_count > 5) { - iput (dir); - iput (inode); - return -ELOOP; - } - if (inode->i_blocks) { - /* read the link from disk */ - /* XXX - error checking */ - block = ufs_bmap(inode, 0); - bh = bread(inode->i_dev, block, BLOCK_SIZE); - if (bh == NULL) { - printk("ufs_follow_link: can't read block 0 for ino %lu on dev %u/%u\n", - inode->i_ino, MAJOR(inode->i_dev), - MINOR(inode->i_dev)); - iput(dir); - iput(inode); - return(-EIO); - } - link = bh->b_data; - } else { - /* fast symlink */ - link = (char *)&(inode->u.ufs_i.i_data[0]); - } - current->link_count++; - error = open_namei (link, flag, mode, res_inode, dir); - current->link_count--; - iput (inode); - if (bh) { - brelse (bh); - } - return(error); -} - - static struct file_operations ufs_symlink_operations = { NULL, /* lseek */ NULL, /* read */ @@ -161,8 +90,7 @@ NULL, /* rmdir */ NULL, /* mknod */ NULL, /* rename */ - &ufs_readlink, /* readlink */ - &ufs_follow_link, /* follow_link */ + ufs_readlink, /* readlink */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c --- v2.1.42/linux/fs/umsdos/dir.c Sun Jan 26 02:07:46 1997 +++ linux/fs/umsdos/dir.c Thu Jun 12 16:22:09 1997 @@ -565,7 +565,7 @@ } } }else{ - dir->i_count++; + atomic_inc(&dir->i_count); } if (ret == 0){ while (dir != dir->i_sb->s_mounted){ @@ -628,7 +628,7 @@ umsdos_startlookup(dir); if (len == 1 && name[0] == '.'){ *result = dir; - dir->i_count++; + atomic_inc(&dir->i_count); ret = 0; }else if (len == 2 && name[0] == '.' && name[1] == '.'){ if (pseudo_root != NULL && dir == pseudo_root->i_sb->s_mounted){ @@ -639,7 +639,7 @@ */ ret = 0; *result = pseudo_root; - pseudo_root->i_count++; + atomic_inc(&pseudo_root->i_count); }else{ /* #Specification: locating .. / strategy We use the msdos filesystem to locate the parent directory. @@ -668,7 +668,7 @@ and return the inode of the real root. */ *result = dir->i_sb->s_mounted; - (*result)->i_count++; + atomic_inc(&((*result)->i_count)); ret = 0; }else{ struct umsdos_info info; @@ -757,7 +757,7 @@ dir = hlink->i_sb->s_mounted; path[hlink->i_size] = '\0'; iput (hlink); - dir->i_count++; + atomic_inc(&dir->i_count); while (1){ char *start = pt; int len; @@ -811,7 +811,6 @@ UMSDOS_mknod, /* mknod */ UMSDOS_rename, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/umsdos/emd.c linux/fs/umsdos/emd.c --- v2.1.42/linux/fs/umsdos/emd.c Thu Mar 27 14:40:06 1997 +++ linux/fs/umsdos/emd.c Thu Jun 12 16:22:09 1997 @@ -137,7 +137,8 @@ if (dir->u.umsdos_i.i_emd_dir != 0){ ret = iget (dir->i_sb,dir->u.umsdos_i.i_emd_dir); PRINTK (("deja trouve %d %x [%d] " - ,dir->u.umsdos_i.i_emd_dir,ret,ret->i_count)); + ,dir->u.umsdos_i.i_emd_dir,ret, + atomic_read(&ret->i_count))); }else{ umsdos_real_lookup (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN,&ret); PRINTK (("emd_dir_lookup ")); @@ -147,7 +148,7 @@ }else if (creat){ int code; PRINTK (("avant create ")); - dir->i_count++; + atomic_inc(&dir->i_count); code = msdos_create (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN ,S_IFREG|0777,&ret); PRINTK (("Creat EMD code %d ret %x ",code,ret)); diff -u --recursive --new-file v2.1.42/linux/fs/umsdos/file.c linux/fs/umsdos/file.c --- v2.1.42/linux/fs/umsdos/file.c Sun Jan 26 02:07:46 1997 +++ linux/fs/umsdos/file.c Thu Jun 12 16:22:09 1997 @@ -86,7 +86,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ generic_readpage, /* readpage */ NULL, /* writepage */ fat_bmap, /* bmap */ @@ -120,7 +119,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c --- v2.1.42/linux/fs/umsdos/inode.c Wed Apr 23 19:01:27 1997 +++ linux/fs/umsdos/inode.c Thu Jun 12 16:22:09 1997 @@ -73,7 +73,7 @@ struct inode **result) /* Will hold inode of the file, if successful */ { int ret; - dir->i_count++; + atomic_inc(&dir->i_count); ret = msdos_lookup (dir,name,len,result); return ret; } @@ -120,7 +120,7 @@ #elif 0 return inode->i_atime != 0; #else - return inode->i_count > 1; + return atomic_read(&inode->i_count) > 1; #endif } /* @@ -224,7 +224,7 @@ { PRINTK (("read inode %x ino = %d ",inode,inode->i_ino)); msdos_read_inode(inode); - PRINTK (("ino = %d %d\n",inode->i_ino,inode->i_count)); + PRINTK (("ino = %d %d\n",inode->i_ino,atomic_read(&inode->i_count))); if (S_ISDIR(inode->i_mode) && (inode->u.umsdos_i.u.dir_info.creating != 0 || inode->u.umsdos_i.u.dir_info.looking != 0 @@ -480,7 +480,7 @@ umsdos_setup_dir_inode (pseudo); Printk (("Activating pseudo root /%s\n",UMSDOS_PSDROOT_NAME)); pseudo_root = pseudo; - pseudo->i_count++; + atomic_inc(&pseudo->i_count); pseudo = NULL; } iput (sbin); @@ -497,7 +497,10 @@ static struct file_system_type umsdos_fs_type = { - UMSDOS_read_super, "umsdos", 1, NULL + "umsdos", + FS_REQUIRES_DEV, + UMSDOS_read_super, + NULL }; __initfunc(int init_umsdos_fs(void)) diff -u --recursive --new-file v2.1.42/linux/fs/umsdos/ioctl.c linux/fs/umsdos/ioctl.c --- v2.1.42/linux/fs/umsdos/ioctl.c Mon Oct 28 04:29:27 1996 +++ linux/fs/umsdos/ioctl.c Thu Jun 12 16:22:09 1997 @@ -215,11 +215,11 @@ This ioctl allows umssync to rename a mangle file name before syncing it back in the EMD. */ - dir->i_count += 2; + atomic_add(2, &dir->i_count); ret = msdos_rename (dir ,data.dos_dirent.d_name,data.dos_dirent.d_reclen ,dir - ,data.umsdos_dirent.name,data.umsdos_dirent.name_len,0); + ,data.umsdos_dirent.name,data.umsdos_dirent.name_len); }else if (cmd == UMSDOS_UNLINK_EMD){ /* #Specification: ioctl / UMSDOS_UNLINK_EMD The umsdos_dirent field of the struct umsdos_ioctl is used @@ -246,7 +246,7 @@ Return 0 if success. */ - dir->i_count++; + atomic_inc(&dir->i_count); ret = msdos_unlink (dir,data.dos_dirent.d_name ,data.dos_dirent.d_reclen); }else if (cmd == UMSDOS_RMDIR_DOS){ @@ -257,7 +257,7 @@ Return 0 if success. */ - dir->i_count++; + atomic_inc(&dir->i_count); ret = msdos_rmdir (dir,data.dos_dirent.d_name ,data.dos_dirent.d_reclen); }else if (cmd == UMSDOS_STAT_DOS){ diff -u --recursive --new-file v2.1.42/linux/fs/umsdos/namei.c linux/fs/umsdos/namei.c --- v2.1.42/linux/fs/umsdos/namei.c Tue May 13 22:41:15 1997 +++ linux/fs/umsdos/namei.c Thu Jun 12 16:22:09 1997 @@ -225,13 +225,14 @@ umsdos_lockcreate(dir); ret = umsdos_newentry (dir,&info); if (ret == 0){ - dir->i_count++; + atomic_inc(&dir->i_count); ret = msdos_create (dir,info.fake.fname,info.fake.len ,S_IFREG|0777,result); if (ret == 0){ struct inode *inode = *result; umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos); - PRINTK (("inode %p[%d] ",inode,inode->i_count)); + PRINTK (("inode %p[%d] ",inode, + atomic_read(&inode->i_count))); PRINTK (("Creation OK: [%d] %s %d pos %d\n",dir->i_ino ,info.fake.fname,current->pid,info.f_pos)); }else{ @@ -351,13 +352,12 @@ PRINTK (("ret %d %d ",ret,new_info.fake.len)); if (ret == 0){ PRINTK (("msdos_rename ")); - old_dir->i_count++; - new_dir->i_count++; /* Both inode are needed later */ + atomic_inc(&old_dir->i_count); + atomic_inc(&new_dir->i_count); /* Both inode are needed later */ ret = msdos_rename (old_dir ,old_info.fake.fname,old_info.fake.len ,new_dir - ,new_info.fake.fname,new_info.fake.len - ,0); + ,new_info.fake.fname,new_info.fake.len); chkstk(); PRINTK (("after m_rename ret %d ",ret)); if (ret != 0){ @@ -378,7 +378,7 @@ Not very efficient ... */ struct inode *inode; - new_dir->i_count++; + atomic_inc(&new_dir->i_count); PRINTK (("rename lookup len %d %d -- ",new_len,new_info.entry.flags)); ret = UMSDOS_lookup (new_dir,new_name,new_len ,&inode); @@ -441,7 +441,7 @@ */ struct inode *inode; int ret; - dir->i_count++; /* We keep the inode in case we need it */ + atomic_inc(&dir->i_count);/* We keep the inode in case we need it */ /* later */ ret = umsdos_create_any (dir,name,len,mode,0,flags,&inode); PRINTK (("umsdos_symlink ret %d ",ret)); @@ -572,7 +572,8 @@ struct inode *olddir; ret = umsdos_get_dirowner(oldinode,&olddir); PRINTK (("umsdos_link dir_owner = %d -> %p [%d] " - ,oldinode->u.umsdos_i.i_dir_owner,olddir,olddir->i_count)); + ,oldinode->u.umsdos_i.i_dir_owner,olddir, + atomic_read(&olddir->i_count))); if (ret == 0){ struct umsdos_dirent entry; umsdos_lockcreate2(dir,olddir); @@ -596,8 +597,9 @@ struct umsdos_info info; ret = umsdos_newhidden (olddir,&info); if (ret == 0){ - olddir->i_count+=2; - PRINTK (("olddir[%d] ",olddir->i_count)); + atomic_add(2, &olddir->i_count); + PRINTK (("olddir[%d] ", + atomic_read(&olddir->i_count))); ret = umsdos_rename_f (olddir,entry.name ,entry.name_len ,olddir,info.entry.name,info.entry.name_len @@ -607,17 +609,19 @@ if (path == NULL){ ret = -ENOMEM; }else{ - PRINTK (("olddir[%d] ",olddir->i_count)); + PRINTK (("olddir[%d] ", + atomic_read(&olddir->i_count))); ret = umsdos_locate_path (oldinode,path); - PRINTK (("olddir[%d] ",olddir->i_count)); + PRINTK (("olddir[%d] ", + atomic_read(&olddir->i_count))); if (ret == 0){ - olddir->i_count++; + atomic_inc(&olddir->i_count); ret = umsdos_symlink_x (olddir ,entry.name ,entry.name_len,path ,S_IFREG|0777,UMSDOS_HLINK); if (ret == 0){ - dir->i_count++; + atomic_inc(&dir->i_count); ret = umsdos_symlink_x (dir,name,len ,path ,S_IFREG|0777,UMSDOS_HLINK); @@ -634,7 +638,7 @@ }else{ ret = umsdos_locate_path (oldinode,path); if (ret == 0){ - dir->i_count++; + atomic_inc(&dir->i_count); ret = umsdos_symlink_x (dir,name,len,path ,S_IFREG|0777,UMSDOS_HLINK); } @@ -703,7 +707,7 @@ ret = umsdos_newentry (dir,&info); PRINTK (("newentry %d ",ret)); if (ret == 0){ - dir->i_count++; + atomic_inc(&dir->i_count); ret = msdos_mkdir (dir,info.fake.fname,info.fake.len,mode); if (ret != 0){ umsdos_delentry (dir,&info,1); @@ -869,16 +873,17 @@ int ret = umsdos_nevercreat(dir,name,len,-EPERM); if (ret == 0){ struct inode *sdir; - dir->i_count++; + atomic_inc(&dir->i_count); ret = UMSDOS_lookup (dir,name,len,&sdir); PRINTK (("rmdir lookup %d ",ret)); if (ret == 0){ int empty; umsdos_lockcreate(dir); - if (sdir->i_count > 1){ + if (atomic_read(&sdir->i_count) > 1){ ret = -EBUSY; }else if ((empty = umsdos_isempty (sdir)) != 0){ - PRINTK (("isempty %d i_count %d ",empty,sdir->i_count)); + PRINTK (("isempty %d i_count %d ",empty, + atomic_read(&sdir->i_count))); /* check sticky bit */ if ( !(dir->i_mode & S_ISVTX) || fsuser() || current->fsuid == sdir->i_uid || @@ -895,7 +900,7 @@ PRINTK (("isempty ret %d nlink %d ",ret,dir->i_nlink)); if (ret == 0){ struct umsdos_info info; - dir->i_count++; + atomic_inc(&dir->i_count); umsdos_parse (name,len,&info); /* The findentry is there only to complete */ /* the mangling */ @@ -960,7 +965,7 @@ using the standard lookup function. */ struct inode *inode; - dir->i_count++; + atomic_inc(&dir->i_count); ret = UMSDOS_lookup (dir,name,len,&inode); if (ret == 0){ PRINTK (("unlink nlink = %d ",inode->i_nlink)); @@ -988,7 +993,7 @@ ret = umsdos_delentry (dir,&info,0); if (ret == 0){ PRINTK (("Avant msdos_unlink %s ",info.fake.fname)); - dir->i_count++; + atomic_inc(&dir->i_count); ret = msdos_unlink_umsdos (dir,info.fake.fname ,info.fake.len); PRINTK (("msdos_unlink %s %o ret %d ",info.fake.fname @@ -1018,8 +1023,7 @@ int old_len, struct inode * new_dir, const char * new_name, - int new_len, - int must_be_dir) + int new_len) { /* #Specification: weakness / rename There is a case where UMSDOS rename has a different behavior @@ -1036,8 +1040,8 @@ int ret = umsdos_nevercreat(new_dir,new_name,new_len,-EEXIST); if (ret == 0){ /* umsdos_rename_f eat the inode and we may need those later */ - old_dir->i_count++; - new_dir->i_count++; + atomic_inc(&old_dir->i_count); + atomic_inc(&new_dir->i_count); ret = umsdos_rename_f (old_dir,old_name,old_len,new_dir,new_name ,new_len,0); if (ret == -EEXIST){ @@ -1075,12 +1079,12 @@ is a problem at all. */ /* This is not super efficient but should work */ - new_dir->i_count++; + atomic_inc(&new_dir->i_count); ret = UMSDOS_unlink (new_dir,new_name,new_len); chkstk(); PRINTK (("rename unlink ret %d %d -- ",ret,new_len)); if (ret == -EISDIR){ - new_dir->i_count++; + atomic_inc(&new_dir->i_count); ret = UMSDOS_rmdir (new_dir,new_name,new_len); chkstk(); PRINTK (("rename rmdir ret %d -- ",ret)); diff -u --recursive --new-file v2.1.42/linux/fs/umsdos/rdir.c linux/fs/umsdos/rdir.c --- v2.1.42/linux/fs/umsdos/rdir.c Sun Jan 26 02:07:46 1997 +++ linux/fs/umsdos/rdir.c Thu Jun 12 16:22:09 1997 @@ -96,7 +96,7 @@ && dir == dir->i_sb->s_mounted && dir == pseudo_root->i_sb->s_mounted){ *result = pseudo_root; - pseudo_root->i_count++; + atomic_inc(&pseudo_root->i_count); ret = 0; /* #Specification: pseudo root / DOS/.. In the real root directory (c:\), the directory .. @@ -165,17 +165,18 @@ ret = -EPERM; }else{ umsdos_lockcreate (dir); - dir->i_count++; + atomic_inc(&dir->i_count); ret = msdos_rmdir (dir,name,len); if (ret == -ENOTEMPTY){ struct inode *sdir; - dir->i_count++; + atomic_inc(&dir->i_count); ret = UMSDOS_rlookup (dir,name,len,&sdir); PRINTK (("rrmdir lookup %d ",ret)); if (ret == 0){ int empty; if ((empty = umsdos_isempty (sdir)) != 0){ - PRINTK (("isempty %d i_count %d ",empty,sdir->i_count)); + PRINTK (("isempty %d i_count %d ",empty, + atomic_read(&sdir->i_count))); if (empty == 2){ /* Not a Umsdos directory, so the previous msdos_rmdir @@ -188,7 +189,7 @@ ,UMSDOS_EMD_NAMELEN); sdir = NULL; if (ret == 0){ - dir->i_count++; + atomic_inc(&dir->i_count); ret = msdos_rmdir (dir,name,len); } } @@ -260,7 +261,6 @@ NULL, /* mknod */ msdos_rename, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/umsdos/symlink.c linux/fs/umsdos/symlink.c --- v2.1.42/linux/fs/umsdos/symlink.c Sun Jan 26 02:07:46 1997 +++ linux/fs/umsdos/symlink.c Thu Jun 12 16:22:09 1997 @@ -42,69 +42,12 @@ } return ret; } -/* - Follow a symbolic link chain by calling open_namei recursively - until an inode is found. - - Return 0 if ok, or a negative error code if not. -*/ -static int UMSDOS_follow_link( - struct inode * dir, - struct inode * inode, - int flag, - int mode, - struct inode ** res_inode) -{ - int ret = -ELOOP; - *res_inode = NULL; - if (current->link_count < 5) { - char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL); - if (path == NULL){ - ret = -ENOMEM; - }else{ - if (!dir) { - dir = current->fs[1].root; - dir->i_count++; - } - if (!inode){ - PRINTK (("symlink: inode = NULL\n")); - ret = -ENOENT; - }else if (!S_ISLNK(inode->i_mode)){ - PRINTK (("symlink: Not ISLNK\n")); - *res_inode = inode; - inode = NULL; - ret = 0; - }else{ - ret = umsdos_readlink_x (inode,path - ,umsdos_file_read_kmem,PATH_MAX-1); - if (ret > 0){ - path[ret] = '\0'; - PRINTK (("follow :%s: %d ",path,ret)); - iput(inode); - inode = NULL; - current->link_count++; - ret = open_namei(path,flag,mode,res_inode,dir); - current->link_count--; - dir = NULL; - }else{ - ret = -EIO; - } - } - kfree (path); - } - } - iput(inode); - iput(dir); - PRINTK (("follow_link ret %d\n",ret)); - return ret; -} static int UMSDOS_readlink(struct inode * inode, char * buffer, int buflen) { - int ret = -EINVAL; - if (S_ISLNK(inode->i_mode)) { - ret = umsdos_readlink_x (inode,buffer,fat_file_read,buflen); - } + int ret; + + ret = umsdos_readlink_x (inode,buffer,fat_file_read,buflen); PRINTK (("readlink %d %x bufsiz %d\n",ret,inode->i_mode,buflen)); iput(inode); return ret; @@ -136,7 +79,6 @@ NULL, /* mknod */ NULL, /* rename */ UMSDOS_readlink, /* readlink */ - UMSDOS_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/fs/vfat/namei.c linux/fs/vfat/namei.c --- v2.1.42/linux/fs/vfat/namei.c Tue May 13 22:41:15 1997 +++ linux/fs/vfat/namei.c Thu Jun 12 16:22:09 1997 @@ -937,12 +937,6 @@ if (!(*result = iget(dir->i_sb,ino))) return -EACCES; return 0; } - if (dcache_lookup(dir, name, len, (unsigned long *) &ino) && ino) { - iput(dir); - if (!(*result = iget(dir->i_sb, ino))) - return -EACCES; - return 0; - } PRINTK (("vfat_lookup 3\n")); if ((res = vfat_find(dir,name,len,1,0,0,&sinfo)) < 0) { iput(dir); @@ -1019,7 +1013,6 @@ (*result)->i_dirt = 1; (*result)->i_version = ++event; dir->i_version = event; - dcache_add(dir, name, len, ino); return 0; } @@ -1132,7 +1125,7 @@ struct buffer_head *bh; struct msdos_dir_entry *de; - if (dir->i_count > 1) + if (atomic_read(&dir->i_count) > 1) return -EBUSY; if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */ pos = 0; @@ -1356,7 +1349,7 @@ int vfat_rename(struct inode *old_dir,const char *old_name,int old_len, - struct inode *new_dir,const char *new_name,int new_len,int must_be_dir) + struct inode *new_dir,const char *new_name,int new_len) { struct super_block *sb = old_dir->i_sb; struct buffer_head *old_bh,*new_bh,*dotdot_bh; @@ -1391,8 +1384,6 @@ if (!(old_inode = iget(old_dir->i_sb,old_ino))) goto rename_done; is_dir = S_ISDIR(old_inode->i_mode); - if (must_be_dir && !is_dir) - goto rename_done; if (is_dir) { if ((old_dir->i_dev != new_dir->i_dev) || (old_ino == new_dir->i_ino)) { @@ -1504,7 +1495,6 @@ PRINTK(("vfat_rename 15b\n")); fat_mark_buffer_dirty(sb, new_bh, 1); - dcache_add(new_dir, new_name, new_len, new_ino); /* XXX: There is some code in the original MSDOS rename that * is not duplicated here and it might cause a problem in @@ -1562,7 +1552,6 @@ NULL, /* mknod */ vfat_rename, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ fat_bmap, /* bmap */ @@ -1577,7 +1566,10 @@ } static struct file_system_type vfat_fs_type = { - vfat_read_super, "vfat", 1, NULL + "vfat", + FS_REQUIRES_DEV, + vfat_read_super, + NULL }; EXPORT_SYMBOL(vfat_create); diff -u --recursive --new-file v2.1.42/linux/include/asm-alpha/byteorder.h linux/include/asm-alpha/byteorder.h --- v2.1.42/linux/include/asm-alpha/byteorder.h Thu Nov 14 05:36:13 1996 +++ linux/include/asm-alpha/byteorder.h Thu Jun 12 16:22:09 1997 @@ -14,90 +14,65 @@ #define __LITTLE_ENDIAN_BITFIELD #endif -#ifdef __KERNEL__ - -/* - * In-kernel byte order macros to handle stuff like - * byte-order-dependent filesystems etc. - */ -#define cpu_to_le32(x) (x) -#define le32_to_cpu(x) (x) -#define cpu_to_le16(x) (x) -#define le16_to_cpu(x) (x) - -#define cpu_to_be32(x) htonl((x)) -#define be32_to_cpu(x) ntohl((x)) -#define cpu_to_be16(x) htons((x)) -#define be16_to_cpu(x) ntohs((x)) - -#endif /* __KERNEL__ */ - -extern unsigned long int ntohl(unsigned long int); +extern unsigned int ntohl(unsigned int); extern unsigned short int ntohs(unsigned short int); -extern unsigned long int htonl(unsigned long int); +extern unsigned int htonl(unsigned int); extern unsigned short int htons(unsigned short int); -extern unsigned long int __ntohl(unsigned long int); +extern unsigned int __ntohl(unsigned int); extern unsigned short int __ntohs(unsigned short int); #ifdef __GNUC__ -extern unsigned long int __constant_ntohl(unsigned long int); +extern unsigned int __constant_ntohl(unsigned int); extern unsigned short int __constant_ntohs(unsigned short int); -/* - * The constant and non-constant versions here are the same. - * Maybe I'll come up with an alpha-optimized routine for the - * non-constant ones (the constant ones don't need it: gcc - * will optimize it to the correct constant) - */ - -extern __inline__ unsigned long int -__ntohl(unsigned long int x) +extern __inline__ unsigned int +__ntohl(unsigned int x) { - unsigned long int res, t1, t2; + unsigned int t1, t2, t3; + + /* Break the final or's out of the block so that gcc can + schedule them at will. Further, use add not or so that + we elide the sign extend gcc will put in because the + return type is not a long. */ __asm__( - "# bswap input: %0 (aabbccdd)\n\t" - "# output: %0, used %1 %2\n\t" - "extlh %0,5,%1 # %1 = dd000000\n\t" - "zap %0,0xfd,%2 # %2 = 0000cc00\n\t" - "sll %2,5,%2 # %2 = 00198000\n\t" - "s8addq %2,%1,%1 # %1 = ddcc0000\n\t" - "zap %0,0xfb,%2 # %2 = 00bb0000\n\t" - "srl %2,8,%2 # %2 = 0000bb00\n\t" - "extbl %0,3,%0 # %0 = 000000aa\n\t" - "or %1,%0,%0 # %0 = ddcc00aa\n\t" - "or %2,%0,%0 # %0 = ddccbbaa\n" - : "r="(res), "r="(t1), "r="(t2) - : "0" (x & 0xffffffffUL)); - return res; + "insbl %3,3,%1 # %1 = dd000000\n\t" + "zapnot %3,2,%2 # %2 = 0000cc00\n\t" + "sll %2,8,%2 # %2 = 00cc0000\n\t" + "or %2,%1,%1 # %1 = ddcc0000\n\t" + "zapnot %3,4,%2 # %2 = 00bb0000\n\t" + "extbl %3,3,%0 # %0 = 000000aa\n\t" + "srl %2,8,%2 # %2 = 0000bb00" + : "=r"(t3), "=&r"(t1), "=&r"(t2) + : "r"(x)); + + return t3 + t2 + t1; } #define __constant_ntohl(x) \ - ((unsigned long int)((((x) & 0x000000ffUL) << 24) | \ - (((x) & 0x0000ff00UL) << 8) | \ - (((x) & 0x00ff0000UL) >> 8) | \ - (((x) & 0xff000000UL) >> 24))) + ((unsigned int)((((x) & 0x000000ff) << 24) | \ + (((x) & 0x0000ff00) << 8) | \ + (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0xff000000) >> 24))) extern __inline__ unsigned short int __ntohs(unsigned short int x) { - unsigned long int res, t1; + unsigned short int t1, t2; __asm__( - "# v0 is result; swap in-place.\n\t" - "bis %2,%2,%0 # v0 = aabb\n\t" - "extwh %0,7,%1 # t1 = bb00\n\t" - "extbl %0,1,%0 # v0 = 00aa\n\t" - "bis %0,%1,%0 # v0 = bbaa\n" - : "r="(res), "r="(t1) : "r"(x)); - return res; + "insbl %2,1,%1 # %1 = bb00\n\t" + "extbl %2,1,%0 # %0 = 00aa" + : "=r"(t1), "=&r"(t2) : "r"(x)); + + return t1 | t2; } #define __constant_ntohs(x) \ -((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \ - (((unsigned short int)(x) & 0xff00) >> 8))) +((unsigned short int)((((x) & 0x00ff) << 8) | \ + (((x) & 0xff00) >> 8))) #define __htonl(x) __ntohl(x) #define __htons(x) __ntohs(x) @@ -124,5 +99,70 @@ #endif /* __OPTIMIZE__ */ #endif /* __GNUC__ */ + +#ifdef __KERNEL__ + +/* + * In-kernel byte order macros to handle stuff like + * byte-order-dependent filesystems etc. + */ +#define cpu_to_le32(x) (x) +#define cpu_to_le16(x) (x) + +#define cpu_to_be32(x) htonl((x)) +#define cpu_to_be16(x) htons((x)) + +/* The same, but returns converted value from the location pointer by addr. */ +extern __inline__ __u16 cpu_to_le16p(__u16 *addr) +{ + return cpu_to_le16(*addr); +} + +extern __inline__ __u32 cpu_to_le32p(__u32 *addr) +{ + return cpu_to_le32(*addr); +} + +extern __inline__ __u16 cpu_to_be16p(__u16 *addr) +{ + return cpu_to_be16(*addr); +} + +extern __inline__ __u32 cpu_to_be32p(__u32 *addr) +{ + return cpu_to_be32(*addr); +} + +/* The same, but do the conversion in situ, ie. put the value back to addr. */ +#define cpu_to_le16s(x) do { } while (0) +#define cpu_to_le32s(x) do { } while (0) + +extern __inline__ void cpu_to_be16s(__u16 *addr) +{ + *addr = cpu_to_be16(*addr); +} + +extern __inline__ void cpu_to_be32s(__u32 *addr) +{ + *addr = cpu_to_be32(*addr); +} + +/* Convert from specified byte order, to CPU byte order. */ +#define le16_to_cpu(x) cpu_to_le16(x) +#define le32_to_cpu(x) cpu_to_le32(x) +#define be16_to_cpu(x) cpu_to_be16(x) +#define be32_to_cpu(x) cpu_to_be32(x) + +#define le16_to_cpup(x) cpu_to_le16p(x) +#define le32_to_cpup(x) cpu_to_le32p(x) +#define be16_to_cpup(x) cpu_to_be16p(x) +#define be32_to_cpup(x) cpu_to_be32p(x) + +#define le16_to_cpus(x) cpu_to_le16s(x) +#define le32_to_cpus(x) cpu_to_le32s(x) +#define be16_to_cpus(x) cpu_to_be16s(x) +#define be32_to_cpus(x) cpu_to_be32s(x) + +#endif /* __KERNEL__ */ #endif /* _ALPHA_BYTEORDER_H */ diff -u --recursive --new-file v2.1.42/linux/include/asm-alpha/fpu.h linux/include/asm-alpha/fpu.h --- v2.1.42/linux/include/asm-alpha/fpu.h Thu Dec 21 22:22:06 1995 +++ linux/include/asm-alpha/fpu.h Thu Jun 12 16:22:09 1997 @@ -57,8 +57,28 @@ IEEE_STATUS_OVF | IEEE_STATUS_UNF | \ IEEE_STATUS_INE) +#define IEEE_SW_MASK (IEEE_TRAP_ENABLE_MASK | IEEE_STATUS_MASK) + #define IEEE_STATUS_TO_EXCSUM_SHIFT 16 #define IEEE_INHERIT (1UL<<63) /* inherit on thread create? */ + +/* + * Convert the spftware IEEE trap enable and status bits into the + * hardware fpcr format. + */ + +static inline unsigned long +ieee_swcr_to_fpcr(unsigned long sw) +{ + unsigned long fp; + fp = (sw & IEEE_STATUS_MASK) << 35; + fp |= sw & IEEE_STATUS_MASK ? FPCR_SUM : 0; + fp |= (~sw & (IEEE_TRAP_ENABLE_INV + | IEEE_TRAP_ENABLE_DZE + | IEEE_TRAP_ENABLE_OVF)) << 48; + fp |= (~sw & (IEEE_TRAP_ENABLE_UNF | IEEE_TRAP_ENABLE_INE)) << 57; + return fp; +} #endif /* __ASM_ALPHA_FPU_H */ diff -u --recursive --new-file v2.1.42/linux/include/asm-alpha/keyboard.h linux/include/asm-alpha/keyboard.h --- v2.1.42/linux/include/asm-alpha/keyboard.h Sat May 24 09:10:24 1997 +++ linux/include/asm-alpha/keyboard.h Thu Jun 12 16:22:09 1997 @@ -16,10 +16,6 @@ #define KEYBOARD_IRQ 1 #define DISABLE_KBD_DURING_INTERRUPTS 0 -#define KBD_REPORT_ERR -#define KBD_REPORT_UNKN -/* #define KBD_IS_FOCUS_9000 */ - extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); extern int pckbd_pretranslate(unsigned char scancode, char raw_mode); diff -u --recursive --new-file v2.1.42/linux/include/asm-alpha/namei.h linux/include/asm-alpha/namei.h --- v2.1.42/linux/include/asm-alpha/namei.h Sun Jan 26 02:07:46 1997 +++ linux/include/asm-alpha/namei.h Thu Jun 12 16:22:09 1997 @@ -7,15 +7,12 @@ #ifndef __ALPHA_NAMEI_H #define __ALPHA_NAMEI_H -/* These dummy routines maybe changed to something useful +/* This dummy routine maybe changed to something useful * for /usr/gnemul/ emulation stuff. * Look at asm-sparc/namei.h for details. */ -#define translate_namei(pathname, base, follow_links, res_inode) \ - do { } while (0) - -#define translate_open_namei(pathname, flag, mode, res_inode, base) \ - do { } while (0) +#define __prefix_namei(retrieve_mode, name, base, buf, res_dir, res_inode, \ + last_name, last_entry, last_error) 1 #endif /* __ALPHA_NAMEI_H */ diff -u --recursive --new-file v2.1.42/linux/include/asm-alpha/processor.h linux/include/asm-alpha/processor.h --- v2.1.42/linux/include/asm-alpha/processor.h Tue May 13 22:41:15 1997 +++ linux/include/asm-alpha/processor.h Thu Jun 12 16:22:09 1997 @@ -43,6 +43,7 @@ /* the fields below are Linux-specific: */ /* bit 1..5: IEEE_TRAP_ENABLE bits (see fpu.h) */ /* bit 6..8: UAC bits (see sysinfo.h) */ + /* bit 17..21: IEEE_STATUS_MASK bits (see fpu.h) */ unsigned long flags; /* perform syscall argument validation (get/set_fs) */ unsigned long fs; diff -u --recursive --new-file v2.1.42/linux/include/asm-i386/bugs.h linux/include/asm-i386/bugs.h --- v2.1.42/linux/include/asm-i386/bugs.h Thu Jun 12 15:28:33 1997 +++ linux/include/asm-i386/bugs.h Sun Jun 15 15:12:29 1997 @@ -35,7 +35,7 @@ fpu_error = 1; timer_table[COPRO_TIMER].expires = jiffies+100; timer_active |= 1< - -/* - * In-kernel byte order macros to handle stuff like - * byte-order-dependent filesystems etc. - */ -#define cpu_to_le32(x) (x) -#define le32_to_cpu(x) (x) -#define cpu_to_le16(x) (x) -#define le16_to_cpu(x) (x) - -#define cpu_to_be32(x) htonl((x)) -#define be32_to_cpu(x) ntohl((x)) -#define cpu_to_be16(x) htons((x)) -#define be16_to_cpu(x) ntohs((x)) - #endif extern unsigned long int ntohl(unsigned long int); @@ -101,5 +86,69 @@ __constant_htons((x)) : \ __htons((x))) #endif + +#ifdef __KERNEL__ +/* + * In-kernel byte order macros to handle stuff like + * byte-order-dependent filesystems etc. + */ +#define cpu_to_le32(x) (x) +#define cpu_to_le16(x) (x) + +#define cpu_to_be32(x) htonl((x)) +#define cpu_to_be16(x) htons((x)) + +/* The same, but returns converted value from the location pointer by addr. */ +extern __inline__ __u16 cpu_to_le16p(__u16 *addr) +{ + return cpu_to_le16(*addr); +} + +extern __inline__ __u32 cpu_to_le32p(__u32 *addr) +{ + return cpu_to_le32(*addr); +} + +extern __inline__ __u16 cpu_to_be16p(__u16 *addr) +{ + return cpu_to_be16(*addr); +} + +extern __inline__ __u32 cpu_to_be32p(__u32 *addr) +{ + return cpu_to_be32(*addr); +} + +/* The same, but do the conversion in situ, ie. put the value back to addr. */ +#define cpu_to_le16s(x) do { } while (0) +#define cpu_to_le32s(x) do { } while (0) + +extern __inline__ void cpu_to_be16s(__u16 *addr) +{ + *addr = cpu_to_be16(*addr); +} + +extern __inline__ void cpu_to_be32s(__u32 *addr) +{ + *addr = cpu_to_be32(*addr); +} + +/* Convert from specified byte order, to CPU byte order. */ +#define le16_to_cpu(x) cpu_to_le16(x) +#define le32_to_cpu(x) cpu_to_le32(x) +#define be16_to_cpu(x) cpu_to_be16(x) +#define be32_to_cpu(x) cpu_to_be32(x) + +#define le16_to_cpup(x) cpu_to_le16p(x) +#define le32_to_cpup(x) cpu_to_le32p(x) +#define be16_to_cpup(x) cpu_to_be16p(x) +#define be32_to_cpup(x) cpu_to_be32p(x) + +#define le16_to_cpus(x) cpu_to_le16s(x) +#define le32_to_cpus(x) cpu_to_le32s(x) +#define be16_to_cpus(x) cpu_to_be16s(x) +#define be32_to_cpus(x) cpu_to_be32s(x) + +#endif /* __KERNEL__ */ #endif diff -u --recursive --new-file v2.1.42/linux/include/asm-i386/keyboard.h linux/include/asm-i386/keyboard.h --- v2.1.42/linux/include/asm-i386/keyboard.h Sat May 24 09:10:24 1997 +++ linux/include/asm-i386/keyboard.h Thu Jun 12 16:22:09 1997 @@ -16,10 +16,6 @@ #define KEYBOARD_IRQ 1 #define DISABLE_KBD_DURING_INTERRUPTS 0 -#define KBD_REPORT_ERR -#define KBD_REPORT_UNKN -/* #define KBD_IS_FOCUS_9000 */ - extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); extern int pckbd_pretranslate(unsigned char scancode, char raw_mode); diff -u --recursive --new-file v2.1.42/linux/include/asm-i386/namei.h linux/include/asm-i386/namei.h --- v2.1.42/linux/include/asm-i386/namei.h Sun Jan 26 02:07:46 1997 +++ linux/include/asm-i386/namei.h Thu Jun 12 16:22:09 1997 @@ -7,15 +7,12 @@ #ifndef __I386_NAMEI_H #define __I386_NAMEI_H -/* These dummy routines maybe changed to something useful +/* This dummy routine maybe changed to something useful * for /usr/gnemul/ emulation stuff. * Look at asm-sparc/namei.h for details. */ -#define translate_namei(pathname, base, follow_links, res_inode) \ - do { } while (0) - -#define translate_open_namei(pathname, flag, mode, res_inode, base) \ - do { } while (0) +#define __prefix_namei(retrieve_mode, name, base, buf, res_dir, res_inode, \ + last_name, last_entry, last_error) 1 #endif /* __I386_NAMEI_H */ diff -u --recursive --new-file v2.1.42/linux/include/asm-m68k/byteorder.h linux/include/asm-m68k/byteorder.h --- v2.1.42/linux/include/asm-m68k/byteorder.h Wed Apr 23 19:01:27 1997 +++ linux/include/asm-m68k/byteorder.h Thu Jun 12 16:22:10 1997 @@ -17,13 +17,6 @@ * byte-order-dependent filesystems etc. */ -#define le16_to_cpu(__val) __swab16(__val) -#define cpu_to_le16(__val) __swab16(__val) -#define le32_to_cpu(x) \ -(__builtin_constant_p(x) ? __constant_swab32(x) : __swab32(x)) -#define cpu_to_le32(x) \ -(__builtin_constant_p(x) ? __constant_swab32(x) : __swab32(x)) - extern __inline__ __u16 __swab16 (__u16 val) { return (val << 8) | (val >> 8); @@ -41,10 +34,63 @@ return val; } -#define cpu_to_be32(x) (x) -#define be32_to_cpu(x) (x) -#define cpu_to_be16(x) (x) -#define be16_to_cpu(x) (x) +/* Convert from CPU byte order, to specified byte order. */ +#define cpu_to_le16(__val) __swab16(__val) +#define cpu_to_le32(__val) \ +(__builtin_constant_p(__val) ? __constant_swab32(__val) : __swab32(__val)) +#define cpu_to_be16(x) (x) +#define cpu_to_be32(x) (x) + +/* The same, but returns converted value from the location pointer by addr. */ +extern __inline__ __u16 cpu_to_le16p(__u16 *addr) +{ + return cpu_to_le16(*addr); +} + +extern __inline__ __u32 cpu_to_le32p(__u32 *addr) +{ + return cpu_to_le32(*addr); +} + +extern __inline__ __u16 cpu_to_be16p(__u16 *addr) +{ + return cpu_to_be16(*addr); +} + +extern __inline__ __u32 cpu_to_be32p(__u32 *addr) +{ + return cpu_to_be32(*addr); +} + +/* The same, but do the conversion in situ, ie. put the value back to addr. */ +extern __inline__ void cpu_to_le16s(__u16 *addr) +{ + *addr = cpu_to_le16(*addr); +} + +extern __inline__ void cpu_to_le32s(__u32 *addr) +{ + *addr = cpu_to_le32(*addr); +} + +#define cpu_to_be16s(x) do { } while (0) +#define cpu_to_be32s(x) do { } while (0) + +/* Convert from specified byte order, to CPU byte order. */ +#define le16_to_cpu(x) cpu_to_le16(x) +#define le32_to_cpu(x) cpu_to_le32(x) +#define be16_to_cpu(x) cpu_to_be16(x) +#define be32_to_cpu(x) cpu_to_be32(x) + +#define le16_to_cpup(x) cpu_to_le16p(x) +#define le32_to_cpup(x) cpu_to_le32p(x) +#define be16_to_cpup(x) cpu_to_be16p(x) +#define be32_to_cpup(x) cpu_to_be32p(x) + +#define le16_to_cpus(x) cpu_to_le16s(x) +#define le32_to_cpus(x) cpu_to_le32s(x) +#define be16_to_cpus(x) cpu_to_be16s(x) +#define be32_to_cpus(x) cpu_to_be32s(x) #endif diff -u --recursive --new-file v2.1.42/linux/include/asm-m68k/entry.h linux/include/asm-m68k/entry.h --- v2.1.42/linux/include/asm-m68k/entry.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-m68k/entry.h Thu Jun 12 16:22:10 1997 @@ -0,0 +1,176 @@ +#ifndef __M68K_ENTRY_H +#define __M68K_ENTRY_H + +#include +#include +#ifdef CONFIG_KGDB +#include +#endif + +/* + * Stack layout in 'ret_from_exception': + * + * This allows access to the syscall arguments in registers d1-d5 + * + * 0(sp) - d1 + * 4(sp) - d2 + * 8(sp) - d3 + * C(sp) - d4 + * 10(sp) - d5 + * 14(sp) - a0 + * 18(sp) - a1 + * 1C(sp) - a2 + * 20(sp) - d0 + * 24(sp) - orig_d0 + * 28(sp) - stack adjustment + * 2C(sp) - sr + * 2E(sp) - pc + * 32(sp) - format & vector + */ + +/* + * 97/05/14 Andreas: Register %a2 is now set to the current task throughout + * the whole kernel. + */ + +#ifdef __ASSEMBLY__ + +#define curptr a2 + +/* + * these are offsets into the task-struct + */ +LTASK_STATE = 0 +LTASK_COUNTER = 4 +LTASK_PRIORITY = 8 +LTASK_SIGNAL = 12 +LTASK_BLOCKED = 16 +LTASK_FLAGS = 20 + +LTSS_KSP = 0 +LTSS_USP = 4 +LTSS_SR = 8 +LTSS_FS = 10 +LTSS_CRP = 12 +LTSS_FPCTXT = 24 + +/* the following macro is used when enabling interrupts */ +#if defined(MACH_ATARI_ONLY) + /* block out HSYNC on the atari */ +#define ALLOWINT 0xfbff +#define MAX_NOINT_IPL 3 +#else + /* portable version */ +#define ALLOWINT 0xf8ff +#define MAX_NOINT_IPL 0 +#endif /* machine compilation types */ + +LPT_OFF_D0 = 0x20 +LPT_OFF_ORIG_D0 = 0x24 +LPT_OFF_SR = 0x2C +LPT_OFF_FORMATVEC = 0x32 + +LFLUSH_I_AND_D = 0x00000808 +LENOSYS = 38 +LSIGTRAP = 5 + +LPF_TRACESYS_OFF = 3 +LPF_TRACESYS_BIT = 5 +LPF_PTRACED_OFF = 3 +LPF_PTRACED_BIT = 4 +LPF_DTRACE_OFF = 1 +LPF_DTRACE_BIT = 5 + +/* + * This defines the normal kernel pt-regs layout. + * + * regs a3-a6 and d6-d7 are preserved by C code + * the kernel doesn't mess with usp unless it needs to + */ +#ifndef CONFIG_KGDB +/* + * a -1 in the orig_d0 field signifies + * that the stack frame is NOT for syscall + */ +#define SAVE_ALL_INT \ + clrl %sp@-; /* stk_adj */ \ + pea -1:w; /* orig d0 */ \ + movel %d0,%sp@-; /* d0 */ \ + moveml %d1-%d5/%a0-%a1/%curptr,%sp@- + +#define SAVE_ALL_SYS \ + clrl %sp@-; /* stk_adj */ \ + movel %d0,%sp@-; /* orig d0 */ \ + movel %d0,%sp@-; /* d0 */ \ + moveml %d1-%d5/%a0-%a1/%curptr,%sp@- +#else +/* Need to save the "missing" registers for kgdb... + */ +#define SAVE_ALL_INT \ + clrl %sp@-; /* stk_adj */ \ + pea -1:w; /* orig d0 */ \ + movel %d0,%sp@-; /* d0 */ \ + moveml %d1-%d5/%a0-%a1/%curptr,%sp@-; \ + moveml %d6-%d7,kgdb_registers+GDBOFFA_D6; \ + moveml %a3-%a6,kgdb_registers+GDBOFFA_A3 + +#define SAVE_ALL_SYS \ + clrl %sp@-; /* stk_adj */ \ + movel %d0,%sp@-; /* orig d0 */ \ + movel %d0,%sp@-; /* d0 */ \ + moveml %d1-%d5/%a0-%a1/%curptr,%sp@-; \ + moveml %d6-%d7,kgdb_registers+GDBOFFA_D6; \ + moveml %a3-%a6,kgdb_registers+GDBOFFA_A3 +#endif + +#define RESTORE_ALL \ + moveml %sp@+,%a0-%a1/%curptr/%d1-%d5; \ + movel %sp@+,%d0; \ + addql #4,%sp; /* orig d0 */ \ + addl %sp@+,%sp; /* stk adj */ \ + rte + +#define SWITCH_STACK_SIZE (6*4+4) /* includes return address */ + +#define SAVE_SWITCH_STACK \ + moveml %a3-%a6/%d6-%d7,%sp@- + +#define RESTORE_SWITCH_STACK \ + moveml %sp@+,%a3-%a6/%d6-%d7 + +#define GET_CURRENT(tmp) \ + movel %sp,tmp; \ + andw &-8192,tmp; \ + movel tmp,%curptr; + +#else /* C source */ + +#define STR(X) STR1(X) +#define STR1(X) #X + +#define PT_OFF_ORIG_D0 0x24 +#define PT_OFF_FORMATVEC 0x32 +#define PT_OFF_SR 0x2C +#ifndef CONFIG_KGDB +#define SAVE_ALL_INT \ + "clrl %%sp@-;" /* stk_adj */ \ + "pea -1:w;" /* orig d0 = -1 */ \ + "movel %%d0,%%sp@-;" /* d0 */ \ + "moveml %%d1-%%d5/%%a0-%%a2,%%sp@-" +#else +#define SAVE_ALL_INT \ + "clrl %%sp@-\n\t" /* stk_adj */ \ + "pea -1:w\n\t" /* orig d0 = -1 */ \ + "movel %%d0,%%sp@-\n\t" /* d0 */ \ + "moveml %%d1-%%d5/%%a0-%%a2,%%sp@-\n\t" \ + "moveml %%d6-%%d7,kgdb_registers+"STR(GDBOFFA_D6)"\n\t" \ + "moveml %%a3-%%a6,kgdb_registers+"STR(GDBOFFA_A3) +#endif +#define GET_CURRENT(tmp) \ + "movel %%sp,"#tmp"\n\t" \ + "andw #-8192,"#tmp"\n\t" \ + "movel "#tmp",%%a2" + +#endif + +#endif /* __M68K_ENTRY_H */ diff -u --recursive --new-file v2.1.42/linux/include/asm-m68k/namei.h linux/include/asm-m68k/namei.h --- v2.1.42/linux/include/asm-m68k/namei.h Tue May 13 22:41:17 1997 +++ linux/include/asm-m68k/namei.h Thu Jun 12 16:22:10 1997 @@ -7,15 +7,12 @@ #ifndef __M68K_NAMEI_H #define __M68K_NAMEI_H -/* These dummy routines maybe changed to something useful +/* This dummy routine maybe changed to something useful * for /usr/gnemul/ emulation stuff. * Look at asm-sparc/namei.h for details. */ -#define translate_namei(pathname, base, follow_links, res_inode) \ - do { } while (0) - -#define translate_open_namei(pathname, flag, mode, res_inode, base) \ - do { } while (0) +#define __prefix_namei(retrieve_mode, name, base, buf, res_dir, res_inode, \ + last_name, last_entry, last_error) 1 #endif diff -u --recursive --new-file v2.1.42/linux/include/asm-m68k/semaphore.h linux/include/asm-m68k/semaphore.h --- v2.1.42/linux/include/asm-m68k/semaphore.h Sat May 24 09:10:24 1997 +++ linux/include/asm-m68k/semaphore.h Thu Jun 12 16:22:10 1997 @@ -20,8 +20,8 @@ struct wait_queue * wait; }; -#define MUTEX ((struct semaphore) { { 1 }, { 0 }, NULL }) -#define MUTEX_LOCKED ((struct semaphore) { { 0 }, { 0 }, NULL }) +#define MUTEX ((struct semaphore) { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL }) +#define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL }) asmlinkage void __down_failed(void /* special register calling convention */); asmlinkage int __down_failed_interruptible(void /* params in registers */); @@ -73,7 +73,7 @@ * "down_failed" is a special asm handler that calls the C * routine that actually waits. See arch/m68k/lib/semaphore.S */ -extern inline void do_down(struct semaphore * sem, void (*failed)(void)) +extern inline void down(struct semaphore * sem) { register struct semaphore *sem1 __asm__ ("%a1") = sem; __asm__ __volatile__( @@ -84,15 +84,34 @@ ".section .text.lock,\"ax\"\n" ".even\n" "2:\tpea 1b\n\t" - "jbra %1\n" + "jbra __down_failed\n" ".previous" : /* no outputs */ - : "a" (sem1), "m" (*(unsigned char *)failed) + : "a" (sem1) : "memory"); } -#define down(sem) do_down((sem),__down_failed) -#define down_interruptible(sem) do_down((sem),__down_failed_interruptible) +extern inline int down_interruptible(struct semaphore * sem) +{ + register struct semaphore *sem1 __asm__ ("%a1") = sem; + register int result __asm__ ("%d0"); + + __asm__ __volatile__( + "| atomic interruptible down operation\n\t" + "subql #1,%1@\n\t" + "jmi 2f\n\t" + "clrl %0\n" + "1:\n" + ".section .text.lock,\"ax\"\n" + ".even\n" + "2:\tpea 1b\n\t" + "jbra __down_failed_interruptible\n" + ".previous" + : "=d" (result) + : "a" (sem1) + : "%d0", "memory"); + return result; +} /* * Note! This is subtle. We jump to wake people up only if @@ -111,10 +130,10 @@ ".section .text.lock,\"ax\"\n" ".even\n" "2:\tpea 1b\n\t" - "jbra %1\n" + "jbra __up_wakeup\n" ".previous" : /* no outputs */ - : "a" (sem1), "m" (*(unsigned char *)__up_wakeup) + : "a" (sem1) : "memory"); } diff -u --recursive --new-file v2.1.42/linux/include/asm-mips/keyboard.h linux/include/asm-mips/keyboard.h --- v2.1.42/linux/include/asm-mips/keyboard.h Sat May 24 09:10:25 1997 +++ linux/include/asm-mips/keyboard.h Thu Jun 12 16:22:10 1997 @@ -16,10 +16,6 @@ #define KEYBOARD_IRQ 1 #define DISABLE_KBD_DURING_INTERRUPTS 0 -#define KBD_REPORT_ERR -#define KBD_REPORT_UNKN -/* #define KBD_IS_FOCUS_9000 */ - extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); extern int pckbd_pretranslate(unsigned char scancode, char raw_mode); diff -u --recursive --new-file v2.1.42/linux/include/asm-ppc/byteorder.h linux/include/asm-ppc/byteorder.h --- v2.1.42/linux/include/asm-ppc/byteorder.h Wed Dec 18 00:54:09 1996 +++ linux/include/asm-ppc/byteorder.h Thu Jun 12 16:22:10 1997 @@ -19,38 +19,72 @@ #define __constant_htonl(x) ntohl(x) #define __constant_htons(x) ntohs(x) -/* - * In-kernel byte order macros to handle stuff like - * byte-order-dependent filesystems etc. - */ +#ifdef __KERNEL__ -#define cpu_to_le32(x) le32_to_cpu((x)) -extern __inline__ unsigned long le32_to_cpu(unsigned long x) +/* Convert from CPU byte order, to specified byte order. */ +extern __inline__ __u16 cpu_to_le16(__u16 value) { - return (((x & 0x000000ffU) << 24) | - ((x & 0x0000ff00U) << 8) | - ((x & 0x00ff0000U) >> 8) | - ((x & 0xff000000U) >> 24)); + return (value >> 8) | (value << 8); } - -#define cpu_to_le16(x) le16_to_cpu((x)) -extern __inline__ unsigned short le16_to_cpu(unsigned short x) +extern __inline__ __u32 cpu_to_le32(__u32 value) { - return (((x & 0x00ff) << 8) | - ((x & 0xff00) >> 8)); + return((value>>24) | ((value>>8)&0xff00) | + ((value<<8)&0xff0000) | (value<<24)); } +#define cpu_to_be16(x) (x) +#define cpu_to_be32(x) (x) -#define cpu_to_be32(x) (x) -#define be32_to_cpu(x) (x) -#define cpu_to_be16(x) (x) -#define be16_to_cpu(x) (x) +/* The same, but returns converted value from the location pointer by addr. */ +extern __inline__ __u16 cpu_to_le16p(__u16 *addr) +{ + return cpu_to_le16(*addr); +} +extern __inline__ __u32 cpu_to_le32p(__u32 *addr) +{ + return cpu_to_le32(*addr); +} -#endif /* !(_PPC_BYTEORDER_H) */ +extern __inline__ __u16 cpu_to_be16p(__u16 *addr) +{ + return cpu_to_be16(*addr); +} +extern __inline__ __u32 cpu_to_be32p(__u32 *addr) +{ + return cpu_to_be32(*addr); +} +/* The same, but do the conversion in situ, ie. put the value back to addr. */ +extern __inline__ void cpu_to_le16s(__u16 *addr) +{ + *addr = cpu_to_le16(*addr); +} +extern __inline__ void cpu_to_le32s(__u32 *addr) +{ + *addr = cpu_to_le32(*addr); +} +#define cpu_to_be16s(x) do { } while (0) +#define cpu_to_be32s(x) do { } while (0) +/* Convert from specified byte order, to CPU byte order. */ +#define le16_to_cpu(x) cpu_to_le16(x) +#define le32_to_cpu(x) cpu_to_le32(x) +#define be16_to_cpu(x) cpu_to_be16(x) +#define be32_to_cpu(x) cpu_to_be32(x) + +#define le16_to_cpup(x) cpu_to_le16p(x) +#define le32_to_cpup(x) cpu_to_le32p(x) +#define be16_to_cpup(x) cpu_to_be16p(x) +#define be32_to_cpup(x) cpu_to_be32p(x) + +#define le16_to_cpus(x) cpu_to_le16s(x) +#define le32_to_cpus(x) cpu_to_le32s(x) +#define be16_to_cpus(x) cpu_to_be16s(x) +#define be32_to_cpus(x) cpu_to_be32s(x) +#endif /* __KERNEL__ */ +#endif /* !(_PPC_BYTEORDER_H) */ diff -u --recursive --new-file v2.1.42/linux/include/asm-ppc/keyboard.h linux/include/asm-ppc/keyboard.h --- v2.1.42/linux/include/asm-ppc/keyboard.h Sat May 24 09:10:25 1997 +++ linux/include/asm-ppc/keyboard.h Thu Jun 12 16:22:10 1997 @@ -16,10 +16,6 @@ #define KEYBOARD_IRQ 1 #define DISABLE_KBD_DURING_INTERRUPTS 0 -#define KBD_REPORT_ERR -#define KBD_REPORT_UNKN -/* #define KBD_IS_FOCUS_9000 */ - extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); extern int pckbd_pretranslate(unsigned char scancode, char raw_mode); diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc/byteorder.h linux/include/asm-sparc/byteorder.h --- v2.1.42/linux/include/asm-sparc/byteorder.h Thu May 29 21:53:09 1997 +++ linux/include/asm-sparc/byteorder.h Thu Jun 12 16:22:10 1997 @@ -1,4 +1,4 @@ -/* $Id: byteorder.h,v 1.13 1997/05/26 23:37:46 davem Exp $ */ +/* $Id: byteorder.h,v 1.14 1997/05/28 11:35:38 jj Exp $ */ #ifndef _SPARC_BYTEORDER_H #define _SPARC_BYTEORDER_H @@ -37,19 +37,56 @@ #define cpu_to_be16(x) (x) #define cpu_to_be32(x) (x) -/* Convert from specified byte order, to CPU byte order. */ -extern __inline__ __u16 le16_to_cpu(__u16 value) +/* The same, but returns converted value from the location pointer by addr. */ +extern __inline__ __u16 cpu_to_le16p(__u16 *addr) { - return (value >> 8) | (value << 8); + return cpu_to_le16(*addr); } -extern __inline__ __u32 le32_to_cpu(__u32 value) +extern __inline__ __u32 cpu_to_le32p(__u32 *addr) { - return((value>>24) | ((value>>8)&0xff00) | - ((value<<8)&0xff0000) | (value<<24)); + return cpu_to_le32(*addr); +} + +extern __inline__ __u16 cpu_to_be16p(__u16 *addr) +{ + return cpu_to_be16(*addr); +} + +extern __inline__ __u32 cpu_to_be32p(__u32 *addr) +{ + return cpu_to_be32(*addr); } -#define be16_to_cpu(x) (x) -#define be32_to_cpu(x) (x) + +/* The same, but do the conversion in situ, ie. put the value back to addr. */ +extern __inline__ void cpu_to_le16s(__u16 *addr) +{ + *addr = cpu_to_le16(*addr); +} + +extern __inline__ void cpu_to_le32s(__u32 *addr) +{ + *addr = cpu_to_le32(*addr); +} + +#define cpu_to_be16s(x) do { } while (0) +#define cpu_to_be32s(x) do { } while (0) + +/* Convert from specified byte order, to CPU byte order. */ +#define le16_to_cpu(x) cpu_to_le16(x) +#define le32_to_cpu(x) cpu_to_le32(x) +#define be16_to_cpu(x) cpu_to_be16(x) +#define be32_to_cpu(x) cpu_to_be32(x) + +#define le16_to_cpup(x) cpu_to_le16p(x) +#define le32_to_cpup(x) cpu_to_le32p(x) +#define be16_to_cpup(x) cpu_to_be16p(x) +#define be32_to_cpup(x) cpu_to_be32p(x) + +#define le16_to_cpus(x) cpu_to_le16s(x) +#define le32_to_cpus(x) cpu_to_le32s(x) +#define be16_to_cpus(x) cpu_to_be16s(x) +#define be32_to_cpus(x) cpu_to_be32s(x) #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc/namei.h linux/include/asm-sparc/namei.h --- v2.1.42/linux/include/asm-sparc/namei.h Mon Jan 27 00:42:54 1997 +++ linux/include/asm-sparc/namei.h Thu Jun 12 16:22:10 1997 @@ -1,4 +1,4 @@ -/* $Id: namei.h,v 1.3 1997/01/26 23:36:36 davem Exp $ +/* $Id: namei.h,v 1.5 1997/06/07 08:32:54 ecd Exp $ * linux/include/asm-sparc/namei.h * * Routines to handle famous /usr/gnemul/s*. @@ -11,44 +11,37 @@ #define SPARC_BSD_EMUL "usr/gnemul/sunos/" #define SPARC_SOL_EMUL "usr/gnemul/solaris/" -#define translate_namei(pathname, base, follow_links, res_inode) ({ \ - if ((current->personality & (PER_BSD|PER_SVR4)) && !base && *pathname == '/') { \ - struct inode *emul_ino; \ - int namelen; \ - const char *name; \ - \ - while (*pathname == '/') \ - pathname++; \ - current->fs->root->i_count++; \ - if (dir_namei (current->personality & PER_BSD ? SPARC_BSD_EMUL : SPARC_SOL_EMUL, \ - &namelen, &name, current->fs->root, &emul_ino) >= 0 && emul_ino) { \ - *res_inode = NULL; \ - if (_namei (pathname, emul_ino, follow_links, res_inode) >= 0 && *res_inode) \ - return 0; \ - } \ - base = current->fs->root; \ - base->i_count++; \ - } \ -}) - -#define translate_open_namei(pathname, flag, mode, res_inode, base) ({ \ - if ((current->personality & (PER_BSD|PER_SVR4)) && !base && *pathname == '/') { \ - struct inode *emul_ino; \ - int namelen; \ - const char *name; \ - \ - while (*pathname == '/') \ - pathname++; \ - current->fs->root->i_count++; \ - if (dir_namei (current->personality & PER_BSD ? SPARC_BSD_EMUL : SPARC_SOL_EMUL, \ - &namelen, &name, current->fs->root, &emul_ino) >= 0 && emul_ino) { \ - *res_inode = NULL; \ - if (open_namei (pathname, flag, mode, res_inode, emul_ino) >= 0 && *res_inode) \ - return 0; \ - } \ - base = current->fs->root; \ - base->i_count++; \ - } \ -}) +extern int __namei(int, const char *, struct inode *, char *, struct inode **, + struct inode **, struct qstr *, struct dentry **, int *); + +static __inline__ int +__prefix_namei(int retrieve_mode, const char * name, struct inode * base, + char * buf, struct inode ** res_dir, struct inode ** res_inode, + struct qstr * last_name, struct dentry ** last_entry, + int * last_error) +{ + int error; + + if (!(current->personality & (PER_BSD|PER_SVR4))) + return -ENOENT; + + while (*name == '/') + name++; + + atomic_inc(¤t->fs->root->i_count); + error = __namei(NAM_FOLLOW_LINK, + current->personality & PER_BSD ? + SPARC_BSD_EMUL : SPARC_SOL_EMUL, current->fs->root, + buf, NULL, &base, NULL, NULL, NULL); + if (error) + return error; + + error = __namei(retrieve_mode, name, base, buf, res_dir, res_inode, + last_name, last_entry, last_error); + if (error) + return error; + + return 0; +} #endif /* __SPARC_NAMEI_H */ diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc/spinlock.h linux/include/asm-sparc/spinlock.h --- v2.1.42/linux/include/asm-sparc/spinlock.h Thu May 15 16:48:04 1997 +++ linux/include/asm-sparc/spinlock.h Thu Jun 12 16:22:10 1997 @@ -56,7 +56,7 @@ #include /* Define this to use the verbose/debugging versions in arch/sparc/lib/debuglocks.c */ -#define SPIN_LOCK_DEBUG +/* #define SPIN_LOCK_DEBUG */ #ifdef SPIN_LOCK_DEBUG struct _spinlock_debug { diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc64/bitops.h linux/include/asm-sparc64/bitops.h --- v2.1.42/linux/include/asm-sparc64/bitops.h Thu May 29 21:53:09 1997 +++ linux/include/asm-sparc64/bitops.h Thu Jun 12 16:22:10 1997 @@ -1,4 +1,4 @@ -/* $Id: bitops.h,v 1.13 1997/05/27 06:47:16 davem Exp $ +/* $Id: bitops.h,v 1.16 1997/05/28 13:48:56 jj Exp $ * bitops.h: Bit string operations on the V9. * * Copyright 1996 David S. Miller (davem@caip.rutgers.edu) @@ -121,11 +121,33 @@ : "0" (word) : "g1", "g2"); #else +#ifdef EASY_CHEESE_VERSION result = 0; while(word & 1) { result++; word >>= 1; } +#else + unsigned long tmp; + + result = 0; + tmp = ~word & -~word; + if (!(unsigned)tmp) { + tmp >>= 32; + result = 32; + } + if (!(unsigned short)tmp) { + tmp >>= 16; + result += 16; + } + if (!(unsigned char)tmp) { + tmp >>= 8; + result += 8; + } + if (tmp & 0xf0) result += 4; + if (tmp & 0xcc) result += 2; + if (tmp & 0xaa) result ++; +#endif #endif return result; } @@ -137,29 +159,31 @@ extern __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset) { - unsigned long *p = ((unsigned long *) addr) + (offset >> 5); - unsigned long result = offset & ~31UL; + unsigned long *p = ((unsigned long *) addr) + (offset >> 6); + unsigned long result = offset & ~63UL; unsigned long tmp; if (offset >= size) return size; size -= result; - offset &= 31UL; + offset &= 63UL; if (offset) { tmp = *(p++); - tmp |= ~0UL >> (32-offset); - if (size < 32) + tmp |= ~0UL >> (64-offset); + if (size < 64) goto found_first; if (~tmp) goto found_middle; - size -= 32; - result += 32; + size -= 64; + result += 64; } - while (size & ~31UL) { + offset = size >> 6; + size &= 63UL; + while (offset) { if (~(tmp = *(p++))) goto found_middle; - result += 32; - size -= 32; + result += 64; + offset--; } if (!size) return result; @@ -248,9 +272,16 @@ ((value<<56) & 0xff00000000000000)); } +extern __inline__ unsigned long __swab64p(unsigned long *addr) +{ + unsigned long ret; + __asm__ __volatile__ ("ldxa [%1] %2, %0" : "=r" (ret) : "r" (addr), "i" (ASI_PL)); + return ret; +} + extern __inline__ unsigned long find_next_zero_le_bit(void *addr, unsigned long size, unsigned long offset) { - unsigned long *p = ((unsigned long *) addr) + (offset >> 5); + unsigned long *p = ((unsigned long *) addr) + (offset >> 6); unsigned long result = offset & ~63UL; unsigned long tmp; @@ -259,8 +290,8 @@ size -= result; offset &= 63UL; if(offset) { - tmp = *(p++); - tmp |= __swab64((~0UL >> (64-offset))); + tmp = __swab64p(p++); + tmp |= (~0UL >> (64-offset)); if(size < 64) goto found_first; if(~tmp) @@ -268,20 +299,21 @@ size -= 64; result += 64; } - while(size & ~63UL) { - if(~(tmp = *(p++))) + offset = size >> 6; + size &= 63UL; + while(offset) { + if(~(tmp = __swab64p(p++))) goto found_middle; result += 64; - size -= 64; + offset--; } if(!size) return result; - tmp = *p; - + tmp = __swab64p(p); found_first: - return result + ffz(__swab64(tmp) | (~0UL << size)); + tmp |= (~0UL << size); found_middle: - return result + ffz(__swab64(tmp)); + return result + ffz(tmp); } #ifdef __KERNEL__ diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc64/byteorder.h linux/include/asm-sparc64/byteorder.h --- v2.1.42/linux/include/asm-sparc64/byteorder.h Thu May 29 21:53:09 1997 +++ linux/include/asm-sparc64/byteorder.h Thu Jun 12 16:22:10 1997 @@ -1,7 +1,9 @@ -/* $Id: byteorder.h,v 1.4 1997/05/26 23:37:47 davem Exp $ */ +/* $Id: byteorder.h,v 1.5 1997/05/28 11:35:41 jj Exp $ */ #ifndef _SPARC64_BYTEORDER_H #define _SPARC64_BYTEORDER_H +#include + #define ntohl(x) ((unsigned long int)(x)) #define ntohs(x) ((unsigned short int)(x)) #define htonl(x) ((unsigned long int)(x)) @@ -34,22 +36,87 @@ return((value>>24) | ((value>>8)&0xff00) | ((value<<8)&0xff0000) | (value<<24)); } + +extern __inline__ __u64 cpu_to_le64(__u64 value) +{ + return (((value>>56) & 0x00000000000000ffUL) | + ((value>>40) & 0x000000000000ff00UL) | + ((value>>24) & 0x0000000000ff0000UL) | + ((value>>8) & 0x00000000ff000000UL) | + ((value<<8) & 0x000000ff00000000UL) | + ((value<<24) & 0x0000ff0000000000UL) | + ((value<<40) & 0x00ff000000000000UL) | + ((value<<56) & 0xff00000000000000UL)); +} #define cpu_to_be16(x) (x) #define cpu_to_be32(x) (x) +#define cpu_to_be64(x) (x) -/* Convert from specified byte order, to CPU byte order. */ -extern __inline__ __u16 le16_to_cpu(__u16 value) +/* The same, but returns converted value from the location pointer by addr. */ +extern __inline__ __u16 cpu_to_le16p(__u16 *addr) { - return (value >> 8) | (value << 8); + __u16 ret; + __asm__ __volatile__ ("lduha [%1] %2, %0" : "=r" (ret) : "r" (addr), "i" (ASI_PL)); + return ret; } -extern __inline__ __u32 le32_to_cpu(__u32 value) +extern __inline__ __u32 cpu_to_le32p(__u32 *addr) { - return((value>>24) | ((value>>8)&0xff00) | - ((value<<8)&0xff0000) | (value<<24)); + __u32 ret; + __asm__ __volatile__ ("lduwa [%1] %2, %0" : "=r" (ret) : "r" (addr), "i" (ASI_PL)); + return ret; +} + +extern __inline__ __u64 cpu_to_le64p(__u64 *addr) +{ + __u64 ret; + __asm__ __volatile__ ("ldxa [%1] %2, %0" : "=r" (ret) : "r" (addr), "i" (ASI_PL)); + return ret; } -#define be16_to_cpu(x) (x) -#define be32_to_cpu(x) (x) +extern __inline__ __u16 cpu_to_be16p(__u16 *addr) { return *addr; } +extern __inline__ __u32 cpu_to_be32p(__u32 *addr) { return *addr; } +extern __inline__ __u64 cpu_to_be64p(__u64 *addr) { return *addr; } + +/* The same, but do the conversion in situ, ie. put the value back to addr. */ +extern __inline__ void cpu_to_le16s(__u16 *addr) +{ + *addr = cpu_to_le16p(addr); +} + +extern __inline__ void cpu_to_le32s(__u32 *addr) +{ + *addr = cpu_to_le32p(addr); +} + +extern __inline__ void cpu_to_le64s(__u64 *addr) +{ + *addr = cpu_to_le64p(addr); +} +#define cpu_to_be16s(x) do { } while (0) +#define cpu_to_be32s(x) do { } while (0) +#define cpu_to_be64s(x) do { } while (0) + +/* Convert from specified byte order, to CPU byte order. */ +#define le16_to_cpu(x) cpu_to_le16(x) +#define le32_to_cpu(x) cpu_to_le32(x) +#define le64_to_cpu(x) cpu_to_le64(x) +#define be16_to_cpu(x) cpu_to_be16(x) +#define be32_to_cpu(x) cpu_to_be32(x) +#define be64_to_cpu(x) cpu_to_be64(x) + +#define le16_to_cpup(x) cpu_to_le16p(x) +#define le32_to_cpup(x) cpu_to_le32p(x) +#define le64_to_cpup(x) cpu_to_le64p(x) +#define be16_to_cpup(x) cpu_to_be16p(x) +#define be32_to_cpup(x) cpu_to_be32p(x) +#define be64_to_cpup(x) cpu_to_be64p(x) + +#define le16_to_cpus(x) cpu_to_le16s(x) +#define le32_to_cpus(x) cpu_to_le32s(x) +#define le64_to_cpus(x) cpu_to_le64s(x) +#define be16_to_cpus(x) cpu_to_be16s(x) +#define be32_to_cpus(x) cpu_to_be32s(x) +#define be64_to_cpus(x) cpu_to_be64s(x) #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc64/checksum.h linux/include/asm-sparc64/checksum.h --- v2.1.42/linux/include/asm-sparc64/checksum.h Thu May 15 16:48:04 1997 +++ linux/include/asm-sparc64/checksum.h Thu Jun 12 16:22:10 1997 @@ -1,4 +1,4 @@ -/* $Id: checksum.h,v 1.7 1997/05/14 07:02:44 davem Exp $ */ +/* $Id: checksum.h,v 1.8 1997/05/29 12:45:03 jj Exp $ */ #ifndef __SPARC64_CHECKSUM_H #define __SPARC64_CHECKSUM_H @@ -41,7 +41,7 @@ #define csum_partial_copy(src, dst, len, sum) \ csum_partial_copy_nocheck(src,dst,len,sum) #define csum_partial_copy_fromuser(s, d, l, w) \ - csum_partial_copy((char *) (s), (d), (l), (w)) + csum_partial_copy_from_user((char *) (s), (d), (l), (w), NULL) extern __inline__ unsigned int csum_partial_copy_nocheck (const char *src, char *dst, int len, @@ -50,12 +50,13 @@ register unsigned long ret asm("o0") = (unsigned long)src; register char *d asm("o1") = dst; register unsigned long l asm("g1") = len; - + __asm__ __volatile__ (" + wr %%g0, %5, %%asi call __csum_partial_copy_sparc_generic mov %4, %%g7 srl %%o0, 0, %%o0 - " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (sum) : + " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (sum), "i" (ASI_P) : "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7"); return (unsigned int)ret; } @@ -64,58 +65,35 @@ csum_partial_copy_from_user(const char *src, char *dst, int len, unsigned int sum, int *err) { - if (!access_ok (VERIFY_READ, src, len)) { - *err = -EFAULT; - memset (dst, 0, len); - return sum; - } else { - register unsigned long ret asm("o0") = (unsigned long)src; - register char *d asm("o1") = dst; - register unsigned long l asm("g1") = len; - register unsigned long s asm("g7") = sum; - - __asm__ __volatile__ (" - .section __ex_table,#alloc - .align 4 - .word 1f,2 - .previous + register unsigned long ret asm("o0") = (unsigned long)src; + register char *d asm("o1") = dst; + register unsigned long l asm("g1") = len; + register unsigned long s asm("g7") = sum; + + __asm__ __volatile__ (" + .section __ex_table,#alloc + .align 8 + .xword 1f,2 + .previous + wr %%g0, %6, %%asi 1: - call __csum_partial_copy_sparc_generic - stx %5, [%%sp + 0x7ff + 128] - srl %%o0, 0, %%o0 - " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (s), "r" (err) : - "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7"); - return (unsigned int)ret; - } + call __csum_partial_copy_sparc_generic + stx %5, [%%sp + 0x7ff + 128] + srl %%o0, 0, %%o0 + " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (s), "r" (err), "i" (ASI_S) : + "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7"); + return (unsigned int)ret; } - + +#if 0 +/* Not implemented, but nobody uses it yet... */ extern __inline__ unsigned int csum_partial_copy_to_user(const char *src, char *dst, int len, unsigned int sum, int *err) { - if (!access_ok (VERIFY_WRITE, dst, len)) { - *err = -EFAULT; - return sum; - } else { - register unsigned long ret asm("o0") = (unsigned long)src; - register char *d asm("o1") = dst; - register unsigned long l asm("g1") = len; - register unsigned long s asm("g7") = sum; - - __asm__ __volatile__ (" - .section __ex_table,#alloc - .align 4 - .word 1f,1 - .previous -1: - call __csum_partial_copy_sparc_generic - stx %5, [%%sp + 0x7ff + 128] - srl %%o0, 0, %%o0 - " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (s), "r" (err) : - "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7"); - return (unsigned int)ret; - } + return 0; } +#endif /* ihl is always 5 or greater, almost always is 5, and iph is word aligned * the majority of the time. diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc64/fpumacro.h linux/include/asm-sparc64/fpumacro.h --- v2.1.42/linux/include/asm-sparc64/fpumacro.h Mon Apr 14 16:28:22 1997 +++ linux/include/asm-sparc64/fpumacro.h Thu Jun 12 16:22:10 1997 @@ -1,12 +1,27 @@ /* fpumacro.h: FPU related macros. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) */ #ifndef _SPARC64_FPUMACRO_H #define _SPARC64_FPUMACRO_H -extern __inline__ void fpsave32(unsigned long *fpregs, unsigned long *fsr) +extern __inline__ unsigned long fprs_read(void) +{ + unsigned long retval; + + __asm__ __volatile__("rd %%fprs, %0" : "=r" (retval)); + + return retval; +} + +extern __inline__ void fprs_write(unsigned long val) +{ + __asm__ __volatile__("wr %0, 0x0, %%fprs" : : "r" (val)); +} + +extern __inline__ void fpsave32(unsigned int *fpregs, unsigned long *fsr) { __asm__ __volatile__ (" wr %%g0, %2, %%asi @@ -16,7 +31,7 @@ " : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P)); } -extern __inline__ void fpload32(unsigned long *fpregs, unsigned long *fsr) +extern __inline__ void fpload32(unsigned int *fpregs, unsigned long *fsr) { __asm__ __volatile__ (" wr %%g0, %2, %%asi @@ -26,7 +41,27 @@ " : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P)); } -extern __inline__ void fpsave(unsigned long *fpregs, unsigned long *fsr) +extern __inline__ void fpsave64hi(unsigned int *fpregs, unsigned long *fsr) +{ + __asm__ __volatile__ (" + wr %%g0, %2, %%asi + stx %%fsr, [%1] + stda %%f32, [%0 + 128] %%asi + stda %%f48, [%0 + 192] %%asi + " : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P)); +} + +extern __inline__ void fpload64hi(unsigned int *fpregs, unsigned long *fsr) +{ + __asm__ __volatile__ (" + wr %%g0, %2, %%asi + ldda [%0 + 128] %%asi, %%f32 + ldda [%0 + 192] %%asi, %%f48 + ldx [%1], %%fsr + " : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P)); +} + +extern __inline__ void fpsave(unsigned int *fpregs, unsigned long *fsr) { __asm__ __volatile__ (" wr %%g0, %2, %%asi @@ -38,7 +73,7 @@ " : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P)); } -extern __inline__ void fpload(unsigned long *fpregs, unsigned long *fsr) +extern __inline__ void fpload(unsigned int *fpregs, unsigned long *fsr) { __asm__ __volatile__ (" wr %%g0, %2, %%asi diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc64/head.h linux/include/asm-sparc64/head.h --- v2.1.42/linux/include/asm-sparc64/head.h Thu May 29 21:53:09 1997 +++ linux/include/asm-sparc64/head.h Thu Jun 12 16:22:10 1997 @@ -1,4 +1,4 @@ -/* $Id: head.h,v 1.21 1997/05/27 06:28:17 davem Exp $ */ +/* $Id: head.h,v 1.22 1997/06/02 06:33:40 davem Exp $ */ #ifndef _SPARC64_HEAD_H #define _SPARC64_HEAD_H @@ -9,12 +9,13 @@ /* We need a "cleaned" instruction... */ #define CLEAN_WINDOW \ + rdpr %cleanwin, %l0; add %l0, 1, %l0; \ + wrpr %l0, 0x0, %cleanwin; \ clr %o0; clr %o1; clr %o2; clr %o3; \ clr %o4; clr %o5; clr %o6; clr %o7; \ clr %l0; clr %l1; clr %l2; clr %l3; \ clr %l4; clr %l5; clr %l6; clr %l7; \ - rdpr %cleanwin, %g1; add %g1, 1, %g1; \ - wrpr %g1, 0x0, %cleanwin; retry; \ + retry; \ nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop; #define TRAP(routine) \ @@ -23,7 +24,7 @@ call routine; \ add %sp, STACK_BIAS + REGWIN_SZ, %o0; \ ba,pt %xcc, rtrap; \ - nop; \ + clr %l6; \ nop; \ nop; @@ -38,7 +39,7 @@ call routine; \ add %sp, STACK_BIAS + REGWIN_SZ, %o0; \ ba,pt %xcc, rtrap; \ - nop; \ + clr %l6; \ nop; \ nop; @@ -60,7 +61,7 @@ call routine; \ mov arg, %o1; \ ba,pt %xcc, rtrap; \ - nop; \ + clr %l6; \ nop; #define TRAPTL1_ARG(routine, arg) \ @@ -70,7 +71,7 @@ call routine; \ mov arg, %o1; \ ba,pt %xcc, rtrap; \ - nop; \ + clr %l6; \ nop; #define SYSCALL_TRAP(routine, systbl) \ @@ -89,7 +90,7 @@ call routine; \ add %sp, STACK_BIAS + REGWIN_SZ, %o0; \ ba,pt %xcc, rtrap; \ - nop; + clr %l6; #define ACCESS_EXCEPTION_TRAPTL1(routine) \ rdpr %pstate, %g1; \ @@ -99,7 +100,7 @@ call routine; \ add %sp, STACK_BIAS + REGWIN_SZ, %o0; \ ba,pt %xcc, rtrap; \ - nop; + clr %l6; #define SUNOS_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sunos_sys_table) #define LINUX_32BIT_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sys_call_table32) @@ -120,7 +121,7 @@ mov level, %o0; \ call routine; \ add %sp, STACK_BIAS + REGWIN_SZ, %o1; \ - ba,a,pt %xcc, rtrap; + ba,a,pt %xcc, rtrap_clr_l6; /* On UP this is ok, and worth the effort, for SMP we need * a different mechanism and thus cannot do it all in trap table. -DaveM @@ -150,7 +151,7 @@ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1; \ add %l1, 4, %l2; \ stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]; \ - ba,pt %xcc, rtrap; \ + ba,pt %xcc, rtrap_clr_l6; \ stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]; /* Before touching these macros, you owe it to yourself to go and @@ -198,7 +199,8 @@ stxa %i6, [%sp + STACK_BIAS + 0x70] %asi; \ stxa %i7, [%sp + STACK_BIAS + 0x78] %asi; \ saved; retry; nop; nop; nop; nop; nop; nop; \ - nop; nop; nop; nop; nop; nop; \ + nop; nop; nop; nop; nop; \ + b,a,pt %xcc, spill_fixup_mna; \ b,a,pt %xcc, spill_fixup; /* Normal 32bit spill */ @@ -215,7 +217,8 @@ stda %i6, [%sp + 0x38] %asi; \ saved; retry; nop; nop; nop; nop; \ nop; nop; nop; nop; nop; nop; nop; nop; \ - nop; nop; nop; nop; nop; nop; nop; \ + nop; nop; nop; nop; nop; nop; \ + b,a,pt %xcc, spill_fixup_mna; \ b,a,pt %xcc, spill_fixup; #define SPILL_1_NORMAL SPILL_1_GENERIC(ASI_AIUP) @@ -276,7 +279,8 @@ ldxa [%sp + STACK_BIAS + 0x70] %asi, %i6; \ ldxa [%sp + STACK_BIAS + 0x78] %asi, %i7; \ restored; retry; nop; nop; nop; nop; nop; nop; \ - nop; nop; nop; nop; nop; nop; \ + nop; nop; nop; nop; nop; \ + b,a,pt %xcc, fill_fixup_mna; \ b,a,pt %xcc, fill_fixup; /* Normal 32bit fill */ @@ -293,7 +297,8 @@ ldda [%sp + 0x38] %asi, %i6; \ restored; retry; nop; nop; nop; nop; \ nop; nop; nop; nop; nop; nop; nop; nop; \ - nop; nop; nop; nop; nop; nop; nop; \ + nop; nop; nop; nop; nop; nop; \ + b,a,pt %xcc, fill_fixup_mna; \ b,a,pt %xcc, fill_fixup; #define FILL_1_NORMAL FILL_1_GENERIC(ASI_AIUP) diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc64/namei.h linux/include/asm-sparc64/namei.h --- v2.1.42/linux/include/asm-sparc64/namei.h Mon Apr 14 16:28:23 1997 +++ linux/include/asm-sparc64/namei.h Thu Jun 12 16:22:10 1997 @@ -1,4 +1,4 @@ -/* $Id: namei.h,v 1.2 1997/03/19 17:28:27 jj Exp $ +/* $Id: namei.h,v 1.4 1997/06/07 08:32:56 ecd Exp $ * linux/include/asm-sparc64/namei.h * * Routines to handle famous /usr/gnemul/s*. @@ -11,44 +11,37 @@ #define SPARC_BSD_EMUL "usr/gnemul/sunos/" #define SPARC_SOL_EMUL "usr/gnemul/solaris/" -#define translate_namei(pathname, base, follow_links, res_inode) ({ \ - if ((current->personality & (PER_BSD|PER_SVR4)) && !base && *pathname == '/') { \ - struct inode *emul_ino; \ - int namelen; \ - const char *name; \ - \ - while (*pathname == '/') \ - pathname++; \ - current->fs->root->i_count++; \ - if (dir_namei (current->personality & PER_BSD ? SPARC_BSD_EMUL : SPARC_SOL_EMUL, \ - &namelen, &name, current->fs->root, &emul_ino) >= 0 && emul_ino) { \ - *res_inode = NULL; \ - if (_namei (pathname, emul_ino, follow_links, res_inode) >= 0 && *res_inode) \ - return 0; \ - } \ - base = current->fs->root; \ - base->i_count++; \ - } \ -}) - -#define translate_open_namei(pathname, flag, mode, res_inode, base) ({ \ - if ((current->personality & (PER_BSD|PER_SVR4)) && !base && *pathname == '/') { \ - struct inode *emul_ino; \ - int namelen; \ - const char *name; \ - \ - while (*pathname == '/') \ - pathname++; \ - current->fs->root->i_count++; \ - if (dir_namei (current->personality & PER_BSD ? SPARC_BSD_EMUL : SPARC_SOL_EMUL, \ - &namelen, &name, current->fs->root, &emul_ino) >= 0 && emul_ino) { \ - *res_inode = NULL; \ - if (open_namei (pathname, flag, mode, res_inode, emul_ino) >= 0 && *res_inode) \ - return 0; \ - } \ - base = current->fs->root; \ - base->i_count++; \ - } \ -}) +extern int __namei(int, const char *, struct inode *, char *, struct inode **, + struct inode **, struct qstr *, struct dentry **, int *); + +static inline int +__prefix_namei(int retrieve_mode, const char * name, struct inode * base, + char * buf, struct inode ** res_dir, struct inode ** res_inode, + struct qstr * last_name, struct dentry ** last_entry, + int * last_error) +{ + int error; + + if (!(current->personality & (PER_BSD|PER_SVR4))) + return -ENOENT; + + while (*name == '/') + name++; + + atomic_inc(¤t->fs->root->i_count); + error = __namei(NAM_FOLLOW_LINK, + current->personality & PER_BSD ? + SPARC_BSD_EMUL : SPARC_SOL_EMUL, current->fs->root, + buf, NULL, &base, NULL, NULL, NULL); + if (error) + return error; + + error = __namei(retrieve_mode, name, base, buf, res_dir, res_inode, + last_name, last_entry, last_error); + if (error) + return error; + + return 0; +} #endif /* __SPARC64_NAMEI_H */ diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h --- v2.1.42/linux/include/asm-sparc64/pgtable.h Thu May 29 21:53:09 1997 +++ linux/include/asm-sparc64/pgtable.h Thu Jun 12 16:22:10 1997 @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.32 1997/05/26 23:39:20 davem Exp $ +/* $Id: pgtable.h,v 1.34 1997/06/02 06:33:41 davem Exp $ * pgtable.h: SpitFire page table operations. * * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -160,45 +160,6 @@ /* Cache and TLB flush operations. */ -/* This is a bit tricky to do most efficiently. The I-CACHE on the - * SpitFire will snoop stores from _other_ processors and changes done - * by DMA, but it does _not_ snoop stores on the local processor. - * Also, even if the I-CACHE snoops the store from someone else correctly, - * you can still lose if the instructions are in the pipeline already. - * A big issue is that this cache is only 16K in size, using a pseudo - * 2-set associative scheme. A full flush of the cache is far too much - * for me to accept, especially since most of the time when we get to - * running this code the icache data we want to flush is not even in - * the cache. Thus the following seems to be the best method. - */ -extern __inline__ void spitfire_flush_icache_page(unsigned long page) -{ - unsigned long temp; - - /* Commit all potential local stores to the instruction space - * on this processor before the flush. - */ - membar("#StoreStore"); - - /* Actually perform the flush. */ - __asm__ __volatile__(" -1: - flush %0 + 0x00 - flush %0 + 0x08 - flush %0 + 0x10 - flush %0 + 0x18 - flush %0 + 0x20 - flush %0 + 0x28 - flush %0 + 0x30 - flush %0 + 0x38 - subcc %1, 0x40, %1 - bge,pt %%icc, 1b - add %2, %1, %0 -" : "=&r" (page), "=&r" (temp) - : "r" (page), "0" (page + PAGE_SIZE - 0x40), "1" (PAGE_SIZE - 0x40) - : "cc"); -} - extern __inline__ void flush_cache_all(void) { unsigned long addr; @@ -283,13 +244,14 @@ 1: stxa %%g0, [%%g3] %3 stxa %%g0, [%%g3] %4 - bne,a,pn %%icc, 1f - stxa %%g2, [%%g7] %2 + be,a,pt %%icc, 1f + nop + stxa %%g2, [%%g7] %2 1: flush %%g4 wrpr %%g1, 0x0, %%pil " : /* no outputs */ - : "r" (mm->context), "i" (SECONDARY_CONTEXT), "i" (ASI_DMMU), + : "r" (mm->context & 0x1fff), "i" (SECONDARY_CONTEXT), "i" (ASI_DMMU), "i" (ASI_DMMU_DEMAP), "i" (ASI_IMMU_DEMAP) : "g1", "g2", "g3", "g7", "cc"); } @@ -300,7 +262,7 @@ { if(mm->context != NO_CONTEXT) { unsigned long old_ctx = spitfire_get_secondary_context(); - unsigned long new_ctx = mm->context; + unsigned long new_ctx = (mm->context & 0x1fff); unsigned long flags; start &= PAGE_MASK; @@ -332,22 +294,20 @@ ldxa [%%g7] %2, %%g2 cmp %%g2, %0 be,pt %%icc, 1f - or %5, 0x10, %5 + or %5, 0x10, %%g3 stxa %0, [%%g7] %2 1: - stxa %%g0, [%5] %3 - brnz,a %6, 1f - stxa %%g0, [%5] %4 -1: - bne,a,pn %%icc, 1f - stxa %%g2, [%%g7] %2 + stxa %%g0, [%%g3] %3 + stxa %%g0, [%%g3] %4 + be,a,pt %%icc, 1f + nop + stxa %%g2, [%%g7] %2 1: flush %%g4 wrpr %%g1, 0x0, %%pil " : /* no outputs */ - : "r" (mm->context), "i" (SECONDARY_CONTEXT), "i" (ASI_DMMU), - "i" (ASI_DMMU_DEMAP), "i" (ASI_IMMU_DEMAP), "r" (page & PAGE_MASK), - "r" (vma->vm_flags & VM_EXEC) + : "r" (mm->context & 0x1fff), "i" (SECONDARY_CONTEXT), "i" (ASI_DMMU), + "i" (ASI_DMMU_DEMAP), "i" (ASI_IMMU_DEMAP), "r" (page & PAGE_MASK) : "g1", "g2", "g3", "g7", "cc"); } } diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc64/psrcompat.h linux/include/asm-sparc64/psrcompat.h --- v2.1.42/linux/include/asm-sparc64/psrcompat.h Mon Apr 14 16:28:23 1997 +++ linux/include/asm-sparc64/psrcompat.h Thu Jun 12 16:22:10 1997 @@ -1,4 +1,4 @@ -/* $Id: psrcompat.h,v 1.2 1997/04/07 18:57:17 jj Exp $ */ +/* $Id: psrcompat.h,v 1.3 1997/06/05 06:22:54 davem Exp $ */ #ifndef _SPARC64_PSRCOMPAT_H #define _SPARC64_PSRCOMPAT_H @@ -47,7 +47,7 @@ { unsigned long tstate; - tstate = (psr & PSR_ICC) << 12; + tstate = ((unsigned long)(psr & PSR_ICC)) << 12; return tstate; } diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc64/pstate.h linux/include/asm-sparc64/pstate.h --- v2.1.42/linux/include/asm-sparc64/pstate.h Mon Apr 14 16:28:23 1997 +++ linux/include/asm-sparc64/pstate.h Thu Jun 12 16:22:10 1997 @@ -1,4 +1,4 @@ -/* $Id: pstate.h,v 1.3 1997/03/25 03:58:31 davem Exp $ */ +/* $Id: pstate.h,v 1.4 1997/05/29 12:45:02 jj Exp $ */ #ifndef _SPARC64_PSTATE_H #define _SPARC64_PSTATE_H @@ -78,5 +78,33 @@ #define VERS_MASK 0x00000000ff000000 /* Mask Set Revision. */ #define VERS_MAXTL 0x000000000000ff00 /* Maximum Trap Level. */ #define VERS_MAXWIN 0x000000000000001f /* Maximum Reg Window Index. */ + +#if defined(__KERNEL__) && !defined(__ASSEMBLY__) +#define set_pstate(bits) \ + __asm__ __volatile__( \ + "rdpr %%pstate, %%g1\n\t" \ + "or %%g1, %0, %%g1\n\t" \ + "wrpr %%g1, 0x0, %%pstate\n\t" \ + : /* no outputs */ \ + : "i" (bits) \ + : "g1") + +#define clear_pstate(bits) \ + __asm__ __volatile__( \ + "rdpr %%pstate, %%g1\n\t" \ + "andn %%g1, %0, %%g1\n\t" \ + "wrpr %%g1, 0x0, %%pstate\n\t" \ + : /* no outputs */ \ + : "i" (bits) \ + : "g1") + +#define change_pstate(bits) \ + __asm__ __volatile__( \ + "rdpr %%pstate, %%g1\n\t" \ + "wrpr %%g1, %0, %%pstate\n\t" \ + : /* no outputs */ \ + : "i" (bits) \ + : "g1") +#endif #endif /* !(_SPARC64_PSTATE_H) */ diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc64/system.h linux/include/asm-sparc64/system.h --- v2.1.42/linux/include/asm-sparc64/system.h Sat May 24 09:10:25 1997 +++ linux/include/asm-sparc64/system.h Thu Jun 12 16:22:10 1997 @@ -1,4 +1,4 @@ -/* $Id: system.h,v 1.19 1997/05/18 22:52:32 davem Exp $ */ +/* $Id: system.h,v 1.22 1997/06/01 10:27:28 davem Exp $ */ #ifndef __SPARC64_SYSTEM_H #define __SPARC64_SYSTEM_H @@ -114,16 +114,24 @@ #define flush_user_windows flushw_user #ifdef __SMP__ -#error SMP not supported on sparc64 + +#include + +#define SWITCH_ENTER(prev) \ + if((prev)->flags & PF_USEDFPU) { \ + fprs_write(FPRS_FEF); \ + fpsave((unsigned long *) &(prev)->tss.float_regs[0], \ + &(prev)->tss.fsr); \ + (prev)->flags &= ~PF_USEDFPU; \ + (prev)->tss.kregs->tstate &= ~TSTATE_PEF; \ + } + +#define SWITCH_DO_LAZY_FPU(next) #else -#if 0 +#define SWITCH_ENTER(prev) #define SWITCH_DO_LAZY_FPU(next) \ if(last_task_used_math != (next)) \ - (next)->tss.kregs->tstate&=~TSTATE_PEF -#else -/* XXX FIX ME BIG TIME XXX -DaveM */ -#define SWITCH_DO_LAZY_FPU(next) do { } while(0) -#endif + (next)->tss.kregs->tstate &= ~TSTATE_PEF #endif /* See what happens when you design the chip correctly? @@ -138,29 +146,33 @@ do { \ __label__ switch_continue; \ register unsigned long task_pc asm("o7"); \ + SWITCH_ENTER(prev) \ SWITCH_DO_LAZY_FPU(next); \ task_pc = ((unsigned long) &&switch_continue) - 0x8; \ __asm__ __volatile__( \ + "rdpr %%pstate, %%g2\n\t" \ + "wrpr %%g2, 0x2, %%pstate\n\t" \ "flushw\n\t" \ "stx %%i6, [%%sp + 2047 + 0x70]\n\t" \ "stx %%i7, [%%sp + 2047 + 0x78]\n\t" \ - "stx %%o6, [%%g6 + %3]\n\t" \ "rdpr %%wstate, %%o5\n\t" \ - "stx %%o7, [%%g6 + %4]\n\t" \ + "stx %%o6, [%%g6 + %3]\n\t" \ "stx %%o5, [%%g6 + %2]\n\t" \ "rdpr %%cwp, %%o5\n\t" \ + "stx %%o7, [%%g6 + %4]\n\t" \ "stx %%o5, [%%g6 + %5]\n\t" \ "mov %0, %%g6\n\t" \ + "ldx [%0 + %5], %%g1\n\t" \ "wr %0, 0x0, %%pic\n\t" \ - "ldx [%%g6 + %5], %%g1\n\t" \ "wrpr %%g1, %%cwp\n\t" \ "ldx [%%g6 + %2], %%o5\n\t" \ "ldx [%%g6 + %3], %%o6\n\t" \ "ldx [%%g6 + %4], %%o7\n\t" \ "wrpr %%o5, 0x0, %%wstate\n\t" \ "ldx [%%sp + 2047 + 0x70], %%i6\n\t" \ + "ldx [%%sp + 2047 + 0x78], %%i7\n\t" \ "jmpl %%o7 + 0x8, %%g0\n\t" \ - " ldx [%%sp + 2047 + 0x78], %%i7\n\t" \ + " wrpr %%g2, 0x0, %%pstate\n\t" \ : /* No outputs */ \ : "r" (next), "r" (task_pc), \ "i" ((const unsigned long)(&((struct task_struct *)0)->tss.wstate)), \ diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc64/uaccess.h linux/include/asm-sparc64/uaccess.h --- v2.1.42/linux/include/asm-sparc64/uaccess.h Mon Apr 14 16:28:24 1997 +++ linux/include/asm-sparc64/uaccess.h Thu Jun 12 16:22:10 1997 @@ -1,4 +1,4 @@ -/* $Id: uaccess.h,v 1.12 1997/04/10 23:32:50 davem Exp $ */ +/* $Id: uaccess.h,v 1.13 1997/05/29 12:45:04 jj Exp $ */ #ifndef _ASM_UACCESS_H #define _ASM_UACCESS_H @@ -151,8 +151,8 @@ " mov %3, %0\n\n\t" \ ".previous\n\t" \ ".section __ex_table,#alloc\n\t" \ - ".align 4\n\t" \ - ".word 1b, 3b\n\t" \ + ".align 8\n\t" \ + ".xword 1b, 3b\n\t" \ ".previous\n\n\t" \ : "=r" (ret) : "r" (x), "r" (__m(addr)), \ "i" (-EFAULT), "i" (ASI_S)) @@ -163,8 +163,8 @@ "/* Put user asm ret, inline. */\n" \ "1:\t" "st"#size "a %1, [%2] %3\n\n\t" \ ".section __ex_table,#alloc\n\t" \ - ".align 4\n\t" \ - ".word 1b, __ret_efault\n\n\t" \ + ".align 8\n\t" \ + ".xword 1b, __ret_efault\n\n\t" \ ".previous\n\n\t" \ : "=r" (foo) : "r" (x), "r" (__m(addr)), "i" (ASI_S)); \ else \ @@ -178,8 +178,8 @@ " restore %%g0, %3, %%o0\n\n\t" \ ".previous\n\t" \ ".section __ex_table,#alloc\n\t" \ - ".align 4\n\t" \ - ".word 1b, 3b\n\n\t" \ + ".align 8\n\t" \ + ".xword 1b, 3b\n\n\t" \ ".previous\n\n\t" \ : "=r" (foo) : "r" (x), "r" (__m(addr)), \ "i" (ret), "i" (ASI_S)) @@ -221,8 +221,8 @@ " mov %3, %0\n\n\t" \ ".previous\n\t" \ ".section __ex_table,#alloc\n\t" \ - ".align 4\n\t" \ - ".word 1b, 3b\n\n\t" \ + ".align 8\n\t" \ + ".xword 1b, 3b\n\n\t" \ ".previous\n\t" \ : "=r" (ret), "=r" (x) : "r" (__m(addr)), \ "i" (-EFAULT), "i" (ASI_S)) @@ -233,8 +233,8 @@ "/* Get user asm ret, inline. */\n" \ "1:\t" "ld"#size "a [%1] %2, %0\n\n\t" \ ".section __ex_table,#alloc\n\t" \ - ".align 4\n\t" \ - ".word 1b,__ret_efault\n\n\t" \ + ".align 8\n\t" \ + ".xword 1b,__ret_efault\n\n\t" \ ".previous\n\t" \ : "=r" (x) : "r" (__m(addr)), "i" (ASI_S)); \ else \ @@ -248,8 +248,8 @@ " restore %%g0, %3, %%o0\n\n\t" \ ".previous\n\t" \ ".section __ex_table,#alloc\n\t" \ - ".align 4\n\t" \ - ".word 1b, 3b\n\n\t" \ + ".align 8\n\t" \ + ".xword 1b, 3b\n\n\t" \ ".previous\n\t" \ : "=r" (x) : "r" (__m(addr)), "i" (retval), "i" (ASI_S)) @@ -291,8 +291,8 @@ __kernel_size_t ret; __asm__ __volatile__ (" .section __ex_table,#alloc - .align 4 - .word 1f,3 + .align 8 + .xword 1f,3 .previous 1: wr %%g0, %3, %%asi diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc64/vuid_event.h linux/include/asm-sparc64/vuid_event.h --- v2.1.42/linux/include/asm-sparc64/vuid_event.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/vuid_event.h Thu Jun 12 16:22:10 1997 @@ -5,8 +5,6 @@ unsigned char pair_type; /* unused by X11 */ unsigned char pair; /* unused by X11 */ int value; /* VKEY_UP, VKEY_DOWN or delta */ - - /* XXX Timeval could hose old 32-bit programs, investigate and fixme XXX */ struct timeval time; } Firm_event; diff -u --recursive --new-file v2.1.42/linux/include/linux/affs_fs.h linux/include/linux/affs_fs.h --- v2.1.42/linux/include/linux/affs_fs.h Tue May 13 22:41:18 1997 +++ linux/include/linux/affs_fs.h Thu Jun 12 16:22:10 1997 @@ -69,8 +69,7 @@ extern int affs_symlink(struct inode *dir, const char *name, int len, const char *symname); extern int affs_rename(struct inode *old_dir, const char *old_name, int old_len, - struct inode *new_dir, const char *new_name, int new_len, - int must_be_dir); + struct inode *new_dir, const char *new_name, int new_len); /* inode.c */ diff -u --recursive --new-file v2.1.42/linux/include/linux/atalk.h linux/include/linux/atalk.h --- v2.1.42/linux/include/linux/atalk.h Thu Jun 12 15:29:21 1997 +++ linux/include/linux/atalk.h Sun Jun 15 15:13:16 1997 @@ -17,6 +17,8 @@ #define ATADDR_BCAST (__u8)255 #define DDP_MAXSZ 587 +#define SIOCATALKDIFADDR (SIOCPROTOPRIVATE + 0) + struct at_addr { __u16 s_net; diff -u --recursive --new-file v2.1.42/linux/include/linux/binfmts.h linux/include/linux/binfmts.h --- v2.1.42/linux/include/linux/binfmts.h Mon Apr 14 16:28:25 1997 +++ linux/include/linux/binfmts.h Thu Jun 12 16:22:10 1997 @@ -53,6 +53,7 @@ extern int init_script_binfmt(void); extern int init_java_binfmt(void); extern int init_em86_binfmt(void); +extern int init_misc_binfmt(void); extern int prepare_binprm(struct linux_binprm *); extern void remove_arg_zero(struct linux_binprm *); diff -u --recursive --new-file v2.1.42/linux/include/linux/console_struct.h linux/include/linux/console_struct.h --- v2.1.42/linux/include/linux/console_struct.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/console_struct.h Thu Jun 12 16:22:10 1997 @@ -0,0 +1,142 @@ +/* + * console_struct.h + * + * Data structure and defines shared between console.c, vga.c and tga.c + */ + +#define NPAR 16 + +struct vc_data { + unsigned long vc_screenbuf_size; + unsigned short vc_video_erase_char; /* Background erase character */ + unsigned char vc_attr; /* Current attributes */ + unsigned char vc_def_color; /* Default colors */ + unsigned char vc_color; /* Foreground & background */ + unsigned char vc_s_color; /* Saved foreground & background */ + unsigned char vc_ulcolor; /* Colour for underline mode */ + unsigned char vc_halfcolor; /* Colour for half intensity mode */ + unsigned long vc_origin; /* Used for EGA/VGA fast scroll */ + unsigned long vc_scr_end; /* Used for EGA/VGA fast scroll */ + unsigned long vc_pos; + unsigned long vc_x,vc_y; + unsigned long vc_top,vc_bottom; + unsigned long vc_state; + unsigned long vc_npar,vc_par[NPAR]; + unsigned long vc_video_mem_start; /* Start of video RAM */ + unsigned long vc_video_mem_end; /* End of video RAM (sort of) */ + unsigned long vc_saved_x; + unsigned long vc_saved_y; + /* mode flags */ + unsigned long vc_charset : 1; /* Character set G0 / G1 */ + unsigned long vc_s_charset : 1; /* Saved character set */ + unsigned long vc_disp_ctrl : 1; /* Display chars < 32? */ + unsigned long vc_toggle_meta : 1; /* Toggle high bit? */ + unsigned long vc_decscnm : 1; /* Screen Mode */ + unsigned long vc_decom : 1; /* Origin Mode */ + unsigned long vc_decawm : 1; /* Autowrap Mode */ + unsigned long vc_deccm : 1; /* Cursor Visible */ + unsigned long vc_decim : 1; /* Insert Mode */ + unsigned long vc_deccolm : 1; /* 80/132 Column Mode */ + /* attribute flags */ + unsigned long vc_intensity : 2; /* 0=half-bright, 1=normal, 2=bold */ + unsigned long vc_underline : 1; + unsigned long vc_blink : 1; + unsigned long vc_reverse : 1; + unsigned long vc_s_intensity : 2; /* saved rendition */ + unsigned long vc_s_underline : 1; + unsigned long vc_s_blink : 1; + unsigned long vc_s_reverse : 1; + /* misc */ + unsigned long vc_ques : 1; + unsigned long vc_need_wrap : 1; + unsigned long vc_can_do_color : 1; + unsigned long vc_has_scrolled : 1; /* Info for unblank_screen */ + unsigned long vc_kmalloced : 1; /* kfree_s() needed */ + unsigned long vc_report_mouse : 2; + unsigned char vc_utf : 1; /* Unicode UTF-8 encoding */ + unsigned char vc_utf_count; + long vc_utf_char; + unsigned long vc_tab_stop[5]; /* Tab stops. 160 columns. */ + unsigned char vc_palette[16*3]; /* Colour palette for VGA+ */ + unsigned short * vc_translate; + unsigned char vc_G0_charset; + unsigned char vc_G1_charset; + unsigned char vc_saved_G0; + unsigned char vc_saved_G1; + unsigned int vc_bell_pitch; /* Console bell pitch */ + unsigned int vc_bell_duration; /* Console bell duration */ + /* additional information is in vt_kern.h */ +}; + +struct vc { + struct vc_data *d; + + /* might add scrmem, vt_struct, kbd at some time, + to have everything in one place - the disadvantage + would be that vc_cons etc can no longer be static */ +}; + +extern struct vc vc_cons [MAX_NR_CONSOLES]; + +#define screenbuf_size (vc_cons[currcons].d->vc_screenbuf_size) +#define origin (vc_cons[currcons].d->vc_origin) +#define scr_end (vc_cons[currcons].d->vc_scr_end) +#define pos (vc_cons[currcons].d->vc_pos) +#define top (vc_cons[currcons].d->vc_top) +#define bottom (vc_cons[currcons].d->vc_bottom) +#define x (vc_cons[currcons].d->vc_x) +#define y (vc_cons[currcons].d->vc_y) +#define vc_state (vc_cons[currcons].d->vc_state) +#define npar (vc_cons[currcons].d->vc_npar) +#define par (vc_cons[currcons].d->vc_par) +#define ques (vc_cons[currcons].d->vc_ques) +#define attr (vc_cons[currcons].d->vc_attr) +#define saved_x (vc_cons[currcons].d->vc_saved_x) +#define saved_y (vc_cons[currcons].d->vc_saved_y) +#define translate (vc_cons[currcons].d->vc_translate) +#define G0_charset (vc_cons[currcons].d->vc_G0_charset) +#define G1_charset (vc_cons[currcons].d->vc_G1_charset) +#define saved_G0 (vc_cons[currcons].d->vc_saved_G0) +#define saved_G1 (vc_cons[currcons].d->vc_saved_G1) +#define utf (vc_cons[currcons].d->vc_utf) +#define utf_count (vc_cons[currcons].d->vc_utf_count) +#define utf_char (vc_cons[currcons].d->vc_utf_char) +#define video_mem_start (vc_cons[currcons].d->vc_video_mem_start) +#define video_mem_end (vc_cons[currcons].d->vc_video_mem_end) +#define video_erase_char (vc_cons[currcons].d->vc_video_erase_char) +#define disp_ctrl (vc_cons[currcons].d->vc_disp_ctrl) +#define toggle_meta (vc_cons[currcons].d->vc_toggle_meta) +#define decscnm (vc_cons[currcons].d->vc_decscnm) +#define decom (vc_cons[currcons].d->vc_decom) +#define decawm (vc_cons[currcons].d->vc_decawm) +#define deccm (vc_cons[currcons].d->vc_deccm) +#define decim (vc_cons[currcons].d->vc_decim) +#define deccolm (vc_cons[currcons].d->vc_deccolm) +#define need_wrap (vc_cons[currcons].d->vc_need_wrap) +#define has_scrolled (vc_cons[currcons].d->vc_has_scrolled) +#define kmalloced (vc_cons[currcons].d->vc_kmalloced) +#define report_mouse (vc_cons[currcons].d->vc_report_mouse) +#define color (vc_cons[currcons].d->vc_color) +#define s_color (vc_cons[currcons].d->vc_s_color) +#define def_color (vc_cons[currcons].d->vc_def_color) +#define foreground (color & 0x0f) +#define background (color & 0xf0) +#define charset (vc_cons[currcons].d->vc_charset) +#define s_charset (vc_cons[currcons].d->vc_s_charset) +#define intensity (vc_cons[currcons].d->vc_intensity) +#define underline (vc_cons[currcons].d->vc_underline) +#define blink (vc_cons[currcons].d->vc_blink) +#define reverse (vc_cons[currcons].d->vc_reverse) +#define s_intensity (vc_cons[currcons].d->vc_s_intensity) +#define s_underline (vc_cons[currcons].d->vc_s_underline) +#define s_blink (vc_cons[currcons].d->vc_s_blink) +#define s_reverse (vc_cons[currcons].d->vc_s_reverse) +#define ulcolor (vc_cons[currcons].d->vc_ulcolor) +#define halfcolor (vc_cons[currcons].d->vc_halfcolor) +#define tab_stop (vc_cons[currcons].d->vc_tab_stop) +#define palette (vc_cons[currcons].d->vc_palette) +#define bell_pitch (vc_cons[currcons].d->vc_bell_pitch) +#define bell_duration (vc_cons[currcons].d->vc_bell_duration) + +#define vcmode (vt_cons[currcons]->vc_mode) +#define structsize (sizeof(struct vc_data) + sizeof(struct vt_struct)) diff -u --recursive --new-file v2.1.42/linux/include/linux/consolemap.h linux/include/linux/consolemap.h --- v2.1.42/linux/include/linux/consolemap.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/consolemap.h Thu Jun 12 16:22:10 1997 @@ -0,0 +1,14 @@ +/* + * consolemap.h + * + * Interface between console.c, selection.c and consolemap.c + */ +#define LAT1_MAP 0 +#define GRAF_MAP 1 +#define IBMPC_MAP 2 +#define USER_MAP 3 + +extern int hashtable_contents_valid; +extern unsigned char inverse_translate(int glyph); +extern unsigned short *set_translate(int m); +extern int conv_uni_to_pc(long ucs); diff -u --recursive --new-file v2.1.42/linux/include/linux/dalloc.h linux/include/linux/dalloc.h --- v2.1.42/linux/include/linux/dalloc.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/dalloc.h Thu Jun 12 21:53:45 1997 @@ -0,0 +1,102 @@ +#ifndef DALLOC_H +#define DALLOC_H +/* + * $Id: dalloc.h,v 1.3 1997/06/13 04:39:34 davem Exp $ + * + * include/linux/dalloc.h - alloc routines for dcache + * alloc / free space for pathname strings + * Copyright (C) 1997, Thomas Schoebel-Theuer, + * . + */ + +#define D_MAXLEN 1024 + +/* public flags for d_add() */ +#define D_NORMAL 0 +#define D_BASKET 1 /* put into basket (deleted/unref'd files) */ +#define D_DUPLICATE 2 /* allow duplicate entries */ +#define D_NOCHECKDUP 4 /* no not check for duplicates */ + +/* public flags for d_flag */ +#define D_PRELOADED 8 + +/* public flags for d_del() */ +#define D_REMOVE 0 +#define D_NO_CLEAR_INODE 1 + +#define IS_ROOT(x) ((x) == (x)->d_parent) + +struct dentry { + union { + struct inode * d_inode; /* Where the name belongs to */ + unsigned long d_ino; /* for preliminary entries */ + } u; + struct dentry * d_parent; /* parent directory */ + struct dentry * d_next; /* hardlink aliasname / empty list */ + struct dentry * d_prev; /* hardlink aliasname */ + struct dentry * d_hash_next; + struct dentry * d_hash_prev; + struct dentry * d_basket_next; + struct dentry * d_basket_prev; + short d_len; /* set by dalloc() */ + short d_flag; + char d_name[D_MAXLEN]; +}; + +/* "quick string" -- I introduced this to shorten the parameter list + * of many routines. Think of it as a (str,stlen) pair. + * Storing the len instead of doing strlen() very often is performance + * critical. + */ +struct qstr { + const char * name; + int len; +}; + +extern struct dentry * the_root; + +/* Note that all these routines must be called with vfs_lock() held */ + +/* get inode, if necessary retrieve it with iget() */ +extern blocking struct inode * d_inode(struct dentry ** changing_entry); + +/* allocate proper space for the len */ +extern struct dentry * d_alloc(struct dentry * parent, int len, int isdir); + +/* only used once at mount_root() */ +extern blocking +struct dentry * d_alloc_root(struct inode * root_inode); + +/* d_inode is connected with inode, and d_name is copied from ininame. + * either of them may be NULL, but when ininame is NULL, dname must be + * set by the caller prior to calling this. */ +extern blocking +void d_add(struct dentry * entry, struct inode * inode, + struct qstr * ininame, int flags); + +/* combination of d_alloc() and d_add(), less lookup overhead */ +extern blocking +struct dentry * d_entry(struct dentry * parent, struct qstr * name, struct inode * inode); +extern blocking +void d_entry_preliminary(struct dentry * parent, struct qstr * name, unsigned long ino); + +/* recursive d_del() all successors */ +extern blocking +void d_del(struct dentry * entry, int flags); + +/* used for rename() and baskets */ +extern blocking +void d_move(struct dentry * entry, struct inode * newdir, + struct qstr * newname, struct qstr * newapp); + +/* appendix may either be NULL or be used for transname suffixes */ +extern struct dentry * d_lookup(struct inode * dir, struct qstr * name, + struct qstr * appendix); + +/* write full pathname into buffer and return length */ +extern int d_path(struct dentry * entry, struct inode * chroot, char * buf); + +extern struct dentry * d_basket(struct dentry * dir_entry); + +extern int d_isbasket(struct dentry * entry); +#endif diff -u --recursive --new-file v2.1.42/linux/include/linux/dlists.h linux/include/linux/dlists.h --- v2.1.42/linux/include/linux/dlists.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/dlists.h Thu Jun 12 16:22:10 1997 @@ -0,0 +1,108 @@ +#ifndef DLISTS_H +#define DLISTS_H +/* + * include/linux/dlists.h - macros for double linked lists + * + * Copyright (C) 1997, Thomas Schoebel-Theuer, + * . + */ + +/* dlists are cyclic ringlists, so the last element cannot be tested + * for NULL. Use the following construct for traversing cyclic lists: + * ptr = anchor; + * if(ptr) do { + * ... + * ptr = ptr->{something}_{next,prev}; + * } while(ptr != anchor); + * The effort here is paid off with much simpler inserts/removes. + * Examples for usage of these macros can be found in fs/ninode.c. + * To access the last element in constant time, simply use + * anchor->{something}_prev. + */ + +#define DEF_GENERIC_INSERT(CHANGE,PREFIX,NAME,TYPE,NEXT,PREV) \ +static inline void PREFIX##NAME(TYPE ** anchor, TYPE * elem)\ +{\ + TYPE * oldfirst = *anchor;\ + if(!oldfirst) {\ + elem->NEXT = elem->PREV = *anchor = elem;\ + } else {\ + elem->PREV = oldfirst->PREV;\ + elem->NEXT = oldfirst;\ + oldfirst->PREV->NEXT = elem;\ + oldfirst->PREV = elem;\ + if(CHANGE)\ + *anchor = elem;\ + }\ +} + +/* insert_* is always at the first position */ +#define DEF_INSERT(NAME,TYPE,NEXT,PREV) \ + DEF_GENERIC_INSERT(1,insert_,NAME,TYPE,NEXT,PREV) + +/* append_* is always at the tail */ +#define DEF_APPEND(NAME,TYPE,NEXT,PREV) \ + DEF_GENERIC_INSERT(0,append_,NAME,TYPE,NEXT,PREV) + +/* use this to insert _before_ oldelem somewhere in the middle of the list. + * the list must not be empty, and oldelem must be already a member.*/ +#define DEF_INSERT_MIDDLE(NAME,TYPE) \ +static inline void insert_middle_##NAME(TYPE ** anchor, TYPE * oldelem, TYPE * elem)\ +{\ + int status = (oldelem == *anchor);\ + insert_##NAME(&oldelem, elem);\ + if(status)\ + *anchor = oldelem;\ +} + +/* remove can be done with any element in the list */ +#define DEF_REMOVE(NAME,TYPE,NEXT,PREV) \ +static inline void remove_##NAME(TYPE ** anchor, TYPE * elem)\ +{\ + TYPE * next = elem->NEXT;\ + if(next == elem) {\ + *anchor = NULL;\ + } else {\ + TYPE * prev = elem->PREV;\ + prev->NEXT = next;\ + next->PREV = prev;\ + elem->NEXT = elem->PREV = NULL;/*leave this during debugging*/\ + if(*anchor == elem)\ + *anchor = next;\ + }\ +} + + +/* According to ideas from David S. Miller, here is a slightly + * more efficient plug-in compatible version using non-cyclic lists, + * but allowing neither backward traversals nor constant time access + * to the last element. + * Note that although the interface is the same, the PPREV pointer must be + * declared doubly indirect and the test for end-of-list is different. */ + +/* as above, this inserts always at the head */ +#define DEF_LIN_INSERT(NAME,TYPE,NEXT,PPREV) \ +static inline void insert_##NAME(TYPE ** anchor, TYPE * elem)\ +{\ + TYPE * first;\ + if((elem->NEXT = first = *anchor))\ + first->PPREV = &elem->NEXT;\ + *anchor = elem;\ + elem->PPREV = anchor;\ +} + +/* as above, this works with any list element */ +#define DEF_LIN_REMOVE(NAME,TYPE,NEXT,PPREV) \ +static inline void remove_##NAME(TYPE ** anchor, TYPE * elem)\ +{\ + TYPE * pprev;\ + if((pprev = elem->PPREV)) {\ + TYPE * next;\ + if((next = elem->NEXT))\ + next->PPREV = pprev;\ + *pprev = next;\ + elem->PPREV = elem->NEXT = NULL; /*leave this for debugging*/\ + }\ +} + +#endif diff -u --recursive --new-file v2.1.42/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h --- v2.1.42/linux/include/linux/ext2_fs.h Tue May 13 22:41:18 1997 +++ linux/include/linux/ext2_fs.h Thu Jun 12 16:22:10 1997 @@ -502,7 +502,7 @@ extern int ext2_link (struct inode *, struct inode *, const char *, int); extern int ext2_mknod (struct inode *, const char *, int, int, int); extern int ext2_rename (struct inode *, const char *, int, - struct inode *, const char *, int, int); + struct inode *, const char *, int); /* super.c */ extern void ext2_error (struct super_block *, const char *, const char *, ...) diff -u --recursive --new-file v2.1.42/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.1.42/linux/include/linux/fs.h Thu Jun 12 15:28:33 1997 +++ linux/include/linux/fs.h Sun Jun 15 15:12:29 1997 @@ -15,6 +15,12 @@ #include #include #include +#include + +/* Prefixes for routines (having no effect), but indicate what + * the routine may do. This can greatly ease reasoning about routines... + */ +#define blocking /*routine may schedule()*/ /* * It's silly to have NR_OPEN bigger than NR_FILE, but I'll fix @@ -34,7 +40,7 @@ #define BLOCK_SIZE_BITS 10 /* And dynamically-tunable limits and defaults: */ -extern int max_inodes, nr_inodes; +extern int max_inodes; extern int max_files, nr_files; #define NR_INODE 4096 /* this should be bigger than NR_FILE */ #define NR_FILE 1024 /* this can well be larger on a larger system */ @@ -60,6 +66,17 @@ #define SEL_OUT 2 #define SEL_EX 4 +/* public flags for file_system_type */ +#define FS_REQUIRES_DEV 1 +#define FS_NO_DCACHE 2 /* Only dcache the necessary things. */ +#define FS_NO_PRELIM 4 /* prevent preloading of dentries, even if + * FS_NO_DCACHE is not set. + */ +#define FS_IBASKET 8 /* FS does callback to free_ibasket() if space gets low. */ + +/* public flags for i_status */ +#define ST_MODIFIED 1024 + /* * These are the fs-independent mount-flags: up to 16 flags are supported */ @@ -87,6 +104,13 @@ #define MS_MGC_MSK 0xffff0000 /* magic flag number mask */ /* + * Public flags for namei() + */ +#define NAM_PLAIN 0 /* Retrieve last component of pathname as is. */ +#define NAM_FOLLOW_LINK 2 /* If last component of path is a symlink, follow it */ +#define NAM_FOLLOW_TRAILSLASH 4 /* Follow last symlink only if trailed by slash. */ + +/* * Note that read-only etc flags are inode-specific: setting some file-system * flags just means all the inodes inherit those flags by default. It might be * possible to override it selectively if you really wanted to with some @@ -281,58 +305,75 @@ #include struct inode { - struct inode *i_hash_next; - struct inode **i_hash_pprev; - struct inode *i_next; - struct inode **i_pprev; - unsigned long i_ino; - kdev_t i_dev; - unsigned short i_count; - umode_t i_mode; - nlink_t i_nlink; - uid_t i_uid; - gid_t i_gid; - kdev_t i_rdev; - off_t i_size; - time_t i_atime; - time_t i_mtime; - time_t i_ctime; - unsigned long i_blksize; - unsigned long i_blocks; - unsigned long i_version; - unsigned long i_nrpages; - struct semaphore i_sem; - struct inode_operations *i_op; - struct super_block *i_sb; - struct wait_queue *i_wait; - struct file_lock *i_flock; - struct vm_area_struct *i_mmap; - struct page *i_pages; - struct dquot *i_dquot[MAXQUOTAS]; - struct inode *i_bound_to, *i_bound_by; - struct inode *i_mount; - unsigned short i_flags; - unsigned char i_lock; - unsigned char i_dirt; - unsigned char i_pipe; - unsigned char i_sock; - int i_writecount; - unsigned int i_attr_flags; + struct inode *i_hash_next; + struct inode *i_hash_prev; + struct inode *i_next; + struct inode *i_prev; + + unsigned long i_ino; + kdev_t i_dev; + atomic_t i_count; + umode_t i_mode; + nlink_t i_nlink; + uid_t i_uid; + gid_t i_gid; + kdev_t i_rdev; + off_t i_size; + time_t i_atime; + time_t i_mtime; + time_t i_ctime; + unsigned long i_blksize; + unsigned long i_blocks; + unsigned long i_version; + unsigned long i_nrpages; + struct semaphore i_sem; + struct inode_operations *i_op; + struct super_block *i_sb; + struct wait_queue *i_wait; + struct file_lock *i_flock; + struct vm_area_struct *i_mmap; + struct page *i_pages; + struct dquot *i_dquot[MAXQUOTAS]; + + struct inode *i_lru_next; + struct inode *i_lru_prev; + + struct inode *i_basket_next; + struct inode *i_basket_prev; + struct dentry *i_dentry; + + short i_ddir_count; + short i_dent_count; + unsigned short i_status; + unsigned short i_reuse_count; + + struct inode *i_mount; + unsigned int i_flags; + unsigned char i_lock; + unsigned char i_dirt; + unsigned char i_pipe; + unsigned char i_sock; + + unsigned char i_level; + unsigned short i_fill; + + int i_writecount; + unsigned int i_attr_flags; union { - struct pipe_inode_info pipe_i; - struct minix_inode_info minix_i; - struct ext2_inode_info ext2_i; - struct hpfs_inode_info hpfs_i; - struct msdos_inode_info msdos_i; - struct umsdos_inode_info umsdos_i; - struct iso_inode_info isofs_i; - struct nfs_inode_info nfs_i; - struct sysv_inode_info sysv_i; - struct affs_inode_info affs_i; - struct ufs_inode_info ufs_i; - struct romfs_inode_info romfs_i; - struct socket socket_i; - void * generic_ip; + struct pipe_inode_info pipe_i; + struct minix_inode_info minix_i; + struct ext2_inode_info ext2_i; + struct hpfs_inode_info hpfs_i; + struct msdos_inode_info msdos_i; + struct umsdos_inode_info umsdos_i; + struct iso_inode_info isofs_i; + struct nfs_inode_info nfs_i; + struct sysv_inode_info sysv_i; + struct affs_inode_info affs_i; + struct ufs_inode_info ufs_i; + struct romfs_inode_info romfs_i; + struct socket socket_i; + void *generic_ip; } u; }; @@ -450,33 +491,38 @@ #include struct super_block { - kdev_t s_dev; - unsigned long s_blocksize; - unsigned char s_blocksize_bits; - unsigned char s_lock; - unsigned char s_rd_only; - unsigned char s_dirt; - struct file_system_type *s_type; - struct super_operations *s_op; - struct dquot_operations *dq_op; - unsigned long s_flags; - unsigned long s_magic; - unsigned long s_time; - struct inode * s_covered; - struct inode * s_mounted; - struct wait_queue * s_wait; + kdev_t s_dev; + unsigned long s_blocksize; + unsigned char s_blocksize_bits; + unsigned char s_lock; + unsigned char s_rd_only; + unsigned char s_dirt; + struct file_system_type *s_type; + struct super_operations *s_op; + struct dquot_operations *dq_op; + unsigned long s_flags; + unsigned long s_magic; + unsigned long s_time; + struct inode *s_covered; + struct inode *s_mounted; + struct wait_queue *s_wait; + + struct inode *s_ibasket; + short int s_ibasket_count; + short int s_ibasket_max; + union { - struct minix_sb_info minix_sb; - struct ext2_sb_info ext2_sb; - struct hpfs_sb_info hpfs_sb; - struct msdos_sb_info msdos_sb; - struct isofs_sb_info isofs_sb; - struct nfs_sb_info nfs_sb; - struct sysv_sb_info sysv_sb; - struct affs_sb_info affs_sb; - struct ufs_sb_info ufs_sb; - struct romfs_sb_info romfs_sb; - void *generic_sbp; + struct minix_sb_info minix_sb; + struct ext2_sb_info ext2_sb; + struct hpfs_sb_info hpfs_sb; + struct msdos_sb_info msdos_sb; + struct isofs_sb_info isofs_sb; + struct nfs_sb_info nfs_sb; + struct sysv_sb_info sysv_sb; + struct affs_sb_info affs_sb; + struct ufs_sb_info ufs_sb; + struct romfs_sb_info romfs_sb; + void *generic_sbp; } u; }; @@ -515,9 +561,8 @@ int (*mkdir) (struct inode *,const char *,int,int); int (*rmdir) (struct inode *,const char *,int); int (*mknod) (struct inode *,const char *,int,int,int); - int (*rename) (struct inode *,const char *,int,struct inode *,const char *,int, int); + int (*rename) (struct inode *,const char *,int,struct inode *,const char *,int); int (*readlink) (struct inode *,char *,int); - int (*follow_link) (struct inode *,struct inode *,int,int,struct inode **); int (*readpage) (struct inode *, struct page *); int (*writepage) (struct inode *, struct page *); int (*bmap) (struct inode *,int); @@ -551,9 +596,9 @@ }; struct file_system_type { - struct super_block *(*read_super) (struct super_block *, void *, int); const char *name; - int requires_dev; + int fs_flags; + struct super_block *(*read_super) (struct super_block *, void *, int); struct file_system_type * next; }; @@ -644,8 +689,7 @@ extern void sync_supers(kdev_t dev); extern int bmap(struct inode * inode,int block); extern int notify_change(struct inode *, struct iattr *); -extern int namei(const char * pathname, struct inode ** res_inode); -extern int lnamei(const char * pathname, struct inode ** res_inode); +extern int namei(int retr_mode, const char *pathname, struct inode **res_inode); extern int permission(struct inode * inode,int mask); extern int get_write_access(struct inode *inode); extern void put_write_access(struct inode *inode); @@ -653,12 +697,116 @@ struct inode ** res_inode, struct inode * base); extern int do_mknod(const char * filename, int mode, dev_t dev); extern int do_pipe(int *); -extern void iput(struct inode * inode); -extern struct inode * __iget(struct super_block * sb,int nr,int crsmnt); -extern struct inode * get_empty_inode(void); + +#include + +/* Intended for short locks of the global data structures in inode.c. + * Could be replaced with spinlocks completely, since there is + * no blocking during manipulation of the static data; however the + * lock in invalidate_inodes() may last relatively long. + */ +extern struct semaphore vfs_sem; +extern inline void vfs_lock(void) +{ +#if 0 +#ifdef __SMP__ + down(&vfs_sem); +#endif +#endif +} + +extern inline void vfs_unlock(void) +{ +#if 0 +#ifdef __SMP__ + up(&vfs_sem); +#endif +#endif +} + +/* Not to be used by ordinary vfs users */ +extern void _get_inode(struct inode * inode); +extern blocking void __iput(struct inode * inode); + +/* This must not be called if the inode is not in use (i.e. given + * back with iput(). The atomic inc assumes that the inode is + * already in use, and just has to be incremented higher. + * Please do not directly manipulate i_count any more. + * Use iget, iinc and iput. + * You may test i_count for zero if you are aware that it + * might change under you. + */ +extern inline void iinc(struct inode * inode) +{ + atomic_inc(&inode->i_count); +} + +/* The same, but the inode may not be in use. This must be called + * with vfslock() held, and be asure that the inode argument is + * valid (i.e. not out of cache). So the vfs_lock() must span the + * retrieval method of the inode. + */ +extern inline void iinc_zero(struct inode * inode) +{ + if(!atomic_read(&inode->i_count)) { + atomic_inc(&inode->i_count); + _get_inode(inode); + } else + atomic_inc(&inode->i_count); +} + +extern blocking void _iput(struct inode * inode); +extern inline blocking void iput(struct inode * inode) +{ + if(inode) { + extern void wake_up_interruptible(struct wait_queue **q); + + if(inode->i_pipe) + wake_up_interruptible(&inode->u.pipe_i.wait); + + /* It does not matter if somebody re-increments it in between, + * only the _last_ user needs to call _iput(). + */ + if(atomic_dec_and_test(&inode->i_count) && inode->i_ddir_count <= 0) + _iput(inode); + } +} + +extern blocking struct inode * __iget(struct super_block * sb, unsigned long nr, int crsmnt); +extern blocking void _clear_inode(struct inode * inode, int external, int verbose); +extern blocking inline void clear_inode(struct inode * inode) +{ + vfs_lock(); + _clear_inode(inode, 1, 1); + vfs_unlock(); +} +extern blocking struct inode * _get_empty_inode(void); +extern inline blocking struct inode * get_empty_inode(void) +{ + struct inode * inode; + vfs_lock(); + inode = _get_empty_inode(); + vfs_unlock(); + return inode; +} +/* Please prefer to use this function in future, instead of using + * a get_empty_inode()/insert_inode_hash() combination. + * It allows for better checking and less race conditions. + */ +blocking struct inode * get_empty_inode_hashed(dev_t i_dev, unsigned long i_ino); + +extern inline blocking int free_ibasket(struct super_block * sb) +{ + extern blocking int _free_ibasket(struct super_block * sb); + int res; + vfs_lock(); + res = _free_ibasket(sb); + vfs_unlock(); + return res; +} + extern void insert_inode_hash(struct inode *); -extern void clear_inode(struct inode *); -extern struct inode * get_pipe_inode(void); +extern blocking struct inode * get_pipe_inode(void); extern int get_unused_fd(void); extern void put_unused_fd(int); extern struct file * get_empty_filp(void); @@ -694,6 +842,7 @@ extern long generic_file_read(struct inode *, struct file *, char *, unsigned long); extern long generic_file_write(struct inode *, struct file *, const char *, unsigned long); +extern struct super_block *get_super(kdev_t dev); extern void put_super(kdev_t dev); unsigned long generate_cluster(kdev_t dev, int b[], int size); unsigned long generate_cluster_swab32(kdev_t dev, int b[], int size); @@ -723,7 +872,8 @@ extern int inode_change_ok(struct inode *, struct iattr *); extern void inode_setattr(struct inode *, struct iattr *); -extern inline struct inode * iget(struct super_block * sb,int nr) +extern inline blocking +struct inode * iget(struct super_block * sb, unsigned long nr) { return __iget(sb, nr, 1); } diff -u --recursive --new-file v2.1.42/linux/include/linux/kbd_diacr.h linux/include/linux/kbd_diacr.h --- v2.1.42/linux/include/linux/kbd_diacr.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/kbd_diacr.h Thu Jun 12 16:22:10 1997 @@ -0,0 +1,8 @@ +#ifndef _DIACR_H +#define _DIACR_H +#include + +extern struct kbdiacr accent_table[]; +extern unsigned int accent_table_size; + +#endif /* _DIACR_H */ diff -u --recursive --new-file v2.1.42/linux/include/linux/kbd_kern.h linux/include/linux/kbd_kern.h --- v2.1.42/linux/include/linux/kbd_kern.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/kbd_kern.h Fri Jun 13 13:46:44 1997 @@ -0,0 +1,141 @@ +#ifndef _KBD_KERN_H +#define _KBD_KERN_H + +#include +#include + +extern int shift_state; + +extern char *func_table[MAX_NR_FUNC]; +extern char func_buf[]; +extern char *funcbufptr; +extern int funcbufsize, funcbufleft; + +/* + * kbd->xxx contains the VC-local things (flag settings etc..) + * + * Note: externally visible are LED_SCR, LED_NUM, LED_CAP defined in kd.h + * The code in KDGETLED / KDSETLED depends on the internal and + * external order being the same. + * + * Note: lockstate is used as index in the array key_map. + */ +struct kbd_struct { + + unsigned char lockstate; +/* 8 modifiers - the names do not have any meaning at all; + they can be associated to arbitrarily chosen keys */ +#define VC_SHIFTLOCK KG_SHIFT /* shift lock mode */ +#define VC_ALTGRLOCK KG_ALTGR /* altgr lock mode */ +#define VC_CTRLLOCK KG_CTRL /* control lock mode */ +#define VC_ALTLOCK KG_ALT /* alt lock mode */ +#define VC_SHIFTLLOCK KG_SHIFTL /* shiftl lock mode */ +#define VC_SHIFTRLOCK KG_SHIFTR /* shiftr lock mode */ +#define VC_CTRLLLOCK KG_CTRLL /* ctrll lock mode */ +#define VC_CTRLRLOCK KG_CTRLR /* ctrlr lock mode */ + unsigned char slockstate; /* for `sticky' Shift, Ctrl, etc. */ + + unsigned char ledmode:2; /* one 2-bit value */ +#define LED_SHOW_FLAGS 0 /* traditional state */ +#define LED_SHOW_IOCTL 1 /* only change leds upon ioctl */ +#define LED_SHOW_MEM 2 /* `heartbeat': peek into memory */ + + unsigned char ledflagstate:3; /* flags, not lights */ + unsigned char default_ledflagstate:3; +#define VC_SCROLLOCK 0 /* scroll-lock mode */ +#define VC_NUMLOCK 1 /* numeric lock mode */ +#define VC_CAPSLOCK 2 /* capslock mode */ + + unsigned char kbdmode:2; /* one 2-bit value */ +#define VC_XLATE 0 /* translate keycodes using keymap */ +#define VC_MEDIUMRAW 1 /* medium raw (keycode) mode */ +#define VC_RAW 2 /* raw (scancode) mode */ +#define VC_UNICODE 3 /* Unicode mode */ + + unsigned char modeflags:5; +#define VC_APPLIC 0 /* application key mode */ +#define VC_CKMODE 1 /* cursor key mode */ +#define VC_REPEAT 2 /* keyboard repeat */ +#define VC_CRLF 3 /* 0 - enter sends CR, 1 - enter sends CRLF */ +#define VC_META 4 /* 0 - meta, 1 - meta=prefix with ESC */ +}; + +extern struct kbd_struct kbd_table[]; + +extern int kbd_init(void); + +extern unsigned char getledstate(void); +extern void setledstate(struct kbd_struct *kbd, unsigned int led); + +extern int do_poke_blanked_console; + +extern inline void show_console(void) +{ + do_poke_blanked_console = 1; + mark_bh(CONSOLE_BH); +} + +extern inline void set_console(int nr) +{ + want_console = nr; + mark_bh(CONSOLE_BH); +} + +extern inline void set_leds(void) +{ + mark_bh(KEYBOARD_BH); +} + +extern inline int vc_kbd_mode(struct kbd_struct * kbd, int flag) +{ + return ((kbd->modeflags >> flag) & 1); +} + +extern inline int vc_kbd_led(struct kbd_struct * kbd, int flag) +{ + return ((kbd->ledflagstate >> flag) & 1); +} + +extern inline void set_vc_kbd_mode(struct kbd_struct * kbd, int flag) +{ + kbd->modeflags |= 1 << flag; +} + +extern inline void set_vc_kbd_led(struct kbd_struct * kbd, int flag) +{ + kbd->ledflagstate |= 1 << flag; +} + +extern inline void clr_vc_kbd_mode(struct kbd_struct * kbd, int flag) +{ + kbd->modeflags &= ~(1 << flag); +} + +extern inline void clr_vc_kbd_led(struct kbd_struct * kbd, int flag) +{ + kbd->ledflagstate &= ~(1 << flag); +} + +extern inline void chg_vc_kbd_lock(struct kbd_struct * kbd, int flag) +{ + kbd->lockstate ^= 1 << flag; +} + +extern inline void chg_vc_kbd_slock(struct kbd_struct * kbd, int flag) +{ + kbd->slockstate ^= 1 << flag; +} + +extern inline void chg_vc_kbd_mode(struct kbd_struct * kbd, int flag) +{ + kbd->modeflags ^= 1 << flag; +} + +extern inline void chg_vc_kbd_led(struct kbd_struct * kbd, int flag) +{ + kbd->ledflagstate ^= 1 << flag; +} + +#define U(x) ((x) ^ 0xf000) + +#endif diff -u --recursive --new-file v2.1.42/linux/include/linux/kbd_ll.h linux/include/linux/kbd_ll.h --- v2.1.42/linux/include/linux/kbd_ll.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/kbd_ll.h Thu Jun 12 16:22:10 1997 @@ -0,0 +1,12 @@ +/* + * Interface between the low-level keyboard driver and the keymapper + */ + +#ifndef _KBD_LL_H +#define _KBD_LL_H + +extern struct pt_regs *kbd_pt_regs; + +void handle_scancode(unsigned char scancode); + +#endif /* _KBD_LL_H */ diff -u --recursive --new-file v2.1.42/linux/include/linux/linkage.h linux/include/linux/linkage.h --- v2.1.42/linux/include/linux/linkage.h Wed Apr 16 14:15:00 1997 +++ linux/include/linux/linkage.h Thu Jun 12 16:22:10 1997 @@ -15,6 +15,10 @@ #define SYMBOL_NAME_LABEL(X) X/**/: #endif +#ifdef __mc68000__ +#define __ALIGN .align 4 +#define __ALIGN_STR ".align 4" +#else #if !defined(__i486__) && !defined(__i586__) #define __ALIGN .align 4,0x90 #define __ALIGN_STR ".align 4,0x90" @@ -22,6 +26,7 @@ #define __ALIGN .align 16,0x90 #define __ALIGN_STR ".align 16,0x90" #endif /* __i486__/__i586__ */ +#endif /* __mc68000__ */ #ifdef __ASSEMBLY__ diff -u --recursive --new-file v2.1.42/linux/include/linux/minix_fs.h linux/include/linux/minix_fs.h --- v2.1.42/linux/include/linux/minix_fs.h Sat Nov 30 02:24:02 1996 +++ linux/include/linux/minix_fs.h Thu Jun 12 16:22:10 1997 @@ -100,7 +100,7 @@ extern int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len); extern int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev); extern int minix_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len, int must_be_dir); + struct inode * new_dir, const char * new_name, int new_len); extern struct inode * minix_new_inode(const struct inode * dir); extern void minix_free_inode(struct inode * inode); extern unsigned long minix_count_free_inodes(struct super_block *sb); diff -u --recursive --new-file v2.1.42/linux/include/linux/mm.h linux/include/linux/mm.h --- v2.1.42/linux/include/linux/mm.h Thu Jun 12 15:28:33 1997 +++ linux/include/linux/mm.h Mon Jun 16 08:46:24 1997 @@ -124,7 +124,7 @@ struct wait_queue *wait; struct page **pprev_hash; struct buffer_head * buffers; - unsigned long swap_unlock_entry; + unsigned long pg_swap_entry; unsigned long map_nr; /* page->map_nr == page - mem_map */ } mem_map_t; @@ -138,6 +138,7 @@ #define PG_swap_unlock_after 6 #define PG_DMA 7 #define PG_Slab 8 +#define PG_swap_cache 9 #define PG_reserved 31 /* Make it prettier to test the above... */ @@ -151,10 +152,19 @@ #define PageSwapUnlockAfter(page) (test_bit(PG_swap_unlock_after, &(page)->flags)) #define PageDMA(page) (test_bit(PG_DMA, &(page)->flags)) #define PageSlab(page) (test_bit(PG_Slab, &(page)->flags)) +#define PageSwapCache(page) (test_bit(PG_swap_cache, &(page)->flags)) #define PageReserved(page) (test_bit(PG_reserved, &(page)->flags)) #define PageSetSlab(page) (set_bit(PG_Slab, &(page)->flags)) +#define PageSetSwapCache(page) (set_bit(PG_swap_cache, &(page)->flags)) +#define PageTestandSetSwapCache(page) \ + (test_and_set_bit(PG_swap_cache, &(page)->flags)) + #define PageClearSlab(page) (clear_bit(PG_Slab, &(page)->flags)) +#define PageClearSwapCache(page)(clear_bit(PG_swap_cache, &(page)->flags)) + +#define PageTestandClearSwapCache(page) \ + (test_and_clear_bit(PG_swap_cache, &(page)->flags)) /* * page->reserved denotes a page which must never be accessed (which diff -u --recursive --new-file v2.1.42/linux/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h --- v2.1.42/linux/include/linux/msdos_fs.h Thu Jun 12 15:30:06 1997 +++ linux/include/linux/msdos_fs.h Sun Jun 15 15:14:00 1997 @@ -261,8 +261,7 @@ extern int msdos_unlink(struct inode *dir,const char *name,int len); extern int msdos_unlink_umsdos(struct inode *dir,const char *name,int len); extern int msdos_rename(struct inode *old_dir,const char *old_name,int old_len, - struct inode *new_dir,const char *new_name,int new_len, - int must_be_dir); + struct inode *new_dir,const char *new_name,int new_len); /* fatfs_syms.c */ extern int init_fat_fs(void); @@ -274,8 +273,7 @@ extern int vfat_mkdir(struct inode *dir,const char *name,int len,int mode); extern int vfat_rmdir(struct inode *dir,const char *name,int len); extern int vfat_rename(struct inode *old_dir,const char *old_name,int old_len, - struct inode *new_dir,const char *new_name,int new_len, - int must_be_dir); + struct inode *new_dir,const char *new_name,int new_len); extern void vfat_put_super(struct super_block *sb); extern struct super_block *vfat_read_super(struct super_block *sb,void *data, int silent); diff -u --recursive --new-file v2.1.42/linux/include/linux/nametrans.h linux/include/linux/nametrans.h --- v2.1.42/linux/include/linux/nametrans.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/nametrans.h Fri Jun 13 13:46:16 1997 @@ -0,0 +1,69 @@ +#ifndef NAMETRANS_H +#define NAMETRANS_H +/* + * $Id: nametrans.h,v 1.1 1997/06/04 08:26:57 davem Exp $ + * + * include/linux/nametrans.h - context-dependend filename suffixes. + * Copyright (C) 1997, Thomas Schoebel-Theuer, + * . + */ + +#include +#include + +#define MAX_DEFAULT_TRANSLEN 128 + +/* only filenames matching the following length restrictions can be + * translated. I introduced these restrictions because they *greatly* + * simplify buffer management (no need to allocate kernel pages and free them). + * The maximal total length of a context-dependend filename is the + * sum of both constants. */ +#define MAX_TRANS_FILELEN 128 /* max len of a name that could be translated */ +#define MAX_TRANS_SUFFIX 64 /* max len of a #keyword=value# suffix */ + +/* max number of translations */ +#define MAX_TRANSLATIONS 16 + +struct translations { + int count; + struct qstr name[MAX_TRANSLATIONS]; + struct qstr c_name[MAX_TRANSLATIONS]; +}; + +/* global/default translations */ +extern char nametrans_txt[MAX_DEFAULT_TRANSLEN]; + +/* Any changer of a built-in translation must set this flag */ +extern int translations_dirty; + + +/* called once at boot time */ +extern void init_nametrans(void); + +/* set global translations */ +extern void nametrans_setup(char * line); + +/* return reusable global buffer. needed by VFS. */ +struct translations * get_translations(char * env); + +/* if the _first_ environment variable is "NAMETRANS", return + * a pointer to the list of appendices. + * You can set the first environment variable using + * 'env - NAMETRANS=... "`env`" command ...' + */ +extern char * env_transl(void); + +/* if name has the correct suffix "#keyword=correct_context#", + * return position of the suffix, else 0. + */ +extern char* testname(int restricted, char* name); + +/* for use in kernel/sysctrl.h */ +extern int nametrans_dostring(ctl_table * table, int write, struct file * filp, + void * buffer, size_t * lenp); +extern int nametrans_string(ctl_table * table, int * name, int nlen, + void * oldval, size_t * oldlenp, + void * newval, size_t newlen, void ** context); + + +#endif diff -u --recursive --new-file v2.1.42/linux/include/linux/nfsd/nfsfh.h linux/include/linux/nfsd/nfsfh.h --- v2.1.42/linux/include/linux/nfsd/nfsfh.h Thu Jun 12 15:30:33 1997 +++ linux/include/linux/nfsd/nfsfh.h Sun Jun 15 15:14:28 1997 @@ -151,7 +151,7 @@ if (!(inode = fhp->fh_inode)) return; - if (!inode->i_count) { + if (!atomic_read(&inode->i_count)) { printk("nfsd: trying to free free inode in %s:%d\n" " dev %04x ino %ld, mode %07o\n", file, line, inode->i_dev, diff -u --recursive --new-file v2.1.42/linux/include/linux/omirr.h linux/include/linux/omirr.h --- v2.1.42/linux/include/linux/omirr.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/omirr.h Sun Jun 15 15:14:39 1997 @@ -0,0 +1,17 @@ +/* + * fs/proc/omirr.c - online mirror support + * + * (C) 1997 Thomas Schoebel-Theuer + */ + +#ifndef OMIRR_H +#define OMIRR_H +#include +#include + +extern int omirr_print(struct dentry * ent1, struct dentry * ent2, + struct qstr * suffix, const char * fmt, ...); + +extern int omirr_printall(struct inode * inode, const char * fmt, ...); + +#endif diff -u --recursive --new-file v2.1.42/linux/include/linux/pci.h linux/include/linux/pci.h --- v2.1.42/linux/include/linux/pci.h Sat May 24 09:10:25 1997 +++ linux/include/linux/pci.h Thu Jun 12 16:22:10 1997 @@ -238,7 +238,9 @@ #define PCI_DEVICE_ID_ATI_68800 0x4158 #define PCI_DEVICE_ID_ATI_215CT222 0x4354 #define PCI_DEVICE_ID_ATI_210888CX 0x4358 +#define PCI_DEVICE_ID_ATI_215GT 0x4754 #define PCI_DEVICE_ID_ATI_210888GX 0x4758 +#define PCI_DEVICE_ID_ATI_264VT 0x5654 #define PCI_VENDOR_ID_VLSI 0x1004 #define PCI_DEVICE_ID_VLSI_82C592 0x0005 @@ -270,6 +272,7 @@ #define PCI_DEVICE_ID_DEC_TULIP_FAST 0x0009 #define PCI_DEVICE_ID_DEC_FDDI 0x000F #define PCI_DEVICE_ID_DEC_TULIP_PLUS 0x0014 +#define PCI_DEVICE_ID_DEC_21142 0x0019 #define PCI_DEVICE_ID_DEC_21052 0x0021 #define PCI_DEVICE_ID_DEC_21152 0x0024 @@ -279,12 +282,16 @@ #define PCI_DEVICE_ID_CIRRUS_5434_4 0x00a4 #define PCI_DEVICE_ID_CIRRUS_5434_8 0x00a8 #define PCI_DEVICE_ID_CIRRUS_5436 0x00ac +#define PCI_DEVICE_ID_CIRRUS_5446 0x00b8 +#define PCI_DEVICE_ID_CIRRUS_5464 0x00d4 #define PCI_DEVICE_ID_CIRRUS_6729 0x1100 #define PCI_DEVICE_ID_CIRRUS_7542 0x1200 #define PCI_DEVICE_ID_CIRRUS_7543 0x1202 +#define PCI_DEVICE_ID_CIRRUS_7541 0x1204 #define PCI_VENDOR_ID_IBM 0x1014 #define PCI_DEVICE_ID_IBM_82G2675 0x001d +#define PCI_DEVICE_ID_IBM_82351 0x0022 #define PCI_VENDOR_ID_WD 0x101c #define PCI_DEVICE_ID_WD_7197 0x3296 @@ -311,6 +318,7 @@ #define PCI_DEVICE_ID_CT_65545 0x00d8 #define PCI_DEVICE_ID_CT_65548 0x00dc #define PCI_DEVICE_ID_CT_65550 0x00e0 +#define PCI_DEVICE_ID_CT_65554 0x00e4 #define PCI_VENDOR_ID_MIRO 0x1031 #define PCI_DEVICE_ID_MIRO_36050 0x5601 @@ -328,6 +336,8 @@ #define PCI_DEVICE_ID_SI_601 0x0601 #define PCI_DEVICE_ID_SI_5511 0x5511 #define PCI_DEVICE_ID_SI_5513 0x5513 +#define PCI_DEVICE_ID_SI_5571 0x5571 +#define PCI_DEVICE_ID_SI_7001 0x7001 #define PCI_VENDOR_ID_HP 0x103c #define PCI_DEVICE_ID_HP_J2585A 0x1030 @@ -363,6 +373,11 @@ #define PCI_VENDOR_ID_WINBOND2 0x1050 #define PCI_DEVICE_ID_WINBOND2_89C940 0x0940 +#define PCI_VENDOR_ID_MOTOROLA 0x1057 +#define PCI_DEVICE_ID_MOTOROLA_MPC105 0x0001 +#define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002 +#define PCI_DEVICE_ID_MOTOROLA_RAVEN 0x4801 + #define PCI_VENDOR_ID_PROMISE 0x105a #define PCI_DEVICE_ID_PROMISE_5300 0x5300 @@ -421,6 +436,7 @@ #define PCI_VENDOR_ID_WINBOND 0x10ad #define PCI_DEVICE_ID_WINBOND_83769 0x0001 #define PCI_DEVICE_ID_WINBOND_82C105 0x0105 +#define PCI_DEVICE_ID_WINBOND_83C553 0x0565 #define PCI_VENDOR_ID_3COM 0x10b7 #define PCI_DEVICE_ID_3COM_3C590 0x5900 @@ -428,6 +444,7 @@ #define PCI_DEVICE_ID_3COM_3C595T4 0x5951 #define PCI_DEVICE_ID_3COM_3C595MII 0x5952 #define PCI_DEVICE_ID_3COM_3C900TPO 0x9000 +#define PCI_DEVICE_ID_3COM_3C900COMBO 0x9001 #define PCI_DEVICE_ID_3COM_3C905TX 0x9050 #define PCI_VENDOR_ID_AL 0x10b9 @@ -445,6 +462,7 @@ #define PCI_VENDOR_ID_ASP 0x10cd #define PCI_DEVICE_ID_ASP_ABP940 0x1200 +#define PCI_DEVICE_ID_ASP_ABP940U 0x1300 #define PCI_VENDOR_ID_CERN 0x10dc #define PCI_DEVICE_ID_CERN_SPSB_PMC 0x0001 @@ -456,8 +474,12 @@ #define PCI_VENDOR_ID_TEKRAM2 0x10e1 #define PCI_DEVICE_ID_TEKRAM2_690c 0x690c +#define PCI_VENDOR_ID_TUNDRA 0x10e3 +#define PCI_DEVICE_ID_TUNDRA_CA91C042 0x0000 + #define PCI_VENDOR_ID_AMCC 0x10e8 #define PCI_DEVICE_ID_AMCC_MYRINET 0x8043 +#define PCI_DEVICE_ID_AMCC_S5933 0x807d #define PCI_VENDOR_ID_INTERG 0x10ea #define PCI_DEVICE_ID_INTERG_1680 0x1680 @@ -472,7 +494,10 @@ #define PCI_VENDOR_ID_VIA 0x1106 #define PCI_DEVICE_ID_VIA_82C505 0x0505 #define PCI_DEVICE_ID_VIA_82C561 0x0561 +#define PCI_DEVICE_ID_VIA_82C586_1 0x0571 #define PCI_DEVICE_ID_VIA_82C576 0x0576 +#define PCI_DEVICE_ID_VIA_82C585 0x0585 +#define PCI_DEVICE_ID_VIA_82C586_0 0x0586 #define PCI_DEVICE_ID_VIA_82C416 0x1571 #define PCI_VENDOR_ID_VORTEX 0x1119 @@ -519,15 +544,22 @@ #define PCI_DEVICE_ID_MUTECH_MV1000 0x0001 #define PCI_VENDOR_ID_TOSHIBA 0x1179 +#define PCI_DEVICE_ID_TOSHIBA_601 0x0601 #define PCI_VENDOR_ID_ZEITNET 0x1193 #define PCI_DEVICE_ID_ZEITNET_1221 0x0001 #define PCI_DEVICE_ID_ZEITNET_1225 0x0002 +#define PCI_VENDOR_ID_OMEGA 0x119b +#define PCI_DEVICE_ID_OMEGA_PCMCIA 0x1221 + #define PCI_VENDOR_ID_SPECIALIX 0x11cb #define PCI_DEVICE_ID_SPECIALIX_XIO 0x4000 #define PCI_DEVICE_ID_SPECIALIX_RIO 0x8000 +#define PCI_VENDOR_ID_ZORAN 0x11de +#define PCI_DEVICE_ID_ZORAN_36120 0x6120 + #define PCI_VENDOR_ID_COMPEX 0x11f6 #define PCI_DEVICE_ID_COMPEX_RL2000 0x1401 @@ -543,6 +575,12 @@ #define PCI_DEVICE_ID_CYCLOM_Z_Lo 0x0200 #define PCI_DEVICE_ID_CYCLOM_Z_Hi 0x0201 +#define PCI_VENDOR_ID_3DFX 0x121a +#define PCI_DEVICE_ID_3DFX_VOODOO 0x0001 + +#define PCI_VENDOR_ID_SIGMADES 0x1236 +#define PCI_DEVICE_ID_SIGMADES_6425 0x6401 + #define PCI_VENDOR_ID_OPTIBASE 0x1255 #define PCI_DEVICE_ID_OPTIBASE_FORGE 0x1110 #define PCI_DEVICE_ID_OPTIBASE_FUSION 0x1210 @@ -556,10 +594,13 @@ #define PCI_VENDOR_ID_TEKRAM 0x1de1 #define PCI_DEVICE_ID_TEKRAM_DC290 0xdc29 -#define PCI_VENDOR_ID_3DLABS 0x3D3D +#define PCI_VENDOR_ID_3DLABS 0x3d3d #define PCI_DEVICE_ID_3DLABS_300SX 0x0001 +#define PCI_DEVICE_ID_3DLABS_DELTA 0x0003 +#define PCI_DEVICE_ID_3DLABS_PERMEDIA 0x0004 #define PCI_VENDOR_ID_AVANCE 0x4005 +#define PCI_DEVICE_ID_AVANCE_ALG2064 0x2064 #define PCI_DEVICE_ID_AVANCE_2302 0x2302 #define PCI_VENDOR_ID_S3 0x5333 @@ -582,6 +623,8 @@ #define PCI_DEVICE_ID_INTEL_82378 0x0484 #define PCI_DEVICE_ID_INTEL_82430 0x0486 #define PCI_DEVICE_ID_INTEL_82434 0x04a3 +#define PCI_DEVICE_ID_INTEL_82092AA_0 0x1221 +#define PCI_DEVICE_ID_INTEL_82092AA_1 0x1222 #define PCI_DEVICE_ID_INTEL_7116 0x1223 #define PCI_DEVICE_ID_INTEL_82596 0x1226 #define PCI_DEVICE_ID_INTEL_82865 0x1227 @@ -589,15 +632,19 @@ #define PCI_DEVICE_ID_INTEL_82437 0x122d #define PCI_DEVICE_ID_INTEL_82371_0 0x122e #define PCI_DEVICE_ID_INTEL_82371_1 0x1230 -#define PCI_DEVICE_ID_INTEL_430MX_0 0x1234 -#define PCI_DEVICE_ID_INTEL_430MX_1 0x1235 +#define PCI_DEVICE_ID_INTEL_82371MX 0x1234 +#define PCI_DEVICE_ID_INTEL_82437MX 0x1235 #define PCI_DEVICE_ID_INTEL_82441 0x1237 #define PCI_DEVICE_ID_INTEL_82439 0x1250 #define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000 #define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010 #define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020 #define PCI_DEVICE_ID_INTEL_82437VX 0x7030 +#define PCI_DEVICE_ID_INTEL_82439TX 0x7100 +#define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110 #define PCI_DEVICE_ID_INTEL_82371AB 0x7111 +#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112 +#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113 #define PCI_DEVICE_ID_INTEL_P6 0x84c4 #define PCI_DEVICE_ID_INTEL_P6_2 0x84c5 diff -u --recursive --new-file v2.1.42/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h --- v2.1.42/linux/include/linux/proc_fs.h Thu Jun 12 15:28:33 1997 +++ linux/include/linux/proc_fs.h Sun Jun 15 15:12:30 1997 @@ -48,8 +48,10 @@ PROC_RTC, PROC_LOCKS, PROC_ZORRO, + PROC_HARDWARE, PROC_SLABINFO, - PROC_PARPORT + PROC_PARPORT, + PROC_OMIRR /* whether enabled or not */ }; enum pid_directory_inos { @@ -133,6 +135,11 @@ PROC_NET_X25_ROUTES, PROC_NET_X25, PROC_NET_TR_RIF, + PROC_NET_DN_DEV, + PROC_NET_DN_ADJ, + PROC_NET_DN_L1, + PROC_NET_DN_L2, + PROC_NET_DN_SKT, PROC_NET_LAST }; @@ -353,6 +360,11 @@ #if CONFIG_AP1000 extern struct inode_operations proc_ringbuf_inode_operations; #endif +extern struct inode_operations proc_omirr_inode_operations; + +/* Not sure whether this belongs here */ +int proc_arbitrary_lookup(struct inode * dir, const char * name, + int len, struct inode ** result); #endif /* diff -u --recursive --new-file v2.1.42/linux/include/linux/sched.h linux/include/linux/sched.h --- v2.1.42/linux/include/linux/sched.h Thu Jun 12 15:28:33 1997 +++ linux/include/linux/sched.h Sun Jun 15 15:12:29 1997 @@ -500,13 +500,8 @@ */ extern inline void __add_wait_queue(struct wait_queue ** p, struct wait_queue * wait) { - struct wait_queue *head = *p; - struct wait_queue *next = WAIT_QUEUE_HEAD(p); - - if (head) - next = head; + wait->next = *p ? : WAIT_QUEUE_HEAD(p); *p = wait; - wait->next = next; } extern rwlock_t waitqueue_lock; diff -u --recursive --new-file v2.1.42/linux/include/linux/selection.h linux/include/linux/selection.h --- v2.1.42/linux/include/linux/selection.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/selection.h Sun Jun 15 15:12:58 1997 @@ -0,0 +1,208 @@ +/* + * selection.h + * + * Interface between console.c, tty_io.c, vt.c, vc_screen.c and selection.c + */ + +#include + +extern int sel_cons; + +extern void clear_selection(void); +extern int set_selection(const unsigned long arg, struct tty_struct *tty, int user); +extern int paste_selection(struct tty_struct *tty); +extern int sel_loadlut(const unsigned long arg); +extern int mouse_reporting(void); +extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry); + +#ifdef CONFIG_FB_CONSOLE +extern unsigned long get_video_num_columns(unsigned int console); +extern unsigned long get_video_num_lines(unsigned int console); +extern unsigned long get_video_size_row(unsigned int console); +#else +#define get_video_num_columns(dummy) video_num_columns +#define get_video_num_lines(dummy) video_num_lines +#define get_video_size_row(dummy) video_size_row +#endif + +extern unsigned long video_num_columns; +extern unsigned long video_num_lines; +extern unsigned long video_size_row; +extern unsigned char video_type; +extern unsigned long video_mem_base; +extern unsigned long video_mem_term; +extern unsigned long video_screen_size; +extern unsigned short video_port_reg; +extern unsigned short video_port_val; + +extern int console_blanked; +extern int can_do_color; + +extern unsigned long video_font_height; +extern unsigned long video_scan_lines; +extern unsigned long default_font_height; +extern int video_font_is_default; + +extern unsigned char color_table[]; +extern int default_red[]; +extern int default_grn[]; +extern int default_blu[]; + +extern unsigned short __real_origin; +extern unsigned short __origin; +extern unsigned char has_wrapped; + +extern unsigned short *vc_scrbuf[MAX_NR_CONSOLES]; + +extern void do_unblank_screen(void); +extern unsigned short *screen_pos(int currcons, int w_offset, int viewed); +extern unsigned short screen_word(int currcons, int offset, int viewed); +extern int scrw2glyph(unsigned short scr_word); +extern void complement_pos(int currcons, int offset); +extern void invert_screen(int currcons, int offset, int count, int shift); + +#define reverse_video_char(a) (((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77)) +#define reverse_video_short(a) (((a) & 0x88ff) | \ + (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4)) +/* this latter line used to have masks 0xf000 and 0x0f00, but selection + requires a self-inverse operation; moreover, the old version looks wrong */ + +extern void getconsxy(int currcons, char *p); +extern void putconsxy(int currcons, char *p); + + +/* how to access screen memory */ + +#if defined(CONFIG_TGA_CONSOLE) + +extern int tga_blitc(unsigned int, unsigned long); +extern unsigned long video_mem_term; + +/* + * TGA console screen memory access + * + * TGA is *not* a character/attribute cell device; font bitmaps must be rendered + * to the screen pixels. + * + * We must test for an Alpha kernel virtual address that falls within + * the "shadow screen" memory. This condition indicates we really want + * to write to the screen, so, we do... :-) + * + * NOTE also: there's only *TWO* operations: to put/get a character/attribute. + * All the others needed by VGA support go away, as Not Applicable for TGA. + */ +static inline void scr_writew(unsigned short val, unsigned short * addr) +{ + /* + * always deposit the char/attr, then see if it was to "screen" mem. + * if so, then render the char/attr onto the real screen. + */ + *addr = val; + if ((unsigned long)addr < video_mem_term && + (unsigned long)addr >= video_mem_base) { + tga_blitc(val, (unsigned long) addr); + } +} + +static inline unsigned short scr_readw(unsigned short * addr) +{ + return *addr; +} + +#elif defined(CONFIG_SUN_CONSOLE) +#include +#include +extern int sun_blitc(unsigned int, unsigned long); +extern void memsetw(void * s, unsigned short c, unsigned int count); +extern void memcpyw(unsigned short *to, unsigned short *from, unsigned int count); +extern unsigned long video_mem_term; + +/* Basically the same as the TGA stuff. */ +static inline void scr_writew(unsigned short val, unsigned short * addr) +{ + /* + * always deposit the char/attr, then see if it was to "screen" mem. + * if so, then render the char/attr onto the real screen. + */ + if (*addr != val) { + *addr = val; + if ((unsigned long)addr < video_mem_term && + (unsigned long)addr >= video_mem_base && + vt_cons [fg_console]->vc_mode == KD_TEXT) + sun_blitc(val, (unsigned long) addr); + } +} + +static inline unsigned short scr_readw(unsigned short * addr) +{ + return *addr; +} + +#else /* CONFIG_TGA_CONSOLE || CONFIG_SUN_CONSOLE */ + +/* + * normal VGA console access + * + */ + +#include + +/* + * NOTE: "(long) addr < 0" tests for an Alpha kernel virtual address; this + * indicates a VC's backing store; otherwise, it's a bus memory address, for + * the VGA's screen memory, so we do the Alpha "swizzle"... :-) + */ +static inline void scr_writeb(unsigned char val, unsigned char * addr) +{ + if ((long) addr < 0) + *addr = val; + else + writeb(val, (unsigned long) addr); +} + +static inline unsigned char scr_readb(unsigned char * addr) +{ + if ((long) addr < 0) + return *addr; + return readb((unsigned long) addr); +} + +static inline void scr_writew(unsigned short val, unsigned short * addr) +{ + if ((long) addr < 0) + *addr = val; + else + writew(val, (unsigned long) addr); +} + +static inline unsigned short scr_readw(unsigned short * addr) +{ + if ((long) addr < 0) + return *addr; + return readw((unsigned long) addr); +} + +#endif /* CONFIG_TGA_CONSOLE */ + +#ifndef CONFIG_SUN_CONSOLE +static inline void memsetw(void * s, unsigned short c, unsigned int count) +{ + unsigned short * addr = (unsigned short *) s; + + count /= 2; + while (count) { + count--; + scr_writew(c, addr++); + } +} + +static inline void memcpyw(unsigned short *to, unsigned short *from, + unsigned int count) +{ + count /= 2; + while (count) { + count--; + scr_writew(scr_readw(from++), to++); + } +} +#endif /* CONFIG_SUN_CONSOLE */ diff -u --recursive --new-file v2.1.42/linux/include/linux/socket.h linux/include/linux/socket.h --- v2.1.42/linux/include/linux/socket.h Thu May 15 16:48:05 1997 +++ linux/include/linux/socket.h Thu Jun 12 16:22:10 1997 @@ -140,7 +140,7 @@ #define AF_X25 9 /* Reserved for X.25 project */ #define AF_INET6 10 /* IP version 6 */ #define AF_ROSE 11 /* Amateur Radio X.25 PLP */ -#define AF_DECNET 12 /* Reserved for DECnet project */ +#define AF_DECnet 12 /* Reserved for DECnet project */ #define AF_NETBEUI 13 /* Reserved for 802.2LLC project*/ #define AF_SECURITY 14 /* Security callback pseudo AF */ #define pseudo_AF_KEY 15 /* PF_KEY key management API */ @@ -160,7 +160,7 @@ #define PF_X25 AF_X25 #define PF_INET6 AF_INET6 #define PF_ROSE AF_ROSE -#define PF_DECNET AF_DECNET +#define PF_DECnet AF_DECnet #define PF_NETBEUI AF_NETBEUI #define PF_SECURITY AF_SECURITY #define PF_KEY pseudo_AF_KEY diff -u --recursive --new-file v2.1.42/linux/include/linux/swap.h linux/include/linux/swap.h --- v2.1.42/linux/include/linux/swap.h Thu Jun 12 15:28:33 1997 +++ linux/include/linux/swap.h Mon Jun 16 08:46:24 1997 @@ -66,8 +66,7 @@ /* 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 int add_to_swap_cache(struct page *, unsigned long); extern void swap_duplicate(unsigned long); /* linux/mm/swapfile.c */ @@ -90,8 +89,6 @@ #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; @@ -101,39 +98,37 @@ extern unsigned long swap_cache_find_success; #endif -extern inline unsigned long in_swap_cache(unsigned long index) +extern inline unsigned long in_swap_cache(struct page *page) { - return swap_cache[index]; + if (PageSwapCache(page)) + return page->pg_swap_entry; + return 0; } -extern inline long find_in_swap_cache(unsigned long index) +extern inline long find_in_swap_cache(struct page *page) { - unsigned long entry; - #ifdef SWAP_CACHE_INFO swap_cache_find_total++; #endif - entry = xchg(swap_cache + index, 0); + if (PageTestandClearSwapCache(page)) { #ifdef SWAP_CACHE_INFO - if (entry) swap_cache_find_success++; #endif - return entry; + return page->pg_swap_entry; + } + return 0; } -extern inline int delete_from_swap_cache(unsigned long index) +extern inline int delete_from_swap_cache(struct page *page) { - unsigned long entry; - #ifdef SWAP_CACHE_INFO swap_cache_del_total++; #endif - entry = xchg(swap_cache + index, 0); - if (entry) { + if (PageTestandClearSwapCache(page)) { #ifdef SWAP_CACHE_INFO swap_cache_del_success++; #endif - swap_free(entry); + swap_free(page->pg_swap_entry); return 1; } return 0; diff -u --recursive --new-file v2.1.42/linux/include/linux/sysctl.h linux/include/linux/sysctl.h --- v2.1.42/linux/include/linux/sysctl.h Thu May 29 21:53:11 1997 +++ linux/include/linux/sysctl.h Thu Jun 12 16:22:10 1997 @@ -68,6 +68,8 @@ KERN_SPARC_REBOOT, /* reboot command on Sparc */ KERN_CTLALTDEL, /* int: allow ctl-alt-del to reboot */ KERN_PRINTK, /* sturct: control printk logging parameters */ + KERN_NAMETRANS, /* Name translation */ + KERN_STATINODE }; @@ -75,7 +77,6 @@ enum { VM_SWAPCTL=1, /* struct: Set vm swapping control */ - VM_KSWAPD, /* struct: control background pageout */ VM_SWAPOUT, /* int: Background pageout interval */ VM_FREEPG, /* struct: Set free page thresholds */ VM_BDFLUSH, /* struct: Control buffer cache flushing */ @@ -100,6 +101,7 @@ NET_ROSE, NET_X25, NET_TR, + NET_DECNET }; @@ -110,6 +112,7 @@ NET_CORE_RMEM_MAX, NET_CORE_WMEM_DEFAULT, NET_CORE_RMEM_DEFAULT, + NET_CORE_DESTROY_DELAY, }; /* /proc/sys/net/ethernet */ @@ -118,12 +121,19 @@ /* /proc/sys/net/unix */ +enum +{ + NET_UNIX_DESTROY_DELAY=1, + NET_UNIX_DELETE_DELAY, +}; + /* /proc/sys/net/ipv4 */ enum { NET_IPV4_ARP_RES_TIME=1, NET_IPV4_ARP_DEAD_RES_TIME, NET_IPV4_ARP_MAX_TRIES, + NET_IPV4_ARP_MAX_PINGS, NET_IPV4_ARP_TIMEOUT, NET_IPV4_ARP_CHECK_INTERVAL, NET_IPV4_ARP_CONFIRM_INTERVAL, @@ -147,9 +157,22 @@ NET_IPV4_ACCEPT_REDIRECTS, NET_IPV4_SECURE_REDIRECTS, NET_IPV4_RFC1620_REDIRECTS, - NET_TCP_SYN_RETRIES, - NET_IPFRAG_HIGH_THRESH, - NET_IPFRAG_LOW_THRESH, + NET_IPV4_TCP_SYN_RETRIES, + NET_IPV4_IPFRAG_HIGH_THRESH, + NET_IPV4_IPFRAG_LOW_THRESH, + NET_IPV4_IPFRAG_TIME, + NET_IPV4_TCP_MAX_KA_PROBES, + NET_IPV4_TCP_KEEPALIVE_TIME, + NET_IPV4_TCP_KEEPALIVE_PROBES, + NET_IPV4_TCP_RETRIES1, + NET_IPV4_TCP_RETRIES2, + NET_IPV4_TCP_MAX_DELAY_ACKS, + NET_IPV4_TCP_FIN_TIMEOUT, + NET_IPV4_IGMP_MAX_HOST_REPORT_DELAY, + NET_IPV4_IGMP_TIMER_SCALE, + NET_IPV4_IGMP_AGE_THRESHOLD, + NET_TCP_SYNCOOKIES, + NET_TCP_ALWAYS_SYNCOOKIE, }; @@ -176,7 +199,15 @@ /* /proc/sys/net/ipx */ + /* /proc/sys/net/appletalk */ +enum { + NET_ATALK_AARP_EXPIRY_TIME = 1, + NET_ATALK_AARP_TICK_TIME, + NET_ATALK_AARP_RETRANSMIT_LIMIT, + NET_ATALK_AARP_RESOLVE_TIME, +}; + /* /proc/sys/net/netrom */ enum { @@ -240,6 +271,16 @@ NET_TR_RIF_TIMEOUT=1 }; +/* /proc/sys/net/decnet */ +enum { + NET_DECNET_DEF_T3_BROADCAST = 1, + NET_DECNET_DEF_T3_POINTTOPOINT, + NET_DECNET_DEF_T1, + NET_DECNET_DEF_BCT1, + NET_DECNET_CACHETIMEOUT, + NET_DECNET_DEBUG_LEVEL +}; + /* CTL_PROC names: */ /* CTL_FS names: */ @@ -269,6 +310,8 @@ void *, size_t *); extern int proc_dointvec_minmax(ctl_table *, int, struct file *, void *, size_t *); +extern int proc_dointvec_jiffies(ctl_table *, int, struct file *, + void *, size_t *); extern int do_sysctl (int *name, int nlen, void *oldval, size_t *oldlenp, diff -u --recursive --new-file v2.1.42/linux/include/linux/sysrq.h linux/include/linux/sysrq.h --- v2.1.42/linux/include/linux/sysrq.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/sysrq.h Sun Jun 15 15:12:30 1997 @@ -0,0 +1,25 @@ +/* -*- linux-c -*- + * + * $Id: sysrq.h,v 1.2 1997/05/31 18:33:41 mj Exp $ + * + * Linux Magic System Request Key Hacks + * + * (c) 1997 Martin Mares + */ + +#include + +extern int emergency_sync_scheduled; + +#define EMERG_SYNC 1 +#define EMERG_REMOUNT 2 + +extern void do_emergency_sync(void); + +#ifdef CONFIG_MAGIC_SYSRQ +#define CHECK_EMERGENCY_SYNC \ + if (emergency_sync_scheduled) \ + do_emergency_sync(); +#else +#define CHECK_EMERGENCY_SYNC +#endif diff -u --recursive --new-file v2.1.42/linux/include/linux/sysv_fs.h linux/include/linux/sysv_fs.h --- v2.1.42/linux/include/linux/sysv_fs.h Thu Jun 12 15:30:55 1997 +++ linux/include/linux/sysv_fs.h Sun Jun 15 15:14:49 1997 @@ -373,7 +373,7 @@ extern int sysv_link(struct inode * oldinode, struct inode * dir, const char * name, int len); extern int sysv_mknod(struct inode * dir, const char * name, int len, int mode, int rdev); extern int sysv_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len, int must_be_dir); + struct inode * new_dir, const char * new_name, int new_len); extern struct inode * sysv_new_inode(const struct inode * dir); extern void sysv_free_inode(struct inode * inode); extern unsigned long sysv_count_free_inodes(struct super_block *sb); diff -u --recursive --new-file v2.1.42/linux/include/linux/umsdos_fs.p linux/include/linux/umsdos_fs.p --- v2.1.42/linux/include/linux/umsdos_fs.p Sat Nov 30 02:24:02 1996 +++ linux/include/linux/umsdos_fs.p Thu Jun 12 16:22:10 1997 @@ -122,8 +122,7 @@ int old_len, struct inode *new_dir, const char *new_name, - int new_len, - int must_be_dir); + int new_len); /* rdir.c 22/03/95 03.31.42 */ int umsdos_rlookup_x (struct inode *dir, const char *name, diff -u --recursive --new-file v2.1.42/linux/include/linux/vt_kern.h linux/include/linux/vt_kern.h --- v2.1.42/linux/include/linux/vt_kern.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/vt_kern.h Thu Jun 12 16:22:10 1997 @@ -0,0 +1,39 @@ +#ifndef _VT_KERN_H +#define _VT_KERN_H + +/* + * this really is an extension of the vc_cons structure in console.c, but + * with information needed by the vt package + */ + +#include + +/* + * Presently, a lot of graphics programs do not restore the contents of + * the higher font pages. Defining this flag will avoid use of them, but + * will lose support for PIO_FONTRESET. Note that many font operations are + * not likely to work with these programs anyway; they need to be + * fixed. The linux/Documentation directory includes a code snippet + * to save and restore the text font. + */ +#define BROKEN_GRAPHICS_PROGRAMS 1 + +extern struct vt_struct { + int vc_num; /* The console number */ + unsigned char vc_mode; /* KD_TEXT, ... */ + unsigned char vc_kbdraw; + unsigned char vc_kbde0; + unsigned char vc_kbdleds; + struct vt_mode vt_mode; + int vt_pid; + int vt_newvt; + struct wait_queue *paste_wait; +} *vt_cons[MAX_NR_CONSOLES]; + +void (*kd_mksound)(unsigned int hz, unsigned int ticks); +int vc_allocate(unsigned int console); +int vc_cons_allocated(unsigned int console); +int vc_resize(unsigned long lines, unsigned long cols); +void vc_disallocate(unsigned int console); + +#endif /* _VT_KERN_H */ diff -u --recursive --new-file v2.1.42/linux/include/linux/wrapper.h linux/include/linux/wrapper.h --- v2.1.42/linux/include/linux/wrapper.h Fri Apr 12 00:33:25 1996 +++ linux/include/linux/wrapper.h Thu Jun 12 16:22:10 1997 @@ -20,9 +20,9 @@ #define module_unregister_blkdev unregister_blkdev #define inode_get_rdev(i) i->i_rdev -#define inode_get_count(i) i->i_count -#define inode_inc_count(i) i->i_count++ -#define inode_dec_count(i) i->i_count-- +#define inode_get_count(i) atomic_read(&((i)->i_count)) +#define inode_inc_count(i) atomic_inc(&((i)->i_count)) +#define inode_dec_count(i) atomic_dec(&((i)->i_count)) #define file_get_flags(f) f->f_flags @@ -35,6 +35,6 @@ #define mem_map_reserve(p) set_bit(PG_reserved, &mem_map[p].flags) #define mem_map_unreserve(p) clear_bit(PG_reserved, &mem_map[p].flags) -#define mem_map_inc_count(p) mem_map[p].count++ -#define mem_map_dec_count(p) mem_map[p].count-- +#define mem_map_inc_count(p) atomic_inc(&(mem_map[p].count)) +#define mem_map_dec_count(p) atomic_dec(&(mem_map[p].count)) #endif diff -u --recursive --new-file v2.1.42/linux/include/net/checksum.h linux/include/net/checksum.h --- v2.1.42/linux/include/net/checksum.h Thu Jun 12 15:31:03 1997 +++ linux/include/net/checksum.h Sun Jun 15 15:14:59 1997 @@ -26,6 +26,7 @@ #ifndef _CHECKSUM_H #define _CHECKSUM_H +#include #include #include #include diff -u --recursive --new-file v2.1.42/linux/include/net/sock.h linux/include/net/sock.h --- v2.1.42/linux/include/net/sock.h Thu Jun 12 15:29:23 1997 +++ linux/include/net/sock.h Sun Jun 15 15:13:17 1997 @@ -70,6 +70,10 @@ #include #endif +#if defined(CONFIG_DECNET) || defined(CONFIG_DECNET_MODULE) +#include +#endif + #include #include @@ -447,6 +451,7 @@ union { + void *destruct_hook; struct unix_opt af_unix; #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) struct atalk_sock af_at; @@ -472,6 +477,9 @@ rose_cb *rose; #endif #endif +#if defined(CONFIG_DECNET) || defined(CONFIG_DECNET_MODULE) + dn_cb *dn; +#endif } protinfo; /* @@ -523,6 +531,7 @@ int (*backlog_rcv) (struct sock *sk, struct sk_buff *skb); + void (*destruct)(struct sock *sk); }; /* diff -u --recursive --new-file v2.1.42/linux/init/main.c linux/init/main.c --- v2.1.42/linux/init/main.c Thu May 29 21:53:11 1997 +++ linux/init/main.c Thu Jun 12 16:22:10 1997 @@ -32,6 +32,7 @@ #include #include #include +#include #include #ifdef CONFIG_ROOT_NFS #include @@ -72,6 +73,7 @@ extern long mca_init(long, long); extern long sbus_init(long, long); extern void sysctl_init(void); +extern void filescache_init(void); extern void smp_setup(char *str, int *ints); extern void no_scroll(char *str, int *ints); @@ -84,6 +86,9 @@ extern void lp_setup(char *str, int *ints); #endif extern void eth_setup(char *str, int *ints); +#ifdef CONFIG_DECNET +extern void decnet_setup(char *str, int *ints); +#endif extern void xd_setup(char *str, int *ints); #ifdef CONFIG_BLK_DEV_EZ extern void ez_setup(char *str, int *ints); @@ -324,6 +329,9 @@ #ifdef CONFIG_INET { "ether=", eth_setup }, #endif +#ifdef CONFIG_DECNET + { "decnet=", decnet_setup }, +#endif #ifdef CONFIG_PRINTER { "lp=", lp_setup }, #endif @@ -551,6 +559,12 @@ return 1; } #endif +#ifdef CONFIG_TRANS_NAMES + if(!strncmp(line,"nametrans=",10)) { + nametrans_setup(line+10); + return 1; + } +#endif while (bootsetups[i].str) { int n = strlen(bootsetups[i].str); if (!strncmp(line,bootsetups[i].str,n)) { @@ -886,6 +900,7 @@ proc_root_init(); #endif uidcache_init(); + filescache_init(); vma_init(); buffer_init(); inode_init(); diff -u --recursive --new-file v2.1.42/linux/kernel/exit.c linux/kernel/exit.c --- v2.1.42/linux/kernel/exit.c Wed May 28 10:51:33 1997 +++ linux/kernel/exit.c Thu Jun 12 16:22:10 1997 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -366,14 +367,18 @@ if (i >= NR_OPEN) break; while (set) { - if (set & 1) + if (set & 1) { close_fp(files->fd[i]); + files->fd[i] = NULL; + } i++; set >>= 1; } } } +extern kmem_cache_t *files_cachep; + static inline void __exit_files(struct task_struct *tsk) { struct files_struct * files = tsk->files; @@ -382,7 +387,7 @@ tsk->files = NULL; if (!--files->count) { close_files(files); - kfree(files); + kmem_cache_free(files_cachep, files); } } } diff -u --recursive --new-file v2.1.42/linux/kernel/fork.c linux/kernel/fork.c --- v2.1.42/linux/kernel/fork.c Sat May 24 09:10:25 1997 +++ linux/kernel/fork.c Thu Jun 12 16:22:10 1997 @@ -11,6 +11,7 @@ * management can be a bitch. See 'mm/mm.c': 'copy_page_tables()' */ +#include #include #include #include @@ -36,6 +37,9 @@ /* SLAB cache for mm_struct's. */ kmem_cache_t *mm_cachep; +/* SLAB cache for files structs */ +kmem_cache_t *files_cachep; + struct task_struct *pidhash[PIDHASH_SZ]; spinlock_t pidhash_lock = SPIN_LOCK_UNLOCKED; @@ -52,7 +56,10 @@ unsigned short uid; int task_count; } *uidhash[UIDHASH_SZ]; + +#ifdef __SMP__ static spinlock_t uidhash_lock = SPIN_LOCK_UNLOCKED; +#endif kmem_cache_t *uid_cachep; @@ -116,7 +123,7 @@ return 0; } -void uidcache_init(void) +__initfunc(void uidcache_init(void)) { int i; @@ -148,8 +155,10 @@ return -EAGAIN; } +#ifdef __SMP__ /* Protects next_safe and last_pid. */ static spinlock_t lastpid_lock = SPIN_LOCK_UNLOCKED; +#endif static int get_pid(unsigned long flags) { @@ -216,7 +225,7 @@ tmp->vm_next = NULL; inode = tmp->vm_inode; if (inode) { - inode->i_count++; + atomic_inc(&inode->i_count); if (tmp->vm_flags & VM_DENYWRITE) inode->i_writecount--; @@ -294,15 +303,35 @@ tsk->fs->count = 1; tsk->fs->umask = current->fs->umask; if ((tsk->fs->root = current->fs->root)) - tsk->fs->root->i_count++; + atomic_inc(&tsk->fs->root->i_count); if ((tsk->fs->pwd = current->fs->pwd)) - tsk->fs->pwd->i_count++; + atomic_inc(&tsk->fs->pwd->i_count); return 0; } +/* return value is only accurate by +-sizeof(long)*8 fds */ +/* XXX make this architecture specific */ +static inline int __copy_fdset(unsigned long *d, unsigned long *src) +{ + int i; + unsigned long *p = src; + unsigned long *max = src; + + for (i = __FDSET_LONGS; i; --i) { + if ((*d++ = *p++) != 0) + max = p; + } + return (max - src)*sizeof(long)*8; +} + +static inline int copy_fdset(fd_set *dst, fd_set *src) +{ + return __copy_fdset(dst->fds_bits, src->fds_bits); +} + static inline int copy_files(unsigned long clone_flags, struct task_struct * tsk) { - int i; + int i; struct files_struct *oldf, *newf; struct file **old_fds, **new_fds; @@ -312,18 +341,18 @@ return 0; } - newf = kmalloc(sizeof(*newf), GFP_KERNEL); + newf = kmem_cache_alloc(files_cachep, SLAB_KERNEL); tsk->files = newf; - if (!newf) + if (!newf) return -1; newf->count = 1; newf->close_on_exec = oldf->close_on_exec; - newf->open_fds = oldf->open_fds; + i = copy_fdset(&newf->open_fds,&oldf->open_fds); old_fds = oldf->fd; new_fds = newf->fd; - for (i = NR_OPEN; i != 0; i--) { + for (; i != 0; i--) { struct file * f = *old_fds; old_fds++; *new_fds = f; @@ -469,4 +498,22 @@ fork_out: unlock_kernel(); return error; +} + +static void files_ctor(void *fp, kmem_cache_t *cachep, unsigned long flags) +{ + struct files_struct *f = fp; + + memset(f, 0, sizeof(*f)); +} + +__initfunc(void filescache_init(void)) +{ + files_cachep = kmem_cache_create("files_cache", + sizeof(struct files_struct), + 0, + SLAB_HWCACHE_ALIGN, + files_ctor, NULL); + if (!files_cachep) + panic("Cannot create files cache"); } diff -u --recursive --new-file v2.1.42/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v2.1.42/linux/kernel/ksyms.c Sat May 24 09:10:25 1997 +++ linux/kernel/ksyms.c Thu Jun 12 16:22:10 1997 @@ -142,9 +142,8 @@ EXPORT_SYMBOL(putname); EXPORT_SYMBOL(__fput); EXPORT_SYMBOL(__iget); -EXPORT_SYMBOL(iput); +EXPORT_SYMBOL(_iput); EXPORT_SYMBOL(namei); -EXPORT_SYMBOL(lnamei); EXPORT_SYMBOL(open_namei); EXPORT_SYMBOL(sys_close); EXPORT_SYMBOL(close_fp); @@ -168,8 +167,6 @@ EXPORT_SYMBOL(__wait_on_buffer); EXPORT_SYMBOL(mark_buffer_uptodate); EXPORT_SYMBOL(unlock_buffer); -EXPORT_SYMBOL(dcache_lookup); -EXPORT_SYMBOL(dcache_add); EXPORT_SYMBOL(add_blkdev_randomness); EXPORT_SYMBOL(generic_file_read); EXPORT_SYMBOL(generic_file_write); @@ -245,6 +242,7 @@ EXPORT_SYMBOL(sysctl_intvec); EXPORT_SYMBOL(proc_dostring); EXPORT_SYMBOL(proc_dointvec); +EXPORT_SYMBOL(proc_dointvec_jiffies); EXPORT_SYMBOL(proc_dointvec_minmax); /* interrupt handling */ @@ -338,11 +336,12 @@ EXPORT_SYMBOL(si_meminfo); /* Added to make file system as module */ +EXPORT_SYMBOL(get_super); EXPORT_SYMBOL(set_writetime); EXPORT_SYMBOL(sys_tz); EXPORT_SYMBOL(__wait_on_super); EXPORT_SYMBOL(file_fsync); -EXPORT_SYMBOL(clear_inode); +EXPORT_SYMBOL(_clear_inode); EXPORT_SYMBOL(refile_buffer); EXPORT_SYMBOL(nr_async_pages); EXPORT_SYMBOL(___strtok); @@ -353,7 +352,7 @@ EXPORT_SYMBOL(blkdev_inode_operations); EXPORT_SYMBOL(read_ahead); EXPORT_SYMBOL(get_hash_table); -EXPORT_SYMBOL(get_empty_inode); +EXPORT_SYMBOL(_get_empty_inode); EXPORT_SYMBOL(insert_inode_hash); EXPORT_SYMBOL(event); EXPORT_SYMBOL(__down); diff -u --recursive --new-file v2.1.42/linux/kernel/panic.c linux/kernel/panic.c --- v2.1.42/linux/kernel/panic.c Tue May 13 22:41:20 1997 +++ linux/kernel/panic.c Thu Jun 12 16:22:10 1997 @@ -16,6 +16,7 @@ #include #include #include +#include asmlinkage void sys_sync(void); /* it's really int */ extern void unblank_console(void); @@ -69,6 +70,8 @@ printk("Press L1-A to return to the boot prom\n"); #endif sti(); - for(;;); + for(;;) { + CHECK_EMERGENCY_SYNC + } } diff -u --recursive --new-file v2.1.42/linux/kernel/sched.c linux/kernel/sched.c --- v2.1.42/linux/kernel/sched.c Sat May 24 09:10:25 1997 +++ linux/kernel/sched.c Thu Jun 12 16:22:10 1997 @@ -140,6 +140,7 @@ prev->next_run = p; } +#ifdef __SMP__ /* * The tasklist_lock protects the linked list of processes. * @@ -154,6 +155,7 @@ rwlock_t tasklist_lock = RW_LOCK_UNLOCKED; spinlock_t scheduler_lock = SPIN_LOCK_UNLOCKED; static spinlock_t runqueue_lock = SPIN_LOCK_UNLOCKED; +#endif /* * Wake up a process. Put it on the run-queue if it's not diff -u --recursive --new-file v2.1.42/linux/kernel/sys.c linux/kernel/sys.c --- v2.1.42/linux/kernel/sys.c Sat May 24 09:10:25 1997 +++ linux/kernel/sys.c Thu Jun 12 16:22:10 1997 @@ -4,6 +4,7 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ +#include #include #include #include @@ -20,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -397,6 +399,7 @@ acct_file.f_op->write(acct_file.f_inode, &acct_file, (char *)&ac, sizeof(struct acct)); + /* inode->i_status |= ST_MODIFIED is willingly *not* done here */ set_fs(fs); } @@ -940,6 +943,9 @@ if(copy_from_user(system_utsname.nodename, name, len)) return -EFAULT; system_utsname.nodename[len] = 0; +#ifdef CONFIG_TRANS_NAMES + translations_dirty = 1; +#endif return 0; } @@ -968,6 +974,9 @@ if(copy_from_user(system_utsname.domainname, name, len)) return -EFAULT; system_utsname.domainname[len] = 0; +#ifdef CONFIG_TRANS_NAMES + translations_dirty = 1; +#endif return 0; } diff -u --recursive --new-file v2.1.42/linux/kernel/sysctl.c linux/kernel/sysctl.c --- v2.1.42/linux/kernel/sysctl.c Tue May 13 22:41:20 1997 +++ linux/kernel/sysctl.c Thu Jun 12 16:22:10 1997 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -37,9 +38,7 @@ /* External variables not in a header file. */ extern int panic_timeout; -extern int console_loglevel, default_message_loglevel; -extern int minimum_console_loglevel, default_console_loglevel; -extern int C_A_D, swapout_interval; +extern int console_loglevel, C_A_D, swapout_interval; extern int bdf_prm[], bdflush_min[], bdflush_max[]; extern char binfmt_java_interpreter[], binfmt_java_appletviewer[]; extern int sysctl_overcommit_memory; @@ -104,7 +103,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -114,6 +112,7 @@ extern struct proc_dir_entry proc_sys_root; +extern int inodes_stat[]; static void register_proc_table(ctl_table *, struct proc_dir_entry *); static void unregister_proc_table(ctl_table *, struct proc_dir_entry *); #endif @@ -142,7 +141,9 @@ 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), + {KERN_NRINODE, "inode-nr", &inodes_stat, 2*sizeof(int), + 0444, NULL, &proc_dointvec}, + {KERN_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int), 0444, NULL, &proc_dointvec}, {KERN_MAXINODE, "inode-max", &max_inodes, sizeof(int), 0644, NULL, &proc_dointvec}, @@ -170,6 +171,10 @@ {KERN_JAVA_APPLETVIEWER, "java-appletviewer", binfmt_java_appletviewer, 64, 0644, NULL, &proc_dostring, &sysctl_string }, #endif +#ifdef CONFIG_TRANS_NAMES + {KERN_NAMETRANS, "nametrans", nametrans_txt, MAX_DEFAULT_TRANSLEN, + 0644, NULL, &nametrans_dostring, &nametrans_string}, +#endif #ifdef __sparc__ {KERN_SPARC_REBOOT, "reboot-cmd", reboot_command, 256, 0644, NULL, &proc_dostring, &sysctl_string }, @@ -184,6 +189,8 @@ static ctl_table vm_table[] = { {VM_SWAPCTL, "swapctl", &swap_control, sizeof(swap_control_t), 0600, NULL, &proc_dointvec}, + {VM_SWAPOUT, "swapout_interval", + &swapout_interval, sizeof(int), 0600, NULL, &proc_dointvec_jiffies}, {VM_FREEPG, "freepages", &min_free_pages, 3*sizeof(int), 0600, NULL, &proc_dointvec}, {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL, @@ -611,8 +618,8 @@ return 0; } -int proc_dointvec(ctl_table *table, int write, struct file *filp, - void *buffer, size_t *lenp) +static int do_proc_dointvec(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp, int conv) { int *i, vleft, first=1, len, left, neg, val; #define TMPBUFLEN 20 @@ -655,7 +662,7 @@ } if (*p < '0' || *p > '9') break; - val = simple_strtoul(p, &p, 0); + val = simple_strtoul(p, &p, 0) * conv; len = p-buf; if ((len < left) && *p && !isspace(*p)) break; @@ -668,7 +675,7 @@ p = buf; if (!first) *p++ = '\t'; - sprintf(p, "%d", *i); + sprintf(p, "%d", (*i) / conv); len = strlen(buf); if (len > left) len = left; @@ -702,6 +709,12 @@ return 0; } +int proc_dointvec(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + return do_proc_dointvec(table,write,filp,buffer,lenp,1); +} + int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp, void *buffer, size_t *lenp) { @@ -800,6 +813,13 @@ return 0; } +/* Like proc_dointvec, but converts seconds to jiffies */ +int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + return do_proc_dointvec(table,write,filp,buffer,lenp,HZ); +} + #else /* CONFIG_PROC_FS */ int proc_dostring(ctl_table *table, int write, struct file *filp, @@ -862,6 +882,9 @@ if (len == table->maxlen) len--; ((char *) table->data)[len] = 0; +#ifdef CONFIG_TRANS_NAMES + translations_dirty = 1; +#endif } return 0; } diff -u --recursive --new-file v2.1.42/linux/mm/filemap.c linux/mm/filemap.c --- v2.1.42/linux/mm/filemap.c Tue May 13 22:41:20 1997 +++ linux/mm/filemap.c Thu Jun 12 16:22:10 1997 @@ -919,6 +919,7 @@ retval = -EIO; if (size == file->f_op->write(inode, file, (const char *) page, size)) retval = 0; + /* inode->i_status |= ST_MODIFIED is willingly *not* done here */ set_fs(old_fs); return retval; } @@ -1193,7 +1194,7 @@ inode->i_dirt = 1; } vma->vm_inode = inode; - inode->i_count++; + atomic_inc(&inode->i_count); vma->vm_ops = ops; return 0; } diff -u --recursive --new-file v2.1.42/linux/mm/memory.c linux/mm/memory.c --- v2.1.42/linux/mm/memory.c Sat May 24 09:10:25 1997 +++ linux/mm/memory.c Mon Jun 16 08:46:24 1997 @@ -195,7 +195,7 @@ } if (cow) pte = pte_wrprotect(pte); - if (delete_from_swap_cache(page_nr)) + if (delete_from_swap_cache(&mem_map[page_nr])) pte = pte_mkdirty(pte); set_pte(new_pte, pte_mkold(pte)); set_pte(old_pte, pte); diff -u --recursive --new-file v2.1.42/linux/mm/mlock.c linux/mm/mlock.c --- v2.1.42/linux/mm/mlock.c Sun Jan 26 02:07:49 1997 +++ linux/mm/mlock.c Thu Jun 12 16:22:11 1997 @@ -39,7 +39,7 @@ vma->vm_offset += vma->vm_start - n->vm_start; n->vm_flags = newflags; if (n->vm_inode) - n->vm_inode->i_count++; + atomic_inc(&n->vm_inode->i_count); if (n->vm_ops && n->vm_ops->open) n->vm_ops->open(n); insert_vm_struct(current->mm, n); @@ -60,7 +60,7 @@ n->vm_offset += n->vm_start - vma->vm_start; n->vm_flags = newflags; if (n->vm_inode) - n->vm_inode->i_count++; + atomic_inc(&n->vm_inode->i_count); if (n->vm_ops && n->vm_ops->open) n->vm_ops->open(n); insert_vm_struct(current->mm, n); @@ -90,7 +90,7 @@ right->vm_offset += right->vm_start - left->vm_start; vma->vm_flags = newflags; if (vma->vm_inode) - vma->vm_inode->i_count += 2; + atomic_add(2, &vma->vm_inode->i_count); if (vma->vm_ops && vma->vm_ops->open) { vma->vm_ops->open(left); vma->vm_ops->open(right); diff -u --recursive --new-file v2.1.42/linux/mm/mmap.c linux/mm/mmap.c --- v2.1.42/linux/mm/mmap.c Thu May 15 16:48:05 1997 +++ linux/mm/mmap.c Thu Jun 12 16:22:11 1997 @@ -409,7 +409,7 @@ mpnt->vm_offset += (end - area->vm_start); mpnt->vm_start = end; if (mpnt->vm_inode) - mpnt->vm_inode->i_count++; + atomic_inc(&mpnt->vm_inode->i_count); if (mpnt->vm_ops && mpnt->vm_ops->open) mpnt->vm_ops->open(mpnt); area->vm_end = addr; /* Truncate area */ @@ -646,7 +646,7 @@ } remove_shared_vm_struct(mpnt); if (mpnt->vm_inode) - mpnt->vm_inode->i_count--; + atomic_dec(&mpnt->vm_inode->i_count); kmem_cache_free(vm_area_cachep, mpnt); mpnt = prev; } diff -u --recursive --new-file v2.1.42/linux/mm/mprotect.c linux/mm/mprotect.c --- v2.1.42/linux/mm/mprotect.c Sun Jan 26 02:07:49 1997 +++ linux/mm/mprotect.c Thu Jun 12 16:22:11 1997 @@ -111,7 +111,7 @@ n->vm_flags = newflags; n->vm_page_prot = prot; if (n->vm_inode) - n->vm_inode->i_count++; + atomic_inc(&n->vm_inode->i_count); if (n->vm_ops && n->vm_ops->open) n->vm_ops->open(n); insert_vm_struct(current->mm, n); @@ -134,7 +134,7 @@ n->vm_flags = newflags; n->vm_page_prot = prot; if (n->vm_inode) - n->vm_inode->i_count++; + atomic_inc(&n->vm_inode->i_count); if (n->vm_ops && n->vm_ops->open) n->vm_ops->open(n); insert_vm_struct(current->mm, n); @@ -166,7 +166,7 @@ vma->vm_flags = newflags; vma->vm_page_prot = prot; if (vma->vm_inode) - vma->vm_inode->i_count += 2; + atomic_add(2, &vma->vm_inode->i_count); if (vma->vm_ops && vma->vm_ops->open) { vma->vm_ops->open(left); vma->vm_ops->open(right); diff -u --recursive --new-file v2.1.42/linux/mm/mremap.c linux/mm/mremap.c --- v2.1.42/linux/mm/mremap.c Sun Jan 26 02:07:49 1997 +++ linux/mm/mremap.c Thu Jun 12 16:22:11 1997 @@ -141,7 +141,7 @@ new_vma->vm_end = new_addr+new_len; new_vma->vm_offset = vma->vm_offset + (addr - vma->vm_start); if (new_vma->vm_inode) - new_vma->vm_inode->i_count++; + atomic_inc(&new_vma->vm_inode->i_count); if (new_vma->vm_ops && new_vma->vm_ops->open) new_vma->vm_ops->open(new_vma); insert_vm_struct(current->mm, new_vma); diff -u --recursive --new-file v2.1.42/linux/mm/page_alloc.c linux/mm/page_alloc.c --- v2.1.42/linux/mm/page_alloc.c Wed May 28 10:51:33 1997 +++ linux/mm/page_alloc.c Mon Jun 16 08:46:24 1997 @@ -97,7 +97,9 @@ * * Hint: -mask = 1+~mask */ +#ifdef __SMP__ static spinlock_t page_alloc_lock; +#endif static inline void free_pages_ok(unsigned long map_nr, unsigned long order) { @@ -131,9 +133,8 @@ void __free_page(struct page *page) { if (!PageReserved(page) && atomic_dec_and_test(&page->count)) { - unsigned long map_nr = page->map_nr; - delete_from_swap_cache(map_nr); - free_pages_ok(map_nr, 0); + delete_from_swap_cache(page); + free_pages_ok(page->map_nr, 0); } } @@ -146,7 +147,7 @@ if (PageReserved(map)) return; if (atomic_dec_and_test(&map->count)) { - delete_from_swap_cache(map_nr); + delete_from_swap_cache(map); free_pages_ok(map_nr, order); return; } @@ -278,8 +279,7 @@ 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; + mem_map = (mem_map_t *) LONG_ALIGN(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); @@ -334,7 +334,7 @@ } vma->vm_mm->rss++; tsk->maj_flt++; - if (!write_access && add_to_swap_cache(MAP_NR(page), entry)) { + if (!write_access && add_to_swap_cache(&mem_map[MAP_NR(page)], entry)) { /* keep swap page allocated for the moment (swap cache) */ set_pte(page_table, mk_pte(page, vma->vm_page_prot)); return; diff -u --recursive --new-file v2.1.42/linux/mm/page_io.c linux/mm/page_io.c --- v2.1.42/linux/mm/page_io.c Tue May 13 22:41:20 1997 +++ linux/mm/page_io.c Mon Jun 16 08:46:24 1997 @@ -83,7 +83,9 @@ set_bit(PG_free_after, &page->flags); set_bit(PG_decr_after, &page->flags); set_bit(PG_swap_unlock_after, &page->flags); - page->swap_unlock_entry = entry; + /* swap-cache shouldn't be set, but play safe */ + PageClearSwapCache(page); + page->pg_swap_entry = entry; atomic_inc(&nr_async_pages); } ll_rw_page(rw,p->swap_device,offset,buf); diff -u --recursive --new-file v2.1.42/linux/mm/slab.c linux/mm/slab.c --- v2.1.42/linux/mm/slab.c Wed May 28 10:51:33 1997 +++ linux/mm/slab.c Thu Jun 12 16:22:11 1997 @@ -769,6 +769,7 @@ printk("%sForcing size word alignment - %s\n", func_nm, name); } + cachep->c_org_size = size; #if SLAB_DEBUG_SUPPORT if (flags & SLAB_RED_ZONE) { /* There is no point trying to honour cache alignment when redzoning. */ @@ -776,7 +777,6 @@ size += 2*BYTES_PER_WORD; /* words for redzone */ } #endif /* SLAB_DEBUG_SUPPORT */ - cachep->c_org_size = size; align = BYTES_PER_WORD; if (flags & SLAB_HWCACHE_ALIGN) @@ -1250,18 +1250,18 @@ opps1: kmem_freepages(cachep, objp); failed: + spin_lock_irq(&cachep->c_spinlock); if (local_flags != SLAB_ATOMIC && cachep->c_gfporder) { /* For large order (>0) slabs, we try again. * Needed because the gfp() functions are not good at giving * out contigious pages unless pushed (but do not push too hard). */ - spin_lock_irq(&cachep->c_spinlock); if (cachep->c_failures++ < 4 && cachep->c_freep == kmem_slab_end(cachep)) goto re_try; cachep->c_failures = 1; /* Memory is low, don't try as hard next time. */ - cachep->c_growing--; - spin_unlock_irqrestore(&cachep->c_spinlock, save_flags); } + cachep->c_growing--; + spin_unlock_irqrestore(&cachep->c_spinlock, save_flags); return 0; } @@ -1467,16 +1467,14 @@ goto null_addr; #if SLAB_DEBUG_SUPPORT - if (cachep->c_flags & SLAB_RED_ZONE) - objp -= BYTES_PER_WORD; -#endif /* SLAB_DEBUG_SUPPORT */ - - -#if SLAB_DEBUG_SUPPORT /* A verify func is called without the cache-lock held. */ if (cachep->c_flags & SLAB_DEBUG_INITIAL) goto init_state_check; finished_initial: + + if (cachep->c_flags & SLAB_RED_ZONE) + goto red_zone; +return_red: #endif /* SLAB_DEBUG_SUPPORT */ spin_lock_irqsave(&cachep->c_spinlock, save_flags); @@ -1511,25 +1509,24 @@ slabp->s_inuse--; bufp->buf_nextp = slabp->s_freep; slabp->s_freep = bufp; - if (slabp->s_inuse) { - if (bufp->buf_nextp) { + if (bufp->buf_nextp) { + if (slabp->s_inuse) { /* (hopefully) The most common case. */ finished: #if SLAB_DEBUG_SUPPORT - /* Need to poision the obj while holding the lock. */ - if (cachep->c_flags & SLAB_POISION) + if (cachep->c_flags & SLAB_POISION) { + if (cachep->c_flags & SLAB_RED_ZONE) + objp += BYTES_PER_WORD; kmem_poision_obj(cachep, objp); - if (cachep->c_flags & SLAB_RED_ZONE) - goto red_zone; -return_red: + } #endif /* SLAB_DEBUG_SUPPORT */ spin_unlock_irqrestore(&cachep->c_spinlock, save_flags); return; } - kmem_cache_one_free(cachep, slabp); + kmem_cache_full_free(cachep, slabp); goto finished; } - kmem_cache_full_free(cachep, slabp); + kmem_cache_one_free(cachep, slabp); goto finished; } @@ -1563,20 +1560,20 @@ } goto passed_extra; red_zone: - /* We hold the cache-lock while checking the red-zone, just incase - * some tries to take this obj from us... + /* We do not hold the cache-lock while checking the red-zone. */ + objp -= BYTES_PER_WORD; if (xchg((unsigned long *)objp, SLAB_RED_MAGIC1) != SLAB_RED_MAGIC2) { /* Either write before start of obj, or a double free. */ kmem_report_free_err("Bad front redzone", objp, cachep); } - objp += BYTES_PER_WORD; - if (xchg((unsigned long *)(objp+cachep->c_org_size), SLAB_RED_MAGIC1) != SLAB_RED_MAGIC2) { + if (xchg((unsigned long *)(objp+cachep->c_org_size+BYTES_PER_WORD), SLAB_RED_MAGIC1) != SLAB_RED_MAGIC2) { /* Either write past end of obj, or a double free. */ kmem_report_free_err("Bad rear redzone", objp, cachep); } goto return_red; #endif /* SLAB_DEBUG_SUPPORT */ + bad_slab: /* Slab doesn't contain the correct magic num. */ if (slabp->s_magic == SLAB_MAGIC_DESTROYED) { @@ -1712,24 +1709,49 @@ kmem_slab_t *slabp; kmem_cache_t *searchp; kmem_cache_t *best_cachep; - unsigned long scan; - unsigned long reap_level; + unsigned int scan; + unsigned int reap_level; + static unsigned long call_count = 0; if (in_interrupt()) { printk("kmem_cache_reap() called within int!\n"); return 0; } - scan = 9-pri; - reap_level = pri >> 1; /* We really need a test semphore op so we can avoid sleeping when * !wait is true. */ down(&cache_chain_sem); + + scan = 10-pri; + if (pri == 6 && !dma) { + if (++call_count == 199) { + /* Hack Alert! + * Occassionally we try hard to reap a slab. + */ + call_count = 0UL; + reap_level = 0; + scan += 2; + } else + reap_level = 3; + } else { + if (pri >= 5) { + /* We also come here for dma==1 at pri==6, just + * to try that bit harder (assumes that there are + * less DMAable pages in a system - not always true, + * but this doesn't hurt). + */ + reap_level = 2; + } else + reap_level = 0; + } + best_cachep = NULL; searchp = clock_searchp; do { - unsigned long full_free; + unsigned int full_free; + unsigned int dma_flag; + /* It's safe to test this without holding the cache-lock. */ if (searchp->c_flags & SLAB_NO_REAP) goto next; @@ -1746,6 +1768,7 @@ printk(KERN_ERR "kmem_reap: Corrupted cache struct for %s\n", searchp->c_name); goto next; } + dma_flag = 0; full_free = 0; /* Count num of fully free slabs. Hopefully there are not many, @@ -1755,9 +1778,14 @@ while (!slabp->s_inuse && slabp != kmem_slab_end(searchp)) { slabp = slabp->s_prevp; full_free++; + if (slabp->s_dma) + dma_flag++; } spin_unlock_irq(&searchp->c_spinlock); + if (dma && !dma_flag) + goto next; + if (full_free) { if (full_free >= 10) { best_cachep = searchp; @@ -1768,10 +1796,8 @@ * more than one page per slab (as it can be difficult * to get high orders from gfp()). */ - if (pri == 6) { /* magic '6' from try_to_free_page() */ - if (searchp->c_ctor) - full_free--; - if (full_free && searchp->c_gfporder) + if (pri == 6) { /* magic '6' from try_to_free_page() */ + if (searchp->c_gfporder || searchp->c_ctor) full_free--; } if (full_free >= reap_level) { @@ -1796,8 +1822,21 @@ spin_lock_irq(&best_cachep->c_spinlock); if (!best_cachep->c_growing && !(slabp = best_cachep->c_lastp)->s_inuse && slabp != kmem_slab_end(best_cachep)) { + if (dma) { + do { + if (slabp->s_dma) + goto good_dma; + slabp = slabp->s_prevp; + } while (!slabp->s_inuse && slabp != kmem_slab_end(best_cachep)); + + /* Didn't found a DMA slab (there was a free one - + * must have been become active). + */ + goto dma_fail; +good_dma: + } if (slabp == best_cachep->c_freep) - best_cachep->c_freep = kmem_slab_end(best_cachep); + best_cachep->c_freep = slabp->s_nextp; kmem_slab_unlink(slabp); SLAB_STATS_INC_REAPED(best_cachep); @@ -1808,6 +1847,7 @@ kmem_slab_destroy(best_cachep, slabp); return 1; } +dma_fail: spin_unlock_irq(&best_cachep->c_spinlock); return 0; } diff -u --recursive --new-file v2.1.42/linux/mm/swap_state.c linux/mm/swap_state.c --- v2.1.42/linux/mm/swap_state.c Tue May 13 22:41:20 1997 +++ linux/mm/swap_state.c Mon Jun 16 08:46:24 1997 @@ -24,15 +24,6 @@ #include #include -/* - * 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; @@ -50,7 +41,7 @@ } #endif -int add_to_swap_cache(unsigned long index, unsigned long entry) +int add_to_swap_cache(struct page *page, unsigned long entry) { struct swap_info_struct * p = &swap_info[SWP_TYPE(entry)]; @@ -58,28 +49,15 @@ swap_cache_add_total++; #endif if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) { - entry = xchg(swap_cache + index, entry); - if (entry) { - printk("swap_cache: replacing non-NULL entry\n"); - } + page->pg_swap_entry = entry; + if (PageTestandSetSwapCache(page)) + printk("swap_cache: replacing non-empty entry\n"); #ifdef SWAP_CACHE_INFO swap_cache_add_success++; #endif return 1; } return 0; -} - -__initfunc(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) diff -u --recursive --new-file v2.1.42/linux/mm/swapfile.c linux/mm/swapfile.c --- v2.1.42/linux/mm/swapfile.c Tue May 13 22:41:20 1997 +++ linux/mm/swapfile.c Mon Jun 16 08:46:24 1997 @@ -176,14 +176,16 @@ if (pte_none(pte)) return 0; if (pte_present(pte)) { + struct page *pg; unsigned long page_nr = MAP_NR(pte_page(pte)); if (page_nr >= max_mapnr) return 0; - if (!in_swap_cache(page_nr)) + pg = mem_map + page_nr; + if (!in_swap_cache(pg)) return 0; - if (SWP_TYPE(in_swap_cache(page_nr)) != type) + if (SWP_TYPE(in_swap_cache(pg)) != type) return 0; - delete_from_swap_cache(page_nr); + delete_from_swap_cache(pg); set_pte(dir, pte_mkdirty(pte)); return 0; } @@ -332,7 +334,7 @@ lock_kernel(); if (!suser()) goto out; - err = namei(specialfile,&inode); + err = namei(NAM_FOLLOW_LINK, specialfile, &inode); if (err) goto out; prev = -1; @@ -486,12 +488,12 @@ } else { p->prio = --least_priority; } - error = namei(specialfile,&swap_inode); + error = namei(NAM_FOLLOW_LINK, specialfile, &swap_inode); if (error) goto bad_swap_2; p->swap_file = swap_inode; error = -EBUSY; - if (swap_inode->i_count != 1) + if (atomic_read(&swap_inode->i_count) != 1) goto bad_swap_2; error = -EINVAL; diff -u --recursive --new-file v2.1.42/linux/mm/vmscan.c linux/mm/vmscan.c --- v2.1.42/linux/mm/vmscan.c Wed May 28 10:51:33 1997 +++ linux/mm/vmscan.c Mon Jun 16 08:46:24 1997 @@ -87,7 +87,7 @@ /* Deal with page aging. Pages age from being unused; they * rejuvenate on being accessed. Only swap old pages (age==0 * is oldest). */ - if ((pte_dirty(pte) && delete_from_swap_cache(MAP_NR(page))) + if ((pte_dirty(pte) && delete_from_swap_cache(page_map)) || pte_young(pte)) { set_pte(page_table, pte_mkold(pte)); touch_page(page_map); @@ -117,7 +117,7 @@ free_page(page); return 1; /* we slept: the process may not exist any more */ } - if ((entry = find_in_swap_cache(MAP_NR(page)))) { + if ((entry = find_in_swap_cache(page_map))) { if (atomic_read(&page_map->count) != 1) { set_pte(page_table, pte_mkdirty(pte)); printk("Aiee.. duplicated cached swap-cache entry\n"); diff -u --recursive --new-file v2.1.42/linux/net/Config.in linux/net/Config.in --- v2.1.42/linux/net/Config.in Thu Mar 27 14:40:12 1997 +++ linux/net/Config.in Thu Jun 12 16:22:11 1997 @@ -42,6 +42,10 @@ dep_tristate 'Amateur Radio X.25 PLP (Rose)' CONFIG_ROSE $CONFIG_AX25 fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +# tristate 'DECnet Support (NOT YET FUNCTIONAL)' CONFIG_DECNET +# if [ "$CONFIG_DECNET" != "n" ]; then +# source net/decnet/Config.in +# fi tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25 tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB bool 'Bridging (EXPERIMENTAL)' CONFIG_BRIDGE diff -u --recursive --new-file v2.1.42/linux/net/Makefile linux/net/Makefile --- v2.1.42/linux/net/Makefile Mon Apr 7 11:35:32 1997 +++ linux/net/Makefile Thu Jun 12 16:22:11 1997 @@ -105,6 +105,14 @@ endif endif +ifeq ($(CONFIG_DECNET),y) +SUB_DIRS += decnet +else + ifeq ($(CONFIG_DECNET),m) + MOD_SUB_DIRS += decnet + endif +endif + # We must attach netsyms.o to socket.o, as otherwise there is nothing # to pull the object file from the archive. diff -u --recursive --new-file v2.1.42/linux/net/README linux/net/README --- v2.1.42/linux/net/README Thu Mar 27 14:40:13 1997 +++ linux/net/README Thu Jun 12 16:22:11 1997 @@ -8,6 +8,7 @@ appletalk alan@lxorguk.ukuu.org.uk and netatalk@umich.edu ax25 jsn@cs.nott.ac.uk core alan@lxorguk.ukuu.org.uk +decnet SteveW@ACM.org ethernet alan@lxorguk.ukuu.org.uk ipv4 davem@caip.rutgers.edu,Eric.Schenk@dna.lth.se ipv6 davem@caip.rutgers.edu,Eric.Schenk@dna.lth.se diff -u --recursive --new-file v2.1.42/linux/net/appletalk/aarp.c linux/net/appletalk/aarp.c --- v2.1.42/linux/net/appletalk/aarp.c Tue May 13 22:41:20 1997 +++ linux/net/appletalk/aarp.c Thu Jun 12 16:22:11 1997 @@ -49,6 +49,12 @@ #include #include + +int sysctl_aarp_expiry_time = AARP_EXPIRY_TIME; +int sysctl_aarp_tick_time = AARP_TICK_TIME; +int sysctl_aarp_retransmit_limit = AARP_RETRANSMIT_LIMIT; +int sysctl_aarp_resolve_time = AARP_RESOLVE_TIME; + /* * Lists of aarp entries */ @@ -309,7 +315,7 @@ { /* Expired - if this will be the 11th transmit, we delete instead */ - if((*n)->xmit_count>=AARP_RETRANSMIT_LIMIT) + if((*n)->xmit_count>=sysctl_aarp_retransmit_limit) { t= *n; *n=(*n)->next; @@ -359,9 +365,9 @@ } del_timer(&aarp_timer); if(unresolved_count==0) - aarp_timer.expires=jiffies+AARP_EXPIRY_TIME; + aarp_timer.expires=jiffies+sysctl_aarp_expiry_time; else - aarp_timer.expires=jiffies+AARP_TICK_TIME; + aarp_timer.expires=jiffies+sysctl_aarp_tick_time; add_timer(&aarp_timer); } @@ -475,6 +481,21 @@ dev_queue_xmit(skb); return 1; } + + /* + * On a PPP link we neither compress nor aarp. + */ + if(dev->type==ARPHRD_PPP) + { + skb->protocol = htons(ETH_P_PPPTALK); + if(skb->sk==NULL) + skb->priority = SOPRI_NORMAL; + else + skb->priority = skb->sk->priority; + skb->dev = dev; + dev_queue_xmit(skb); + return 1; + } /* * Non ELAP we cannot do. @@ -514,7 +535,7 @@ * Return 1 and fill in the address */ - a->expires_at=jiffies+AARP_EXPIRY_TIME*10; + a->expires_at=jiffies+sysctl_aarp_expiry_time*10; ddp_dl->datalink_header(ddp_dl, skb, a->hwaddr); if(skb->sk==NULL) skb->priority = SOPRI_NORMAL; @@ -561,7 +582,7 @@ */ skb_queue_tail(&a->packet_queue, skb); - a->expires_at=jiffies+AARP_RESOLVE_TIME; + a->expires_at=jiffies+sysctl_aarp_resolve_time; a->dev=dev; a->next=unresolved[hash]; a->target_addr= *sa; @@ -584,7 +605,7 @@ if(unresolved_count==1) { del_timer(&aarp_timer); - aarp_timer.expires=jiffies+AARP_TICK_TIME; + aarp_timer.expires=jiffies+sysctl_aarp_tick_time; add_timer(&aarp_timer); } @@ -623,7 +644,7 @@ while((skb=skb_dequeue(&a->packet_queue))!=NULL) { - a->expires_at=jiffies+AARP_EXPIRY_TIME*10; + a->expires_at=jiffies+sysctl_aarp_expiry_time*10; ddp_dl->datalink_header(ddp_dl,skb,a->hwaddr); if(skb->sk==NULL) skb->priority = SOPRI_NORMAL; @@ -751,7 +772,7 @@ if(unresolved_count==0) { del_timer(&aarp_timer); - aarp_timer.expires=jiffies+AARP_EXPIRY_TIME; + aarp_timer.expires=jiffies+sysctl_aarp_expiry_time; add_timer(&aarp_timer); } break; @@ -804,7 +825,7 @@ init_timer(&aarp_timer); aarp_timer.function=aarp_expire_timeout; aarp_timer.data=0; - aarp_timer.expires=jiffies+AARP_EXPIRY_TIME; + aarp_timer.expires=jiffies+sysctl_aarp_expiry_time; add_timer(&aarp_timer); register_netdevice_notifier(&aarp_notifier); } diff -u --recursive --new-file v2.1.42/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c --- v2.1.42/linux/net/appletalk/ddp.c Tue May 13 22:41:20 1997 +++ linux/net/appletalk/ddp.c Thu Jun 12 16:22:11 1997 @@ -79,6 +79,11 @@ #define DPRINT(x) #endif +#ifdef CONFIG_SYSCTL +extern inline void atalk_register_sysctl(void); +extern inline void atalk_unregister_sysctl(void); +#endif + struct datalink_proto *ddp_dl, *aarp_dl; static struct proto_ops atalk_dgram_ops; @@ -262,7 +267,6 @@ else iface = &tmp->next; } - MOD_DEC_USE_COUNT; } static struct atalk_iface *atif_add_device(struct device *dev, struct at_addr *sa) @@ -281,7 +285,6 @@ iface->next=atalk_iface_list; atalk_iface_list=iface; restore_flags(flags); - MOD_INC_USE_COUNT; return iface; } @@ -399,9 +402,21 @@ static struct at_addr *atalk_find_primary(void) { struct atalk_iface *iface; + struct atalk_iface *fiface; + /* + * Return a point-to-point interface only if + * there is no non-ptp interface available. + */ + fiface=NULL; for(iface=atalk_iface_list;iface!=NULL;iface=iface->next) - if(!(iface->dev->flags&IFF_LOOPBACK)) + { + if(!fiface && !(iface->dev->flags&IFF_LOOPBACK)) + fiface=iface; + if(!(iface->dev->flags&(IFF_LOOPBACK|IFF_POINTOPOINT))) return &iface->address; + } + if (fiface) + return &fiface->address; if ( atalk_iface_list != NULL ) return &atalk_iface_list->address; else @@ -779,6 +794,16 @@ ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr.s_net=atif->address.s_net; ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr.s_node=ATADDR_BCAST; break; + case SIOCATALKDIFADDR: + if(!suser()) + return -EPERM; + if(sa->sat_family!=AF_APPLETALK) + return -EINVAL; + if(atif==NULL) + return -EADDRNOTAVAIL; + atrtr_device_down(atif->dev); + atif_drop_device(atif->dev); + break; } err = copy_to_user(arg,&atreq,sizeof(atreq)); @@ -951,7 +976,8 @@ MOD_INC_USE_COUNT; sock_init_data(sock,sk); - + + sk->destruct=NULL; /* Checksums on by default */ sk->mtu=DDP_MAXSZ; sk->zapped=1; @@ -1928,6 +1954,7 @@ case SIOCGIFADDR: case SIOCSIFADDR: case SIOCGIFBRDADDR: + case SIOCATALKDIFADDR: return atif_ioctl(cmd,(void *)arg); /* * Physical layer ioctl calls @@ -2056,6 +2083,10 @@ proc_net_register(&proc_atalk_iface); #endif +#ifdef CONFIG_SYSCTL + atalk_register_sysctl(); +#endif + #ifdef CONFIG_IPDDP register_netdev(&dev_ipddp); #endif /* CONFIG_IPDDP */ @@ -2098,6 +2129,7 @@ while (list != NULL) { tmp = list->next; + list->dev->atalk_ptr = NULL; kfree_s(list, sizeof(struct atalk_iface)); list = tmp; } @@ -2111,6 +2143,10 @@ cli(); aarp_cleanup_module(); + +#ifdef CONFIG_SYSCTL + atalk_unregister_sysctl(); +#endif #ifdef CONFIG_PROC_FS proc_net_unregister(PROC_NET_ATALK); diff -u --recursive --new-file v2.1.42/linux/net/appletalk/sysctl_net_atalk.c linux/net/appletalk/sysctl_net_atalk.c --- v2.1.42/linux/net/appletalk/sysctl_net_atalk.c Mon Apr 1 22:03:35 1996 +++ linux/net/appletalk/sysctl_net_atalk.c Thu Jun 12 16:22:11 1997 @@ -3,11 +3,55 @@ * * Begun April 1, 1996, Mike Shaver. * Added /proc/sys/net/atalk directory entry (empty =) ). [MS] + * Dynamic registration, added aarp entries. (5/30/97 Chris Horn) */ #include #include -ctl_table atalk_table[] = { +extern int sysctl_aarp_expiry_time; +extern int sysctl_aarp_tick_time; +extern int sysctl_aarp_retransmit_limit; +extern int sysctl_aarp_resolve_time; + + +static ctl_table atalk_table[] = { + {NET_ATALK_AARP_EXPIRY_TIME, "aarp-expiry-time", + &sysctl_aarp_expiry_time, sizeof(int), 0644, NULL, &proc_dointvec_jiffies}, + {NET_ATALK_AARP_TICK_TIME, "aarp-tick-time", + &sysctl_aarp_tick_time, sizeof(int), 0644, NULL, &proc_dointvec_jiffies}, + {NET_ATALK_AARP_RETRANSMIT_LIMIT, "aarp-retransmit-limit", + &sysctl_aarp_retransmit_limit, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_ATALK_AARP_RESOLVE_TIME, "aarp-resolve-time", + &sysctl_aarp_resolve_time, sizeof(int), 0644, NULL, &proc_dointvec_jiffies}, + {0} +}; + +static ctl_table atalk_dir_table[] = { + {NET_ATALK, "appletalk", NULL, 0, 0555, atalk_table}, {0} }; + +static ctl_table atalk_root_table[] = { + {CTL_NET, "net", NULL, 0, 0555, atalk_dir_table}, + {0} +}; + +static struct ctl_table_header *atalk_table_header; + +inline void atalk_register_sysctl(void) +{ + atalk_table_header = register_sysctl_table(atalk_root_table, 1); +} + +inline void atalk_unregister_sysctl(void) +{ + unregister_sysctl_table(atalk_table_header); +} + + + + + + + diff -u --recursive --new-file v2.1.42/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c --- v2.1.42/linux/net/ax25/af_ax25.c Thu May 29 21:53:11 1997 +++ linux/net/ax25/af_ax25.c Thu Jun 12 16:22:11 1997 @@ -148,6 +148,11 @@ MOD_DEC_USE_COUNT; } +static void ax25_free_sock(struct sock *sk) +{ + ax25_free_cb(sk->protinfo.ax25); +} + /* * Socket removal during an interrupt is now safe. */ @@ -428,7 +433,6 @@ add_timer(&ax25->timer); } else { sk_free(ax25->sk); - ax25_free_cb(ax25); } } else { ax25_free_cb(ax25); @@ -858,7 +862,8 @@ } sock_init_data(sock, sk); - + + sk->destruct = ax25_free_sock; sock->ops = &ax25_proto_ops; sk->protocol = protocol; sk->mtu = AX25_MTU; /* 256 */ @@ -894,7 +899,8 @@ } sock_init_data(NULL, sk); - + + sk->destruct = ax25_free_sock; sk->type = osk->type; sk->socket = osk->socket; sk->priority = osk->priority; @@ -926,7 +932,6 @@ if (osk->protinfo.ax25->digipeat != NULL) { if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { sk_free(sk); - ax25_free_cb(ax25); return NULL; } @@ -1182,8 +1187,8 @@ #ifdef CONFIG_AX25_DAMA_SLAVE case AX25_PROTO_DAMA_SLAVE: - ax25->modulus = AX25_MODULUS; - ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; + sk->protinfo.ax25->modulus = AX25_MODULUS; + sk->protinfo.ax25->window = sk->protinfo.ax25->ax25_dev->values[AX25_VALUES_WINDOW]; if (sk->protinfo.ax25->ax25_dev->dama.slave) ax25_ds_establish_data_link(sk->protinfo.ax25); else diff -u --recursive --new-file v2.1.42/linux/net/core/dev.c linux/net/core/dev.c --- v2.1.42/linux/net/core/dev.c Sat May 24 09:10:25 1997 +++ linux/net/core/dev.c Thu Jun 12 16:22:11 1997 @@ -1485,7 +1485,6 @@ case SIOCGIFMTU: case SIOCGIFMEM: case SIOCGIFHWADDR: - case SIOCSIFHWADDR: case SIOCGIFSLAVE: case SIOCGIFMAP: case SIOGIFINDEX: @@ -1499,6 +1498,7 @@ case SIOCSIFMETRIC: case SIOCSIFMTU: case SIOCSIFMEM: + case SIOCSIFHWADDR: case SIOCSIFMAP: case SIOCSIFSLAVE: case SIOCADDMULTI: diff -u --recursive --new-file v2.1.42/linux/net/core/sock.c linux/net/core/sock.c --- v2.1.42/linux/net/core/sock.c Tue May 13 22:41:21 1997 +++ linux/net/core/sock.c Thu Jun 12 16:22:11 1997 @@ -71,6 +71,8 @@ * Alan Cox : Generic socket allocation to make hooks * easier (suggested by Craig Metz). * Michael Pall : SO_ERROR returns positive errno again + * Steve Whitehouse: Added default destructor to free + * protocol private data. * * To Fix: * @@ -124,6 +126,8 @@ __u32 sysctl_wmem_default = SK_WMEM_MAX; __u32 sysctl_rmem_default = SK_RMEM_MAX; +int sysctl_core_destroy_delay = SOCK_DESTROY_TIME; + /* * This is meant for all protocols to use and covers goings on * at the socket level. Everything here is generic. @@ -465,6 +469,9 @@ void sk_free(struct sock *sk) { + if (sk->destruct) + sk->destruct(sk); + kmem_cache_free(sk_cachep, sk); } @@ -787,7 +794,7 @@ * Someone is using our buffers still.. defer */ init_timer(&sk->timer); - sk->timer.expires=jiffies+10*HZ; + sk->timer.expires=jiffies+sysctl_core_destroy_delay; sk->timer.function=sklist_destroy_timer; sk->timer.data = (unsigned long)sk; add_timer(&sk->timer); @@ -874,6 +881,12 @@ } } +void sock_def_destruct(struct sock *sk) +{ + if (sk->protinfo.destruct_hook) + kfree(sk->protinfo.destruct_hook); +} + void sock_init_data(struct socket *sock, struct sock *sk) { skb_queue_head_init(&sk->receive_queue); @@ -901,6 +914,7 @@ sk->data_ready = sock_def_callback2; sk->write_space = sock_def_callback3; sk->error_report = sock_def_callback1; + sk->destruct = sock_def_destruct; sk->peercred.pid = 0; sk->peercred.uid = -1; diff -u --recursive --new-file v2.1.42/linux/net/core/sysctl_net_core.c linux/net/core/sysctl_net_core.c --- v2.1.42/linux/net/core/sysctl_net_core.c Tue May 13 22:41:21 1997 +++ linux/net/core/sysctl_net_core.c Thu Jun 12 16:22:11 1997 @@ -13,6 +13,8 @@ extern __u32 sysctl_wmem_default; extern __u32 sysctl_rmem_default; +extern int sysctl_core_destroy_delay; + ctl_table core_table[] = { {NET_CORE_WMEM_MAX, "wmem_max", &sysctl_wmem_max, sizeof(int), 0644, NULL, @@ -26,5 +28,8 @@ {NET_CORE_RMEM_DEFAULT, "rmem_default", &sysctl_rmem_default, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_CORE_DESTROY_DELAY, "destroy_delay", + &sysctl_core_destroy_delay, sizeof(int), 0644, NULL, + &proc_dointvec_jiffies}, { 0 } }; diff -u --recursive --new-file v2.1.42/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- v2.1.42/linux/net/ipv4/af_inet.c Tue May 13 22:41:23 1997 +++ linux/net/ipv4/af_inet.c Thu Jun 12 16:22:11 1997 @@ -114,6 +114,7 @@ #define min(a,b) ((a)<(b)?(a):(b)) +extern int sysctl_core_destroy_delay; extern struct proto packet_prot; extern int raw_get_info(char *, char **, off_t, int, int); extern int snmp_get_info(char *, char **, off_t, int, int); @@ -190,7 +191,7 @@ sk->destroy = 1; sk->ack_backlog = 0; release_sock(sk); - net_reset_timer(sk, TIME_DESTROY, SOCK_DESTROY_TIME); + net_reset_timer(sk, TIME_DESTROY, sysctl_core_destroy_delay); } void destroy_sock(struct sock *sk) @@ -366,7 +367,8 @@ } sock_init_data(sock,sk); - + sk->destruct = NULL; + sk->zapped=0; #ifdef CONFIG_TCP_NAGLE_OFF sk->nonagle = 1; diff -u --recursive --new-file v2.1.42/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c --- v2.1.42/linux/net/ipv4/devinet.c Sun Jan 19 05:47:28 1997 +++ linux/net/ipv4/devinet.c Thu Jun 12 16:22:11 1997 @@ -81,7 +81,7 @@ * This checks bitmasks for the ioctl calls for devices. */ -static inline int bad_mask(unsigned long mask, unsigned long addr) +static inline int bad_mask(__u32 mask, __u32 addr) { if (addr & (mask = ~mask)) return 1; diff -u --recursive --new-file v2.1.42/linux/net/ipv4/fib.c linux/net/ipv4/fib.c --- v2.1.42/linux/net/ipv4/fib.c Tue May 13 22:41:23 1997 +++ linux/net/ipv4/fib.c Thu Jun 12 16:22:11 1997 @@ -1896,8 +1896,8 @@ void ip_rt_change_broadcast(struct device *dev, u32 new_brd) { fib_lock(); - printk(KERN_DEBUG "%s changes brd %08lX -> %08X\n", - dev->name, dev->pa_brdaddr, new_brd); + printk(KERN_DEBUG "%s changes brd %08X -> %08X\n", + dev->name, (u32)dev->pa_brdaddr, new_brd); if (!ZERONET(dev->pa_addr) && dev->flags&IFF_BROADCAST) { fib_magic(RTMSG_DELROUTE, RTF_IFBRD, dev->pa_brdaddr, ~0, dev); rtmsg_dev(RTMSG_DELDEVICE, dev, NULL); @@ -1911,8 +1911,8 @@ { fib_lock(); if (!ZERONET(dev->pa_addr) && (dev->flags&IFF_POINTOPOINT) && dev->type != ARPHRD_TUNNEL) { - printk(KERN_DEBUG "%s changes dst %08lX -> %08X\n", - dev->name, dev->pa_dstaddr, dstaddr); + printk(KERN_DEBUG "%s changes dst %08X -> %08X\n", + dev->name, (u32)dev->pa_dstaddr, dstaddr); fib_magic(RTMSG_DELROUTE, RTF_IFPREFIX, dev->pa_dstaddr, ~0, dev); rtmsg_dev(RTMSG_DELDEVICE, dev, NULL); rtmsg_dev(RTMSG_NEWDEVICE, dev, NULL); @@ -1927,8 +1927,8 @@ u32 net; fib_lock(); - printk(KERN_DEBUG "%s changes netmask %08lX -> %08X\n", - dev->name, dev->pa_mask, mask); + printk(KERN_DEBUG "%s changes netmask %08X -> %08X\n", + dev->name, (u32)dev->pa_mask, mask); if (ZERONET(dev->pa_addr)) { fib_unlock(); return; @@ -1961,9 +1961,9 @@ return NOTIFY_DONE; } if (event == NETDEV_CHANGE) { - printk(KERN_DEBUG "%s(%s) changes state fl=%08x pa=%08lX/%08lX brd=%08lX dst=%08lX\n", - dev->name, current->comm, dev->flags, dev->pa_addr, dev->pa_mask, - dev->pa_brdaddr, dev->pa_dstaddr); + printk(KERN_DEBUG "%s(%s) changes state fl=%08x pa=%08X/%08X brd=%08X dst=%08X\n", + dev->name, current->comm, dev->flags, (u32)dev->pa_addr, (u32)dev->pa_mask, + (u32)dev->pa_brdaddr, (u32)dev->pa_dstaddr); if (!(dev->flags&IFF_BROADCAST)) fib_magic(RTMSG_DELROUTE, RTF_IFBRD, dev->pa_brdaddr, ~0, dev); if (!(dev->flags&IFF_POINTOPOINT)) @@ -1985,9 +1985,9 @@ } if (event == NETDEV_UP) - printk(KERN_DEBUG "%s UP fl=%08x pa=%08lX/%08lX brd=%08lX dst=%08lX\n", - dev->name, dev->flags, dev->pa_addr, - dev->pa_mask, dev->pa_brdaddr, dev->pa_dstaddr); + printk(KERN_DEBUG "%s UP fl=%08x pa=%08X/%08X brd=%08X dst=%08X\n", + dev->name, dev->flags, (u32)dev->pa_addr, + (u32)dev->pa_mask, (u32)dev->pa_brdaddr, (u32)dev->pa_dstaddr); rtmsg_dev(RTMSG_NEWDEVICE, dev, NULL); diff -u --recursive --new-file v2.1.42/linux/net/ipv4/igmp.c linux/net/ipv4/igmp.c --- v2.1.42/linux/net/ipv4/igmp.c Fri Apr 4 08:52:28 1997 +++ linux/net/ipv4/igmp.c Thu Jun 12 16:22:11 1997 @@ -88,6 +88,9 @@ #include #include +int sysctl_igmp_max_host_report_delay = IGMP_MAX_HOST_REPORT_DELAY; +int sysctl_igmp_timer_scale = IGMP_TIMER_SCALE; +int sysctl_igmp_age_threshold = IGMP_AGE_THRESHOLD; /* * If time expired, change the router type to IGMP_NEW_ROUTER. @@ -133,7 +136,7 @@ return NULL; i->dev = dev; i->type = IGMP_NEW_ROUTER; - i->time = IGMP_AGE_THRESHOLD; + i->time = sysctl_igmp_age_threshold; i->next = ip_router_info_head; ip_router_info_head = i; @@ -229,7 +232,7 @@ int tv; if(im->tm_running) return; - tv=random()%(max_resp_time*HZ/IGMP_TIMER_SCALE); /* Pick a number any number 8) */ + tv=random()%(max_resp_time*HZ/sysctl_igmp_timer_scale); /* Pick a number any number 8) */ im->timer.expires=jiffies+tv; im->tm_running=1; add_timer(&im->timer); @@ -363,7 +366,7 @@ if (group && group != im->multiaddr) continue; if(im->tm_running) { - if(im->timer.expires>jiffies+max_resp_time*HZ/IGMP_TIMER_SCALE) { + if(im->timer.expires>jiffies+max_resp_time*HZ/sysctl_igmp_timer_scale) { igmp_stop_timer(im); igmp_start_timer(im,max_resp_time); } @@ -372,9 +375,9 @@ } } else { mrouter_type=IGMP_OLD_ROUTER; - max_resp_time=IGMP_MAX_HOST_REPORT_DELAY*IGMP_TIMER_SCALE; + max_resp_time=sysctl_igmp_max_host_report_delay*sysctl_igmp_timer_scale; - if(igmp_set_mrouter_info(dev,mrouter_type,IGMP_AGE_THRESHOLD)==NULL) + if(igmp_set_mrouter_info(dev,mrouter_type,sysctl_igmp_age_threshold)==NULL) return; /* diff -u --recursive --new-file v2.1.42/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c --- v2.1.42/linux/net/ipv4/ip_fragment.c Sat May 24 09:10:25 1997 +++ linux/net/ipv4/ip_fragment.c Thu Jun 12 16:22:11 1997 @@ -5,7 +5,7 @@ * * The IP fragmentation functionality. * - * Version: $Id: ip_fragment.c,v 1.22 1997/05/17 05:21:56 freitag Exp $ + * Version: $Id: ip_fragment.c,v 1.23 1997/05/31 12:36:35 freitag Exp $ * * Authors: Fred N. van Kempen * Alan Cox @@ -41,6 +41,8 @@ int sysctl_ipfrag_high_thresh = 256*1024; int sysctl_ipfrag_low_thresh = 192*1024; +int sysctl_ipfrag_time = IP_FRAG_TIME; + /* Describe an IP fragment. */ struct ipfrag { int offset; /* offset of fragment in IP datagram */ @@ -251,7 +253,7 @@ qp->dev = skb->dev; /* Start a timer for this entry. */ - qp->timer.expires = jiffies + IP_FRAG_TIME; /* about 30 seconds */ + qp->timer.expires = jiffies + sysctl_ipfrag_time; /* about 30 seconds */ qp->timer.data = (unsigned long) qp; /* pointer to queue */ qp->timer.function = ip_expire; /* expire function */ add_timer(&qp->timer); @@ -417,7 +419,7 @@ memcpy(qp->iph, iph, ihl+8); } del_timer(&qp->timer); - qp->timer.expires = jiffies + IP_FRAG_TIME; /* about 30 seconds */ + qp->timer.expires = jiffies + sysctl_ipfrag_time; /* about 30 seconds */ qp->timer.data = (unsigned long) qp; /* pointer to queue */ qp->timer.function = ip_expire; /* expire function */ add_timer(&qp->timer); diff -u --recursive --new-file v2.1.42/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c --- v2.1.42/linux/net/ipv4/ipmr.c Tue May 13 22:41:23 1997 +++ linux/net/ipv4/ipmr.c Thu Jun 12 16:22:11 1997 @@ -1031,7 +1031,7 @@ } if(pos>offset+length) { - sti(); + end_bh_atomic(); goto done; } mfc=mfc->next; diff -u --recursive --new-file v2.1.42/linux/net/ipv4/packet.c linux/net/ipv4/packet.c --- v2.1.42/linux/net/ipv4/packet.c Tue Mar 4 10:25:27 1997 +++ linux/net/ipv4/packet.c Thu Jun 12 16:22:11 1997 @@ -160,7 +160,7 @@ if(len>dev->mtu+dev->hard_header_len) return -EMSGSIZE; - skb = sock_wmalloc(sk, len, 0, GFP_KERNEL); + skb = sock_wmalloc(sk, len+dev->hard_header_len, 0, GFP_KERNEL); /* * If the write buffer is full, then tough. At this level the user gets to @@ -177,6 +177,11 @@ * Fill it in */ + /* FIXME: Save some space for broken drivers that write a + * hard header at transmission time by themselves. PPP is the + * notable one here. This should really be fixed at the driver level. + */ + skb_reserve(skb,dev->hard_header_len); err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len); skb->arp = 1; /* No ARP needs doing on this (complete) frame */ skb->protocol = proto; diff -u --recursive --new-file v2.1.42/linux/net/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c --- v2.1.42/linux/net/ipv4/sysctl_net_ipv4.c Sat May 24 09:10:25 1997 +++ linux/net/ipv4/sysctl_net_ipv4.c Thu Jun 12 16:22:11 1997 @@ -34,10 +34,17 @@ extern int sysctl_arp_check_interval; extern int sysctl_arp_confirm_interval; extern int sysctl_arp_confirm_timeout; +extern int sysctl_arp_max_pings; /* From ip_fragment.c */ extern int sysctl_ipfrag_low_thresh; extern int sysctl_ipfrag_high_thresh; +extern int sysctl_ipfrag_time; + +/* From igmp.c */ +extern int sysctl_igmp_max_host_report_delay; +extern int sysctl_igmp_timer_scale; +extern int sysctl_igmp_age_threshold; extern int sysctl_tcp_cong_avoidance; extern int sysctl_tcp_hoe_retransmits; @@ -45,7 +52,16 @@ extern int sysctl_tcp_tsack; extern int sysctl_tcp_timestamps; extern int sysctl_tcp_window_scaling; -extern int sysctl_syn_retries; +extern int sysctl_tcp_keepalive_time; +extern int sysctl_tcp_keepalive_probes; +extern int sysctl_tcp_max_ka_probes; +extern int sysctl_tcp_retries1; +extern int sysctl_tcp_retries2; +extern int sysctl_tcp_max_delay_acks; +extern int sysctl_tcp_fin_timeout; +extern int sysctl_tcp_syncookies; +extern int sysctl_tcp_always_syncookie; +extern int sysctl_tcp_syn_retries; extern int tcp_sysctl_congavoid(ctl_table *ctl, int write, struct file * filp, void *buffer, size_t *lenp); @@ -82,6 +98,8 @@ &sysctl_arp_dead_res_time, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV4_ARP_MAX_TRIES, "arp_max_tries", &sysctl_arp_max_tries, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_IPV4_ARP_MAX_PINGS, "arp_max_pings", + &sysctl_arp_max_pings, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV4_ARP_TIMEOUT, "arp_timeout", &sysctl_arp_timeout, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV4_ARP_CHECK_INTERVAL, "arp_check_interval", @@ -149,12 +167,46 @@ {NET_IPV4_RFC1620_REDIRECTS, "ip_rfc1620_redirects", &ipv4_config.rfc1620_redirects, sizeof(int), 0644, NULL, &proc_dointvec}, - {NET_TCP_SYN_RETRIES, "tcp_syn_retries", - &sysctl_syn_retries, sizeof(int), 0644, NULL, &proc_dointvec}, - {NET_IPFRAG_HIGH_THRESH, "ipfrag_high_thresh", - &sysctl_ipfrag_high_thresh, sizeof(int), 0644, NULL, &proc_dointvec}, - {NET_IPFRAG_LOW_THRESH, "ipfrag_low_thresh", - &sysctl_ipfrag_low_thresh, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_IPV4_TCP_SYN_RETRIES, "tcp_syn_retries", + &sysctl_tcp_syn_retries, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_IPV4_IPFRAG_HIGH_THRESH, "ipfrag_high_thresh", + &sysctl_ipfrag_high_thresh, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_IPV4_IPFRAG_LOW_THRESH, "ipfrag_low_thresh", + &sysctl_ipfrag_low_thresh, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_IPV4_IPFRAG_TIME, "ipfrag_time", + &sysctl_ipfrag_time, sizeof(int), 0644, NULL, &proc_dointvec_jiffies}, + {NET_IPV4_TCP_MAX_KA_PROBES, "tcp_max_ka_probes", + &sysctl_tcp_max_ka_probes, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_IPV4_TCP_KEEPALIVE_TIME, "tcp_keepalive_time", + &sysctl_tcp_keepalive_time, sizeof(int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_TCP_KEEPALIVE_PROBES, "tcp_keepalive_probes", + &sysctl_tcp_keepalive_probes, sizeof(int), 0644, NULL, + &proc_dointvec}, + {NET_IPV4_TCP_RETRIES1, "tcp_retries1", + &sysctl_tcp_retries1, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_IPV4_TCP_RETRIES2, "tcp_retries2", + &sysctl_tcp_retries2, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_IPV4_TCP_MAX_DELAY_ACKS, "tcp_max_delay_acks", + &sysctl_tcp_max_delay_acks, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_IPV4_TCP_FIN_TIMEOUT, "tcp_fin_timeout", + &sysctl_tcp_fin_timeout, sizeof(int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_IGMP_MAX_HOST_REPORT_DELAY, "igmp_max_host_report_delay", + &sysctl_igmp_max_host_report_delay, sizeof(int), 0644, NULL, + &proc_dointvec}, + {NET_IPV4_IGMP_TIMER_SCALE, "igmp_timer_scale", + &sysctl_igmp_timer_scale, sizeof(int), 0644, NULL, &proc_dointvec}, +#if 0 + /* This one shouldn't be exposed to the user (too implementation + specific): */ + {NET_IPV4_IGMP_AGE_THRESHOLD, "igmp_age_threshold", + &sysctl_igmp_age_threshold, sizeof(int), 0644, NULL, &proc_dointvec}, +#endif + {NET_TCP_SYNCOOKIES, "tcp_syncookies", + &sysctl_tcp_syncookies, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_TCP_ALWAYS_SYNCOOKIE, "tcp_always_syncookie", + &sysctl_tcp_always_syncookie, sizeof(int), 0644, NULL, &proc_dointvec}, {0} }; diff -u --recursive --new-file v2.1.42/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v2.1.42/linux/net/ipv4/tcp.c Thu May 15 16:48:06 1997 +++ linux/net/ipv4/tcp.c Thu Jun 12 16:22:11 1997 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp.c,v 1.65 1997/05/06 09:31:43 davem Exp $ + * Version: $Id: tcp.c,v 1.66 1997/05/31 12:36:39 freitag Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -431,6 +431,8 @@ #include +int sysctl_tcp_fin_timeout = TCP_FIN_TIMEOUT; + unsigned long seq_offset; struct tcp_mib tcp_statistics; @@ -1385,7 +1387,7 @@ if(timer_active) add_timer(&sk->timer); else - tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_FIN_TIMEOUT); + tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout); } return send_fin; @@ -1499,7 +1501,7 @@ if(timer_active) add_timer(&sk->timer); else - tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_FIN_TIMEOUT); + tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout); } sk->dead = 1; diff -u --recursive --new-file v2.1.42/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c --- v2.1.42/linux/net/ipv4/tcp_input.c Tue May 13 22:41:23 1997 +++ linux/net/ipv4/tcp_input.c Thu Jun 12 16:22:11 1997 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_input.c,v 1.51 1997/04/27 19:24:40 schenk Exp $ + * Version: $Id: tcp_input.c,v 1.52 1997/05/31 12:36:42 freitag Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -56,13 +56,15 @@ static void tcp_cong_avoid_vegas(struct sock *sk, u32 seq, u32 ack, u32 seq_rtt); -int sysctl_tcp_cong_avoidance = 0; -int sysctl_tcp_hoe_retransmits = 0; -int sysctl_tcp_sack = 0; -int sysctl_tcp_tsack = 0; -int sysctl_tcp_timestamps = 0; -int sysctl_tcp_window_scaling = 0; - +int sysctl_tcp_cong_avoidance; +int sysctl_tcp_hoe_retransmits; +int sysctl_tcp_sack; +int sysctl_tcp_tsack; +int sysctl_tcp_timestamps; +int sysctl_tcp_window_scaling; +int sysctl_tcp_syncookies; +int sysctl_tcp_always_syncookie; +int sysctl_tcp_max_delay_acks = MAX_DELAY_ACK; static tcp_sys_cong_ctl_t tcp_sys_cong_ctl_f = &tcp_cong_avoid_vanj; @@ -1080,7 +1082,7 @@ /* A retransmit, 2nd most common case. Force an imediate ack. */ SOCK_DEBUG(sk, "retransmit received: seq %X\n", skb->seq); - tp->delayed_acks = MAX_DELAY_ACK; + tp->delayed_acks = sysctl_tcp_max_delay_acks; kfree_skb(skb, FREE_READ); return; } @@ -1094,7 +1096,7 @@ } /* Ok. This is an out_of_order segment, force an ack. */ - tp->delayed_acks = MAX_DELAY_ACK; + tp->delayed_acks = sysctl_tcp_max_delay_acks; /* Disable header predition. */ tp->pred_flags = 0; @@ -1218,7 +1220,7 @@ return; } - if (tp->delayed_acks >= MAX_DELAY_ACK || tcp_raise_window(sk)) + if (tp->delayed_acks >= sysctl_tcp_max_delay_acks || tcp_raise_window(sk)) tcp_send_ack(sk); else tcp_send_delayed_ack(sk, HZ/2); diff -u --recursive --new-file v2.1.42/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c --- v2.1.42/linux/net/ipv4/tcp_timer.c Thu May 15 16:48:06 1997 +++ linux/net/ipv4/tcp_timer.c Thu Jun 12 16:22:11 1997 @@ -22,7 +22,11 @@ #include -int sysctl_syn_retries = TCP_SYN_RETRIES; +int sysctl_tcp_syn_retries = TCP_SYN_RETRIES; +int sysctl_tcp_keepalive_time = TCP_KEEPALIVE_TIME; +int sysctl_tcp_keepalive_probes = TCP_KEEPALIVE_PROBES; +int sysctl_tcp_retries1 = TCP_RETR1; +int sysctl_tcp_retries2 = TCP_RETR2; static void tcp_sltimer_handler(unsigned long); static void tcp_syn_recv_timer(unsigned long); @@ -172,7 +176,7 @@ /* Eric, what the heck is this doing?!?! */ tp->retransmits && !(tp->retransmits & 7)) || - (sk->state != TCP_ESTABLISHED && tp->retransmits > TCP_RETR1)) { + (sk->state != TCP_ESTABLISHED && tp->retransmits > sysctl_tcp_retries1)) { /* Attempt to recover if arp has changed (unlikely!) or * a route has shifted (not supported prior to 1.3). */ @@ -180,7 +184,7 @@ } /* Have we tried to SYN too many times (repent repent 8)) */ - if(tp->retransmits > sysctl_syn_retries && sk->state==TCP_SYN_SENT) { + if(tp->retransmits > sysctl_tcp_syn_retries && sk->state==TCP_SYN_SENT) { if(sk->err_soft) sk->err=sk->err_soft; else @@ -198,7 +202,7 @@ } /* Has it gone just too far? */ - if (tp->retransmits > TCP_RETR2) { + if (tp->retransmits > sysctl_tcp_retries2) { if(sk->err_soft) sk->err = sk->err_soft; else @@ -251,7 +255,7 @@ * FIXME: We ought not to do it, Solaris 2.5 actually has fixing * this behaviour in Solaris down as a bug fix. [AC] */ - if (tp->probes_out > TCP_RETR2) { + if (tp->probes_out > sysctl_tcp_retries2) { if(sk->err_soft) sk->err = sk->err_soft; else @@ -281,8 +285,8 @@ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; __u32 elapsed = jiffies - tp->rcv_tstamp; - if (elapsed >= TCP_KEEPALIVE_TIME) { - if (tp->probes_out > TCP_KEEPALIVE_PROBES) { + if (elapsed >= sysctl_tcp_keepalive_time) { + if (tp->probes_out > sysctl_tcp_keepalive_probes) { if(sk->err_soft) sk->err = sk->err_soft; else @@ -316,6 +320,8 @@ */ #define MAX_KA_PROBES 5 +int sysctl_tcp_max_ka_probes = MAX_KA_PROBES; + /* Keepopen's are only valid for "established" TCP's, nicely our listener * hash gets rid of most of the useless testing, so we run through a couple * of the established hash chains each clock tick. -DaveM @@ -341,7 +347,7 @@ while(sk) { if(sk->keepopen) { count += tcp_keepopen_proc(sk); - if(count == MAX_KA_PROBES) + if(count == sysctl_tcp_max_ka_probes) goto out; } sk = sk->next; @@ -455,7 +461,7 @@ break; tcp_synq_unlink(tp, conn); - if (conn->retrans >= TCP_RETR1) { + if (conn->retrans >= sysctl_tcp_retries1) { #ifdef TCP_DEBUG printk(KERN_DEBUG "syn_recv: " "too many retransmits\n"); diff -u --recursive --new-file v2.1.42/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c --- v2.1.42/linux/net/ipv6/af_inet6.c Thu May 15 16:48:06 1997 +++ linux/net/ipv6/af_inet6.c Thu Jun 12 16:22:11 1997 @@ -7,7 +7,7 @@ * * Adapted from linux/net/ipv4/af_inet.c * - * $Id: af_inet6.c,v 1.18 1997/05/07 09:40:12 davem Exp $ + * $Id: af_inet6.c,v 1.19 1997/06/02 14:40:40 alan Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -105,6 +105,7 @@ sock_init_data(sock, sk); + sk->destruct = NULL; sk->zapped = 0; sk->family = AF_INET6; sk->protocol = protocol; diff -u --recursive --new-file v2.1.42/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c --- v2.1.42/linux/net/ipv6/tcp_ipv6.c Tue May 13 22:41:24 1997 +++ linux/net/ipv6/tcp_ipv6.c Thu Jun 12 16:22:11 1997 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: tcp_ipv6.c,v 1.31 1997/04/29 21:51:23 davem Exp $ + * $Id: tcp_ipv6.c,v 1.32 1997/06/04 08:28:58 davem Exp $ * * Based on: * linux/net/ipv4/tcp.c @@ -643,7 +643,6 @@ skb->end_seq = skb->seq + 1; th->seq = ntohl(skb->seq); th->ack_seq = htonl(req->rcv_isn + 1); - th->doff = sizeof(*th)/4 + 1; /* Don't offer more than they did. * This way we don't have to memorize who said what. @@ -669,8 +668,9 @@ th->window = htons(req->rcv_wnd); tmp = tcp_syn_build_options(skb, req->mss, req->sack_ok, req->tstamp_ok, - req->snd_wscale,req->rcv_wscale); - th->doff = sizeof(*th)/4 + (tmp>>2); + req->wscale_ok,req->rcv_wscale); + skb->csum = 0; + th->doff = (sizeof(*th) + tmp)>>2; th->check = tcp_v6_check(th, sizeof(*th) + tmp, &req->af.v6_req.loc_addr, &req->af.v6_req.rmt_addr, csum_partial((char *)th, sizeof(*th)+tmp, skb->csum)); diff -u --recursive --new-file v2.1.42/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c --- v2.1.42/linux/net/ipx/af_ipx.c Tue May 13 22:41:24 1997 +++ linux/net/ipx/af_ipx.c Thu Jun 12 16:22:11 1997 @@ -751,7 +751,7 @@ } #ifdef CONFIG_IPX_PPROP_ROUTING - if( ipx->ipx_type == IPX_TYPE_PPROP && ipx->ipx_tctrl < 8 ) + if( ipx->ipx_type == IPX_TYPE_PPROP && ipx->ipx_tctrl < 8 && skb->pkt_type == PACKET_HOST ) { int i; ipx_interface *ifcs; @@ -759,35 +759,10 @@ long *l; char *c; - if(skb->pkt_type!=PACKET_HOST) - { - kfree_skb(skb, FREE_READ); - return 0; - } - -#ifdef DEBUG_IPX_PPROP_ROUTING - printk(KERN_INFO "IPX: PPROP packet received\n" - " Src: %8x:%02x:%02x:%02x:%02x:%02x:%02x:%d/%d\n", - htonl(ipx->ipx_source.net), - ipx->ipx_source.node[0], ipx->ipx_source.node[1], - ipx->ipx_source.node[2], ipx->ipx_source.node[3], - ipx->ipx_source.node[4], ipx->ipx_source.node[5], - htons(ipx->ipx_source.sock), - htons(ipx->ipx_dest.sock) - ); -#endif - c = (char *) skb->data; c += sizeof( struct ipxhdr ); - l = (long *) c; -#ifdef DEBUG_IPX_PPROP_ROUTING - printk( "IPX: Routing PPROP from net num %08x\n", (unsigned int) htonl(intrfc->if_netnum) ); - for( i = 0 ; i < ipx->ipx_tctrl ; i++ ) - printk( "IPX: Routing PPROP seen net num %08x\n", (unsigned int) htonl(*l++) ); - l = (long *) c; -#endif i = 0; /* * Dump packet if too many hops or already seen this net @@ -812,25 +787,13 @@ if( i - 1 == ipx->ipx_tctrl ) { ipx->ipx_dest.net = ifcs->if_netnum; -#ifdef DEBUG_IPX_PPROP_ROUTING - printk( "IPX: Forward PPROP onto net num %08x\n", (unsigned int) htonl(ifcs->if_netnum) ); -#endif - skb2 = skb_clone(skb, GFP_ATOMIC); - - /* - * See if we are allowed to firewall forward - */ - if (call_fw_firewall(PF_IPX, skb2->dev, ipx, NULL, &skb)!=FW_ACCEPT) + /* See if we are allowed to firewall forward */ + if (call_fw_firewall(PF_IPX, skb->dev, ipx, NULL, &skb)==FW_ACCEPT) { - kfree_skb(skb, FREE_READ); - return 0; - } + skb2 = skb_clone(skb, GFP_ATOMIC); ipxrtr_route_skb(skb2); } -#ifdef DEBUG_IPX_PPROP_ROUTING - else - printk( "IPX: Ignoring PPROP for net num %08x\n", (unsigned int) htonl(ifcs->if_netnum) ); -#endif + } } /* * Reset network number in packet @@ -1793,6 +1756,7 @@ return(-ESOCKTNOSUPPORT); } sock_init_data(sock,sk); + sk->destruct=NULL; sk->mtu=IPX_MTU; sk->no_check = 1; /* Checksum off by default */ MOD_INC_USE_COUNT; diff -u --recursive --new-file v2.1.42/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c --- v2.1.42/linux/net/netrom/af_netrom.c Thu May 29 21:53:11 1997 +++ linux/net/netrom/af_netrom.c Thu Jun 12 16:22:11 1997 @@ -86,8 +86,6 @@ static void nr_free_sock(struct sock *sk) { - kfree(sk->protinfo.nr); - sk_free(sk); MOD_DEC_USE_COUNT; diff -u --recursive --new-file v2.1.42/linux/net/netsyms.c linux/net/netsyms.c --- v2.1.42/linux/net/netsyms.c Thu May 29 21:53:11 1997 +++ linux/net/netsyms.c Thu Jun 12 16:22:11 1997 @@ -326,6 +326,17 @@ EXPORT_SYMBOL(kill_fasync); EXPORT_SYMBOL(ip_rcv); EXPORT_SYMBOL(arp_rcv); + +#if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) +#include +EXPORT_SYMBOL(ltalk_setup); +#endif + +#ifdef CONFIG_DLCI_MODULE +extern int (*dlci_ioctl_hook)(unsigned int, void *); +EXPORT_SYMBOL(dlci_ioctl_hook); +#endif + #endif /* CONFIG_NET */ #ifdef CONFIG_NETLINK diff -u --recursive --new-file v2.1.42/linux/net/protocols.c linux/net/protocols.c --- v2.1.42/linux/net/protocols.c Thu Jan 2 05:13:29 1997 +++ linux/net/protocols.c Thu Jun 12 16:22:11 1997 @@ -47,6 +47,10 @@ #endif #endif +#if defined(CONFIG_DECNET) +#include +#endif + #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) #define NEED_802 #include @@ -107,9 +111,11 @@ { "Rose", rose_proto_init }, /* Amateur Radio X.25 PLP */ #endif #endif - +#ifdef CONFIG_DECNET + { "DECnet", decnet_proto_init }, /* DECnet */ +#endif #ifdef CONFIG_INET - { "INET", inet_proto_init }, /* TCP/IP */ + { "INET", inet_proto_init }, /* TCP/IP */ #ifdef CONFIG_IPV6 { "INET6", inet6_proto_init}, /* IPv6 */ #endif diff -u --recursive --new-file v2.1.42/linux/net/rose/af_rose.c linux/net/rose/af_rose.c --- v2.1.42/linux/net/rose/af_rose.c Thu May 29 21:53:12 1997 +++ linux/net/rose/af_rose.c Thu Jun 12 16:22:11 1997 @@ -136,8 +136,6 @@ static void rose_free_sock(struct sock *sk) { - kfree(sk->protinfo.rose); - sk_free(sk); MOD_DEC_USE_COUNT; diff -u --recursive --new-file v2.1.42/linux/net/socket.c linux/net/socket.c --- v2.1.42/linux/net/socket.c Thu May 15 16:48:07 1997 +++ linux/net/socket.c Thu Jun 12 16:22:11 1997 @@ -212,7 +212,7 @@ file->f_flags = O_RDWR; file->f_inode = inode; if (inode) - inode->i_count++; + atomic_inc(&inode->i_count); file->f_pos = 0; } return fd; @@ -797,6 +797,7 @@ int len; lock_kernel(); +restart: if ((sock = sockfd_lookup(fd, &err))!=NULL) { if (!(newsock = sock_alloc())) @@ -834,7 +835,13 @@ if (upeer_sockaddr) { - newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 1); + /* Handle the race where the accept works and we + then getname after it has closed again */ + if(newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 1)<0) + { + sys_close(err); + goto restart; + } move_addr_to_user(address,len, upeer_sockaddr, upeer_addrlen); } out: diff -u --recursive --new-file v2.1.42/linux/net/sysctl_net.c linux/net/sysctl_net.c --- v2.1.42/linux/net/sysctl_net.c Fri Feb 7 05:54:55 1997 +++ linux/net/sysctl_net.c Thu Jun 12 16:22:11 1997 @@ -24,10 +24,6 @@ extern ctl_table ipx_table[]; #endif -#ifdef CONFIG_ATALK -extern ctl_table atalk_table[]; -#endif - extern ctl_table core_table[], unix_table[]; #ifdef CONFIG_NET @@ -58,9 +54,6 @@ #endif #ifdef CONFIG_IPX {NET_IPX, "ipx", NULL, 0, 0555, ipx_table}, -#endif -#ifdef CONFIG_ATALK - {NET_ATALK, "appletalk", NULL, 0, 0555, atalk_table}, #endif #ifdef CONFIG_BRIDGE {NET_BRIDGE, "bridge", NULL, 0, 0555, bridge_table}, diff -u --recursive --new-file v2.1.42/linux/net/unix/af_unix.c linux/net/unix/af_unix.c --- v2.1.42/linux/net/unix/af_unix.c Tue May 13 22:41:25 1997 +++ linux/net/unix/af_unix.c Thu Jun 12 16:22:11 1997 @@ -87,6 +87,8 @@ #define min(a,b) (((a)<(b))?(a):(b)) +int sysctl_unix_delete_delay = HZ; +int sysctl_unix_destroy_delay = 10*HZ; unix_socket *unix_socket_table[UNIX_HASH_SIZE+1]; @@ -138,6 +140,12 @@ } } +static void unix_destruct_addr(struct sock *sk) +{ + struct unix_address *addr = sk->protinfo.af_unix.addr; + + unix_release_addr(addr); +} /* * Check unix socket name: @@ -231,7 +239,6 @@ unix_socket *sk=(unix_socket *)data; if(!unix_locked(sk) && atomic_read(&sk->wmem_alloc) == 0) { - unix_release_addr(sk->protinfo.af_unix.addr); sk_free(sk); return; } @@ -240,7 +247,7 @@ * Retry; */ - sk->timer.expires=jiffies+10*HZ; /* No real hurry try it every 10 seconds or so */ + sk->timer.expires=jiffies+sysctl_unix_destroy_delay; /* No real hurry try it every 10 seconds or so */ add_timer(&sk->timer); } @@ -248,7 +255,7 @@ static void unix_delayed_delete(unix_socket *sk) { sk->timer.data=(unsigned long)sk; - sk->timer.expires=jiffies+HZ; /* Normally 1 second after will clean up. After that we try every 10 */ + sk->timer.expires=jiffies+sysctl_unix_delete_delay; /* Normally 1 second after will clean up. After that we try every 10 */ sk->timer.function=unix_destroy_timer; add_timer(&sk->timer); } @@ -284,7 +291,6 @@ if(!unix_unlock(sk) && atomic_read(&sk->wmem_alloc) == 0) { - unix_release_addr(sk->protinfo.af_unix.addr); sk_free(sk); } else @@ -346,7 +352,8 @@ return -ENOMEM; sock_init_data(sock,sk); - + + sk->destruct = unix_destruct_addr; sk->protinfo.af_unix.family=AF_UNIX; sk->protinfo.af_unix.inode=NULL; sk->sock_readers=1; /* Us */ @@ -792,7 +799,7 @@ } if (sk->protinfo.af_unix.inode) { - sk->protinfo.af_unix.inode->i_count++; + atomic_inc(&sk->protinfo.af_unix.inode->i_count); newsk->protinfo.af_unix.inode=sk->protinfo.af_unix.inode; } diff -u --recursive --new-file v2.1.42/linux/net/unix/sysctl_net_unix.c linux/net/unix/sysctl_net_unix.c --- v2.1.42/linux/net/unix/sysctl_net_unix.c Thu Jan 2 05:13:35 1997 +++ linux/net/unix/sysctl_net_unix.c Thu Jun 12 16:22:11 1997 @@ -14,6 +14,15 @@ #include #include +extern int sysctl_unix_destroy_delay; +extern int sysctl_unix_delete_delay; + ctl_table unix_table[] = { + {NET_UNIX_DESTROY_DELAY, "destroy_delay", + &sysctl_unix_destroy_delay, sizeof(int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_UNIX_DELETE_DELAY, "delete_delay", + &sysctl_unix_delete_delay, sizeof(int), 0644, NULL, + &proc_dointvec_jiffies}, {0} }; diff -u --recursive --new-file v2.1.42/linux/net/wanrouter/wanproc.c linux/net/wanrouter/wanproc.c --- v2.1.42/linux/net/wanrouter/wanproc.c Tue May 13 22:41:25 1997 +++ linux/net/wanrouter/wanproc.c Thu Jun 12 16:22:11 1997 @@ -121,7 +121,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -160,7 +159,6 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.42/linux/net/x25/af_x25.c linux/net/x25/af_x25.c --- v2.1.42/linux/net/x25/af_x25.c Thu May 29 21:53:12 1997 +++ linux/net/x25/af_x25.c Thu Jun 12 16:22:11 1997 @@ -341,7 +341,6 @@ sk->timer.data = (unsigned long)sk; add_timer(&sk->timer); } else { - kfree(sk->protinfo.x25); sk_free(sk); MOD_DEC_USE_COUNT; } diff -u --recursive --new-file v2.1.42/linux/scripts/Configure linux/scripts/Configure --- v2.1.42/linux/scripts/Configure Mon Apr 14 16:28:29 1997 +++ linux/scripts/Configure Thu Jun 12 16:22:11 1997 @@ -363,6 +363,28 @@ } # +# define_string sets the value of a string argument +# +# define_string define value +# +function define_string () { + echo "$1="'"'$2'"' >>$CONFIG + echo "#define $1 "'"'$2'"' >>$CONFIG_H + eval "$1=$2" +} + +# +# string processes a string argument +# +# string question define default +# +function string () { + old=$(eval echo "\${$2}") + def=${old:-$3} + readln "$1 ($2) [$def] " "$def" "$old" + define_string "$2" "$ans" +} +# # choice processes a choice list (1-out-of-n) # # choice question choice-list default diff -u --recursive --new-file v2.1.42/linux/scripts/header.tk linux/scripts/header.tk --- v2.1.42/linux/scripts/header.tk Sat Apr 13 04:20:03 1996 +++ linux/scripts/header.tk Thu Jun 12 16:22:11 1997 @@ -209,6 +209,10 @@ set cmd "global $var; set $var $value" eval $cmd } + if [regexp {([0-9A-Za-z_]+)="([0-9A-Za-z]+)"} $line foo var value] { + set cmd "global $var; set $var $value" + eval $cmd + } } close $file1 update_choices @@ -260,6 +264,16 @@ } } +proc write_string { file1 file2 varname variable dep } { + if { $dep == 0 } \ + then { puts $file1 "# $varname is not set"; \ + puts $file2 "#undef $varname"} \ + else { + puts $file1 "$varname=\"$variable\""; \ + puts $file2 "#define $varname \"$variable\""; \ + } +} + proc option_name {w mnum line text helpidx} { button $w.x$line.l -text "$text" -relief groove -anchor w $w.x$line.l configure -activefore [cget $w.x$line.l -fg] \ @@ -310,6 +324,15 @@ proc hex { w mnum line text variable } { int $w $mnum $line $text $variable +} + +proc istring { w mnum line text variable } { + frame $w.x$line + entry $w.x$line.x -width 18 -relief sunken -borderwidth 2 \ + -textvariable $variable + option_name $w $mnum $line $text $variable + pack $w.x$line.x -anchor w -side right -fill y + pack $w.x$line -anchor w -fill both -expand on } proc minimenu { w mnum line text variable helpidx } { diff -u --recursive --new-file v2.1.42/linux/scripts/mkdep.c linux/scripts/mkdep.c --- v2.1.42/linux/scripts/mkdep.c Tue May 13 22:41:25 1997 +++ linux/scripts/mkdep.c Thu Jun 12 16:22:12 1997 @@ -6,7 +6,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.1.42/linux/scripts/tkcond.c linux/scripts/tkcond.c --- v2.1.42/linux/scripts/tkcond.c Mon May 6 02:26:18 1996 +++ linux/scripts/tkcond.c Thu Jun 12 16:22:12 1997 @@ -195,6 +195,7 @@ if( cfg->tok != tok_bool && cfg->tok != tok_int && cfg->tok != tok_hex + && cfg->tok != tok_string && cfg->tok != tok_tristate && cfg->tok != tok_choice && cfg->tok != tok_dep_tristate) @@ -358,6 +359,7 @@ case tok_tristate: case tok_int: case tok_hex: + case tok_string: case tok_choice: case tok_make: /* @@ -402,6 +404,7 @@ case tok_dep_tristate: case tok_int: case tok_hex: + case tok_string: for(cfg1=cfg;cfg1 != NULL; cfg1 = cfg1->next) { switch(cfg1->tok) @@ -412,6 +415,7 @@ case tok_dep_tristate: case tok_int: case tok_hex: + case tok_string: if( strcmp(cfg->optionname, cfg1->optionname) == 0) { cfg->flags |= CFG_DUP; diff -u --recursive --new-file v2.1.42/linux/scripts/tkgen.c linux/scripts/tkgen.c --- v2.1.42/linux/scripts/tkgen.c Fri Jan 3 01:33:27 1997 +++ linux/scripts/tkgen.c Thu Jun 12 16:22:12 1997 @@ -289,6 +289,7 @@ break; case tok_int: case tok_hex: + case tok_string: printf("} then { "); printf(".menu%d.config.f.x%d.x configure -state normal -fore [ cget .ref -foreground ]; ", menu_num, line_num); printf(".menu%d.config.f.x%d.l configure -state normal; ", menu_num, line_num); @@ -487,6 +488,10 @@ printf("} then { write_hex $cfg $autocfg %s $%s $notmod }\n", item->optionname, item->optionname); break; + case tok_string: + printf("} then { write_string $cfg $autocfg %s $%s $notmod }\n", + item->optionname, item->optionname); + break; case tok_make: printf("} then { do_make {%s} }\n",item->value); break; @@ -646,6 +651,7 @@ case tok_dep_tristate: case tok_int: case tok_hex: + case tok_string: case tok_choose: tot++; break; @@ -702,6 +708,7 @@ case tok_dep_tristate: case tok_int: case tok_hex: + case tok_string: case tok_choose: /* * If we have overfilled the menu, then go to the next one. @@ -862,6 +869,19 @@ cfg->label, cfg->optionname); break; + case tok_string: + if( cfg->menu_number != menu_num ) + { + end_proc(menu_num); + start_proc(menulabel, cfg->menu_number, FALSE); + menu_num = cfg->menu_number; + } + printf("\tistring $w.config.f %d %d \"%s\" %s\n", + cfg->menu_number, + cfg->menu_line, + cfg->label, + cfg->optionname); + break; default: break; } @@ -951,6 +971,7 @@ break; case tok_int: case tok_hex: + case tok_string: printf("set %s %s\n", cfg->optionname, cfg->value); break; case tok_choose: @@ -985,6 +1006,7 @@ { case tok_int: case tok_hex: + case tok_string: case tok_bool: case tok_tristate: case tok_dep_tristate: @@ -1047,6 +1069,12 @@ else if (cfg->tok == tok_hex ) { printf("\twrite_hex $cfg $autocfg %s $%s $notmod\n", + cfg->optionname, + cfg->optionname); + } + else if (cfg->tok == tok_string ) + { + printf("\twrite_string $cfg $autocfg %s $%s $notmod\n", cfg->optionname, cfg->optionname); } diff -u --recursive --new-file v2.1.42/linux/scripts/tkparse.c linux/scripts/tkparse.c --- v2.1.42/linux/scripts/tkparse.c Mon May 6 02:26:18 1996 +++ linux/scripts/tkparse.c Thu Jun 12 16:22:12 1997 @@ -370,6 +370,11 @@ tok = tok_hex; pnt += 3; } + else if (strncmp(pnt, "string", 6) == 0) + { + tok = tok_string; + pnt += 6; + } else if (strncmp(pnt, "if", 2) == 0) { tok = tok_if; @@ -457,6 +462,7 @@ break; case tok_int: case tok_hex: + case tok_string: pnt = get_qstring(pnt, &kcfg->label); pnt = get_string(pnt, &kcfg->optionname); pnt = get_string(pnt, &kcfg->value); @@ -702,6 +708,9 @@ case tok_hex: printf("hex "); break; + case tok_string: + printf("istring "); + break; case tok_comment: printf("comment "); break; @@ -732,6 +741,7 @@ case tok_dep_tristate: case tok_int: case tok_hex: + case tok_string: printf("%s %s\n", cfg->label, cfg->optionname); break; case tok_if: diff -u --recursive --new-file v2.1.42/linux/scripts/tkparse.h linux/scripts/tkparse.h --- v2.1.42/linux/scripts/tkparse.h Sat Mar 16 23:58:21 1996 +++ linux/scripts/tkparse.h Thu Jun 12 16:22:12 1997 @@ -12,6 +12,7 @@ tok_fi, tok_int, tok_hex, + tok_string, tok_make, tok_define, tok_choose,