diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-06-17 13:20:30 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1997-06-17 13:20:30 +0000 |
commit | 7acb77a6e7bddd4c4c5aa975bbf976927c013798 (patch) | |
tree | 4139829ec6edb85f73774bb95cdec376758bfc73 | |
parent | 64d58d4c8cd6a89ee218301ec0dc0ebfec91a4db (diff) |
Merge with 2.1.43.
362 files changed, 13387 insertions, 5976 deletions
@@ -508,6 +508,13 @@ S: 906-1001 Bay St. 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: Sevilla 41005 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 @@ -1557,6 +1564,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 D: AFFS rewrite diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index 63466ffd5..86a2391ea 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX @@ -18,6 +18,8 @@ IO-mapping.txt - 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 --git a/Documentation/Changes b/Documentation/Changes index 0b840fee6..143d90eec 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -29,28 +29,30 @@ English-language HTML version. 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! - -- 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 +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 ; 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 @@ available, so if you need to upgrade, use it. If you get a release 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 @@ presence. 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 @@ parallel port may no longer be where you expect it; for example, LPT1 /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 @@ Procps utilities ================ 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 @@ ftp://ftp.win.tue.nl/pub/linux/util/mount-2.6g.tar.gz 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 === @@ -321,6 +322,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 --git a/Documentation/Configure.help b/Documentation/Configure.help index 669b645f1..863c1d3ac 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -795,6 +795,20 @@ CONFIG_BINFMT_JAVA 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 @@ CONFIG_SOUNDMODEM_SBC 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 @@ CONFIG_SOUNDMODEM_AFSK1200 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 @@ CONFIG_SOUNDMODEM_FSK9600 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 @@ CONFIG_ISP16_CDI 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 @@ CONFIG_QUOTA 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 <filename>#host=<hostname>#. 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=<hostname>#". + +Kerneltype translation +CONFIG_TR_KERNTYPE + Enables translation of name suffixes like in "/etc/config#ktype=default#". + The syntax is <filename>#ktype=<string>#. 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=<something># 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 <filename>#machine=<id>#. 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 <filename>#system=<id>#. 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 @@ CONFIG_PROFILE_SHIFT 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 --git a/Documentation/binfmt_misc.txt b/Documentation/binfmt_misc.txt new file mode 100644 index 000000000..81d49b2bc --- /dev/null +++ b/Documentation/binfmt_misc.txt @@ -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 --git a/Documentation/transname.txt b/Documentation/transname.txt new file mode 100644 index 000000000..ed0a82177 --- /dev/null +++ b/Documentation/transname.txt @@ -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: + + * <name>#host=<hostname># depends on the hostname, see "uname -n" + * <name>#kname=<string># works with a hard compiled-in string + * <name>#ktype=<string># works with a hard compiled-in string + * <name>#machine=<id># depends on architecture, see "uname -m" + * <name>#system=<id># 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 --git a/MAINTAINERS b/MAINTAINERS index 7ff7cefac..9012dede9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -125,6 +125,12 @@ M: net-patches@lxorguk.ukuu.org.uk 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 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 42 +SUBLEVEL = 43 ARCH = mips diff --git a/arch/alpha/config.in b/arch/alpha/config.in index e62ec31d0..774686ebd 100644 --- a/arch/alpha/config.in +++ b/arch/alpha/config.in @@ -94,10 +94,11 @@ bool 'System V IPC' CONFIG_SYSVIPC 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 @@ bool 'Kernel profiling support' CONFIG_PROFILE if [ "$CONFIG_PROFILE" = "y" ]; then int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi +bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index ef9576492..3b3d8574b 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -295,7 +295,7 @@ asmlinkage int osf_statfs(char *path, struct osf_statfs *buffer, unsigned long b 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 @@ static int getdev(const char *name, int rdonly, struct inode **ino) 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 @@ asmlinkage unsigned long osf_getsysinfo(unsigned long op, void *buffer, 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 @@ asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer, 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 @@ asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer, */ 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 @@ asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer, } } return 0; + } default: break; diff --git a/arch/alpha/math-emu/fp-emul.c b/arch/alpha/math-emu/fp-emul.c index 38df501fd..f1ff5a2be 100644 --- a/arch/alpha/math-emu/fp-emul.c +++ b/arch/alpha/math-emu/fp-emul.c @@ -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 @@ alpha_fp_emul (unsigned long pc) * * - 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 @@ alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask) { 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 --git a/arch/i386/config.in b/arch/i386/config.in index f95590407..1612b614f 100644 --- a/arch/i386/config.in +++ b/arch/i386/config.in @@ -34,6 +34,7 @@ bool 'System V IPC' CONFIG_SYSVIPC 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 @@ bool 'Kernel profiling support' CONFIG_PROFILE if [ "$CONFIG_PROFILE" = "y" ]; then int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi +bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu diff --git a/arch/i386/defconfig b/arch/i386/defconfig index a27b6ebce..ab30a25c8 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -25,6 +25,7 @@ CONFIG_SYSVIPC=y 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 @@ CONFIG_EEXPRESS_PRO100=y # 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 @@ CONFIG_82C710_MOUSE=y # Kernel hacking # # CONFIG_PROFILE is not set +# CONFIG_MAGIC_SYSRQ is not set diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S index a42b87b1b..bd4bf56cf 100644 --- a/arch/i386/kernel/head.S +++ b/arch/i386/kernel/head.S @@ -532,8 +532,8 @@ ENTRY(gdt) .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 --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index e5fb5acb1..eedb1d0fe 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -142,21 +142,6 @@ void enable_irq(unsigned int irq_nr) * 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 @@ asmlinkage void do_IRQ(struct pt_regs regs) 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 @@ asmlinkage void do_IRQ(struct pt_regs regs) } while (action); if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - __cli(); spin_lock(&irq_controller_lock); unmask_irq(irq); diff --git a/arch/i386/kernel/irq.h b/arch/i386/kernel/irq.h index 1f9e89399..7d70264ba 100644 --- a/arch/i386/kernel/irq.h +++ b/arch/i386/kernel/irq.h @@ -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 --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c index 1dc615501..5a020b723 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c @@ -870,6 +870,8 @@ __initfunc(static void do_boot_cpu(int i)) *((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 @@ __initfunc(void smp_boot_cpus(void)) * 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 @@ -1302,9 +1311,6 @@ void smp_flush_tlb(void) * 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) { int cpu = smp_processor_id(); diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index e45cc7279..a08c9c49c 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c @@ -515,7 +515,7 @@ unsigned long get_cmos_time(void) 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 --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 696e37004..b397fc76d 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -191,8 +191,6 @@ spinlock_t die_lock; 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 --git a/arch/m68k/amiga/amifb.c b/arch/m68k/amiga/amifb.c index eb72970d7..15e424ea7 100644 --- a/arch/m68k/amiga/amifb.c +++ b/arch/m68k/amiga/amifb.c @@ -1307,6 +1307,7 @@ static void ami_rebuild_copper(void); */ extern unsigned short ami_intena_vals[]; +extern void amiga_init_sound(void); /* * Support for Graphics Boards @@ -1810,6 +1811,11 @@ __initfunc(struct fb_info *amiga_fb_init(long *mem_start)) u_long chipptr; /* + * Our beloved beeper + */ + amiga_init_sound(); + + /* * Check for a Graphics Board */ diff --git a/arch/m68k/amiga/amikeyb.c b/arch/m68k/amiga/amikeyb.c index 1058270dd..06fe55d29 100644 --- a/arch/m68k/amiga/amikeyb.c +++ b/arch/m68k/amiga/amikeyb.c @@ -23,18 +23,17 @@ #include <linux/random.h> #include <linux/kernel.h> #include <linux/init.h> +#include <linux/kbd_ll.h> #include <asm/amigaints.h> #include <asm/amigahw.h> #include <asm/irq.h> -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 unsigned char rep_scancode; 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 void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp) 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 @@ __initfunc(int amiga_keyb_init(void)) 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 --git a/arch/m68k/amiga/amisound.c b/arch/m68k/amiga/amisound.c index d5656d170..72d2091f5 100644 --- a/arch/m68k/amiga/amisound.c +++ b/arch/m68k/amiga/amisound.c @@ -40,7 +40,7 @@ u_short amiga_audio_period = MAX_PERIOD; 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,14 +58,8 @@ static struct timer_list sound_timer = { NULL, NULL, 0, 0, nosound }; 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 --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c index 7b6bd208f..e36016306 100644 --- a/arch/m68k/amiga/config.c +++ b/arch/m68k/amiga/config.c @@ -78,6 +78,7 @@ static void amiga_wait_key(void); 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 --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c index b2887f7da..189095cfc 100644 --- a/arch/m68k/atari/ataints.c +++ b/arch/m68k/atari/ataints.c @@ -48,6 +48,7 @@ #include <asm/atariints.h> #include <asm/atari_stdma.h> #include <asm/irq.h> +#include <asm/entry.h> /* @@ -161,22 +162,6 @@ static int free_vme_vec_bitmap = 0; #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 @@ void atari_slow_irq_##n##_dummy (void) { \ __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 @@ SYMBOL_NAME_STR(atari_fast_irq_handler) ": 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 @@ SYMBOL_NAME_STR(atari_fast_irq_handler) ": addql #8,%%sp addql #4,%%sp jbra "SYMBOL_NAME_STR(ret_from_interrupt) - : : "i" (&kstat.interrupts) + : : "i" (&kstat.interrupts), "n" (PT_OFF_FORMATVEC) ); } diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c index beccf9a84..d5d45be01 100644 --- a/arch/m68k/atari/atakeyb.c +++ b/arch/m68k/atari/atakeyb.c @@ -23,6 +23,7 @@ #include <linux/kd.h> #include <linux/random.h> #include <linux/init.h> +#include <linux/kbd_ll.h> #include <asm/atariints.h> #include <asm/atarihw.h> @@ -31,7 +32,6 @@ #include <asm/atari_joystick.h> #include <asm/irq.h> -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 @@ static unsigned long broken_keys[128/(sizeof(unsigned long)*8)] = { 0, }; * - 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 atashift_map[NR_KEYS] = { 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 atactrl_map[NR_KEYS] = { 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 @@ static u_short atashift_alt_map[NR_KEYS] = { 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 atashift_alt_map[NR_KEYS] = { 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 @@ static u_short atactrl_alt_map[NR_KEYS] = { 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 atactrl_alt_map[NR_KEYS] = { 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 int key_repeat_rate = DEFAULT_KEYB_REP_RATE; 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 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp) 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 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp) * 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 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp) } else if (test_bit( scancode, broken_keys )) break; - + if (break_flag) { del_timer( &atakeyb_rep_timer ); rep_scancode = 0; @@ -808,7 +806,7 @@ void atari_kbd_leds (unsigned int leds) __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 @@ __initfunc(int atari_keyb_init(void)) 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 --git a/arch/m68k/console/fbcon.c b/arch/m68k/console/fbcon.c index 376249c90..62457c0cb 100644 --- a/arch/m68k/console/fbcon.c +++ b/arch/m68k/console/fbcon.c @@ -69,8 +69,8 @@ #include <asm/system.h> #include <asm/uaccess.h> -#include "../../../drivers/char/vt_kern.h" /* vt_cons and vc_resize_con() */ -#include "../../../drivers/char/console_struct.h" +#include <linux/vt_kern.h> +#include <linux/console_struct.h> /* Import console_blanked from console.c */ diff --git a/arch/m68k/fpsp040/skeleton.S b/arch/m68k/fpsp040/skeleton.S index 466cf3fbc..719bcc9ce 100644 --- a/arch/m68k/fpsp040/skeleton.S +++ b/arch/m68k/fpsp040/skeleton.S @@ -39,6 +39,7 @@ | #include <linux/linkage.h> +#include <asm/entry.h> |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 @@ real_dz: 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 @@ inex_done: 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 @@ ovfl_done: 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 @@ unfl_done: 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 @@ real_snan: 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 @@ real_operr: 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 @@ real_bsun: 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 @@ fline: 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 @@ real_unsupp: 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 @@ Lnotkern: 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 --git a/arch/m68k/kernel/console.c b/arch/m68k/kernel/console.c index 468ae0b59..31608e904 100644 --- a/arch/m68k/kernel/console.c +++ b/arch/m68k/kernel/console.c @@ -109,7 +109,6 @@ #include <linux/interrupt.h> #include <linux/tty.h> #include <linux/tty_flip.h> -#include <linux/console.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/errno.h> @@ -119,17 +118,18 @@ #include <linux/major.h> #include <linux/mm.h> #include <linux/ioport.h> +#include <linux/init.h> #include <asm/io.h> #include <asm/uaccess.h> #include <asm/system.h> #include <asm/bitops.h> -#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 <linux/kbd_kern.h> +#include <linux/vt_kern.h> +#include <linux/consolemap.h> +#include <linux/selection.h> +#include <linux/console_struct.h> #ifndef MIN @@ -159,6 +159,8 @@ static void set_vesa_blanking(unsigned long arg); 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 @@ struct consw *conswitchp; #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 @@ void vc_disallocate(unsigned int currcons) 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 @@ static int do_con_write(struct tty_struct * tty, int from_user, 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 @@ static int do_con_write(struct tty_struct * tty, int from_user, 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 @@ static int do_con_write(struct tty_struct * tty, int from_user, 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 @@ static int do_con_write(struct tty_struct * tty, int from_user, palette[i] = 16*par[j++]; palette[i] += par[j]; set_palette() ; -#endif vc_state = ESnormal; } } else @@ -2283,7 +2290,7 @@ static void console_bh(void) * 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 @@ static int set_get_font(char * arg, int set, int ch512) * 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 --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index ef5ef46d6..33542ca96 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S @@ -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 <linux/sys.h> #include <linux/config.h> #include <linux/linkage.h> +#include <asm/entry.h> #include <asm/setup.h> #include <asm/segment.h> -#ifdef CONFIG_KGDB -#include <asm/kgdb.h> -.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 @@ LFORMATVEC = 0x32 .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 @@ ENTRY(buserr) 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 @@ ENTRY(reschedule) 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 @@ SYMBOL_NAME_LABEL(ret_from_signal) jra SYMBOL_NAME(ret_from_exception) ENTRY(system_call) - SAVE_ALL + SAVE_ALL_SYS movel %d0,%d2 GET_CURRENT(%d0) @@ -213,19 +104,20 @@ ENTRY(system_call) 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 @@ SYMBOL_NAME_LABEL(ret_from_exception) 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 @@ Lsignal_return: 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 @@ do_delayed_trace: ** 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 @@ SYMBOL_NAME_LABEL(ret_from_interrupt) 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 @@ ENTRY(sys_sigreturn) 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 @@ SYMBOL_NAME_LABEL(resume) #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 --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c index def50a747..c27f7f320 100644 --- a/arch/m68k/kernel/setup.c +++ b/arch/m68k/kernel/setup.c @@ -142,8 +142,8 @@ __initfunc(static void m68k_parse_bootinfo(const struct bi_record *record)) } } - __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 --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c index 25be40007..44e45b9a0 100644 --- a/arch/m68k/kernel/traps.c +++ b/arch/m68k/kernel/traps.c @@ -201,7 +201,7 @@ static inline void access_error060 (struct frame *fp) 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 --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c index b46037f80..02dff0eea 100644 --- a/arch/m68k/mm/init.c +++ b/arch/m68k/mm/init.c @@ -296,7 +296,8 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; * 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 --git a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c index 77eb2dbfe..dea7695e8 100644 --- a/arch/m68k/mm/memory.c +++ b/arch/m68k/mm/memory.c @@ -552,39 +552,26 @@ unsigned long mm_ptov (unsigned long paddr) 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_clear (unsigned long paddr, int len) 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) { - pushcli040(paddr); - len -= PAGE_SIZE; - paddr += PAGE_SIZE; - } - if (len > 0) { + len += paddr & (PAGE_SIZE - 1); + do { 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 (unsigned long paddr, int len) 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) { - pushv040(vaddr); - len -= PAGE_SIZE; - vaddr += PAGE_SIZE; - } - if (len > 0) { + len += vaddr & (PAGE_SIZE - 1); + do { 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) { - pushv060(vaddr); - len -= PAGE_SIZE; - vaddr += PAGE_SIZE; - } - if (len > 0) { + len += vaddr & (PAGE_SIZE - 1); + do { 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 --git a/arch/mips/defconfig b/arch/mips/defconfig index 33f54a301..9c6fb9073 100644 --- a/arch/mips/defconfig +++ b/arch/mips/defconfig @@ -153,6 +153,9 @@ CONFIG_PCNET32=y # 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 is not set CONFIG_EXT2_FS=y # CONFIG_FAT_FS is not set diff --git a/arch/mips/jazz/g364.c b/arch/mips/jazz/g364.c index 92e130522..1503cc559 100644 --- a/arch/mips/jazz/g364.c +++ b/arch/mips/jazz/g364.c @@ -25,6 +25,11 @@ #include <linux/major.h> #include <linux/mm.h> #include <linux/ioport.h> +#include <linux/kbd_kern.h> +#include <linux/vt_kern.h> +#include <linux/consolemap.h> +#include <linux/selection.h> +#include <linux/console_struct.h> #include <asm/io.h> #include <asm/system.h> @@ -33,12 +38,6 @@ #include <asm/bootinfo.h> #include <asm/types.h> -#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" - extern void register_console(void (*proc)(const char *)); extern void console_print(const char *); unsigned video_res_x; diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c index d994155d0..fc0d542fc 100644 --- a/arch/mips/kernel/irixelf.c +++ b/arch/mips/kernel/irixelf.c @@ -465,7 +465,7 @@ static inline int look_for_irix_interpreter(char **name, goto losing; old_fs = get_fs(); set_fs(get_ds()); - retval = namei(*name, interpreter_inode); + retval = namei(NAM_FOLLOW_LINK, *name, interpreter_inode); set_fs(old_fs); if(retval < 0) goto losing; @@ -973,6 +973,7 @@ unsigned long irix_mapelf(int fd, struct elf_phdr *user_phdrp, int cnt) */ 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 --git a/arch/sparc/config.in b/arch/sparc/config.in index 0005004be..85566667f 100644 --- a/arch/sparc/config.in +++ b/arch/sparc/config.in @@ -54,6 +54,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 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 --git a/arch/sparc/defconfig b/arch/sparc/defconfig index ff91819b0..a6df2dcc0 100644 --- a/arch/sparc/defconfig +++ b/arch/sparc/defconfig @@ -42,6 +42,7 @@ SUN_FB_CGFOURTEEN=y SUN_FB_BWTWO=y SUN_FB_LEO=y TADPOLE_FB_WEITEK=y +SUN_FB_CREATOR=y # # Misc Linux/SPARC drivers @@ -177,6 +178,9 @@ CONFIG_MYRI_SBUS=m # 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 --git a/arch/sparc64/config.in b/arch/sparc64/config.in index c8cdc0134..6354edded 100644 --- a/arch/sparc64/config.in +++ b/arch/sparc64/config.in @@ -59,6 +59,9 @@ fi 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 --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index 579fbb4c2..0d95e1b75 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -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 <asm/signal.h> #include <asm/pgtable.h> -/* 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 @@ sparc64_itlb_refbit_catch: .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 --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S index 0c166ec25..efb1b48fc 100644 --- a/arch/sparc64/kernel/etrap.S +++ b/arch/sparc64/kernel/etrap.S @@ -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 @@ etrap_irq: 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 @@ etrap_irq: 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 @@ etrap_irq: 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 @@ etrap_irq: 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 --git a/arch/sparc64/kernel/hack.S b/arch/sparc64/kernel/hack.S index 6303bd9e9..843221395 100644 --- a/arch/sparc64/kernel/hack.S +++ b/arch/sparc64/kernel/hack.S @@ -24,16 +24,12 @@ do_fpother_tl1: retl;nop 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 @@ do_vaw_tl1: retl;nop .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 --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S index 4babe3eb4..3844c24c3 100644 --- a/arch/sparc64/kernel/head.S +++ b/arch/sparc64/kernel/head.S @@ -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 @@ ramdisk_image: .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 --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c index 3db6fa945..d3792dec6 100644 --- a/arch/sparc64/kernel/ioctl32.c +++ b/arch/sparc64/kernel/ioctl32.c @@ -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 <linux/types.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/smp.h> #include <linux/smp_lock.h> #include <linux/ioctl.h> +#include <linux/if.h> +#include <linux/malloc.h> +#include <linux/hdreg.h> +#include <linux/md.h> +#include <linux/kd.h> +#include <linux/route.h> +#include <linux/netlink.h> #include <asm/types.h> #include <asm/uaccess.h> -/* 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 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) 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 --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 593c1efc6..cc8183618 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -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 @@ void exit_thread(void) #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 @@ void flush_thread(void) #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 @@ clone_stackframe(struct sparc_stackf *dst, struct sparc_stackf *src) 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 @@ static inline void shift_window_buffer(int first_win, int last_win, 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 @@ void synchronize_user_stack(void) 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 @@ void fault_in_user_windows(struct pt_regs *regs) } 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 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, 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 --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S index 0f1dceb33..165b17ef0 100644 --- a/arch/sparc64/kernel/rtrap.S +++ b/arch/sparc64/kernel/rtrap.S @@ -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 +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 - 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_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_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_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_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 + 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 - 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 + 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 - 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 + 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 - wrpr %l2, %g0, %canrestore - wrpr %l1, %g0, %wstate - wrpr %g0, %g0, %otherwin -1: restore - retry +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 --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c index f81e30093..fe4615a6b 100644 --- a/arch/sparc64/kernel/signal.c +++ b/arch/sparc64/kernel/signal.c @@ -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 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu) { #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 --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c index 33892065f..c0454658b 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c @@ -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 @@ restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu32_t *fpu) 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 @@ asmlinkage void do_sigreturn32(struct pt_regs *regs) 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 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, 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 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, } 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 @@ save_fpu_state32(struct pt_regs *regs, __siginfo_fpu32_t *fpu) { #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 @@ new_setup_frame32(struct sigaction *sa, struct pt_regs *regs, { 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 @@ new_setup_frame32(struct sigaction *sa, struct pt_regs *regs, 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 @@ new_setup_frame32(struct sigaction *sa, struct pt_regs *regs, } __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 --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index c54036de6..59815b7a8 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -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 <linux/smb_fs.h> #include <linux/ncp_fs.h> #include <linux/quota.h> +#include <linux/file.h> #include <asm/types.h> #include <asm/poll.h> @@ -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 @@ static inline int do_getname32(u32 filename, char *page) 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 @@ int getname32(u32 filename, char **result) 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 @@ out: 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 @@ asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, u32 arg) 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 @@ asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, u32 arg) } } +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 @@ struct dqblk32 { __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 @@ asmlinkage int sys32_quotactl(int cmd, u32 special, int id, u32 addr) 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 @@ asmlinkage int sys32_fstatfs(unsigned int fd, u32 buf) 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 @@ asmlinkage int sys32_utime(u32 filename, u32 times) 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 @@ asmlinkage long sys32_write(unsigned int fd, u32 buf, u32 count) 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--; } - 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 (); + + 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; } - 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; - } + /* 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; } - 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; - } + + if (!file->f_op) { + if (iov != iovstack) + kfree(iov); + return -EINVAL; } - 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 (); + /* 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; } - 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 @@ struct readdir_callback32 { 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 @@ asmlinkage int old32_readdir(unsigned int fd, u32 dirent, unsigned int count) 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 @@ out: /* 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) -{ - 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))) +static inline int putstat(struct stat32 *ubuf, struct stat *kbuf) +{ + 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 @@ asmlinkage int sys32_newstat(u32 filename, u32 statbuf) 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 @@ asmlinkage int sys32_newlstat(u32 filename, u32 statbuf) 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 @@ asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf) 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 @@ asmlinkage int sys32_sysfs(int option, ...) 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 @@ static int put_rusage (u32 ru, struct rusage *r) 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 @@ asmlinkage int sys32_wait4(__kernel_pid_t32 pid, u32 stat_addr, int options, u32 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 @@ struct sysinfo32 { char _f[22]; }; +extern asmlinkage int sys_sysinfo(struct sysinfo *info); + asmlinkage int sys32_sysinfo(u32 info) { struct sysinfo s; @@ -1336,28 +1462,41 @@ asmlinkage int sys32_sysinfo(u32 info) 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 @@ struct timespec32 { 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 @@ asmlinkage int sys32_sched_rr_get_interval(__kernel_pid_t32 pid, u32 interval) 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 @@ asmlinkage int sys32_nanosleep(u32 rqtp, u32 rmtp) 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 @@ asmlinkage int sys32_sigprocmask(int how, u32 set, u32 oset) return ret; } +extern asmlinkage int sys_sigpending(sigset_t *set); + asmlinkage int sys32_sigpending(u32 set) { sigset_t s; @@ -1430,21 +1577,29 @@ asmlinkage int sys32_sigpending(u32 set) 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 @@ struct tms32 { __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 @@ asmlinkage long sys32_times(u32 tbuf) 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 @@ asmlinkage int sys32_getgroups(int gidsetsize, u32 grouplist) 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 @@ asmlinkage int sys32_setgroups(int gidsetsize, u32 grouplist) 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 @@ struct rlimit32 { 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 @@ asmlinkage int sys32_getrlimit(unsigned int resource, u32 rlim) 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 @@ asmlinkage int sys32_setrlimit(unsigned int resource, u32 rlim) 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 @@ asmlinkage int sys32_getrusage(int who, u32 ru) 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 @@ struct timex32 { 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 @@ asmlinkage int sys32_adjtimex(u32 txc_p) 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 @@ asmlinkage int sys32_setsockopt(int fd, int level, int optname, u32 optval, int 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 @@ struct cmsghdr32 { 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) { - 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))) - 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; + 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; +} - 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; +static inline int msghdr_from_user32_to_kern(struct msghdr *kmsg, + struct msghdr32 *umsg) +{ + 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; + + 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; } - - m.msg_iov = v; - 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 (); - } - return ret; + 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_recvmsg(int fd, u32 msg, unsigned int flags) +asmlinkage int sys32_sendmsg(int fd, u32 user_msg, unsigned 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 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; - - 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; + 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; + } } - } - - 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; + __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.? */ + 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); } - 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; + 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 user_msg, unsigned int user_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; + if(kern_msg.msg_iovlen > UIO_MAXIOV) + return -EINVAL; + + 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; + + 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 (call<SYS_SOCKET||call>SYS_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 @@ out: 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 */ @@ -2204,6 +2553,12 @@ asmlinkage int sparc32_execve(struct pt_regs *regs) return error; } +/* Modules will be supported with 64bit modutils only */ +asmlinkage int sys32_no_modules(void) +{ + return -ENOSYS; +} + struct ncp_mount_data32 { int version; unsigned int ncp_fd; diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index 02707186a..a74d0ffbd 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -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 @@ sys_call_table32: .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 --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index 6f96408ad..824a3ddb4 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -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 <asm/pgtable.h> #include <asm/unistd.h> #include <asm/uaccess.h> +#include <asm/fpumacro.h> /* #define SYSCALL_TRACING */ /* #define VERBOSE_SYSCALL_TRACING */ @@ -122,7 +123,8 @@ void syscall_trace_entry(unsigned long g1, struct pt_regs *regs) 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 @@ void syscall_trace_entry(unsigned long g1, struct pt_regs *regs) 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 @@ void do_iae(struct pt_regs *regs) 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 @@ void do_illegal_instruction(struct pt_regs *regs) 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 --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S index 326382c3f..8db708f07 100644 --- a/arch/sparc64/kernel/ttable.S +++ b/arch/sparc64/kernel/ttable.S @@ -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_dax: ACCESS_EXCEPTION_TRAP(data_access_exception) 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_dax: ACCESS_EXCEPTION_TRAPTL1(data_access_exception) 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 --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S index a8293c453..2ac19a440 100644 --- a/arch/sparc64/kernel/winfixup.S +++ b/arch/sparc64/kernel/winfixup.S @@ -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 <asm/page.h> #include <asm/ptrace.h> #include <asm/processor.h> +#include <asm/spitfire.h> #include <asm/asm_offsets.h> .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 --git a/arch/sparc64/lib/checksum.S b/arch/sparc64/lib/checksum.S index b63f0d6e8..10eebb8df 100644 --- a/arch/sparc64/lib/checksum.S +++ b/arch/sparc64/lib/checksum.S @@ -71,8 +71,9 @@ csum_partial_end_cruft: 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 @@ csum_partial_fix_alignment: */ .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 @@ __csum_partial_copy_start: 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 @@ __csum_partial_copy_start: * 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 @@ __csum_partial_copy_start: * 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 @@ __csum_partial_copy_start: /* 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 @@ cc_end_cruft: 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 @@ cc_end_cruft: 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 @@ cc_end_cruft: 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 @@ cc_end_cruft: .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 @@ __csum_partial_copy_sparc_generic: 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 @@ __csum_partial_copy_sparc_generic: 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 @@ cctbl: CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x68,%g2,%g3,%g4,%g5) 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 @@ ccslow: mov 0, %g5 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 @@ ccslow: mov 0, %g5 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 @@ ccslow: mov 0, %g5 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 @@ ccslow: mov 0, %g5 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 @@ ccslow: mov 0, %g5 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 @@ ccslow: mov 0, %g5 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 @@ ccslow: mov 0, %g5 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 --git a/arch/sparc64/lib/copy_from_user.S b/arch/sparc64/lib/copy_from_user.S index 50ec7bb3d..196435aed 100644 --- a/arch/sparc64/lib/copy_from_user.S +++ b/arch/sparc64/lib/copy_from_user.S @@ -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 --git a/arch/sparc64/lib/copy_to_user.S b/arch/sparc64/lib/copy_to_user.S index 733953743..cc6db141f 100644 --- a/arch/sparc64/lib/copy_to_user.S +++ b/arch/sparc64/lib/copy_to_user.S @@ -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 --git a/arch/sparc64/lib/memset.S b/arch/sparc64/lib/memset.S index 55de4ea9d..713c78ca8 100644 --- a/arch/sparc64/lib/memset.S +++ b/arch/sparc64/lib/memset.S @@ -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 --git a/arch/sparc64/lib/strlen_user.S b/arch/sparc64/lib/strlen_user.S index 30beee3ff..4d57aed64 100644 --- a/arch/sparc64/lib/strlen_user.S +++ b/arch/sparc64/lib/strlen_user.S @@ -92,10 +92,10 @@ __strlen_user: 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 --git a/arch/sparc64/lib/strncpy_from_user.S b/arch/sparc64/lib/strncpy_from_user.S index e0fb0f09b..7a5dc768f 100644 --- a/arch/sparc64/lib/strncpy_from_user.S +++ b/arch/sparc64/lib/strncpy_from_user.S @@ -49,6 +49,6 @@ __strncpy_from_user: mov -EFAULT, %o0 .section __ex_table,#alloc - .align 4 - .word 10b, 4b - .word 11b, 4b + .align 8 + .xword 10b, 4b + .xword 11b, 4b diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c index e23e736a9..6df923a4b 100644 --- a/arch/sparc64/mm/fault.c +++ b/arch/sparc64/mm/fault.c @@ -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 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, } /* #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 @@ asmlinkage void do_sparc64_fault(struct pt_regs *regs, int text_fault, int write 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 @@ bad_area: 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 @@ bad_area: unhandled_fault (address, tsk, regs); out: unlock_kernel(); +#ifdef FAULT_TRACER +#ifdef FAULT_TRACER_VERBOSE + printk(" done\n"); +#else + printk("]"); +#endif +#endif } + diff --git a/arch/sparc64/vmlinux.lds b/arch/sparc64/vmlinux.lds index f8ba23528..d2d0cac34 100644 --- a/arch/sparc64/vmlinux.lds +++ b/arch/sparc64/vmlinux.lds @@ -26,6 +26,7 @@ SECTIONS _edata = .; PROVIDE (edata = .); .fixup : { *(.fixup) } + . = ALIGN(16); __start___ex_table = .; __ex_table : { *(__ex_table) } __stop___ex_table = .; diff --git a/drivers/ap1000/ringbuf.c b/drivers/ap1000/ringbuf.c index b8bcbb541..ee33a03d4 100644 --- a/drivers/ap1000/ringbuf.c +++ b/drivers/ap1000/ringbuf.c @@ -318,7 +318,6 @@ struct inode_operations proc_ringbuf_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index ad0e79b1b..0217dcb52 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -380,7 +380,7 @@ check_table: && (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; @@ -740,6 +740,141 @@ rdb_done: } #endif /* CONFIG_AMIGA_PARTITION */ +#ifdef CONFIG_ATARI_PARTITION +#include <asm/atari_rootsec.h> + +/* ++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; @@ -777,6 +912,10 @@ static void check_partition(struct gendisk *hd, kdev_t dev) if(amiga_partition(hd, dev, first_sector)) return; #endif +#ifdef CONFIG_ATARI_PARTITION + if(atari_partition(hd, dev, first_sector)) + return; +#endif #ifdef CONFIG_SGI_PARTITION if(sgi_partition(hd, dev, first_sector)) return; diff --git a/drivers/block/ide.c b/drivers/block/ide.c index 89759dd32..1b293c539 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -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 @@ int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeou 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 --git a/drivers/block/ide.h b/drivers/block/ide.h index 241a571ca..95724e6e9 100644 --- a/drivers/block/ide.h +++ b/drivers/block/ide.h @@ -134,7 +134,7 @@ typedef unsigned char byte; /* used everywhere */ #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 --git a/drivers/block/loop.c b/drivers/block/loop.c index 212efece2..53fef9b74 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -318,7 +318,7 @@ static int loop_set_fd(struct loop_device *lo, kdev_t dev, unsigned int arg) } 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 --git a/drivers/block/md.c b/drivers/block/md.c index 078e1e1ee..12cb6dcf0 100644 --- a/drivers/block/md.c +++ b/drivers/block/md.c @@ -202,9 +202,10 @@ static int do_md_stop (int minor, struct inode *inode) { 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 --git a/drivers/char/Makefile b/drivers/char/Makefile index d5a19d343..900cb935f 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -46,6 +46,9 @@ endif 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 --git a/drivers/char/atarimouse.c b/drivers/char/atarimouse.c index 18debb66b..950cb1546 100644 --- a/drivers/char/atarimouse.c +++ b/drivers/char/atarimouse.c @@ -176,7 +176,7 @@ __initfunc(int atari_mouse_init(void)) #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 --git a/drivers/char/console.c b/drivers/char/console.c index 56748c068..61ab64aac 100644 --- a/drivers/char/console.c +++ b/drivers/char/console.c @@ -125,11 +125,11 @@ unsigned long video_port_base; #include <asm/uaccess.h> #include <asm/bitops.h> -#include "kbd_kern.h" -#include "vt_kern.h" -#include "consolemap.h" -#include "selection.h" -#include "console_struct.h" +#include <linux/kbd_kern.h> +#include <linux/vt_kern.h> +#include <linux/consolemap.h> +#include <linux/selection.h> +#include <linux/console_struct.h> #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c index 878ac0d72..5b0e61fea 100644 --- a/drivers/char/consolemap.c +++ b/drivers/char/consolemap.c @@ -13,7 +13,7 @@ #include <linux/malloc.h> #include <linux/init.h> #include <asm/uaccess.h> -#include "consolemap.h" +#include <linux/consolemap.h> static unsigned short translations[][256] = { /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */ diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c index ef97f7255..5928869e9 100644 --- a/drivers/char/dsp56k.c +++ b/drivers/char/dsp56k.c @@ -488,7 +488,7 @@ static int dsp56k_open(struct inode *inode, struct file *file) 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 @@ static void dsp56k_release(struct inode *inode, struct file *file) 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 --git a/drivers/char/fbmem.c b/drivers/char/fbmem.c index b267f84d3..7db3b5dba 100644 --- a/drivers/char/fbmem.c +++ b/drivers/char/fbmem.c @@ -222,7 +222,7 @@ fb_mmap(struct inode *inode, struct file *file, struct vm_area_struct * vma) 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 --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 0185c2bda..66523964a 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -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 <linux/config.h> #include <linux/sched.h> #include <linux/tty.h> #include <linux/tty_flip.h> @@ -30,9 +33,10 @@ #include <asm/keyboard.h> #include <asm/bitops.h> -#include "kbd_kern.h" -#include "diacr.h" -#include "vt_kern.h" +#include <linux/kbd_kern.h> +#include <linux/kbd_diacr.h> +#include <linux/vt_kern.h> +#include <linux/kbd_ll.h> #define SIZE(x) (sizeof(x)/sizeof((x)[0])) @@ -82,7 +86,7 @@ static int dead_key_next = 0; * 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 @@ const int NR_TYPES = SIZE(max_vals); 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 @@ void handle_scancode(unsigned char scancode) } 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 caps_on(void) 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 --git a/drivers/char/lp_m68k.c b/drivers/char/lp_m68k.c index 17405c191..117dc3fe7 100644 --- a/drivers/char/lp_m68k.c +++ b/drivers/char/lp_m68k.c @@ -462,7 +462,6 @@ static struct file_operations lp_fops = { 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 --git a/drivers/char/mem.c b/drivers/char/mem.c index 56d537fb3..499132bf8 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -35,6 +35,33 @@ void isdn_init(void); 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 @@ static long read_mem(struct inode * inode, struct file * file, 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 @@ static long read_mem(struct inode * inode, struct file * file, 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 @@ static long write_mem(struct inode * inode, struct file * file, { 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 @@ static int mmap_mem(struct inode * inode, struct file * file, struct vm_area_str 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 @@ static long write_kmem(struct inode * inode, struct file * file, 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 @@ static long read_port(struct inode * inode, struct file * file, 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 @@ static long write_port(struct inode * inode, struct file * file, 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 --git a/drivers/char/misc.c b/drivers/char/misc.c index d632e4788..ed06f6314 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -44,8 +44,8 @@ #include <linux/apm_bios.h> #endif -#include <linux/tty.h> /* needed by selection.h */ -#include "selection.h" /* export its symbols */ +#include <linux/tty.h> +#include <linux/selection.h> #ifdef CONFIG_KERNELD #include <linux/kerneld.h> #endif diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c index 2d075636f..9e3267aaf 100644 --- a/drivers/char/pc_keyb.c +++ b/drivers/char/pc_keyb.c @@ -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 <linux/sched.h> @@ -24,89 +14,181 @@ #include <linux/signal.h> #include <linux/ioport.h> #include <linux/init.h> +#include <linux/kbd_ll.h> -#include <asm/bitops.h> +/* Some configuration switches are present in the include file... */ -/* - * Define these here, include/asm-mips/keyboard.h depends on them. - * - * keyboard controller registers - */ -#define KBD_STATUS_REG (unsigned int) 0x64 -#define KBD_CNTL_REG (unsigned int) 0x64 -#define KBD_DATA_REG (unsigned int) 0x60 -/* - * controller commands - */ -#define KBD_READ_MODE (unsigned int) 0x20 -#define KBD_WRITE_MODE (unsigned int) 0x60 -#define KBD_SELF_TEST (unsigned int) 0xAA -#define KBD_SELF_TEST2 (unsigned int) 0xAB -#define KBD_CNTL_ENABLE (unsigned int) 0xAE -/* - * keyboard commands - */ -#define KBD_ENABLE (unsigned int) 0xF4 -#define KBD_DISABLE (unsigned int) 0xF5 -#define KBD_RESET (unsigned int) 0xFF -/* - * keyboard replies - */ -#define KBD_ACK (unsigned int) 0xFA -#define KBD_POR (unsigned int) 0xAA -/* - * status register bits - */ -#define KBD_OBF (unsigned int) 0x01 -#define KBD_IBF (unsigned int) 0x02 -#define KBD_GTO (unsigned int) 0x40 -#define KBD_PERR (unsigned int) 0x80 -/* - * keyboard controller mode register bits - */ -#define KBD_EKI (unsigned int) 0x01 -#define KBD_SYS (unsigned int) 0x04 -#define KBD_DMS (unsigned int) 0x20 -#define KBD_KCC (unsigned int) 0x40 +#include "pc_keyb.h" #include <asm/keyboard.h> +#include <asm/bitops.h> +#include <asm/io.h> +#include <asm/system.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 -int initialize_kbd(void); -#endif -#include <asm/io.h> -#include <asm/system.h> +__initfunc(static int kbd_wait_for_input(void)) +{ + int n; + int status, data; + + n = KBD_TIMEOUT; + do { + status = kbd_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 = kbd_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 = kbd_inb(KBD_STATUS_REG); + } while (status & KBD_STAT_IBF); + kbd_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(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); +} -unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */ +#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 ((kbd_inb_p(0x64) & 0x02) == 0) + for (i=0; i<KBD_TIMEOUT; i++) + if (! (kbd_inb_p(KBD_STATUS_REG) & KBD_STAT_IBF)) return; printk(KERN_WARNING "Keyboard timed out\n"); } -extern struct pt_regs *pt_regs; - -extern void handle_scancode(unsigned char scancode); - - /* * Translation of escaped scancodes to keycodes. * This is now user-settable. @@ -247,11 +329,11 @@ int pckbd_getkeycode(unsigned int scancode) static inline void send_cmd(unsigned char c) { kb_wait(); - kbd_outb(c,0x64); + kbd_outb(c, KBD_CNTL_REG); } -#define disable_keyboard() do { send_cmd(0xAD); kb_wait(); } while (0) -#define enable_keyboard() send_cmd(0xAE) +#define disable_keyboard() do { send_cmd(KBD_CCMD_KBD_DISABLE); kb_wait(); } while (0) +#define enable_keyboard() send_cmd(KBD_CCMD_KBD_ENABLE) #else #define disable_keyboard() /* nothing */ #define enable_keyboard() /* nothing */ @@ -260,18 +342,21 @@ static inline void send_cmd(unsigned char c) static int do_acknowledge(unsigned char scancode) { if (reply_expected) { - /* 0xfa, 0xfe only mean "acknowledge", "resend" for most keyboards */ - /* but they are the key-up scancodes for PF6, PF10 on a FOCUS 9000 */ - reply_expected = 0; - if (scancode == 0xfa) { + /* Unfortunately, we must recognise these codes only if we know they + * are known to be valid (i.e., after sending a command), because there + * are some brain-damaged keyboards (yes, FOCUS 9000 again) which have + * keys with such codes :( + */ + if (scancode == KBD_REPLY_ACK) { acknowledge = 1; + reply_expected = 0; return 0; - } else if (scancode == 0xfe) { + } else if (scancode == KBD_REPLY_RESEND) { resend = 1; + reply_expected = 0; return 0; } - /* strange ... */ - reply_expected = 1; + /* Should not happen... */ #if 0 printk(KERN_DEBUG "keyboard reply expected - got %02x\n", scancode); @@ -402,23 +487,23 @@ static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs) { unsigned char status; - pt_regs = regs; + kbd_pt_regs = regs; disable_keyboard(); - status = kbd_inb_p(0x64); + status = kbd_inb_p(KBD_STATUS_REG); do { unsigned char scancode; /* mouse data? */ - if (status & kbd_read_mask & 0x20) + if (status & kbd_read_mask & KBD_STAT_MOUSE_OBF) break; - scancode = kbd_inb(0x60); - if ((status & 0x01) && do_acknowledge(scancode)) + scancode = kbd_inb(KBD_DATA_REG); + if ((status & KBD_STAT_OBF) && do_acknowledge(scancode)) handle_scancode(scancode); - status = kbd_inb(0x64); - } while (status & 0x01); + status = kbd_inb(KBD_STATUS_REG); + } while (status & (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF)); mark_bh(KEYBOARD_BH); enable_keyboard(); @@ -439,9 +524,9 @@ static int send_data(unsigned char data) acknowledge = 0; resend = 0; reply_expected = 1; - kbd_outb_p(data, 0x60); + kbd_outb_p(data, KBD_DATA_REG); for(i=0; i<0x200000; i++) { - kbd_inb_p(0x64); /* just as a delay */ + kbd_inb_p(KBD_STATUS_REG); /* just as a delay */ if (acknowledge) return 1; if (resend) @@ -455,8 +540,8 @@ static int send_data(unsigned char data) void pckbd_leds(unsigned char leds) { - if (!send_data(0xed) || !send_data(leds)) - send_data(0xf4); /* re-enable kbd if any errors */ + if (!send_data(KBD_CMD_SET_LEDS) || !send_data(leds)) + send_data(KBD_CMD_ENABLE); /* re-enable kbd if any errors */ } __initfunc(void pckbd_init_hw(void)) @@ -467,180 +552,3 @@ __initfunc(void pckbd_init_hw(void)) initialize_kbd(); #endif } - -#ifdef INIT_KBD - -/* - * controller commands - */ -#define KBD_READ_MODE (unsigned int) 0x20 -#define KBD_WRITE_MODE (unsigned int) 0x60 -#define KBD_SELF_TEST (unsigned int) 0xAA -#define KBD_SELF_TEST2 (unsigned int) 0xAB -#define KBD_CNTL_ENABLE (unsigned int) 0xAE -/* - * keyboard commands - */ -#define KBD_ENABLE (unsigned int) 0xF4 -#define KBD_DISABLE (unsigned int) 0xF5 -#define KBD_RESET (unsigned int) 0xFF -/* - * keyboard replies - */ -#define KBD_ACK (unsigned int) 0xFA -#define KBD_POR (unsigned int) 0xAA -/* - * status register bits - */ -#define KBD_OBF (unsigned int) 0x01 -#define KBD_IBF (unsigned int) 0x02 -#define KBD_GTO (unsigned int) 0x40 -#define KBD_PERR (unsigned int) 0x80 -/* - * keyboard controller mode register bits - */ -#define KBD_EKI (unsigned int) 0x01 -#define KBD_SYS (unsigned int) 0x04 -#define KBD_DMS (unsigned int) 0x20 -#define KBD_KCC (unsigned int) 0x40 - -#define TIMEOUT_CONST 500000 - -static int kbd_wait_for_input(void) -{ - int n; - int status, data; - - n = TIMEOUT_CONST; - do { - status = kbd_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_OBF)) - continue; - - data = kbd_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_GTO | KBD_PERR)) { - continue; - } - return (data & 0xff); - } while (--n); - return (-1); /* timed-out if fell through to here... */ -} - -static void kbd_write(int address, int data) -{ - int status; - - do { - status = kbd_inb(KBD_STATUS_REG); /* spin until input buffer empty*/ - } while (status & KBD_IBF); - kbd_outb(data, address); /* write out the data*/ -} - -__initfunc(int initialize_kbd(void)) -{ - unsigned long flags; - - save_flags(flags); cli(); - - /* Flush any pending input. */ - while (kbd_wait_for_input() != -1) - continue; - - /* - * 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_SELF_TEST); - if (kbd_wait_for_input() != 0x55) { - printk(KERN_WARNING "initialize_kbd: " - "keyboard failed self test.\n"); - restore_flags(flags); - return(-1); - } - - /* - * 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_SELF_TEST2); - if (kbd_wait_for_input() != 0x00) { - printk(KERN_WARNING "initialize_kbd: " - "keyboard failed self test 2.\n"); - restore_flags(flags); - return(-1); - } - - /* Enable the keyboard by allowing the keyboard clock to run. */ - kbd_write(KBD_CNTL_REG, KBD_CNTL_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_RESET); - if (kbd_wait_for_input() != KBD_ACK) { - printk(KERN_WARNING "initialize_kbd: " - "reset kbd failed, no ACK.\n"); - restore_flags(flags); - return(-1); - } - - if (kbd_wait_for_input() != KBD_POR) { - printk(KERN_WARNING "initialize_kbd: " - "reset kbd failed, not POR.\n"); - restore_flags(flags); - return(-1); - } - - /* - * now do a DEFAULTS_DISABLE always - */ - kbd_write(KBD_DATA_REG, KBD_DISABLE); - if (kbd_wait_for_input() != KBD_ACK) { - printk(KERN_WARNING "initialize_kbd: " - "disable kbd failed, no ACK.\n"); - restore_flags(flags); - return(-1); - } - - /* - * Enable keyboard interrupt, operate in "sys" mode, - * enable keyboard (by clearing the disable keyboard bit), - * disable mouse, do conversion of keycodes. - */ - kbd_write(KBD_CNTL_REG, KBD_WRITE_MODE); - kbd_write(KBD_DATA_REG, KBD_EKI|KBD_SYS|KBD_DMS|KBD_KCC); - - /* - * now ENABLE the keyboard to set it scanning... - */ - kbd_write(KBD_DATA_REG, KBD_ENABLE); - if (kbd_wait_for_input() != KBD_ACK) { - printk(KERN_WARNING "initialize_kbd: " - "keyboard enable failed.\n"); - restore_flags(flags); - return(-1); - } - - restore_flags(flags); - - return (1); -} -#endif /* INIT_KBD */ diff --git a/drivers/char/pc_keyb.h b/drivers/char/pc_keyb.h new file mode 100644 index 000000000..f12ddab08 --- /dev/null +++ b/drivers/char/pc_keyb.h @@ -0,0 +1,107 @@ +/* + * linux/drivers/char/pc_keyb.h + * + * PC Keyboard And Keyboard Controller + * + * (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz> + */ + +/* + * 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 --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 3235ebeaa..a8614999d 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -43,6 +43,7 @@ * this driver.) */ +#include <linux/config.h> #include <linux/types.h> #include <linux/errno.h> #include <linux/miscdevice.h> @@ -156,10 +157,6 @@ static long rtc_read(struct inode *inode, struct file *file, char *buf, 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 @@ static long rtc_read(struct inode *inode, struct file *file, char *buf, 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 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, { unsigned long flags; + struct rtc_time wtime; switch (cmd) { case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ @@ -254,18 +251,9 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, * 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 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, 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 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, } 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 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, 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 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, } 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 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, default: return -EINVAL; } + return copy_to_user(arg, &wtime, sizeof wtime) ? -EFAULT : 0; } /* @@ -536,11 +504,11 @@ __initfunc(int rtc_init(void)) { 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 --git a/drivers/char/selection.c b/drivers/char/selection.c index b3f6d1570..b34d73665 100644 --- a/drivers/char/selection.c +++ b/drivers/char/selection.c @@ -21,9 +21,9 @@ #include <asm/uaccess.h> -#include "vt_kern.h" -#include "consolemap.h" -#include "selection.h" +#include <linux/vt_kern.h> +#include <linux/consolemap.h> +#include <linux/selection.h> #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -101,9 +101,9 @@ int sel_loadlut(const unsigned long arg) } /* 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 @@ int set_selection(const unsigned long arg, struct tty_struct *tty, int user) /* 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 --git a/drivers/char/softdog.c b/drivers/char/softdog.c index d16227d83..2eda6ef10 100644 --- a/drivers/char/softdog.c +++ b/drivers/char/softdog.c @@ -42,6 +42,10 @@ static int soft_margin = TIMER_MARGIN; /* in seconds */ +#ifdef MODULE +MODULE_PARM(soft_margin,"i"); +#endif + /* * Our timer */ diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c new file mode 100644 index 000000000..e2044c086 --- /dev/null +++ b/drivers/char/sysrq.c @@ -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 <mj@atrey.karlin.mff.cuni.cz> + * based on ideas by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz> + */ + +#include <linux/config.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/mm.h> +#include <linux/fs.h> +#include <linux/mount.h> +#include <linux/kdev_t.h> +#include <linux/major.h> +#include <linux/reboot.h> +#include <linux/sysrq.h> +#include <linux/kbd_kern.h> +#include <asm/ptrace.h> +#include <asm/smp_lock.h> + +#ifdef CONFIG_APM +#include <linux/apm_bios.h> +#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 --git a/drivers/char/tga.c b/drivers/char/tga.c index a85f4cba4..f4e7b48ab 100644 --- a/drivers/char/tga.c +++ b/drivers/char/tga.c @@ -33,11 +33,11 @@ #include <asm/uaccess.h> #include <asm/bitops.h> -#include "kbd_kern.h" -#include "vt_kern.h" -#include "consolemap.h" -#include "selection.h" -#include "console_struct.h" +#include <linux/kbd_kern.h> +#include <linux/vt_kern.h> +#include <linux/consolemap.h> +#include <linux/selection.h> +#include <linux/console_struct.h> extern struct console vt_console_driver; diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 12109e524..c08e44a27 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -77,9 +77,9 @@ #include <asm/system.h> #include <asm/bitops.h> -#include "kbd_kern.h" -#include "vt_kern.h" -#include "selection.h" +#include <linux/kbd_kern.h> +#include <linux/vt_kern.h> +#include <linux/selection.h> #ifdef CONFIG_KERNELD #include <linux/kerneld.h> diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c index cb91431dc..603250b81 100644 --- a/drivers/char/vc_screen.c +++ b/drivers/char/vc_screen.c @@ -31,9 +31,9 @@ #include <linux/interrupt.h> #include <linux/mm.h> #include <linux/init.h> +#include <linux/vt_kern.h> +#include <linux/selection.h> #include <asm/uaccess.h> -#include "vt_kern.h" -#include "selection.h" #undef attr #undef org diff --git a/drivers/char/vga.c b/drivers/char/vga.c index e82bbc083..afce24c98 100644 --- a/drivers/char/vga.c +++ b/drivers/char/vga.c @@ -72,11 +72,11 @@ unsigned long video_port_base; #include <asm/uaccess.h> #include <asm/bitops.h> -#include "kbd_kern.h" -#include "vt_kern.h" -#include "consolemap.h" -#include "selection.h" -#include "console_struct.h" +#include <linux/kbd_kern.h> +#include <linux/vt_kern.h> +#include <linux/consolemap.h> +#include <linux/selection.h> +#include <linux/console_struct.h> #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 --git a/drivers/char/vt.c b/drivers/char/vt.c index b3e25c010..7b007f465 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -26,10 +26,10 @@ #include <asm/io.h> #include <asm/uaccess.h> -#include "kbd_kern.h" -#include "vt_kern.h" -#include "diacr.h" -#include "selection.h" +#include <linux/kbd_kern.h> +#include <linux/vt_kern.h> +#include <linux/kbd_diacr.h> +#include <linux/selection.h> char vt_dont_switch = 0; extern struct tty_driver console_driver; diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c index dc29bdf79..91c868942 100644 --- a/drivers/isdn/hisax/callc.c +++ b/drivers/isdn/hisax/callc.c @@ -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 @@ extern long mod_use_count_; #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 @@ init_chan(int chan, struct IsdnCardState *csta, int hscx, chanp->debug = 0; chanp->Flags = 0; chanp->leased = 0; + chanp->impair = 0; init_is(chanp, ces); chanp->fi.fsm = &callcfsm; diff --git a/drivers/net/Config.in b/drivers/net/Config.in index e14c76a61..23befe03c 100644 --- a/drivers/net/Config.in +++ b/drivers/net/Config.in @@ -142,10 +142,15 @@ if [ "$CONFIG_NET_RADIO" != "n" ]; then 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 --git a/drivers/net/arcnet.c b/drivers/net/arcnet.c index 7a8069fd6..c9f13150c 100644 --- a/drivers/net/arcnet.c +++ b/drivers/net/arcnet.c @@ -751,8 +751,8 @@ __initfunc(int arcnet_probe(struct device *dev)) * 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 --git a/drivers/net/baycom.c b/drivers/net/baycom.c index 7569d66e7..74c041342 100644 --- a/drivers/net/baycom.c +++ b/drivers/net/baycom.c @@ -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 <linux/netdevice.h> #include <linux/hdlcdrv.h> #include <linux/baycom.h> -#include <linux/init.h> /* --------------------------------------------------------------------- */ @@ -133,6 +133,14 @@ extern inline int copy_to_user(void *to, const void *from, unsigned long n) } #endif +#if LINUX_VERSION_CODE >= 0x20123 +#include <linux/init.h> +#else +#define __init +#define __initdata +#define __initfunc(x) x +#endif + /* --------------------------------------------------------------------- */ #define BAYCOM_DEBUG @@ -1001,7 +1009,7 @@ MODULE_DESCRIPTION("Baycom ser12, par96 and picpar amateur radio modem driver"); #endif -int init_module(void) +__initfunc(int init_module(void)) { baycom_ports[0].mode = mode; baycom_ports[0].iobase = iobase; diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index 659e71f32..b841a01bb 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -229,7 +229,11 @@ static const char *version = "defxx.c:v1.04 09/16/96 Lawrence V. Stefani (stefa #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 @@ void dfx_rcv_init( 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 @@ void dfx_rcv_queue_process( 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 @@ void dfx_rcv_queue_process( 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 @@ int dfx_xmt_queue_pkt( 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 @@ int dfx_xmt_queue_pkt( * 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 @@ int dfx_xmt_queue_pkt( * 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 --git a/drivers/net/hdlcdrv.c b/drivers/net/hdlcdrv.c index 467980406..666bf3858 100644 --- a/drivers/net/hdlcdrv.c +++ b/drivers/net/hdlcdrv.c @@ -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 @@ extern __inline__ void dev_init_buffers(struct device *dev) /* --------------------------------------------------------------------- */ +#if LINUX_VERSION_CODE >= 0x20123 +#include <linux/init.h> +#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 @@ MODULE_DESCRIPTION("Packet Radio network interface HDLC encoder/decoder"); /* --------------------------------------------------------------------- */ -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 --git a/drivers/net/net_init.c b/drivers/net/net_init.c index 9d8e30761..ef15a14da 100644 --- a/drivers/net/net_init.c +++ b/drivers/net/net_init.c @@ -248,7 +248,7 @@ void fddi_setup(struct device *dev) #endif -#ifdef CONFIG_ATALK +#if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) static int ltalk_change_mtu(struct device *dev, int mtu) { diff --git a/drivers/net/soundmodem/Makefile b/drivers/net/soundmodem/Makefile index 119118128..5259b724c 100644 --- a/drivers/net/soundmodem/Makefile +++ b/drivers/net/soundmodem/Makefile @@ -21,6 +21,12 @@ endif 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 @@ M_OBJS := $(O_TARGET) 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 --git a/drivers/net/soundmodem/gentbl.c b/drivers/net/soundmodem/gentbl.c index d617865e3..cb8cb246f 100644 --- a/drivers/net/soundmodem/gentbl.c +++ b/drivers/net/soundmodem/gentbl.c @@ -31,27 +31,44 @@ /* -------------------------------------------------------------------- */ -#define OFFSCOSTABBITS 6 -#define OFFSCOSTABSIZE (1<<OFFSCOSTABBITS) - -static void gentbl_offscostab(FILE *f) +static void gentbl_offscostab(FILE *f, unsigned int nbits) { int i; fprintf(f, "\n/*\n * small cosine table in U8 format\n */\n" "#define OFFSCOSTABBITS %u\n" "#define OFFSCOSTABSIZE (1<<OFFSCOSTABBITS)\n\n", - OFFSCOSTABBITS); + nbits); fprintf(f, "static unsigned char offscostab[OFFSCOSTABSIZE] = {\n\t"); - for (i = 0; i < OFFSCOSTABSIZE; i++) { + for (i = 0; i < (1<<nbits); i++) { fprintf(f, "%4u", (int) - (128+127.0*cos(i*2.0*M_PI/OFFSCOSTABSIZE))); - if (i < OFFSCOSTABSIZE-1) + (128+127.0*cos(i*2.0*M_PI/(1<<nbits)))); + if (i < (1<<nbits)-1) fprintf(f, "%s", (i & 7) == 7 ? ",\n\t" : ","); } fprintf(f, "\n};\n\n" "#define OFFSCOS(x) offscostab[((x)>>%d)&0x%x]\n\n", - 16-OFFSCOSTABBITS, OFFSCOSTABSIZE-1); + 16-nbits, (1<<nbits)-1); +} + +/* -------------------------------------------------------------------- */ + +static void gentbl_costab(FILE *f, unsigned int nbits) +{ + int i; + + fprintf(f, "\n/*\n * more accurate cosine table\n */\n\n" + "static const short costab[%d] = {", (1<<nbits)); + for (i = 0; i < (1<<nbits); i++) { + if (!(i & 7)) + fprintf(f, "\n\t"); + fprintf(f, "%6d", (int)(32767.0*cos(i*2.0*M_PI/(1<<nbits)))); + if (i != ((1<<nbits)-1)) + fprintf(f, ", "); + } + fprintf(f, "\n};\n\n#define COS(x) costab[((x)>>%d)&0x%x]\n" + "#define SIN(x) COS((x)+0xc000)\n\n", 16-nbits, + (1<<nbits)-1); } /* -------------------------------------------------------------------- */ @@ -63,7 +80,8 @@ static void gentbl_offscostab(FILE *f) static void gentbl_afsk1200(FILE *f) { - int i; + int i, v, sum; + float fv, fsum; #define ARGLO(x) 2.0*M_PI*(double)x*(double)AFSK12_TX_FREQ_LO/(double)AFSK12_SAMPLE_RATE #define ARGHI(x) 2.0*M_PI*(double)x*(double)AFSK12_TX_FREQ_HI/(double)AFSK12_SAMPLE_RATE @@ -75,42 +93,58 @@ static void gentbl_afsk1200(FILE *f) "#define AFSK12_CORRLEN %u\n\n", AFSK12_SAMPLE_RATE, AFSK12_TX_FREQ_LO, AFSK12_TX_FREQ_HI, AFSK12_CORRLEN); - fprintf(f, "#if defined (CONFIG_SOUNDMODEM__AFSK1200_FP) && " + fprintf(f, "#if defined(CONFIG_SOUNDMODEM_FLOAT) && " "(defined(CONFIG_M586) || defined(CONFIG_M686))\n\n" "static const float afsk12_tx_lo_i_f[] = {\n\t"); - for(i = 0; i < AFSK12_CORRLEN; i++) - fprintf(f, " %7f%c", cos(ARGLO(i)), - (i < AFSK12_CORRLEN-1) ? ',' : ' '); - fprintf(f, "\n};\n\nstatic const float afsk12_tx_lo_q_f[] = {\n\t"); - for(i = 0; i < AFSK12_CORRLEN; i++) - fprintf(f, " %7f%c", sin(ARGLO(i)), - (i < AFSK12_CORRLEN-1) ? ',' : ' '); - fprintf(f, "\n};\n\nstatic const float afsk12_tx_hi_i_f[] = {\n\t"); - for(i = 0; i < AFSK12_CORRLEN; i++) - fprintf(f, " %7f%c", cos(ARGHI(i)), - (i < AFSK12_CORRLEN-1) ? ',' : ' '); - fprintf(f, "\n};\n\nstatic const float afsk12_tx_hi_q_f[] = {\n\t"); - for(i = 0; i < AFSK12_CORRLEN; i++) - fprintf(f, " %7f%c", sin(ARGHI(i)), - (i < AFSK12_CORRLEN-1) ? ',' : ' '); - fprintf(f, "\n};\n\n#else /* CONFIG_SOUNDMODEM_AFSK1200_FP */\n\n" - "static const signed char afsk12_tx_lo_i[] = {\n\t"); - for(i = 0; i < AFSK12_CORRLEN; i++) - fprintf(f, " %4i%c", (int)(127.0*cos(ARGLO(i))), - (i < AFSK12_CORRLEN-1) ? ',' : ' '); - fprintf(f, "\n};\n\nstatic const signed char afsk12_tx_lo_q[] = {\n\t"); - for(i = 0; i < AFSK12_CORRLEN; i++) - fprintf(f, " %4i%c", (int)(127.0*sin(ARGLO(i))), - (i < AFSK12_CORRLEN-1) ? ',' : ' '); - fprintf(f, "\n};\n\nstatic const signed char afsk12_tx_hi_i[] = {\n\t"); - for(i = 0; i < AFSK12_CORRLEN; i++) - fprintf(f, " %4i%c", (int)(127.0*cos(ARGHI(i))), - (i < AFSK12_CORRLEN-1) ? ',' : ' '); - fprintf(f, "\n};\n\nstatic const signed char afsk12_tx_hi_q[] = {\n\t"); - for(i = 0; i < AFSK12_CORRLEN; i++) - fprintf(f, " %4i%c", (int)(127.0*sin(ARGHI(i))), - (i < AFSK12_CORRLEN-1) ? ',' : ' '); - fprintf(f, "\n};\n\n#endif /* CONFIG_SOUNDMODEM_AFSK1200_FP */\n\n"); + for(fsum = i = 0; i < AFSK12_CORRLEN; i++) { + fsum += (fv = cos(ARGLO(i))); + fprintf(f, " %7f%c", fv, (i < AFSK12_CORRLEN-1) ? ',' : ' '); + } + fprintf(f, "\n};\n#define SUM_AFSK12_TX_LO_Q %7f\n\n" + "static const float afsk12_tx_lo_q_f[] = {\n\t", fsum); + for(fsum = i = 0; i < AFSK12_CORRLEN; i++) { + fsum += (fv = sin(ARGLO(i))); + fprintf(f, " %7f%c", fv, (i < AFSK12_CORRLEN-1) ? ',' : ' '); + } + fprintf(f, "\n};\n#define SUM_AFSK12_TX_LO_Q %7f\n\n" + "static const float afsk12_tx_hi_i_f[] = {\n\t", fsum); + for(fsum = i = 0; i < AFSK12_CORRLEN; i++) { + fsum += (fv = cos(ARGHI(i))); + fprintf(f, " %7f%c", fv, (i < AFSK12_CORRLEN-1) ? ',' : ' '); + } + fprintf(f, "\n};\n#define SUM_AFSK12_TX_HI_I %7f\n\n" + "static const float afsk12_tx_hi_q_f[] = {\n\t", fsum); + for(fsum = i = 0; i < AFSK12_CORRLEN; i++) { + fsum += (fv = sin(ARGHI(i))); + fprintf(f, " %7f%c", fv, (i < AFSK12_CORRLEN-1) ? ',' : ' '); + } + fprintf(f, "\n};\n#define SUM_AFSK12_TX_HI_Q %7f\n\n" + "#else /* CONFIG_SOUNDMODEM_FLOAT */\n\n" + "static const int afsk12_tx_lo_i[] = {\n\t", fsum); + for(sum = i = 0; i < AFSK12_CORRLEN; i++) { + sum += (v = 127.0*cos(ARGLO(i))); + fprintf(f, " %4i%c", v, (i < AFSK12_CORRLEN-1) ? ',' : ' '); + } + fprintf(f, "\n};\n#define SUM_AFSK12_TX_LO_I %d\n\n" + "static const int afsk12_tx_lo_q[] = {\n\t", sum); + for(sum = i = 0; i < AFSK12_CORRLEN; i++) { + sum += (v = 127.0*sin(ARGLO(i))); + fprintf(f, " %4i%c", v, (i < AFSK12_CORRLEN-1) ? ',' : ' '); + } + fprintf(f, "\n};\n#define SUM_AFSK12_TX_LO_Q %d\n\n" + "static const int afsk12_tx_hi_i[] = {\n\t", sum); + for(sum = i = 0; i < AFSK12_CORRLEN; i++) { + sum += (v = 127.0*cos(ARGHI(i))); + fprintf(f, " %4i%c", v, (i < AFSK12_CORRLEN-1) ? ',' : ' '); + } + fprintf(f, "\n};\n#define SUM_AFSK12_TX_HI_I %d\n\n" + "static const int afsk12_tx_hi_q[] = {\n\t", sum); + for(sum = i = 0; i < AFSK12_CORRLEN; i++) { + sum += (v = 127.0*sin(ARGHI(i))); + fprintf(f, " %4i%c", v, (i < AFSK12_CORRLEN-1) ? ',' : ' '); + } + fprintf(f, "\n};\n#define SUM_AFSK12_TX_HI_Q %d\n\n" + "#endif /* CONFIG_SOUNDMODEM_FLOAT */\n\n", sum); #undef ARGLO #undef ARGHI } @@ -252,7 +286,7 @@ static void gentbl_fsk9600(FILE *f) static void gentbl_afsk2666(FILE *f) { - int i, j, k, l, o; + int i, j, k, l, o, v, sumi, sumq; float window[AFSK26_DEMCORRLEN*AFSK26_RXOVER]; int cfreq[AFSK26_NUMCAR]; @@ -274,32 +308,30 @@ static void gentbl_afsk2666(FILE *f) window[i] = AFSK26_WINDOW(((float)i)/(AFSK26_DEMCORRLEN* AFSK26_RXOVER)) * 127.0; fprintf(f, "\nstatic const struct {\n\t" - "signed char i[%d];\n\tsigned char q[%d];\n} afsk26_dem_tables[%d][2] = {\n", - AFSK26_DEMCORRLEN, AFSK26_DEMCORRLEN, AFSK26_RXOVER); + "int i[%d];\n\tint q[%d];\n} afsk26_dem_tables[%d][%d] = {\n", + AFSK26_DEMCORRLEN, AFSK26_DEMCORRLEN, AFSK26_RXOVER, AFSK26_NUMCAR); for (o = AFSK26_RXOVER-1; o >= 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 @@ static void gentbl_afsk2666(FILE *f) /* -------------------------------------------------------------------- */ -#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<<COSTABBITS)); - for (i = 0; i < (1<<COSTABBITS); i++) { - if (!(i & 7)) - fprintf(f, "\n\t"); - fprintf(f, "%6d", (int)(32767.0*cos(i*2.0*M_PI/(1<<COSTABBITS)))); - if (i != ((1<<COSTABBITS)-1)) - fprintf(f, ", "); - } - fprintf(f, "\n};\n\n#define COS(x) costab[((x)>>%d)&0x%x]\n" - "#define SIN(x) COS((x)+0xc000)\n\n", 16-COSTABBITS, - (1<<COSTABBITS)-1); -} - -/* -------------------------------------------------------------------- */ - #define ATAN_TABLEN 1024 static void gentbl_atantab(FILE *f) @@ -578,6 +588,85 @@ static void gentbl_hapn4800(FILE *f) /* -------------------------------------------------------------------- */ +#define AFSK24_SAMPLERATE 16000 +#define AFSK24_CORRLEN 14 + +static void gentbl_afsk2400(FILE *f, float tcm3105clk) +{ + int i, sum, v; + float fsum, fv; + + fprintf(f, "\n/*\n * afsk2400 specific tables (tcm3105 clk %7fHz)\n */\n" + "#define AFSK24_TX_FREQ_LO %d\n" + "#define AFSK24_TX_FREQ_HI %d\n" + "#define AFSK24_BITPLL_INC %d\n" + "#define AFSK24_SAMPLERATE %d\n\n", tcm3105clk, + (int)(tcm3105clk/3694.0), (int)(tcm3105clk/2015.0), + 0x10000*2400/AFSK24_SAMPLERATE, AFSK24_SAMPLERATE); + +#define ARGLO(x) 2.0*M_PI*(double)x*(tcm3105clk/3694.0)/(double)AFSK24_SAMPLERATE +#define ARGHI(x) 2.0*M_PI*(double)x*(tcm3105clk/2015.0)/(double)AFSK24_SAMPLERATE +#define WINDOW(x) hamming((float)(x)/(AFSK24_CORRLEN-1.0)) + + fprintf(f, "#if defined(CONFIG_SOUNDMODEM_FLOAT) && " + "(defined(CONFIG_M586) || defined(CONFIG_M686))\n\n" + "static const float afsk24_tx_lo_i_f[] = {\n\t"); + for(fsum = i = 0; i < AFSK24_CORRLEN; i++) { + fsum += (fv = cos(ARGLO(i))*WINDOW(i)); + fprintf(f, " %7f%c", fv, (i < AFSK24_CORRLEN-1) ? ',' : ' '); + } + fprintf(f, "\n};\n#define SUM_AFSK24_TX_LO_Q %7f\n\n" + "static const float afsk24_tx_lo_q_f[] = {\n\t", fsum); + for(fsum = i = 0; i < AFSK24_CORRLEN; i++) { + fsum += (fv = sin(ARGLO(i))*WINDOW(i)); + fprintf(f, " %7f%c", fv, (i < AFSK24_CORRLEN-1) ? ',' : ' '); + } + fprintf(f, "\n};\n#define SUM_AFSK24_TX_LO_Q %7f\n\n" + "static const float afsk24_tx_hi_i_f[] = {\n\t", fsum); + for(fsum = i = 0; i < AFSK24_CORRLEN; i++) { + fsum += (fv = cos(ARGHI(i))*WINDOW(i)); + fprintf(f, " %7f%c", fv, (i < AFSK24_CORRLEN-1) ? ',' : ' '); + } + fprintf(f, "\n};\n#define SUM_AFSK24_TX_HI_I %7f\n\n" + "static const float afsk24_tx_hi_q_f[] = {\n\t", fsum); + for(fsum = i = 0; i < AFSK24_CORRLEN; i++) { + fsum += (fv = sin(ARGHI(i))*WINDOW(i)); + fprintf(f, " %7f%c", fv, (i < AFSK24_CORRLEN-1) ? ',' : ' '); + } + fprintf(f, "\n};\n#define SUM_AFSK24_TX_HI_Q %7f\n\n" + "#else /* CONFIG_SOUNDMODEM_FLOAT */\n\n" + "static const int afsk24_tx_lo_i[] = {\n\t", fsum); + for(sum = i = 0; i < AFSK24_CORRLEN; i++) { + sum += (v = 127.0*cos(ARGLO(i))*WINDOW(i)); + fprintf(f, " %4i%c", v, (i < AFSK24_CORRLEN-1) ? ',' : ' '); + } + fprintf(f, "\n};\n#define SUM_AFSK24_TX_LO_I %d\n\n" + "static const int afsk24_tx_lo_q[] = {\n\t", sum); + for(sum = i = 0; i < AFSK24_CORRLEN; i++) { + sum += (v = 127.0*sin(ARGLO(i))*WINDOW(i)); + fprintf(f, " %4i%c", v, (i < AFSK24_CORRLEN-1) ? ',' : ' '); + } + fprintf(f, "\n};\n#define SUM_AFSK24_TX_LO_Q %d\n\n" + "static const int afsk24_tx_hi_i[] = {\n\t", sum); + for(sum = i = 0; i < AFSK24_CORRLEN; i++) { + sum += (v = 127.0*cos(ARGHI(i))*WINDOW(i)); + fprintf(f, " %4i%c", v, (i < AFSK24_CORRLEN-1) ? ',' : ' '); + } + fprintf(f, "\n};\n#define SUM_AFSK24_TX_HI_I %d\n\n" + "static const int afsk24_tx_hi_q[] = {\n\t", sum); + for(sum = i = 0; i < AFSK24_CORRLEN; i++) { + sum += (v = 127.0*sin(ARGHI(i))*WINDOW(i)); + fprintf(f, " %4i%c", v, (i < AFSK24_CORRLEN-1) ? ',' : ' '); + } + fprintf(f, "\n};\n#define SUM_AFSK24_TX_HI_Q %d\n\n" + "#endif /* CONFIG_SOUNDMODEM_FLOAT */\n\n", sum); +#undef ARGLO +#undef ARGHI +#undef WINDOW +} + +/* -------------------------------------------------------------------- */ + static char *progname; static void gentbl_banner(FILE *f) @@ -586,6 +675,11 @@ static void gentbl_banner(FILE *f) "DO NOT EDIT!\n */\n\n", progname); } +static void gentbl_needs_config(FILE *f) +{ + fprintf(f, "\n#include <linux/config.h>\n\n"); +} + /* -------------------------------------------------------------------- */ void main(int argc, char *argv[]) @@ -596,20 +690,23 @@ void main(int argc, char *argv[]) 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"))) @@ -622,6 +719,22 @@ void main(int argc, char *argv[]) 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 --git a/drivers/net/soundmodem/sm.c b/drivers/net/soundmodem/sm.c index d55bc0c04..ac1fbac48 100644 --- a/drivers/net/soundmodem/sm.c +++ b/drivers/net/soundmodem/sm.c @@ -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 <asm/bitops.h> #include <linux/delay.h> #include <linux/errno.h> -#include <linux/init.h> #include "sm.h" /* --------------------------------------------------------------------- */ @@ -101,18 +101,32 @@ extern inline int copy_to_user(void *to, const void *from, unsigned long n) } #endif +#if LINUX_VERSION_CODE >= 0x20123 +#include <linux/init.h> +#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 @@ const struct modem_tx_info *sm_modem_tx_table[] = { 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 @@ void sm_output_status(struct sm_state *sm) 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 @@ static int sm_open(struct device *dev) 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 @@ static int sm_ioctl(struct device *dev, struct ifreq *ifr, /* --------------------------------------------------------------------- */ +#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 @@ __initfunc(int sm_init(void)) char ifname[HDLCDRV_IFNAMELEN]; printk(sm_drvinfo); +#ifdef __i386__ + i386_capability(); +#endif /* __i386__ */ /* * register net devices */ @@ -745,7 +817,7 @@ MODULE_DESCRIPTION("Soundcard amateur radio modem driver"); #endif -int init_module(void) +__initfunc(int init_module(void)) { if (mode) { if (iobase == -1) diff --git a/drivers/net/soundmodem/sm.h b/drivers/net/soundmodem/sm.h index 2cce82992..25bbc8ba9 100644 --- a/drivers/net/soundmodem/sm.h +++ b/drivers/net/soundmodem/sm.h @@ -30,16 +30,11 @@ /* ---------------------------------------------------------------------- */ -#include <linux/config.h> #include <linux/hdlcdrv.h> #include <linux/soundmodem.h> #define SM_DEBUG -/* --------------------------------------------------------------------- */ - -#define DMA_MODE_AUTOINIT 0x10 - /* ---------------------------------------------------------------------- */ /* * Information that need to be kept for each board. @@ -56,6 +51,18 @@ struct sm_state { /* * 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 @@ struct modem_tx_info { 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 @@ struct modem_rx_info { 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 @@ extern inline unsigned int lcm(unsigned int x, unsigned int y) */ -#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_4_tx; 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 --git a/drivers/net/soundmodem/sm_afsk1200.c b/drivers/net/soundmodem/sm_afsk1200.c index 0519c5e79..64b20a57c 100644 --- a/drivers/net/soundmodem/sm_afsk1200.c +++ b/drivers/net/soundmodem/sm_afsk1200.c @@ -38,174 +38,176 @@ struct demod_state_afsk12 { 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)) - + 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; + } +} +/* --------------------------------------------------------------------- */ -#define ENV_STORAGE unsigned char fpu_save[108]; +extern __inline__ int convolution8_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]); -#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)); + sum >>= 7; + return sum * sum; +} -static inline float convolution8(const float *st, const float *coeff) +extern __inline__ int convolution8_s16(const short *st, const int *coeff, int csum) { - 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; + 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 >>= 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) { - 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); + 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; } -#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 do_filter_1200_s16(const short *buf) { - memmove(st+1, st, 7); - *st = newval - 0x80; + 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; } -static inline int convolution8(const signed char *st, const signed char *coeff) -{ - int 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 const int pll_corr[2] = { -0x1000, 0x1000 }; -static inline int do_filter_1200(struct demod_state_afsk12 *st, unsigned char newval) +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; - 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); - return sum; + 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); + } } -#endif /* defined (CONFIG_SOUNDMODEM__AFSK1200_FP) && (defined(CONFIG_M586) || defined(CONFIG_M686)) */ - - /* --------------------------------------------------------------------- */ -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 @@ static void demodulator_1200(struct sm_state *sm, unsigned char *buf, int buflen st->shreg = 0x10000; } } - diag_add(sm, (((int)*buf)-0x80) << 8, sum); + diag_add(sm, *buf, sum); } - ENV_RESTORE; } /* --------------------------------------------------------------------- */ @@ -259,13 +260,13 @@ static void demod_init_1200(struct sm_state *sm) 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 --git a/drivers/net/soundmodem/sm_afsk2400_7.c b/drivers/net/soundmodem/sm_afsk2400_7.c new file mode 100644 index 000000000..36e0f328f --- /dev/null +++ b/drivers/net/soundmodem/sm_afsk2400_7.c @@ -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 <linux/config.h> +#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 --git a/drivers/net/soundmodem/sm_afsk2400_8.c b/drivers/net/soundmodem/sm_afsk2400_8.c new file mode 100644 index 000000000..8234815d6 --- /dev/null +++ b/drivers/net/soundmodem/sm_afsk2400_8.c @@ -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 <linux/config.h> +#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 --git a/drivers/net/soundmodem/sm_fsk9600.c b/drivers/net/soundmodem/sm_fsk9600.c index 8fbf9d218..bc2fb53b1 100644 --- a/drivers/net/soundmodem/sm_fsk9600.c +++ b/drivers/net/soundmodem/sm_fsk9600.c @@ -45,6 +45,8 @@ struct mod_state_fsk96 { unsigned int shreg; unsigned long scram; unsigned char tx_bit; + unsigned char *txtbl; + unsigned int txphase; }; /* --------------------------------------------------------------------- */ @@ -62,30 +64,57 @@ struct mod_state_fsk96 { /* --------------------------------------------------------------------- */ -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 demodulator_9600_4(struct sm_state *sm, unsigned char *buf, int bufl /* --------------------------------------------------------------------- */ -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(struct sm_state *sm, unsigned char *buf, int bufl /* --------------------------------------------------------------------- */ +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 @@ static void demod_init_9600(struct sm_state *sm) /* --------------------------------------------------------------------- */ 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 --git a/drivers/net/soundmodem/sm_hapn4800.c b/drivers/net/soundmodem/sm_hapn4800.c index 9472d5e06..f6babcd9d 100644 --- a/drivers/net/soundmodem/sm_hapn4800.c +++ b/drivers/net/soundmodem/sm_hapn4800.c @@ -49,133 +49,290 @@ struct demod_state_hapn48 { 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_8(struct sm_state *sm, unsigned char *buf, int buflen) +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); - 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_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_pm10(struct sm_state *sm, unsigned char *buf, int buflen) +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); - 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_8 + (st->tx_bit & 0xf); + } + if (st->tx_seq >= 8) + 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_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_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_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_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_pm10 + (st->tx_bit & 0xf); + } + if (st->tx_seq >= 10) + st->tx_seq = 0; + *buf = *st->tbl; + st->tbl += 0x10; + } +} + +/* --------------------------------------------------------------------- */ + +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); + + 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 @@ static void demodulator_hapn4800_10(struct sm_state *sm, unsigned char *buf, int } 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 @@ static void demodulator_hapn4800_8(struct sm_state *sm, unsigned char *buf, int } diag_trigger(sm); } - diag_add_one(sm, st->inphist[2]); + diag_add_one(sm, inv); } } @@ -297,51 +512,49 @@ static void demod_init_hapn4800(struct sm_state *sm) /* --------------------------------------------------------------------- */ 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 --git a/drivers/net/soundmodem/sm_sbc.c b/drivers/net/soundmodem/sm_sbc.c index 1011dca97..2a2f874aa 100644 --- a/drivers/net/soundmodem/sm_sbc.c +++ b/drivers/net/soundmodem/sm_sbc.c @@ -26,12 +26,14 @@ */ #include <linux/ptrace.h> +#include <linux/sched.h> #include <linux/interrupt.h> #include <asm/io.h> #include <asm/dma.h> #include <linux/ioport.h> #include <linux/soundmodem.h> #include "sm.h" +#include "smdma.h" /* --------------------------------------------------------------------- */ @@ -81,12 +83,6 @@ struct sc_state_sbc { 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 @@ struct sc_state_sbc { #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 @@ static int config_resources(struct device *dev, struct sm_state *sm, int fdx) 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 @@ static void setup_dma_dsp(struct device *dev, struct sm_state *sm, int send) { 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 @@ static void sbc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { 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 void sbc_interrupt(int irq, void *dev_id, struct pt_regs *regs) 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 @@ static int sbc_open(struct device *dev, struct sm_state *sm) /* * 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 @@ static int sbc_open(struct device *dev, struct sm_state *sm) /* * 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 @@ static int sbc_open(struct device *dev, struct sm_state *sm) 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 @@ static int sbc_close(struct device *dev, struct sm_state *sm) 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 @@ static int sbc_sethw(struct device *dev, struct sm_state *sm, char *mode) 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 @@ static int sbc_sethw(struct device *dev, struct sm_state *sm, char *mode) 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 @@ static int sbc_sethw(struct device *dev, struct sm_state *sm, char *mode) 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 @@ const struct hardware_info sm_hw_sbc = { 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 @@ static void sbcfdx_interrupt(int irq, void *dev_id, struct pt_regs *regs) { 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 @@ static int sbcfdx_open(struct device *dev, struct sm_state *sm) /* * 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 @@ static int sbcfdx_open(struct device *dev, struct sm_state *sm) /* * 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 @@ static int sbcfdx_open(struct device *dev, struct sm_state *sm) 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 @@ static int sbcfdx_close(struct device *dev, struct sm_state *sm) 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 @@ static int sbcfdx_sethw(struct device *dev, struct sm_state *sm, char *mode) 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 @@ static int sbcfdx_sethw(struct device *dev, struct sm_state *sm, char *mode) 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 --git a/drivers/net/soundmodem/sm_wss.c b/drivers/net/soundmodem/sm_wss.c index 0123a9aa4..021ecc165 100644 --- a/drivers/net/soundmodem/sm_wss.c +++ b/drivers/net/soundmodem/sm_wss.c @@ -26,12 +26,14 @@ */ #include <linux/ptrace.h> +#include <linux/sched.h> #include <linux/interrupt.h> #include <asm/io.h> #include <asm/dma.h> #include <linux/ioport.h> #include <linux/soundmodem.h> #include "sm.h" +#include "smdma.h" /* --------------------------------------------------------------------- */ @@ -81,12 +83,6 @@ struct sc_state_wss { 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_srate_index(int srate) /* --------------------------------------------------------------------- */ -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 @@ static int wss_set_codec_fmt(struct device *dev, struct sm_state *sm, /* 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 @@ static int wss_init_codec(struct device *dev, struct sm_state *sm, char fdx, 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 @@ static void setup_dma_wss(struct device *dev, struct sm_state *sm, int send) { 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 @@ static void setup_dma_wss(struct device *dev, struct sm_state *sm, int send) 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 @@ static void wss_interrupt(int irq, void *dev_id, struct pt_regs *regs) { 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 void wss_interrupt(int irq, void *dev_id, struct pt_regs *regs) 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 @@ static int wss_open(struct device *dev, struct sm_state *sm) /* * 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 @@ static int wss_open(struct device *dev, struct sm_state *sm) 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 @@ static int wss_close(struct device *dev, struct sm_state *sm) 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 @@ static int wss_sethw(struct device *dev, struct sm_state *sm, char *mode) 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 @@ static int wss_sethw(struct device *dev, struct sm_state *sm, char *mode) 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 @@ static void setup_fdx_dma_wss(struct device *dev, struct sm_state *sm) 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 @@ static void setup_fdx_dma_wss(struct device *dev, struct sm_state *sm) 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 @@ static void wssfdx_interrupt(int irq, void *dev_id, struct pt_regs *regs) { 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 @@ static int wssfdx_open(struct device *dev, struct sm_state *sm) /* * 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 @@ static int wssfdx_open(struct device *dev, struct sm_state *sm) 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 @@ static int wssfdx_close(struct device *dev, struct sm_state *sm) * 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 @@ static int wssfdx_sethw(struct device *dev, struct sm_state *sm, char *mode) 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 @@ static int wssfdx_sethw(struct device *dev, struct sm_state *sm, char *mode) 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 --git a/drivers/net/soundmodem/smdma.h b/drivers/net/soundmodem/smdma.h new file mode 100644 index 000000000..27cea09e7 --- /dev/null +++ b/drivers/net/soundmodem/smdma.h @@ -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 --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 2aae7a2db..7118164b6 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -56,7 +56,9 @@ struct pci_dev_info dev_info[] = { 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 @@ struct pci_dev_info dev_info[] = { 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 @@ struct pci_dev_info dev_info[] = { 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 @@ struct pci_dev_info dev_info[] = { 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 @@ struct pci_dev_info dev_info[] = { 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 @@ struct pci_dev_info dev_info[] = { 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 @@ struct pci_dev_info dev_info[] = { 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 @@ struct pci_dev_info dev_info[] = { 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 @@ struct pci_dev_info dev_info[] = { 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 @@ struct pci_dev_info dev_info[] = { 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 @@ struct pci_dev_info dev_info[] = { 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 @@ struct pci_dev_info dev_info[] = { 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 @@ struct pci_dev_info dev_info[] = { 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 @@ const char *pci_strvendor(unsigned int vendor) 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 @@ const char *pci_strvendor(unsigned int vendor) 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 @@ const char *pci_strvendor(unsigned int vendor) 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 --git a/drivers/sbus/char/bwtwo.c b/drivers/sbus/char/bwtwo.c index be68d09c9..ae81e1260 100644 --- a/drivers/sbus/char/bwtwo.c +++ b/drivers/sbus/char/bwtwo.c @@ -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 <asm/fbio.h> #include <asm/pgtable.h> -#include "../../char/vt_kern.h" -#include "../../char/selection.h" -#include "../../char/console_struct.h" +/* These must be included after asm/fbio.h */ +#include <linux/vt_kern.h> +#include <linux/selection.h> +#include <linux/console_struct.h> + #include "fb.h" #include "cg_common.h" @@ -91,7 +93,7 @@ bwtwo_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, 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 --git a/drivers/sbus/char/cgfourteen.c b/drivers/sbus/char/cgfourteen.c index d42a4343c..2cb4c21c9 100644 --- a/drivers/sbus/char/cgfourteen.c +++ b/drivers/sbus/char/cgfourteen.c @@ -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 <asm/pgtable.h> #include <asm/uaccess.h> -#include "../../char/vt_kern.h" -#include "../../char/selection.h" -#include "../../char/console_struct.h" +/* These must be included after asm/fbio.h */ +#include <linux/vt_kern.h> +#include <linux/selection.h> +#include <linux/console_struct.h> #include "fb.h" #define CG14_MCR_INTENABLE_SHIFT 7 @@ -272,7 +273,7 @@ cg14_mmap (struct inode *inode, struct file *file, page += map_size; } vma->vm_inode = inode; - inode->i_count++; + atomic_inc(&inode->i_count); return 0; } diff --git a/drivers/sbus/char/cgsix.c b/drivers/sbus/char/cgsix.c index 5f91c1308..e53fcf09e 100644 --- a/drivers/sbus/char/cgsix.c +++ b/drivers/sbus/char/cgsix.c @@ -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 <asm/fbio.h> #include <asm/pgtable.h> -#include "../../char/vt_kern.h" -#include "../../char/selection.h" -#include "../../char/console_struct.h" +/* These must be included after asm/fbio.h */ +#include <linux/vt_kern.h> +#include <linux/selection.h> +#include <linux/console_struct.h> #include "fb.h" #include "cg_common.h" @@ -296,7 +297,7 @@ cg6_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, page += map_size; } vma->vm_inode = inode; - inode->i_count++; + atomic_inc(&inode->i_count); return 0; } diff --git a/drivers/sbus/char/cgthree.c b/drivers/sbus/char/cgthree.c index ac1265c61..0e1446c0e 100644 --- a/drivers/sbus/char/cgthree.c +++ b/drivers/sbus/char/cgthree.c @@ -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 <asm/fbio.h> #include <asm/pgtable.h> -#include "../../char/vt_kern.h" -#include "../../char/selection.h" -#include "../../char/console_struct.h" +/* These must be included after asm/fbio.h */ +#include <linux/vt_kern.h> +#include <linux/selection.h> +#include <linux/console_struct.h> #include "fb.h" #include "cg_common.h" @@ -131,7 +132,7 @@ cg3_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, page += map_size; } vma->vm_inode = inode; - inode->i_count++; + atomic_inc(&inode->i_count); return 0; } diff --git a/drivers/sbus/char/creator.c b/drivers/sbus/char/creator.c index 9bf72a3b9..4ff2caf31 100644 --- a/drivers/sbus/char/creator.c +++ b/drivers/sbus/char/creator.c @@ -15,9 +15,10 @@ #include <asm/pgtable.h> #include <asm/uaccess.h> -#include "../../char/vt_kern.h" -#include "../../char/selection.h" -#include "../../char/console_struct.h" +/* These must be included after asm/fbio.h */ +#include <linux/vt_kern.h> +#include <linux/selection.h> +#include <linux/console_struct.h> #include "fb.h" __initfunc(void creator_setup (fbinfo_t *fb, int slot, int con_node, unsigned long creator, int creator_io)) diff --git a/drivers/sbus/char/leo.c b/drivers/sbus/char/leo.c index b3ec23867..61e646e9f 100644 --- a/drivers/sbus/char/leo.c +++ b/drivers/sbus/char/leo.c @@ -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 <asm/delay.h> #include <asm/uaccess.h> -#include "../../char/vt_kern.h" -#include "../../char/selection.h" -#include "../../char/console_struct.h" +/* These must be included after asm/fbio.h */ +#include <linux/vt_kern.h> +#include <linux/selection.h> +#include <linux/console_struct.h> #include "fb.h" #include "cg_common.h" @@ -221,7 +222,7 @@ leo_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, page += map_size; } vma->vm_inode = inode; - inode->i_count++; + atomic_inc(&inode->i_count); return 0; } diff --git a/drivers/sbus/char/suncons.c b/drivers/sbus/char/suncons.c index d1a2dfd45..1d3815dd3 100644 --- a/drivers/sbus/char/suncons.c +++ b/drivers/sbus/char/suncons.c @@ -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 <asm/io.h> #include <asm/smp.h> -#include "../../char/kbd_kern.h" -#include "../../char/vt_kern.h" -#include "../../char/consolemap.h" -#include "../../char/selection.h" -#include "../../char/console_struct.h" +#include <linux/kbd_kern.h> +#include <linux/vt_kern.h> +#include <linux/consolemap.h> +#include <linux/selection.h> +#include <linux/console_struct.h> #include "fb.h" diff --git a/drivers/sbus/char/sunfb.c b/drivers/sbus/char/sunfb.c index e803344bd..68856c9ee 100644 --- a/drivers/sbus/char/sunfb.c +++ b/drivers/sbus/char/sunfb.c @@ -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 <asm/fbio.h> #include <asm/io.h> -#include "../../char/kbd_kern.h" -#include "../../char/vt_kern.h" -#include "../../char/consolemap.h" -#include "../../char/selection.h" -#include "../../char/console_struct.h" +#include <linux/kbd_kern.h> +#include <linux/vt_kern.h> +#include <linux/consolemap.h> +#include <linux/selection.h> +#include <linux/console_struct.h> #include "fb.h" diff --git a/drivers/sbus/char/sunkbd.c b/drivers/sbus/char/sunkbd.c index 8e398f345..1ddaaecd4 100644 --- a/drivers/sbus/char/sunkbd.c +++ b/drivers/sbus/char/sunkbd.c @@ -25,9 +25,9 @@ #include <asm/oplib.h> #include <asm/uaccess.h> -#include "../../char/kbd_kern.h" -#include "../../char/diacr.h" -#include "../../char/vt_kern.h" +#include <linux/kbd_kern.h> +#include <linux/kbd_diacr.h> +#include <linux/vt_kern.h> #define SIZE(x) (sizeof(x)/sizeof((x)[0])) diff --git a/drivers/sbus/char/tcx.c b/drivers/sbus/char/tcx.c index 2ecabda62..db66383ac 100644 --- a/drivers/sbus/char/tcx.c +++ b/drivers/sbus/char/tcx.c @@ -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 <asm/fbio.h> #include <asm/pgtable.h> -#include "../../char/vt_kern.h" -#include "../../char/selection.h" -#include "../../char/console_struct.h" +/* These must be included after asm/fbio.h */ +#include <linux/vt_kern.h> +#include <linux/selection.h> +#include <linux/console_struct.h> #include "fb.h" #include "cg_common.h" @@ -171,7 +172,7 @@ tcx_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, page += map_size; } vma->vm_inode = inode; - inode->i_count++; + atomic_inc(&inode->i_count); return 0; } diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c index 20e04258b..00cdfe35c 100644 --- a/drivers/sbus/char/vfc_dev.c +++ b/drivers/sbus/char/vfc_dev.c @@ -581,7 +581,7 @@ static int vfc_mmap(struct inode *inode, struct file *file, 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 --git a/drivers/sbus/char/weitek.c b/drivers/sbus/char/weitek.c index 0fa0cb5fc..d2ac4d135 100644 --- a/drivers/sbus/char/weitek.c +++ b/drivers/sbus/char/weitek.c @@ -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 <asm/fbio.h> #include <asm/pgtable.h> -#include "../../char/vt_kern.h" -#include "../../char/selection.h" -#include "../../char/console_struct.h" +/* These must be included after asm/fbio.h */ +#include <linux/vt_kern.h> +#include <linux/selection.h> +#include <linux/console_struct.h> #include "fb.h" #include "cg_common.h" @@ -82,7 +83,7 @@ weitek_mmap(struct inode *inode, struct file *file, struct vm_area_struct *vma, page += map_size; } vma->vm_inode = inode; - inode->i_count++; + atomic_inc(&inode->i_count); return 0; } #endif diff --git a/drivers/scsi/amiga7xx.c b/drivers/scsi/amiga7xx.c index 2e4b1aa3e..6edd01320 100644 --- a/drivers/scsi/amiga7xx.c +++ b/drivers/scsi/amiga7xx.c @@ -50,20 +50,20 @@ int amiga7xx_detect(Scsi_Host_Template *tpnt) #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 @@ int amiga7xx_detect(Scsi_Host_Template *tpnt) 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 --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index 5bffb2762..1e398a152 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -619,7 +619,10 @@ int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int leng 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 --git a/drivers/scsi/script_asm.pl b/drivers/scsi/script_asm.pl index 2599a966e..d99fcc950 100644 --- a/drivers/scsi/script_asm.pl +++ b/drivers/scsi/script_asm.pl @@ -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 <richard@sleepie.demon.co.uk> - 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 @@ $prefix = ''; # define all arrays having this prefix so we # 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 @@ $prefix = ''; # define all arrays having this prefix so we # 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 @@ $prefix = ''; # define all arrays having this prefix so we '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 @@ print STDERR "value regex = $value\n" if ($debug); $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 @@ print STDERR "defined external $1 to $external\n" if ($debug_external); if ($1 =~ /^($identifier)\s*$/) { push (@entry, $1); } else { + die "$0 : syntax error in line $lineno : $_ expected ENTRY <identifier> "; @@ -558,13 +598,13 @@ print STDERR "data8 source\n" if ($debug); # 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 @@ print STDERR "data8 source\n" if ($debug); "; } - $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 --git a/drivers/sound/dmabuf.c b/drivers/sound/dmabuf.c index 38b7af597..54523d88f 100644 --- a/drivers/sound/dmabuf.c +++ b/drivers/sound/dmabuf.c @@ -802,6 +802,8 @@ DMAbuf_space_in_queue (int dev) */ max = dmap->max_fragments; + if (max > dmap->nbufs) + max = dmap->nbufs; len = dmap->qlen; if (audio_devs[dev]->d->local_qlen) diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c index 088591b9d..957150f7b 100644 --- a/drivers/sound/soundcard.c +++ b/drivers/sound/soundcard.c @@ -327,7 +327,7 @@ sound_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma) return -EAGAIN; vma->vm_inode = inode; - inode->i_count++; + atomic_inc(&inode->i_count); dmap->mapping_flags |= DMA_MAP_MAPPED; diff --git a/fs/Config.in b/fs/Config.in index fe279dc94..a9f922d8a 100644 --- a/fs/Config.in +++ b/fs/Config.in @@ -5,6 +5,27 @@ mainmenu_option next_comment 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 --git a/fs/Makefile b/fs/Makefile index 471a9de5c..fb9da7124 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -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 @@ else O_OBJS += noquot.o endif +ifeq ($(CONFIG_TRANS_NAMES),y) +O_OBJS += nametrans.o +endif + ifeq ($(CONFIG_MINIX_FS),y) SUB_DIRS += minix else @@ -211,6 +215,14 @@ else 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 --git a/fs/affs/dir.c b/fs/affs/dir.c index 8ae71e5bd..5baea0b7d 100644 --- a/fs/affs/dir.c +++ b/fs/affs/dir.c @@ -55,7 +55,6 @@ struct inode_operations affs_dir_inode_operations = { NULL, /* mknod */ affs_rename, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/fs/affs/file.c b/fs/affs/file.c index 0fffbf41e..46b10bcb1 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -71,7 +71,6 @@ struct inode_operations affs_file_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ generic_readpage, /* readpage */ NULL, /* writepage */ affs_bmap, /* bmap */ @@ -105,7 +104,6 @@ struct inode_operations affs_file_inode_operations_ofs = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/fs/affs/inode.c b/fs/affs/inode.c index 654a8ca61..2805f1ccf 100644 --- a/fs/affs/inode.c +++ b/fs/affs/inode.c @@ -899,7 +899,7 @@ affs_new_inode(const struct inode *dir) 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 @@ addentry_done: } static struct file_system_type affs_fs_type = { - affs_read_super, "affs", - 1, + FS_REQUIRES_DEV, + affs_read_super, NULL }; diff --git a/fs/affs/namei.c b/fs/affs/namei.c index 6a9b02bac..5ea649425 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -343,7 +343,7 @@ affs_rmdir(struct inode *dir, const char *name, int len) 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 @@ subdir(struct inode *new_inode, struct inode *old_inode) 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 @@ subdir(struct inode *new_inode, struct inode *old_inode) 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 @@ start_up: 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 @@ start_up: 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 --git a/fs/affs/symlink.c b/fs/affs/symlink.c index de93eac5c..24d1ed118 100644 --- a/fs/affs/symlink.c +++ b/fs/affs/symlink.c @@ -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 @@ struct inode_operations affs_symlink_inode_operations = { 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 @@ affs_readlink(struct inode *inode, char *buffer, int buflen) 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 --git a/fs/attr.c b/fs/attr.c new file mode 100644 index 000000000..be824dd4a --- /dev/null +++ b/fs/attr.c @@ -0,0 +1,99 @@ +/* + * linux/fs/attr.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * changes by Thomas Schoebel-Theuer + */ + +#include <linux/stat.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/string.h> +#include <asm/system.h> + +/* 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 --git a/fs/autofs/dir.c b/fs/autofs/dir.c index 461688e9f..0f529c900 100644 --- a/fs/autofs/dir.c +++ b/fs/autofs/dir.c @@ -80,7 +80,6 @@ struct inode_operations autofs_dir_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* read_page */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/fs/autofs/init.c b/fs/autofs/init.c index 1b3f6f165..4dbb76c85 100644 --- a/fs/autofs/init.c +++ b/fs/autofs/init.c @@ -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 --git a/fs/autofs/root.c b/fs/autofs/root.c index 69e62f823..a615ede29 100644 --- a/fs/autofs/root.c +++ b/fs/autofs/root.c @@ -48,7 +48,6 @@ struct inode_operations autofs_root_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/fs/autofs/symlink.c b/fs/autofs/symlink.c index 46c333103..d6ac82ed4 100644 --- a/fs/autofs/symlink.c +++ b/fs/autofs/symlink.c @@ -14,39 +14,6 @@ #include <linux/sched.h> #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 @@ struct inode_operations autofs_symlink_inode_operations = { NULL, /* mknod */ NULL, /* rename */ autofs_readlink, /* readlink */ - autofs_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index d9ef6d6ac..394f41eb1 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c @@ -214,6 +214,7 @@ do_aout_core_dump(long signr, struct pt_regs * regs) /* 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 --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index f12d89ef3..ff987e0e8 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -717,7 +717,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) #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; @@ -923,6 +923,7 @@ static int load_elf_library(int fd) */ 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 --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c new file mode 100644 index 000000000..28dced394 --- /dev/null +++ b/fs/binfmt_misc.c @@ -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 <linux/module.h> + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/malloc.h> +#include <linux/binfmts.h> +#include <linux/init.h> +#include <linux/proc_fs.h> +#include <linux/string.h> +#include <linux/ctype.h> +#include <asm/uaccess.h> +#include <asm/spinlock.h> + + +#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 --git a/fs/buffer.c b/fs/buffer.c index b8bd754c1..bd06972f3 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -36,6 +36,7 @@ #include <linux/smp_lock.h> #include <linux/vmalloc.h> #include <linux/blkdev.h> +#include <linux/sysrq.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -81,8 +82,6 @@ int buffermem = 0; * 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 @@ union bdflush_param{ 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 @@ static inline void after_unlock_page (struct page * page) { 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_wait = NULL; 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 @@ int bdflush(void * unused) #ifdef DEBUG printk("bdflush() activated..."); #endif - + + CHECK_EMERGENCY_SYNC + ncount = 0; #ifdef DEBUG for(nlist = 0; nlist < NR_LIST; nlist++) diff --git a/fs/dcache.c b/fs/dcache.c index f6ab04693..0472487e0 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -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. + * Notes on the allocation strategy: * - * The idea is that new additions (from readdir(), for example) will not - * flush the cache of entries that have really been used. - * - * 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 <linux/fs.h> +#include <linux/config.h> #include <linux/string.h> +#include <linux/mm.h> +#include <linux/fs.h> +#include <linux/dalloc.h> +#include <linux/dlists.h> -#include <asm/unaligned.h> -#include <asm/spinlock.h> +/* this should be removed after the beta phase */ +/* #define DEBUG */ +/*#undef DEBUG*/ +/* #define DEBUG_DDIR_COUNT */ -spinlock_t dcache_lock = SPIN_LOCK_UNLOCKED; +#define D_HASHSIZE 64 -/* - * 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. +/* 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)) + +/* 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)); - de->next_lru = head; - de->prev_lru = prev; - prev->next_lru = de; - head->prev_lru = de; + 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; } -static inline void update_lru(struct dir_cache_entry * de) +static /*inline*/ struct dentry * __dalloc(struct anchors * anchor, + struct dentry * parent, int isdir, + int len, int size) { - if (de == *de->lru_head) - *de->lru_head = de->next_lru; - else { - remove_lru(de); - add_lru(de,*de->lru_head); + 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; } -/* - * Hash queue manipulation. Look out for the casts.. - * - * What casts? 8-) -DaveM - */ -static inline void remove_hash(struct dir_cache_entry * de) +struct dentry * d_alloc(struct dentry * parent, int len, int isdir) { - if(de->pprev) { - if(de->next) - de->next->pprev = de->pprev; - *de->pprev = de->next; - de->pprev = NULL; + 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); } -static inline void add_hash(struct dir_cache_entry * de, struct dir_cache_entry ** hash) +extern blocking struct dentry * d_alloc_root(struct inode * root_inode) { - if((de->next = *hash) != NULL) - (*hash)->pprev = &de->next; - *hash = de; - de->pprev = hash; + 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; } -/* - * 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 unsigned long d_hash(char first, char last) +{ + return ((unsigned long)first ^ ((unsigned long)last << 4)) & (D_HASHSIZE-1); +} + +static inline struct dentry ** d_base_entry(struct ddir * pdir, struct dentry * entry) +{ + return &pdir->dd_hashtable[d_hash(entry->d_name[0], + entry->d_name[entry->d_len-1])]; +} + +static inline struct dentry ** d_base_qstr(struct ddir * pdir, + struct qstr * s1, + struct qstr * s2) { - struct dir_cache_entry *de; + unsigned long hash; - 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; + 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); - if (old_de->lru_head == &level2_head) { - update_lru(old_de); - return; - } - de = level2_head; - level2_head = de->next_lru; - remove_hash(de); - COPYDATA(old_de, de); - add_hash(de, hash); + /* 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 + } + } } -int dcache_lookup(struct inode * dir, const char * name, int len, unsigned long * ino) +static /*inline*/ blocking void _d_del(struct dentry * entry, + struct anchors * anchor, + int flags) { - int ret = 0; + 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; - if(len <= DCACHE_NAME_LEN) { - struct dir_cache_entry **hash = get_hlist(dir, name, len); - struct dir_cache_entry *de; +#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); + + /* 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; + + 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); - 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; + /* 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); } - spin_unlock(&dcache_lock); +#ifdef DEBUG + x_freed++; +#endif } - return ret; +#ifndef DEBUG +done: +#else + x_free++; +#endif } -void dcache_add(struct inode * dir, const char * name, int len, unsigned long ino) +blocking void d_del(struct dentry * entry, int flags) { - if (len <= DCACHE_NAME_LEN) { - struct dir_cache_entry **hash = get_hlist(dir, name, len); - struct dir_cache_entry *de; + int i; - spin_lock(&dcache_lock); - de = find_entry(dir, name, (unsigned char) len, hash); - if (de) { - de->ino = ino; - update_lru(de); + if(!entry) + return; + LOG("d_clear", entry); + if(entry->d_len >= D_MEDIUM) { + if(entry->d_len >= D_LARGE) { + i = 3; } 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); + 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); + } +} + +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"); + + 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++; } + entry->u.d_inode = inode; } -unsigned long name_cache_init(unsigned long mem_start, unsigned long mem_end) +blocking struct dentry * d_entry(struct dentry * parent, + struct qstr * name, + struct inode * inode) { - int i; - struct dir_cache_entry * p; + struct ddir * pdir = d_dir(parent); + struct dentry ** base = d_base_qstr(pdir, name, NULL); + struct dentry * found = __dlookup(base, name, NULL); - /* - * 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; - - /* - * 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; - - /* - * Empty hash queues.. - */ - for (i = 0 ; i < DCACHE_HASH_QUEUES ; i++) - hash_table[i] = NULL; + if(!found) { + int isdir = (inode && S_ISDIR(inode->i_mode)); - return mem_start; + 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; +} + +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++; + } + memcpy(buf, entry->d_name, entry->d_len); + return len + entry->d_len; + } +} + +struct dentry * d_basket(struct dentry * dir_entry) +{ + if(dir_entry && (dir_entry->d_flag & D_DIR)) { + struct ddir * ddir = d_dir(dir_entry); + + return ddir->dd_basketlist; + } else + return NULL; +} + +int d_isbasket(struct dentry * entry) +{ + return entry->d_flag & D_BASKET; +} + +blocking struct inode * d_inode(struct dentry ** changing_entry) +{ + struct dentry * entry = *changing_entry; + struct inode * inode; + +#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 --git a/fs/devices.c b/fs/devices.c index 6ea9880ba..d3b1d6846 100644 --- a/fs/devices.c +++ b/fs/devices.c @@ -273,7 +273,6 @@ struct inode_operations blkdev_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -326,7 +325,6 @@ struct inode_operations chrdev_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/fs/dquot.c b/fs/dquot.c index dda3f642a..59d2112d9 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -237,9 +237,12 @@ static void write_dquot(struct dquot *dquot) 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 @@ asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr) 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; @@ -68,6 +68,10 @@ static struct linux_binfmt *formats = (struct linux_binfmt *) NULL; __initfunc(void binfmt_setup(void)) { +#ifdef CONFIG_BINFMT_MISC + init_misc_binfmt(); +#endif + #ifdef CONFIG_BINFMT_ELF init_elf_binfmt(); #endif @@ -158,7 +162,7 @@ int open_inode(struct inode * inode, int mode) } } current->files->fd[fd] = f; - inode->i_count++; + atomic_inc(&inode->i_count); } return fd; } diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index 171de1cf5..4d2b561ee 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -291,6 +291,7 @@ int ext2_new_block (const struct inode * inode, unsigned long goal, 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 @@ int ext2_new_block (const struct inode * inode, unsigned long goal, (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 @@ repeat: } 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 --git a/fs/ext2/dir.c b/fs/ext2/dir.c index fce6fc4c8..d9b1957e3 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -65,7 +65,6 @@ struct inode_operations ext2_dir_inode_operations = { ext2_mknod, /* mknod */ ext2_rename, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -194,12 +193,13 @@ revalidate: * 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 --git a/fs/ext2/file.c b/fs/ext2/file.c index 274dc31fd..1627f5cee 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -72,7 +72,6 @@ struct inode_operations ext2_file_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ generic_readpage, /* readpage */ NULL, /* writepage */ ext2_bmap, /* bmap */ diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c index 16751329e..a486679f9 100644 --- a/fs/ext2/ialloc.c +++ b/fs/ext2/ialloc.c @@ -171,9 +171,9 @@ void ext2_free_inode (struct inode * inode) 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 @@ repeat: 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 --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 39716678a..421393581 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -172,27 +172,12 @@ int ext2_lookup (struct inode * dir, const char * name, int len, 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 @@ int ext2_create (struct inode * dir,const char * name, int len, int mode, } 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 @@ int ext2_mknod (struct inode * dir, const char * name, int len, int mode, } 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 @@ int ext2_mkdir (struct inode * dir, const char * name, int len, int mode) } 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 @@ repeat: 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 @@ int ext2_symlink (struct inode * dir, const char * name, int len, } 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 @@ int ext2_link (struct inode * oldinode, struct inode * dir, } 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 @@ static int subdir (struct inode * new_inode, struct inode * old_inode) 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 subdir (struct inode * new_inode, struct inode * old_inode) */ 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 @@ start_up: 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 @@ start_up: 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 @@ start_up: * 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 @@ start_up: 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 @@ end_rename: * 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 @@ int ext2_rename (struct inode * old_dir, const char * old_name, int old_len, 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 --git a/fs/ext2/super.c b/fs/ext2/super.c index 5885e3067..635a45692 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -319,6 +319,13 @@ static void ext2_setup_super (struct super_block * sb, 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 @@ int ext2_remount (struct super_block * sb, int * flags, char * data) } 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 --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c index 31f8276b0..4d5a5cada 100644 --- a/fs/ext2/symlink.c +++ b/fs/ext2/symlink.c @@ -25,8 +25,6 @@ #include <linux/stat.h> 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 @@ struct inode_operations ext2_symlink_inode_operations = { NULL, /* mknod */ NULL, /* rename */ ext2_readlink, /* readlink */ - ext2_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -52,70 +49,20 @@ struct inode_operations ext2_symlink_inode_operations = { 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 --git a/fs/fat/dir.c b/fs/fat/dir.c index 45b31836b..c39661904 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -260,10 +260,8 @@ int fat_readdirx( 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 @@ int fat_readdirx( } } 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 --git a/fs/fat/file.c b/fs/fat/file.c index 6dec1ba42..82787075a 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -52,7 +52,6 @@ struct inode_operations fat_file_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ generic_readpage, /* readpage */ NULL, /* writepage */ fat_bmap, /* bmap */ @@ -100,7 +99,6 @@ struct inode_operations fat_file_inode_operations_1024 = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/fs/fat/mmap.c b/fs/fat/mmap.c index 7896a4cfe..6a3515eef 100644 --- a/fs/fat/mmap.c +++ b/fs/fat/mmap.c @@ -105,7 +105,7 @@ int fat_mmap(struct inode * inode, struct file * file, struct vm_area_struct * v } vma->vm_inode = inode; - inode->i_count++; + atomic_inc(&inode->i_count); vma->vm_ops = &fat_file_mmap; return 0; } @@ -143,7 +143,6 @@ struct inode_operations fifo_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/fs/filesystems.c b/fs/filesystems.c index 74016aa67..004ee0aff 100644 --- a/fs/filesystems.c +++ b/fs/filesystems.c @@ -8,6 +8,7 @@ #include <linux/config.h> #include <linux/fs.h> +#include <linux/nametrans.h> #include <linux/minix_fs.h> #include <linux/ext2_fs.h> @@ -44,6 +45,10 @@ __initfunc(static void do_sys_setup(void)) binfmt_setup(); +#ifdef CONFIG_TRANS_NAMES + init_nametrans(); +#endif + #ifdef CONFIG_EXT2_FS init_ext2_fs(); #endif diff --git a/fs/hpfs/hpfs_fs.c b/fs/hpfs/hpfs_fs.c index 5bc73819c..878a3f069 100644 --- a/fs/hpfs/hpfs_fs.c +++ b/fs/hpfs/hpfs_fs.c @@ -175,7 +175,6 @@ static const struct inode_operations hpfs_file_iops = NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ generic_readpage, /* readpage */ NULL, /* writepage */ (int (*)(struct inode *, int)) @@ -219,7 +218,6 @@ static const struct inode_operations hpfs_dir_iops = NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -1746,7 +1744,10 @@ static void brelse4(struct quad_buffer_head *qbh) } 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 --git a/fs/inode.c b/fs/inode.c index 307b76063..7215e1204 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -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 <linux/kernel.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/slab.h> +/* 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 <linux/config.h> +#include <linux/errno.h> +#include <linux/fs.h> #include <linux/string.h> +#include <linux/mm.h> +#include <linux/kernel.h> +#include <linux/dlists.h> +#include <linux/dalloc.h> +#include <linux/omirr.h> + +/* #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) +void inode_init(void) { - 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; + 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)); } -#define hash_inode(inode) insert_inode_hash(inode) +/* 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 -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; - } -} +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) -static inline struct inode *find_inode(unsigned int hashent, - kdev_t dev, unsigned long ino) -{ - struct inode *inode; +DEF_INSERT(hash,struct inode,i_hash_next,i_hash_prev) +DEF_REMOVE(hash,struct inode,i_hash_next,i_hash_prev) - for(inode = inode_hash[hashent]; inode; inode = inode->i_hash_next) - if(inode->i_dev == dev && inode->i_ino == ino) - break; - return inode; -} +DEF_INSERT(ibasket,struct inode,i_basket_next,i_basket_prev) +DEF_REMOVE(ibasket,struct inode,i_basket_next,i_basket_prev) -/* 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++; -} +#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) -{ - if(inode->i_lock) - __wait_on_inode(inode); -} - -static inline void lock_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); - inode->i_lock = 1; + wait_io(inode, waitflags); + inode->i_status |= setflags; + vfs_unlock(); } -static inline void unlock_inode(struct inode *inode) +static inline blocking int release_io(struct inode * inode, unsigned short flags) { - inode->i_lock = 0; - wake_up(&inode->i_wait); -} - -static void __wait_on_inode(struct inode * inode) -{ - 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; + 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 inline blocking void _io(void (*op)(struct inode*), struct inode * inode, + unsigned short waitflags, unsigned short setflags) +{ + /* 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; - } - if(pass == 0) { - inode = inuse_list; - pass = 1; - goto repeat; + 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); } - 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; +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; } - if(pass == 0) { - inode = inuse_list; - pass = 1; - goto repeat; + 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]--; } - return 1; /* Tis' cool bro. */ -} - -/* This belongs in file_table.c, not here... */ -int fs_may_remount_ro(kdev_t dev) -{ - struct file * file; - - /* 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; + if(!external && inode->i_status & ST_IO) { + printk("VFS: clearing inode during IO operation\n"); } - 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; + 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(); +} + +blocking struct inode * _get_empty_inode(void) +{ + struct inode * inode; + int retry = 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; } } -} - -static inline void read_inode(struct inode *inode) -{ - 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); + 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; } -int inode_change_ok(struct inode *inode, struct iattr *attr) +static inline blocking struct inode * _get_empty_inode_hashed(dev_t i_dev, + unsigned long i_ino) { - 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; + 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; } - } - return 0; -} - -void inode_setattr(struct inode *inode, struct iattr *attr) -{ - 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; + 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; } -int notify_change(struct inode *inode, struct iattr *attr) +blocking struct inode * get_empty_inode_hashed(dev_t i_dev, unsigned long i_ino) { - 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); - - if(inode_change_ok(inode, attr) != 0) - return -EPERM; + struct inode * inode; - 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(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(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(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; } - if(pass == 0) { - inode = inuse_list; - pass = 1; - goto repeat; + 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; + 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(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; + 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; + } } - /* 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 */ + 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; } -static kmem_cache_t *inode_cachep; - -static void grow_inodes(void) +blocking void _iput(struct inode * inode) { - 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++; - } + vfs_lock(); + __iput(inode); + vfs_unlock(); } -/* 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) +blocking void sync_inodes(kdev_t dev) { - struct inode *best = NULL; + 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(); + (void)dev; + return 1; /* not checked any more */ +} - 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; +int fs_may_umount(kdev_t dev, struct inode * mount_root) +{ + 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; } -static int inode_updating[INODE_HASHSZ]; +extern struct inode_operations pipe_inode_operations; -struct inode *__iget(struct super_block *sb, int nr, int crossmntp) +blocking struct inode * get_pipe_inode(void) { - 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 = 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 --git a/fs/isofs/dir.c b/fs/isofs/dir.c index 30d0bf4c4..e22c3ca3b 100644 --- a/fs/isofs/dir.c +++ b/fs/isofs/dir.c @@ -54,7 +54,6 @@ struct inode_operations isofs_dir_inode_operations = NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ isofs_bmap, /* bmap */ @@ -226,7 +225,6 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp, /* 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 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp, 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 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp, 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 --git a/fs/isofs/file.c b/fs/isofs/file.c index d14a558a0..2742283f7 100644 --- a/fs/isofs/file.c +++ b/fs/isofs/file.c @@ -47,7 +47,6 @@ struct inode_operations isofs_file_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ generic_readpage, /* readpage */ NULL, /* writepage */ isofs_bmap, /* bmap */ diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 708198a00..d081a4cdd 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -912,7 +912,10 @@ void leak_check_brelse(struct buffer_head * bh){ #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 --git a/fs/isofs/namei.c b/fs/isofs/namei.c index 06ccfde5c..155f4ae43 100644 --- a/fs/isofs/namei.c +++ b/fs/isofs/namei.c @@ -206,6 +206,7 @@ int isofs_lookup(struct inode * dir,const char * name, int len, { 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 @@ int isofs_lookup(struct inode * dir,const char * name, int len, return -ENOENT; } - ino = 0; + /* 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; - 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<len; i++) { - c = name[i]; - if (c >= '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; + for (i=0; i<len; i++) { + c = name[i]; + if (c >= '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 @@ int isofs_lookup(struct inode * dir,const char * name, int len, } /* 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 --git a/fs/isofs/symlink.c b/fs/isofs/symlink.c index 87e544324..f49bc3ee3 100644 --- a/fs/isofs/symlink.c +++ b/fs/isofs/symlink.c @@ -19,7 +19,6 @@ #include <asm/uaccess.h> 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 @@ struct inode_operations isofs_symlink_inode_operations = { NULL, /* mknod */ NULL, /* rename */ isofs_readlink, /* readlink */ - isofs_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -44,51 +42,11 @@ struct inode_operations isofs_symlink_inode_operations = { 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; pnt = get_rock_ridge_symlink(inode); diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c index 2acbe5c17..81ac9b047 100644 --- a/fs/minix/bitmap.c +++ b/fs/minix/bitmap.c @@ -191,8 +191,8 @@ void minix_free_inode(struct inode * inode) 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 @@ struct inode * minix_new_inode(const struct inode * dir) 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 --git a/fs/minix/dir.c b/fs/minix/dir.c index ec5113c4a..439005f4e 100644 --- a/fs/minix/dir.c +++ b/fs/minix/dir.c @@ -50,7 +50,6 @@ struct inode_operations minix_dir_inode_operations = { minix_mknod, /* mknod */ minix_rename, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/fs/minix/file.c b/fs/minix/file.c index 23aa70268..86cbca2b2 100644 --- a/fs/minix/file.c +++ b/fs/minix/file.c @@ -58,7 +58,6 @@ struct inode_operations minix_file_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ generic_readpage, /* readpage */ NULL, /* writepage */ minix_bmap, /* bmap */ diff --git a/fs/minix/inode.c b/fs/minix/inode.c index faf5ce8a4..cbd735ef1 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -944,7 +944,10 @@ int minix_sync_inode(struct inode * inode) } 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 --git a/fs/minix/namei.c b/fs/minix/namei.c index c55d77fbc..b6041ad92 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -462,7 +462,7 @@ int minix_rmdir(struct inode * dir, const char * name, int len) 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 @@ static int subdir(struct inode * new_inode, struct inode * old_inode) 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 @@ static int subdir(struct inode * new_inode, struct inode * old_inode) * 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 @@ start_up: 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 @@ start_up: 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 @@ end_rename: * 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 @@ int minix_rename(struct inode * old_dir, const char * old_name, int old_len, 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 --git a/fs/minix/symlink.c b/fs/minix/symlink.c index 9a340ec9b..92539cded 100644 --- a/fs/minix/symlink.c +++ b/fs/minix/symlink.c @@ -15,7 +15,6 @@ #include <asm/uaccess.h> 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 @@ struct inode_operations minix_symlink_inode_operations = { NULL, /* mknod */ NULL, /* rename */ minix_readlink, /* readlink */ - minix_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -40,54 +38,12 @@ struct inode_operations minix_symlink_inode_operations = { 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 --git a/fs/msdos/msdosfs_syms.c b/fs/msdos/msdosfs_syms.c index 9e2c26bd6..c8b1e8092 100644 --- a/fs/msdos/msdosfs_syms.c +++ b/fs/msdos/msdosfs_syms.c @@ -31,7 +31,10 @@ EXPORT_SYMBOL(msdos_put_super); 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 --git a/fs/msdos/namei.c b/fs/msdos/namei.c index 1c76bdc41..bcf6782d0 100644 --- a/fs/msdos/namei.c +++ b/fs/msdos/namei.c @@ -219,14 +219,6 @@ int msdos_lookup(struct inode *dir,const char *name,int len, 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 @@ static int msdos_create_entry(struct inode *dir, const char *name,int len, (*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 @@ static int msdos_empty(struct inode *dir) 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 @@ static int rename_same_dir(struct inode *old_dir,char *old_name,int old_len, 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 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,int old_len, 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_done: /***** 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 @@ struct inode_operations msdos_dir_inode_operations = { NULL, /* mknod */ msdos_rename, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ fat_bmap, /* bmap */ diff --git a/fs/namei.c b/fs/namei.c index 35ebbd4f4..198179b98 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -8,6 +8,11 @@ * Some corrections by tytso. */ +/* [Feb 1997 T. Schoebel-Theuer] Complete rewrite of the pathname + * lookup logic. + */ + +#include <linux/config.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -15,18 +20,114 @@ #include <linux/fcntl.h> #include <linux/stat.h> #include <linux/mm.h> +#include <linux/dalloc.h> +#include <linux/nametrans.h> +#include <linux/proc_fs.h> +#include <linux/omirr.h> #include <linux/smp.h> #include <linux/smp_lock.h> #include <asm/uaccess.h> #include <asm/unaligned.h> +#include <asm/semaphore.h> #include <asm/namei.h> +/* 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 <fs>_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; i<quickcount; i++) + tmp = *(char**)tmp; + if(tmp) + printk("bad quicklist %x\n", (int)tmp); +#endif + quicklist = *(char**)res; + quickcount--; + } + else + res = (char*)__get_free_page(GFP_KERNEL); + up(&quicklock); + return res; +} + +inline void putname(char * name) +{ + if(name) { + down(&quicklock); + *(char**)name = quicklist; + quicklist = name; + quickcount++; + up(&quicklock); + } + /* if a quicklist limit is necessary to introduce, call + * free_page((unsigned long) name); + */ +} + +/* 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.. * @@ -53,44 +154,22 @@ static inline int do_getname(const char *filename, char *page) return retval; } -/* - * 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). - * -- Michael Chastain, based on idea of Linus Torvalds, 1 Dec 1996. - */ -static unsigned long name_page_cache = 0; - int getname(const char * filename, char **result) { - unsigned long page; + char *tmp; int retval; - page = name_page_cache; - name_page_cache = 0; - if (!page) { - page = __get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - } - - retval = do_getname(filename, (char *) page); + tmp = get_page(); + if(!tmp) + return -ENOMEM; + retval = do_getname(filename, tmp); if (retval < 0) - putname( (char *) page ); + putname(tmp); else - *result = (char *) page; + *result = tmp; return retval; } -void putname(char * name) -{ - if (name_page_cache == 0) - name_page_cache = (unsigned long) name; - else - free_page((unsigned long) name); -} - /* * permission() * @@ -143,155 +222,416 @@ void put_write_access(struct inode * inode) inode->i_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(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; } - } - 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; - } - return dir->i_op->lookup(dir, name, len, result); -} + vfs_unlock(); + if(res_entry) + *res_entry = cached; -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; - } - if (!inode->i_op || !inode->i_op->follow_link) { - iput(dir); - *res_inode = inode; - return 0; + /* 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 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. +#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 dir_namei(const char *pathname, int *namelen, const char **name, - struct inode * base, struct inode **res_inode) +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) { - unsigned char c; - const char * thisname; - int len,error; - struct inode * inode; + struct translations * trans; + char * env; + struct qstr * suffixes; + int i; + int error = -ENOENT; - *res_inode = NULL; - if (!base) { - base = current->fs->pwd; - base->i_count++; - } - if ((c = *pathname) == '/') { - iput(base); - base = current->fs->root; - pathname++; - base->i_count++; - } - while (1) { - thisname = pathname; - for(len=0;(c = *(pathname++))&&(c != '/');len++) - /* nothing */ ; - if (!c) + 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; - base->i_count++; - error = lookup(base, thisname, len, &inode); - if (error) { - iput(base); - return error; } - error = follow_link(base,inode,0,0,&base); - if (error) - return error; } - if (!base->i_op || !base->i_op->lookup) { - iput(base); - return -ENOTDIR; + 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); } - *name = thisname; - *namelen = len; - *res_inode = base; - return 0; + return error; } -int _namei(const char * pathname, struct inode * base, - int follow_links, struct inode ** res_inode) +/* 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) { - const char *basename; - int namelen,error; - struct inode * inode; + int perm; - 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; + *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); + } } - if (follow_links) { - error = follow_link(base, inode, 0, 0, &inode); - if (error) - return error; - } else - iput(base); - *res_inode = inode; - return 0; +#endif +done: + return perm; } -int lnamei(const char *pathname, struct inode **res_inode) +/* [8-Feb-97 T. Schoebel-Theuer] follow_link() modified for generic operation + * on the VFS layer: first call <fs>_readlink() and then open_namei(). + * All <fs>_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 /*inline*/ int _read_link(struct inode * inode, char ** linkname, int loopcount) { + unsigned long old_fs; int error; - char * tmp; - error = getname(pathname, &tmp); - if (!error) { - error = _namei(tmp, NULL, 0, res_inode); - putname(tmp); + 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; + } +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; + atomic_inc(&base->i_count); + this.name++; + } else if (!base) { + base = current->fs->pwd; + atomic_inc(&base->i_count); } + for(;;) { + struct inode * inode; + const char * tmp = this.name; + int len; + + for(len = 0; (c = *tmp++) && (c != '/'); len++) ; + this.len = len; + if(!c) + break; + while((c = *tmp) == '/') /* remove embedded/trailing slashes */ + tmp++; + if(!c) { + trail_flag = 1; + if(retrieve_mode & NAM_NO_TRAILSLASH) { + error = -EISDIR; + goto alldone; + } + break; + } +#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) + 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); + base = inode; + } + 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; + } + } +alldone: + if(!error && res_dir) + *res_dir = base; + else + iput(base); + putname(linkname); + putname(oldlinkname); return error; } @@ -302,14 +642,20 @@ int lnamei(const char *pathname, struct inode **res_inode) * 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 @@ int namei(const char *pathname, struct inode **res_inode) * 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, - struct inode ** res_inode, struct inode * base) +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 @@ open_namei(const char * pathname, int flag, int mode, 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 @@ open_namei(const char * pathname, int flag, int mode, } 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 (IS_RDONLY(dir)) { - iput(dir); - return -EROFS; + if (!last.len) { + error = -ENOENT; + goto exit_inode; } - if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) { - iput(dir); - return error; + if (IS_RDONLY(dir)) { + 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 @@ out: 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 (IS_RDONLY(dir)) { - iput(dir); - return -EROFS; + if (!last.len) { + error = -ENOENT; + goto exit_inode; } - if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) { - iput(dir); - return error; + if (IS_RDONLY(dir)) { + 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 @@ asmlinkage int sys_mkdir(const char * pathname, int mode) lock_kernel(); error = getname(pathname,&tmp); if (!error) { - remove_trailing_slashes(tmp); error = do_mkdir(tmp,mode); putname(tmp); } @@ -610,43 +945,125 @@ asmlinkage int sys_mkdir(const char * pathname, int mode) return error; } -static int do_rmdir(const char * name) +#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) { - 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); + /* [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 @@ asmlinkage int sys_rmdir(const char * pathname) lock_kernel(); error = getname(pathname,&tmp); if (!error) { - remove_trailing_slashes(tmp); error = do_rmdir(tmp); putname(tmp); } @@ -666,43 +1082,93 @@ asmlinkage int sys_rmdir(const char * pathname) 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 @@ asmlinkage int sys_unlink(const char * pathname) 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 @@ asmlinkage int sys_symlink(const char * oldname, const char * newname) 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 = 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_NO_TRAILSLASH, + oldname, NULL, oldbuf, + NULL, &oldinode, &oldlast, &oldent, NULL); + if (error) + goto exit; + + 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; - } - 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); + error = -EPERM; + goto new_exit; + } + 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; - } - 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; + 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 (!new_len || (new_base[0] == '.' && - (new_len == 1 || (new_base[1] == '.' && - new_len == 2)))) { - iput(old_dir); - iput(new_dir); - return -EPERM; + + 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; } - if (new_dir->i_dev != old_dir->i_dev) { - iput(old_dir); - iput(new_dir); - return -EXDEV; + /* + * A file cannot be removed from an append-only directory. + */ + if (IS_APPEND(olddir)) { + error = -EPERM; + goto new_exit; } - if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir)) { - iput(old_dir); - iput(new_dir); - return -EROFS; + if (!olddir->i_op || !olddir->i_op->rename) { + error = -ENOSYS; /* was EPERM */ + goto new_exit; } - /* - * A file cannot be removed from an append-only directory +#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 @@ asmlinkage int sys_rename(const char * oldname, const char * newname) 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 --git a/fs/nametrans.c b/fs/nametrans.c new file mode 100644 index 000000000..15c98ed70 --- /dev/null +++ b/fs/nametrans.c @@ -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, + * <schoebel@informatik.uni-stuttgart.de>. + * + * 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 <linux/config.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/utsname.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <asm/uaccess.h> +#include <linux/nametrans.h> + +char nametrans_txt[MAX_DEFAULT_TRANSLEN] = ""; +static struct translations * global_trans = NULL; +static int default_trans = 1; +static const char version[] = "revision: 2.3 <schoebel@informatik.uni-stuttgart.de>"; +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 --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index e62e26e47..5eb73dbd0 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -67,8 +67,7 @@ static int 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 @@ struct inode_operations ncp_dir_inode_operations = NULL, /* mknod */ ncp_rename, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* bmap */ NULL, /* truncate */ NULL, /* permission */ @@ -965,8 +963,7 @@ static int ncp_unlink(struct inode *dir, const char *name, int len) } 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 --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c index 9bdc793cc..3cb50fbbd 100644 --- a/fs/ncpfs/file.c +++ b/fs/ncpfs/file.c @@ -232,7 +232,6 @@ struct inode_operations ncp_file_inode_operations = NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* bmap */ NULL /* truncate */ }; diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 4cf65f8a9..72ca3e6dd 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -406,9 +406,11 @@ int ncp_malloced; 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 --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c index 52ff3c76a..8e814d153 100644 --- a/fs/ncpfs/mmap.c +++ b/fs/ncpfs/mmap.c @@ -133,7 +133,7 @@ int ncp_mmap(struct inode *inode, struct file *file, struct vm_area_struct *vma) 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 --git a/fs/nfs/dir.c b/fs/nfs/dir.c index a11b9fb6a..71835c255 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -51,7 +51,7 @@ static int nfs_symlink(struct inode *, const char *, int, const char *); 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 @@ struct inode_operations nfs_dir_inode_operations = { nfs_mknod, /* mknod */ nfs_rename, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -351,7 +350,7 @@ static struct nfs_lookup_cache_entry { 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 @@ static int nfs_lookup(struct inode *dir, const char *__name, int len, } 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 @@ static int nfs_sillyrename(struct inode *dir, const char *name, int len) 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 @@ static int nfs_sillyrename(struct inode *dir, const char *name, int len) 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 @@ static int nfs_link(struct inode *oldinode, struct inode *dir, * 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 @@ static int nfs_rename(struct inode *old_dir, const char *old_name, int old_len, 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 @@ void nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) 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 --git a/fs/nfs/file.c b/fs/nfs/file.c index ca42719bd..56540bbdc 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -69,7 +69,6 @@ struct inode_operations nfs_file_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ nfs_readpage, /* readpage */ nfs_writepage, /* writepage */ NULL, /* bmap */ @@ -143,7 +142,7 @@ nfs_file_write(struct inode *inode, struct file *file, 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 --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 7f883270a..5ab9600e9 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -316,7 +316,8 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle, 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 @@ done: * 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 --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index 66070efd7..add3309f3 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -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 <gero@gkminix.han.de> * @@ -78,6 +78,7 @@ #include <asm/param.h> #include <linux/utsname.h> +#include <linux/nametrans.h> #include <linux/in.h> #include <linux/if.h> #include <linux/inet.h> @@ -832,6 +833,9 @@ __initfunc(static void root_do_bootp_ext(u8 *ext)) root_bootp_string(nfs_path, ext+1, *ext, NFS_MAXPATHLEN); break; } +#ifdef CONFIG_TRANS_NAMES + translations_dirty = 1; +#endif } @@ -1254,6 +1258,9 @@ __initfunc(static void root_nfs_addrs(char *addrs)) 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 @@ __initfunc(static void root_nfs_addrs(char *addrs)) } 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 @@ __initfunc(static int root_nfs_setup(void)) 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 --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 714101bb7..58dcd95d0 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -177,8 +177,8 @@ nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, const char *name) 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 --git a/fs/nfs/read.c b/fs/nfs/read.c index cf7c5ece7..2c3b59036 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -188,7 +188,7 @@ nfs_readpage_async(struct inode *inode, struct page *page) nfs_readpage_result, req); if (result >= 0) { - inode->i_count++; + atomic_inc(&inode->i_count); atomic_inc(&page->count); return 0; } diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c index 7ea2d6f99..a22f96239 100644 --- a/fs/nfs/symlink.c +++ b/fs/nfs/symlink.c @@ -19,8 +19,6 @@ #include <asm/uaccess.h> 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 @@ struct inode_operations nfs_symlink_inode_operations = { NULL, /* mknod */ NULL, /* rename */ nfs_readlink, /* readlink */ - nfs_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -45,55 +42,6 @@ struct inode_operations nfs_symlink_inode_operations = { 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 @@ static int nfs_readlink(struct inode *inode, char *buffer, int buflen) 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 --git a/fs/nfs/write.c b/fs/nfs/write.c index 4e2de9cfc..f27d083e4 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -133,7 +133,7 @@ nfs_unlock_page(struct page *page) 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 @@ create_write_request(struct inode *inode, struct page *page, 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 @@ nfs_wback_result(struct rpc_task *task) 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 --git a/fs/nfsd/export.c b/fs/nfsd/export.c index c83150b5f..a3b29313a 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -331,7 +331,7 @@ exp_rootfh(struct svc_client *clp, dev_t dev, ino_t ino, struct knfs_fh *f) 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 --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index c466321ed..88b69cb40 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -35,8 +35,8 @@ # define copy_to_user memcpy_tofs # define access_ok !verify_area #endif -#include <asm/smp.h> -#include <asm/smp_lock.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> extern long sys_call_table[]; @@ -214,8 +214,6 @@ EXPORT_NO_SYMBOLS; MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>"); #endif -static unsigned long old_syscallvec; - extern int (*do_nfsservctl)(int, void *, void *); /* diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 6327cee48..a68fca997 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -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 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, 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 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, 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 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, 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 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, } } - inode->i_count++; + atomic_inc(&inode->i_count); return 0; } @@ -307,7 +304,7 @@ nfsd_close(struct file *filp) 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 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, 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 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, * 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 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp) 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 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, 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 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, /* * 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 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, 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 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, 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 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, 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); } @@ -1041,26 +1038,6 @@ nfsd_parentdev(dev_t* devp) 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; -} - /* * This is a copy from fs/inode.c because it wasn't exported. */ @@ -4,6 +4,7 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ +#include <linux/config.h> #include <linux/vfs.h> #include <linux/types.h> #include <linux/utime.h> @@ -20,6 +21,7 @@ #include <linux/file.h> #include <linux/smp.h> #include <linux/smp_lock.h> +#include <linux/omirr.h> #include <asm/uaccess.h> #include <asm/bitops.h> @@ -33,7 +35,7 @@ asmlinkage int sys_statfs(const char * path, struct statfs * buf) 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 @@ int do_truncate(struct inode *inode, unsigned long length) 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 @@ asmlinkage int sys_truncate(const char * path, unsigned long length) int error; lock_kernel(); - error = namei(path,&inode); + error = namei(NAM_FOLLOW_LINK, path, &inode); if (error) goto out; @@ -185,33 +188,36 @@ asmlinkage int sys_utime(char * filename, struct utimbuf * times) 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 @@ asmlinkage int sys_utimes(char * filename, struct timeval * utimes) 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 @@ asmlinkage int sys_utimes(char * filename, struct timeval * utimes) 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 @@ asmlinkage int sys_access(const char * filename, int mode) 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 @@ out: 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 @@ asmlinkage int sys_fchdir(unsigned int fd) 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 @@ out: 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 @@ asmlinkage int sys_fchmod(unsigned int fd, mode_t mode) 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 @@ asmlinkage int sys_chmod(const char * filename, mode_t mode) 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 @@ asmlinkage int sys_chmod(const char * filename, mode_t mode) 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 @@ asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group) 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 @@ asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group) 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 @@ asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group) 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: @@ -385,7 +385,6 @@ struct inode_operations pipe_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -442,7 +441,7 @@ int do_pipe(int *fd) 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 --git a/fs/proc/Makefile b/fs/proc/Makefile index 75ec3dd85..6f336245d 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile @@ -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 --git a/fs/proc/arbitrary.c b/fs/proc/arbitrary.c new file mode 100644 index 000000000..1e18e594e --- /dev/null +++ b/fs/proc/arbitrary.c @@ -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, + * <schoebel@informatik.uni-stuttgart.de>. + */ + +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/kdev_t.h> +#include <linux/fs.h> + +/* Format of dev/inode pairs that can be used as file names: + * [<dev_number_in_hex]:<inode_number_in_decimal> + * (the same format that is already in use in /proc/<pid>/exe, + * /proc/<pid>/cwd and /proc/<pid>/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 --git a/fs/proc/array.c b/fs/proc/array.c index 516e87813..518ef1b4c 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -154,8 +154,6 @@ static long read_profile(struct inode *inode, struct file *file, return read; } - - /* * Writing to /proc/profile resets the counters * @@ -1042,6 +1040,9 @@ extern int get_smp_prof_list(char *); #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) @@ -1126,6 +1127,10 @@ static long get_root_array(char * page, int type, char **start, 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; } @@ -1232,7 +1237,6 @@ struct inode_operations proc_array_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -1278,7 +1282,6 @@ struct inode_operations proc_arraylong_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/fs/proc/base.c b/fs/proc/base.c index 7e9a65e08..b983e73f6 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -42,7 +42,6 @@ static struct inode_operations proc_base_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/fs/proc/fd.c b/fs/proc/fd.c index fd262bc9d..884631db8 100644 --- a/fs/proc/fd.c +++ b/fs/proc/fd.c @@ -44,7 +44,6 @@ struct inode_operations proc_fd_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 6e80e8298..1424dd1ef 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -51,7 +51,6 @@ struct inode_operations proc_file_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -74,7 +73,6 @@ struct inode_operations proc_net_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/fs/proc/kmsg.c b/fs/proc/kmsg.c index 1cc6a9c83..6ef386ffa 100644 --- a/fs/proc/kmsg.c +++ b/fs/proc/kmsg.c @@ -70,7 +70,6 @@ struct inode_operations proc_kmsg_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/fs/proc/link.c b/fs/proc/link.c index d5c08eafd..695ed9bba 100644 --- a/fs/proc/link.c +++ b/fs/proc/link.c @@ -14,10 +14,9 @@ #include <linux/mm.h> #include <linux/proc_fs.h> #include <linux/stat.h> +#include <linux/dalloc.h> 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 @@ struct inode_operations proc_link_inode_operations = { NULL, /* mknod */ NULL, /* rename */ proc_readlink, /* readlink */ - proc_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -61,7 +59,11 @@ struct inode_operations proc_link_inode_operations = { 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 @@ static int proc_follow_link(struct inode * dir, struct inode * inode, 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<PAGE_SIZE ? buflen : PAGE_SIZE; + if(len <= min) + min = len+1; + copy_to_user(buffer, tmp, min); + free_page((unsigned long)tmp); + error = len; + } else { + error= -ENOENT; + } iput(inode); - i = sprintf(buf,"[%04x]:%u", dev, ino); - if (buflen > i) - buflen = i; - i = 0; - while (i < buflen) - put_user(buf[i++],buffer++); - return i; + return error; } diff --git a/fs/proc/mem.c b/fs/proc/mem.c index 97acb5ee8..a64ead624 100644 --- a/fs/proc/mem.c +++ b/fs/proc/mem.c @@ -328,7 +328,6 @@ struct inode_operations proc_mem_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/fs/proc/net.c b/fs/proc/net.c index 257487569..3bc5c339c 100644 --- a/fs/proc/net.c +++ b/fs/proc/net.c @@ -111,7 +111,6 @@ struct inode_operations proc_net_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/fs/proc/omirr.c b/fs/proc/omirr.c new file mode 100644 index 000000000..0e6377fb2 --- /dev/null +++ b/fs/proc/omirr.c @@ -0,0 +1,297 @@ +/* + * fs/proc/omirr.c - online mirror support + * + * (C) 1997 Thomas Schoebel-Theuer + */ + +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/fs.h> +#include <linux/dalloc.h> +#include <linux/omirr.h> +#include <asm/uaccess.h> + +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 --git a/fs/proc/openpromfs.c b/fs/proc/openpromfs.c index a9f84b9eb..7d741cfaf 100644 --- a/fs/proc/openpromfs.c +++ b/fs/proc/openpromfs.c @@ -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 @@ static struct inode_operations openpromfs_prop_inode_ops = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -517,7 +516,6 @@ static struct inode_operations openpromfs_nodenum_inode_ops = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -550,7 +548,6 @@ static struct inode_operations openprom_alias_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -1015,7 +1012,7 @@ void openpromfs_use (struct inode *inode, int inc) 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 @@ void openpromfs_use (struct inode *inode, int inc) 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 --git a/fs/proc/procfs_syms.c b/fs/proc/procfs_syms.c index 809a26084..71c29dd75 100644 --- a/fs/proc/procfs_syms.c +++ b/fs/proc/procfs_syms.c @@ -37,7 +37,10 @@ EXPORT_SYMBOL(proc_openprom_deregister); #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 --git a/fs/proc/root.c b/fs/proc/root.c index 11c27699a..f42557d2c 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -64,7 +64,6 @@ struct inode_operations proc_dir_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -105,7 +104,6 @@ static struct inode_operations proc_root_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -266,7 +264,6 @@ struct inode_operations proc_openprom_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -348,17 +345,6 @@ int proc_unregister(struct proc_dir_entry * dir, int ino) /* * /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 @@ static struct inode_operations proc_self_inode_operations = { NULL, /* mknod */ NULL, /* rename */ proc_self_readlink, /* readlink */ - proc_self_followlink, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -436,6 +421,13 @@ static struct proc_dir_entry proc_root_cpuinfo = { 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 @@ static struct proc_dir_entry proc_root_slab = { 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 @@ void proc_root_init(void) #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 @@ int proc_lookup(struct inode * dir,const char * name, int len, 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 @@ static int proc_root_lookup(struct inode * dir,const char * name, int len, 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 --git a/fs/proc/scsi.c b/fs/proc/scsi.c index b1e77398c..fd629a75c 100644 --- a/fs/proc/scsi.c +++ b/fs/proc/scsi.c @@ -69,7 +69,6 @@ struct inode_operations proc_scsi_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/fs/read_write.c b/fs/read_write.c index dd4092301..81b19ac30 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -168,6 +168,7 @@ asmlinkage long sys_write(unsigned int fd, const char * buf, unsigned long count 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 @@ static long do_readv_writev(int type, struct inode * inode, struct file * file, 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 @@ static long do_readv_writev(int type, struct inode * inode, struct file * file, 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 --git a/fs/readdir.c b/fs/readdir.c index aaea5b45f..a86398ac3 100644 --- a/fs/readdir.c +++ b/fs/readdir.c @@ -1,20 +1,35 @@ /* - * linux/fs/readdir.c + * fs/readdir.c * * Copyright (C) 1995 Linus Torvalds */ +#include <linux/config.h> #include <linux/types.h> #include <linux/errno.h> #include <linux/stat.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/mm.h> +#ifdef CONFIG_TRANS_NAMES +#include <linux/nametrans.h> +#endif +#include <linux/dalloc.h> #include <linux/smp.h> #include <linux/smp_lock.h> #include <asm/uaccess.h> +/* [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 old_linux_dirent { struct readdir_callback { struct old_linux_dirent * dirent; + struct file * file; + int translate; + off_t oldoffset; int count; }; @@ -47,11 +65,26 @@ static int fillonedir(void * __buf, const char * name, int namlen, off_t offset, 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 @@ asmlinkage int old_readdir(unsigned int fd, void * dirent, unsigned int count) 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 @@ asmlinkage int old_readdir(unsigned int fd, void * dirent, unsigned int count) 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 linux_dirent { 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 @@ static int filldir(void * __buf, const char * name, int namlen, off_t offset, in 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 @@ static int filldir(void * __buf, const char * name, int namlen, off_t offset, in 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 @@ asmlinkage int sys_getdents(unsigned int fd, void * dirent, unsigned int count) 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 --git a/fs/romfs/inode.c b/fs/romfs/inode.c index f3f73c66e..0ddda855d 100644 --- a/fs/romfs/inode.c +++ b/fs/romfs/inode.c @@ -417,59 +417,6 @@ out: 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 @@ static struct inode_operations romfs_file_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ romfs_readpage, /* readpage */ NULL, /* writepage */ NULL, /* bmap -- not really */ @@ -525,7 +471,7 @@ static struct file_operations romfs_dir_operations = { 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 @@ static struct inode_operations romfs_dirlink_inode_operations = { NULL, /* mknod */ NULL, /* rename */ romfs_readlink, /* readlink */ - romfs_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -638,7 +583,10 @@ static struct super_operations romfs_ops = { }; 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 --git a/fs/select.c b/fs/select.c index 683865a30..c7ea0e015 100644 --- a/fs/select.c +++ b/fs/select.c @@ -208,17 +208,18 @@ out: * 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 @@ static int __get_fd_set(unsigned long nr, int * fs_pointer, int * fdset) 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 @@ static inline void __zero_fd_set(long nr, unsigned long * fdset) * 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 @@ asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct 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 @@ asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct 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 --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c index e23dbb979..bd723b142 100644 --- a/fs/smbfs/dir.c +++ b/fs/smbfs/dir.c @@ -47,8 +47,7 @@ static int 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 @@ struct inode_operations smb_dir_inode_operations = NULL, /* mknod */ smb_rename, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -798,8 +796,7 @@ smb_unlink(struct inode *dir, const char *name, int len) 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 --git a/fs/smbfs/file.c b/fs/smbfs/file.c index 93c57e38f..0451ee427 100644 --- a/fs/smbfs/file.c +++ b/fs/smbfs/file.c @@ -236,7 +236,6 @@ struct inode_operations smb_file_inode_operations = NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 1943045bb..20738b0d2 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -429,9 +429,11 @@ int smb_current_kmalloced; 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 --git a/fs/smbfs/mmap.c b/fs/smbfs/mmap.c index 9fd157b2a..472fad6de 100644 --- a/fs/smbfs/mmap.c +++ b/fs/smbfs/mmap.c @@ -120,7 +120,7 @@ smb_mmap(struct inode *inode, struct file *file, struct vm_area_struct *vma) inode->i_dirt = 1; } vma->vm_inode = inode; - inode->i_count++; + atomic_inc(&inode->i_count); vma->vm_ops = &smb_file_mmap; return 0; } @@ -127,7 +127,7 @@ asmlinkage int sys_stat(char * filename, struct __old_kernel_stat * statbuf) 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 @@ asmlinkage int sys_newstat(char * filename, struct stat * statbuf) 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 @@ asmlinkage int sys_lstat(char * filename, struct __old_kernel_stat * statbuf) 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 @@ asmlinkage int sys_newlstat(char * filename, struct stat * statbuf) 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,15 +249,19 @@ asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz) 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: unlock_kernel(); diff --git a/fs/super.c b/fs/super.c index 6048b1ae7..ec47301aa 100644 --- a/fs/super.c +++ b/fs/super.c @@ -33,6 +33,7 @@ #include <linux/smp.h> #include <linux/smp_lock.h> #include <linux/fd.h> +#include <linux/dalloc.h> #include <linux/init.h> #include <asm/system.h> @@ -59,8 +60,8 @@ kdev_t ROOT_DEV; 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 @@ int get_filesystem_list(char * buf) 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 @@ void sync_supers(kdev_t dev) } } -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 @@ static int do_umount(kdev_t dev,int unmount_root) 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 @@ asmlinkage int sys_umount(char * name) { 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 @@ asmlinkage int sys_umount(char * name) } 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 @@ asmlinkage int sys_umount(char * name) put_unnamed_dev(dev); } } - if (inode != &dummy_inode) - iput(inode); + iput(inode); if (!retval) fsync_dev(dev); out: @@ -697,22 +700,42 @@ out: * 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 @@ int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const cha 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 @@ int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const cha 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 @@ static int do_remount(const char *dir,int flags,char *data) 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 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, 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 @@ __initfunc(static void do_mount_root(void)) 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 @@ __initfunc(static void do_mount_root(void)) 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 @@ __initfunc(static void do_mount_root(void)) #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 @@ __initfunc(static void do_mount_root(void)) 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 @@ __initfunc(static int do_change_root(kdev_t new_root_dev,const char *put_old)) 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 --git a/fs/sysv/dir.c b/fs/sysv/dir.c index 3dd0931cf..8b942a5b1 100644 --- a/fs/sysv/dir.c +++ b/fs/sysv/dir.c @@ -57,7 +57,6 @@ struct inode_operations sysv_dir_inode_operations = { sysv_mknod, /* mknod */ sysv_rename, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/fs/sysv/file.c b/fs/sysv/file.c index f3aadb509..da07ef7a8 100644 --- a/fs/sysv/file.c +++ b/fs/sysv/file.c @@ -64,7 +64,6 @@ struct inode_operations sysv_file_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ generic_readpage, /* readpage */ NULL, /* writepage */ sysv_bmap, /* bmap */ diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c index 85ba640d1..97bc7284f 100644 --- a/fs/sysv/ialloc.c +++ b/fs/sysv/ialloc.c @@ -62,8 +62,9 @@ void sysv_free_inode(struct inode * inode) 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 @@ struct inode * sysv_new_inode(const struct inode * dir) 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 --git a/fs/sysv/inode.c b/fs/sysv/inode.c index ebbf0bb4f..f8c6a1b38 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -975,9 +975,9 @@ int sysv_sync_inode(struct inode * inode) /* 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 --git a/fs/sysv/namei.c b/fs/sysv/namei.c index 735d158d4..d1b67ab5f 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c @@ -454,7 +454,7 @@ int sysv_rmdir(struct inode * dir, const char * name, int len) 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 @@ static int subdir(struct inode * new_inode, struct inode * old_inode) 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 @@ static int subdir(struct inode * new_inode, struct inode * old_inode) * 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 @@ start_up: 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 @@ start_up: 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 @@ end_rename: * 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 @@ int sysv_rename(struct inode * old_dir, const char * old_name, int old_len, 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 --git a/fs/sysv/symlink.c b/fs/sysv/symlink.c index 9a33d9fab..4e8a5e349 100644 --- a/fs/sysv/symlink.c +++ b/fs/sysv/symlink.c @@ -21,7 +21,6 @@ #include <asm/uaccess.h> 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 @@ struct inode_operations sysv_symlink_inode_operations = { NULL, /* mknod */ NULL, /* rename */ sysv_readlink, /* readlink */ - sysv_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -46,44 +44,6 @@ struct inode_operations sysv_symlink_inode_operations = { 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 @@ static int sysv_readlink(struct inode * inode, char * buffer, int buflen) 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 --git a/fs/ufs/ufs_dir.c b/fs/ufs/ufs_dir.c index 26ae02abe..15396589f 100644 --- a/fs/ufs/ufs_dir.c +++ b/fs/ufs/ufs_dir.c @@ -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 @@ revalidate: * 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 @@ struct inode_operations ufs_dir_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -174,13 +170,3 @@ struct inode_operations ufs_dir_inode_operations = { 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 --git a/fs/ufs/ufs_file.c b/fs/ufs/ufs_file.c index 4b479a65e..74ae1a470 100644 --- a/fs/ufs/ufs_file.c +++ b/fs/ufs/ufs_file.c @@ -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 @@ struct inode_operations ufs_file_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ generic_readpage, /* readpage */ NULL, /* writepage */ ufs_bmap, /* bmap */ diff --git a/fs/ufs/ufs_inode.c b/fs/ufs/ufs_inode.c index 0d89fd6f0..f0fdd5d5f 100644 --- a/fs/ufs/ufs_inode.c +++ b/fs/ufs/ufs_inode.c @@ -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 @@ void ufs_print_inode(struct inode * inode) { 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 --git a/fs/ufs/ufs_super.c b/fs/ufs/ufs_super.c index 44d7241ef..342722237 100644 --- a/fs/ufs/ufs_super.c +++ b/fs/ufs/ufs_super.c @@ -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 super_operations ufs_super_ops = { }; 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 --git a/fs/ufs/ufs_symlink.c b/fs/ufs/ufs_symlink.c index 13d2285e6..d98f99ff7 100644 --- a/fs/ufs/ufs_symlink.c +++ b/fs/ufs/ufs_symlink.c @@ -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 @@ ufs_readlink(struct inode * inode, char * buffer, int buflen) 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 @@ ufs_readlink(struct inode * inode, char * buffer, int buflen) 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 @@ struct inode_operations ufs_symlink_inode_operations = { NULL, /* rmdir */ NULL, /* mknod */ NULL, /* rename */ - &ufs_readlink, /* readlink */ - &ufs_follow_link, /* follow_link */ + ufs_readlink, /* readlink */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c index 8f8a6bbb6..a3f23181c 100644 --- a/fs/umsdos/dir.c +++ b/fs/umsdos/dir.c @@ -565,7 +565,7 @@ int umsdos_locate_path ( } } }else{ - dir->i_count++; + atomic_inc(&dir->i_count); } if (ret == 0){ while (dir != dir->i_sb->s_mounted){ @@ -628,7 +628,7 @@ static int umsdos_lookup_x ( 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 @@ static int umsdos_lookup_x ( */ 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 @@ static int umsdos_lookup_x ( 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 @@ int umsdos_hlink2inode (struct inode *hlink, struct inode **result) 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 @@ struct inode_operations umsdos_dir_inode_operations = { UMSDOS_mknod, /* mknod */ UMSDOS_rename, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/fs/umsdos/emd.c b/fs/umsdos/emd.c index 0d4a89298..ec064b2b1 100644 --- a/fs/umsdos/emd.c +++ b/fs/umsdos/emd.c @@ -137,7 +137,8 @@ struct inode *umsdos_emd_dir_lookup(struct inode *dir, int creat) 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 @@ struct inode *umsdos_emd_dir_lookup(struct inode *dir, int creat) }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 --git a/fs/umsdos/file.c b/fs/umsdos/file.c index cda0e4e8d..32d76ac06 100644 --- a/fs/umsdos/file.c +++ b/fs/umsdos/file.c @@ -86,7 +86,6 @@ struct inode_operations umsdos_file_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ generic_readpage, /* readpage */ NULL, /* writepage */ fat_bmap, /* bmap */ @@ -120,7 +119,6 @@ struct inode_operations umsdos_file_inode_operations_no_bmap = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c index 8a00fd833..137235731 100644 --- a/fs/umsdos/inode.c +++ b/fs/umsdos/inode.c @@ -73,7 +73,7 @@ int umsdos_real_lookup ( 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 @@ int umsdos_isinit (struct inode *inode) #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 @@ void UMSDOS_read_inode(struct inode *inode) { 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 @@ struct super_block *UMSDOS_read_super( 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 @@ struct super_block *UMSDOS_read_super( 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 --git a/fs/umsdos/ioctl.c b/fs/umsdos/ioctl.c index a4d4108b8..ba56963ca 100644 --- a/fs/umsdos/ioctl.c +++ b/fs/umsdos/ioctl.c @@ -215,11 +215,11 @@ int UMSDOS_ioctl_dir ( 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 @@ int UMSDOS_ioctl_dir ( 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 @@ int UMSDOS_ioctl_dir ( 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 --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c index c4c9e73ba..b2a1e2e56 100644 --- a/fs/umsdos/namei.c +++ b/fs/umsdos/namei.c @@ -225,13 +225,14 @@ static int umsdos_create_any ( 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 @@ chkstk(); 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 @@ chkstk(); 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 @@ static int umsdos_symlink_x( */ 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 @@ int UMSDOS_link ( 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 @@ int UMSDOS_link ( 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 @@ int UMSDOS_link ( 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 @@ int UMSDOS_link ( }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 @@ int UMSDOS_mkdir( 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 UMSDOS_rmdir( 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 @@ int UMSDOS_rmdir( 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 @@ int UMSDOS_unlink ( 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 @@ int UMSDOS_unlink ( 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 UMSDOS_rename( 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 UMSDOS_rename( 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 @@ int UMSDOS_rename( 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 --git a/fs/umsdos/rdir.c b/fs/umsdos/rdir.c index a2a5364f6..e3b7678e4 100644 --- a/fs/umsdos/rdir.c +++ b/fs/umsdos/rdir.c @@ -96,7 +96,7 @@ int umsdos_rlookup_x( && 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 @@ static int UMSDOS_rrmdir ( 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 @@ static int UMSDOS_rrmdir ( ,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 @@ struct inode_operations umsdos_rdir_inode_operations = { NULL, /* mknod */ msdos_rename, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/fs/umsdos/symlink.c b/fs/umsdos/symlink.c index 8b6678ae9..d714c5ab9 100644 --- a/fs/umsdos/symlink.c +++ b/fs/umsdos/symlink.c @@ -42,69 +42,12 @@ static int umsdos_readlink_x ( } 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 @@ struct inode_operations umsdos_symlink_inode_operations = { NULL, /* mknod */ NULL, /* rename */ UMSDOS_readlink, /* readlink */ - UMSDOS_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index e3db004cc..161bc791e 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -937,12 +937,6 @@ int vfat_lookup(struct inode *dir,const char *name,int len, 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 @@ static int vfat_create_entry(struct inode *dir,const char *name,int len, (*result)->i_dirt = 1; (*result)->i_version = ++event; dir->i_version = event; - dcache_add(dir, name, len, ino); return 0; } @@ -1132,7 +1125,7 @@ static int vfat_empty(struct inode *dir) 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_unlink(struct inode *dir,const char *name,int len) 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 @@ int vfat_rename(struct inode *old_dir,const char *old_name,int old_len, 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 @@ int vfat_rename(struct inode *old_dir,const char *old_name,int old_len, 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 @@ struct inode_operations vfat_dir_inode_operations = { NULL, /* mknod */ vfat_rename, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ fat_bmap, /* bmap */ @@ -1577,7 +1566,10 @@ void vfat_read_inode(struct inode *inode) } 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 --git a/include/asm-alpha/byteorder.h b/include/asm-alpha/byteorder.h index 438ecb89c..a753084ce 100644 --- a/include/asm-alpha/byteorder.h +++ b/include/asm-alpha/byteorder.h @@ -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) @@ -125,4 +100,69 @@ __ntohs(unsigned short int x) #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 --git a/include/asm-alpha/fpu.h b/include/asm-alpha/fpu.h index f32b95f27..25148b14b 100644 --- a/include/asm-alpha/fpu.h +++ b/include/asm-alpha/fpu.h @@ -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 --git a/include/asm-alpha/keyboard.h b/include/asm-alpha/keyboard.h index 1edaa52bb..3caa220eb 100644 --- a/include/asm-alpha/keyboard.h +++ b/include/asm-alpha/keyboard.h @@ -19,10 +19,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 --git a/include/asm-alpha/namei.h b/include/asm-alpha/namei.h index a03cc1e8b..22e14bdce 100644 --- a/include/asm-alpha/namei.h +++ b/include/asm-alpha/namei.h @@ -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 --git a/include/asm-alpha/processor.h b/include/asm-alpha/processor.h index 93bc9e31a..17674b56d 100644 --- a/include/asm-alpha/processor.h +++ b/include/asm-alpha/processor.h @@ -43,6 +43,7 @@ struct thread_struct { /* 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 --git a/include/asm-i386/bugs.h b/include/asm-i386/bugs.h index 1f7b33910..a19ff035e 100644 --- a/include/asm-i386/bugs.h +++ b/include/asm-i386/bugs.h @@ -35,7 +35,7 @@ static void copro_timeout(void) fpu_error = 1; timer_table[COPRO_TIMER].expires = jiffies+100; timer_active |= 1<<COPRO_TIMER; - printk("387 failed: trying to reset\n"); + printk(KERN_ERR "387 failed: trying to reset\n"); send_sig(SIGFPE, last_task_used_math, 1); outb_p(0,0xf1); outb_p(0,0xf0); @@ -49,8 +49,8 @@ static void check_fpu(void) if (!hard_math) { #ifndef CONFIG_MATH_EMULATION - printk("No coprocessor found and no math emulation present.\n"); - printk("Giving up.\n"); + printk(KERN_EMERG "No coprocessor found and no math emulation present.\n"); + printk(KERN_EMERG "Giving up.\n"); for (;;) ; #endif return; @@ -64,7 +64,7 @@ static void check_fpu(void) * So the irq13 will happen eventually, but the exception 16 * should get there first.. */ - printk("Checking 386/387 coupling... "); + printk(KERN_INFO "Checking 386/387 coupling... "); timer_table[COPRO_TIMER].expires = jiffies+50; timer_table[COPRO_TIMER].fn = copro_timeout; timer_active |= 1<<COPRO_TIMER; @@ -101,7 +101,7 @@ static void check_fpu(void) static void check_hlt(void) { - printk("Checking 'hlt' instruction... "); + printk(KERN_INFO "Checking 'hlt' instruction... "); if (!hlt_works_ok) { printk("disabled\n"); return; @@ -118,7 +118,7 @@ static void check_tlb(void) * They will fault when they hit an invlpg instruction. */ if (x86 == 3) { - printk("CPU is a 386 and this kernel was compiled for 486 or better.\n"); + printk(KERN_EMERG "CPU is a 386 and this kernel was compiled for 486 or better.\n"); printk("Giving up.\n"); for (;;) ; } diff --git a/include/asm-i386/byteorder.h b/include/asm-i386/byteorder.h index 7dff2a869..ef55ae3ca 100644 --- a/include/asm-i386/byteorder.h +++ b/include/asm-i386/byteorder.h @@ -17,21 +17,6 @@ /* For avoiding bswap on i386 */ #ifdef __KERNEL__ #include <linux/config.h> - -/* - * In-kernel byte order macros to handle stuff like - * byte-order-dependent filesystems etc. - */ -#define cpu_to_le32(x) (x) -#define le32_to_cpu(x) (x) -#define cpu_to_le16(x) (x) -#define le16_to_cpu(x) (x) - -#define cpu_to_be32(x) htonl((x)) -#define be32_to_cpu(x) ntohl((x)) -#define cpu_to_be16(x) htons((x)) -#define be16_to_cpu(x) ntohs((x)) - #endif extern unsigned long int ntohl(unsigned long int); @@ -102,4 +87,68 @@ __ntohs(unsigned short int 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 --git a/include/asm-i386/keyboard.h b/include/asm-i386/keyboard.h index 180d747e5..2ea9ce385 100644 --- a/include/asm-i386/keyboard.h +++ b/include/asm-i386/keyboard.h @@ -18,10 +18,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 --git a/include/asm-i386/namei.h b/include/asm-i386/namei.h index c0dc3b3f8..981627be7 100644 --- a/include/asm-i386/namei.h +++ b/include/asm-i386/namei.h @@ -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 --git a/include/asm-m68k/byteorder.h b/include/asm-m68k/byteorder.h index cbc560777..a5f0ce8bb 100644 --- a/include/asm-m68k/byteorder.h +++ b/include/asm-m68k/byteorder.h @@ -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 @@ extern __inline__ __u32 __swab32 (__u32 val) 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 --git a/include/asm-m68k/entry.h b/include/asm-m68k/entry.h new file mode 100644 index 000000000..6f907936a --- /dev/null +++ b/include/asm-m68k/entry.h @@ -0,0 +1,176 @@ +#ifndef __M68K_ENTRY_H +#define __M68K_ENTRY_H + +#include <linux/config.h> +#include <asm/setup.h> +#ifdef CONFIG_KGDB +#include <asm/kgdb.h> +#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 --git a/include/asm-m68k/namei.h b/include/asm-m68k/namei.h index 13502e13e..4ecdd7ca7 100644 --- a/include/asm-m68k/namei.h +++ b/include/asm-m68k/namei.h @@ -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 --git a/include/asm-m68k/semaphore.h b/include/asm-m68k/semaphore.h index 7890c4f19..50aabc1c8 100644 --- a/include/asm-m68k/semaphore.h +++ b/include/asm-m68k/semaphore.h @@ -20,8 +20,8 @@ struct semaphore { 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 @@ static inline int waking_non_zero(struct semaphore *sem) * "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 @@ extern inline void do_down(struct semaphore * sem, void (*failed)(void)) ".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 @@ extern inline void up(struct semaphore * sem) ".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 --git a/include/asm-mips/byteorder.h b/include/asm-mips/byteorder.h index 92e3b8863..1263d9fe7 100644 --- a/include/asm-mips/byteorder.h +++ b/include/asm-mips/byteorder.h @@ -6,6 +6,8 @@ * for more details. * * Copyright (C) 1995, 1996, 1997 by Ralf Baechle + * + * $Id:$ */ #ifndef __ASM_MIPS_BYTEORDER_H #define __ASM_MIPS_BYTEORDER_H @@ -94,6 +96,60 @@ extern unsigned long int htonl(unsigned long int __x); #error "MIPS but neither __MIPSEL__ nor __MIPSEB__?" #endif +/* 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); +} + +#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) + + +/* 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); +} + +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); +} + +#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) + + extern __inline__ unsigned long int ntohl(unsigned long int __x) { return __constant_ntohl(__x); diff --git a/include/asm-mips/namei.h b/include/asm-mips/namei.h index 8f3267eda..0ff96ac00 100644 --- a/include/asm-mips/namei.h +++ b/include/asm-mips/namei.h @@ -11,55 +11,43 @@ #ifdef CONFIG_BINFMT_IRIX /* Only one at this time. */ -#define IRIX32_EMUL "/usr/gnemul/irix" +#define IRIX32_EMUL "usr/gnemul/irix/" -#define translate_namei(pathname, base, follow_links, res_inode) ({ \ - if ((current->personality == PER_IRIX32) && !base && *pathname == '/') { \ - struct inode *emul_ino; \ - int namelen; \ - const char *name; \ - \ - while (*pathname == '/') \ - pathname++; \ - current->fs->root->i_count++; \ - if (dir_namei (IRIX32_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++; \ - } \ -}) +extern int __namei(int, const char *, struct inode *, char *, struct inode **, + struct inode **, struct qstr *, struct dentry **, int *); -#define translate_open_namei(pathname, flag, mode, res_inode, base) ({ \ - if ((current->personality == PER_IRIX32) && !base && *pathname == '/') { \ - struct inode *emul_ino; \ - int namelen; \ - const char *name; \ - \ - while (*pathname == '/') \ - pathname++; \ - current->fs->root->i_count++; \ - if (dir_namei (IRIX32_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++; \ - } \ -}) +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; -#else /* !defined(CONFIG_BINFMT_IRIX) */ + if (current->personality != PER_IRIX32) + return -EINVAL; + + while (*name == '/') + name++; + + atomic_inc(¤t->fs->root->i_count); + error = __namei(NAM_FOLLOW_LINK, IRIX32_EMUL, current->fs->root, + buf, NULL, &base, NULL, NULL, NULL); + if (error) + return error; -#define translate_namei(pathname, base, follow_links, res_inode) \ - do { } while (0) + error = __namei(retrieve_mode, name, base, buf, res_dir, res_inode, + last_name, last_entry, last_error); + if (error) + return error; + + return 0; +} + +#else /* !defined(CONFIG_BINFMT_IRIX) */ -#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 /* !defined(CONFIG_BINFMT_IRIX) */ diff --git a/include/asm-ppc/byteorder.h b/include/asm-ppc/byteorder.h index 0c771b2f4..bbb257941 100644 --- a/include/asm-ppc/byteorder.h +++ b/include/asm-ppc/byteorder.h @@ -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); } +extern __inline__ __u32 cpu_to_le32(__u32 value) +{ + 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_le16(x) le16_to_cpu((x)) -extern __inline__ unsigned short le16_to_cpu(unsigned short x) +/* The same, but returns converted value from the location pointer by addr. */ +extern __inline__ __u16 cpu_to_le16p(__u16 *addr) { - return (((x & 0x00ff) << 8) | - ((x & 0xff00) >> 8)); + return cpu_to_le16(*addr); } -#define cpu_to_be32(x) (x) -#define be32_to_cpu(x) (x) -#define cpu_to_be16(x) (x) -#define be16_to_cpu(x) (x) +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); +} -#endif /* !(_PPC_BYTEORDER_H) */ +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 --git a/include/asm-ppc/keyboard.h b/include/asm-ppc/keyboard.h index 6cd1391de..418476b2d 100644 --- a/include/asm-ppc/keyboard.h +++ b/include/asm-ppc/keyboard.h @@ -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 --git a/include/asm-sparc/byteorder.h b/include/asm-sparc/byteorder.h index 758324f39..5becb7c5d 100644 --- a/include/asm-sparc/byteorder.h +++ b/include/asm-sparc/byteorder.h @@ -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 @@ extern __inline__ __u32 cpu_to_le32(__u32 value) #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); } -#define be16_to_cpu(x) (x) -#define be32_to_cpu(x) (x) + +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__ */ diff --git a/include/asm-sparc/namei.h b/include/asm-sparc/namei.h index b71537565..e74a76bce 100644 --- a/include/asm-sparc/namei.h +++ b/include/asm-sparc/namei.h @@ -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 --git a/include/asm-sparc/spinlock.h b/include/asm-sparc/spinlock.h index eb612dca4..c38b6af50 100644 --- a/include/asm-sparc/spinlock.h +++ b/include/asm-sparc/spinlock.h @@ -56,7 +56,7 @@ typedef struct { } rwlock_t; #include <asm/psr.h> /* 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 --git a/include/asm-sparc64/bitops.h b/include/asm-sparc64/bitops.h index b76772016..5060d88ae 100644 --- a/include/asm-sparc64/bitops.h +++ b/include/asm-sparc64/bitops.h @@ -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 @@ extern __inline__ unsigned long ffz(unsigned long word) : "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 ffz(unsigned long word) 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 @@ extern __inline__ unsigned long __swab64(unsigned long value) ((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 @@ extern __inline__ unsigned long find_next_zero_le_bit(void *addr, unsigned long 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 @@ extern __inline__ unsigned long find_next_zero_le_bit(void *addr, unsigned long 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 --git a/include/asm-sparc64/byteorder.h b/include/asm-sparc64/byteorder.h index 21f4b0ba0..2325ef29c 100644 --- a/include/asm-sparc64/byteorder.h +++ b/include/asm-sparc64/byteorder.h @@ -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 <asm/asi.h> + #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 @@ extern __inline__ __u32 cpu_to_le32(__u32 value) 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; +} +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 be16_to_cpu(x) (x) -#define be32_to_cpu(x) (x) +#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 --git a/include/asm-sparc64/checksum.h b/include/asm-sparc64/checksum.h index 63dbfec3d..d04abac7e 100644 --- a/include/asm-sparc64/checksum.h +++ b/include/asm-sparc64/checksum.h @@ -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 @@ extern unsigned int csum_partial(unsigned char * buff, int len, unsigned int sum #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 @@ csum_partial_copy_nocheck (const char *src, char *dst, int len, 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 @@ extern __inline__ unsigned int 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 --git a/include/asm-sparc64/fpumacro.h b/include/asm-sparc64/fpumacro.h index 9928a38c2..f6323254d 100644 --- a/include/asm-sparc64/fpumacro.h +++ b/include/asm-sparc64/fpumacro.h @@ -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 @@ extern __inline__ void fpsave32(unsigned long *fpregs, unsigned long *fsr) " : : "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 @@ extern __inline__ void fpload32(unsigned long *fpregs, unsigned long *fsr) " : : "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 @@ extern __inline__ void fpsave(unsigned long *fpregs, unsigned long *fsr) " : : "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 --git a/include/asm-sparc64/head.h b/include/asm-sparc64/head.h index 7127ca74c..62fe9a08f 100644 --- a/include/asm-sparc64/head.h +++ b/include/asm-sparc64/head.h @@ -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 --git a/include/asm-sparc64/namei.h b/include/asm-sparc64/namei.h index f8fdbb533..af5afb721 100644 --- a/include/asm-sparc64/namei.h +++ b/include/asm-sparc64/namei.h @@ -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 --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h index a739cea5e..e56a4024d 100644 --- a/include/asm-sparc64/pgtable.h +++ b/include/asm-sparc64/pgtable.h @@ -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 @@ extern void *sparc_init_alloc(unsigned long *kbrk, unsigned long size); /* 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 @@ extern __inline__ void flush_tlb_mm(struct mm_struct *mm) 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 @@ extern __inline__ void flush_tlb_range(struct mm_struct *mm, unsigned long start { 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 @@ extern __inline__ void flush_tlb_page(struct vm_area_struct *vma, unsigned long 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 --git a/include/asm-sparc64/psrcompat.h b/include/asm-sparc64/psrcompat.h index dccc4f69a..b971514d6 100644 --- a/include/asm-sparc64/psrcompat.h +++ b/include/asm-sparc64/psrcompat.h @@ -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 @@ extern inline unsigned long psr_to_tstate_icc(unsigned int psr) { unsigned long tstate; - tstate = (psr & PSR_ICC) << 12; + tstate = ((unsigned long)(psr & PSR_ICC)) << 12; return tstate; } diff --git a/include/asm-sparc64/pstate.h b/include/asm-sparc64/pstate.h index 490d837a8..2233ee7f0 100644 --- a/include/asm-sparc64/pstate.h +++ b/include/asm-sparc64/pstate.h @@ -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 @@ -79,4 +79,32 @@ #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 --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h index 786cfd2af..d0d88fa5c 100644 --- a/include/asm-sparc64/system.h +++ b/include/asm-sparc64/system.h @@ -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 @@ extern __inline__ void flushw_user(void) #define flush_user_windows flushw_user #ifdef __SMP__ -#error SMP not supported on sparc64 + +#include <asm/fpumacro.h> + +#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 @@ extern __inline__ void flushw_user(void) 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 --git a/include/asm-sparc64/uaccess.h b/include/asm-sparc64/uaccess.h index 93320f335..40ad3ee21 100644 --- a/include/asm-sparc64/uaccess.h +++ b/include/asm-sparc64/uaccess.h @@ -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 @@ __asm__ __volatile__( \ " 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 @@ __asm__ __volatile__( \ "/* 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 @@ __asm__ __volatile( \ " 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 @@ __asm__ __volatile__( \ " 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 @@ __asm__ __volatile__( \ "/* 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 @@ __asm__ __volatile__( \ " 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 @@ extern __inline__ __kernel_size_t __clear_user(void *addr, __kernel_size_t size) __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 --git a/include/asm-sparc64/vuid_event.h b/include/asm-sparc64/vuid_event.h index 0c5977fab..9ef4d17ad 100644 --- a/include/asm-sparc64/vuid_event.h +++ b/include/asm-sparc64/vuid_event.h @@ -5,8 +5,6 @@ typedef struct firm_event { 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 --git a/include/linux/affs_fs.h b/include/linux/affs_fs.h index fc7c46dc8..cfb891c4e 100644 --- a/include/linux/affs_fs.h +++ b/include/linux/affs_fs.h @@ -69,8 +69,7 @@ extern int affs_link(struct inode *oldinode, struct inode *dir, 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 --git a/include/linux/atalk.h b/include/linux/atalk.h index 2e4de841c..70e691251 100644 --- a/include/linux/atalk.h +++ b/include/linux/atalk.h @@ -17,6 +17,8 @@ #define ATADDR_BCAST (__u8)255 #define DDP_MAXSZ 587 +#define SIOCATALKDIFADDR (SIOCPROTOPRIVATE + 0) + struct at_addr { __u16 s_net; diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index a96e034ce..eb91dd0fa 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -54,6 +54,7 @@ extern int init_aout_binfmt(void); 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 --git a/drivers/char/console_struct.h b/include/linux/console_struct.h index a73836ad4..e9ef418f7 100644 --- a/drivers/char/console_struct.h +++ b/include/linux/console_struct.h @@ -49,6 +49,7 @@ struct vc_data { /* 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; diff --git a/drivers/char/consolemap.h b/include/linux/consolemap.h index 9aba19db3..9aba19db3 100644 --- a/drivers/char/consolemap.h +++ b/include/linux/consolemap.h diff --git a/include/linux/dalloc.h b/include/linux/dalloc.h new file mode 100644 index 000000000..659eef522 --- /dev/null +++ b/include/linux/dalloc.h @@ -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, + * <schoebel@informatik.uni-stuttgart.de>. + */ + +#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 --git a/include/linux/dlists.h b/include/linux/dlists.h new file mode 100644 index 000000000..f92485e40 --- /dev/null +++ b/include/linux/dlists.h @@ -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, + * <schoebel@informatik.uni-stuttgart.de>. + */ + +/* 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 --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h index b5f2b5f15..9c66cfc29 100644 --- a/include/linux/ext2_fs.h +++ b/include/linux/ext2_fs.h @@ -502,7 +502,7 @@ extern int ext2_symlink (struct inode *, const char *, int, const char *); 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 --git a/include/linux/fs.h b/include/linux/fs.h index 1918471ab..76fa53a7e 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -15,6 +15,12 @@ #include <linux/net.h> #include <linux/kdev_t.h> #include <linux/ioctl.h> +#include <asm/atomic.h> + +/* 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 @@ extern int max_files, nr_files; #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 @@ extern int max_files, nr_files; #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 @@ struct iattr { #include <linux/quota.h> 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 @@ extern int fasync_helper(struct inode *, struct file *, int, struct fasync_struc #include <linux/romfs_fs_sb.h> 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 @@ struct inode_operations { 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 dquot_operations { }; 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 int fsync_dev(kdev_t dev); 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 @@ extern int open_namei(const char * pathname, int flag, int mode, 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 <asm/semaphore.h> + +/* 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 int generic_file_mmap(struct inode *, struct file *, struct vm_area_struc 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 dcache_lookup(struct inode *, const char *, int, unsigned long *); 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 --git a/drivers/char/diacr.h b/include/linux/kbd_diacr.h index 1c1a3ff05..1c1a3ff05 100644 --- a/drivers/char/diacr.h +++ b/include/linux/kbd_diacr.h diff --git a/drivers/char/kbd_kern.h b/include/linux/kbd_kern.h index 2d7dc1b7e..2d7dc1b7e 100644 --- a/drivers/char/kbd_kern.h +++ b/include/linux/kbd_kern.h diff --git a/include/linux/kbd_ll.h b/include/linux/kbd_ll.h new file mode 100644 index 000000000..d83f9ea8a --- /dev/null +++ b/include/linux/kbd_ll.h @@ -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 --git a/include/linux/linkage.h b/include/linux/linkage.h index 462a90808..148eaad22 100644 --- a/include/linux/linkage.h +++ b/include/linux/linkage.h @@ -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 --git a/include/linux/minix_fs.h b/include/linux/minix_fs.h index 3bc020fcd..069686fff 100644 --- a/include/linux/minix_fs.h +++ b/include/linux/minix_fs.h @@ -100,7 +100,7 @@ extern int minix_symlink(struct inode * inode, const char * name, int len, 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 --git a/include/linux/mm.h b/include/linux/mm.h index 6ebf15a55..c8b9046a7 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -124,7 +124,7 @@ typedef struct page { 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 @@ typedef struct page { #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 @@ typedef struct page { #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 --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h index d7f46b1d8..36ed2a890 100644 --- a/include/linux/msdos_fs.h +++ b/include/linux/msdos_fs.h @@ -261,8 +261,7 @@ extern int msdos_mkdir(struct inode *dir,const char *name,int len,int mode); 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_unlink(struct inode *dir,const char *name,int len); 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 --git a/include/linux/nametrans.h b/include/linux/nametrans.h new file mode 100644 index 000000000..838e5a7f8 --- /dev/null +++ b/include/linux/nametrans.h @@ -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, + * <schoebel@informatik.uni-stuttgart.de>. + */ + +#include <linux/dalloc.h> +#include <linux/sysctl.h> + +#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 --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h index 320a2816c..489762a36 100644 --- a/include/linux/nfsd/nfsfh.h +++ b/include/linux/nfsd/nfsfh.h @@ -151,7 +151,7 @@ __fh_put(struct svc_fh *fhp, char *file, int line) 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 --git a/include/linux/omirr.h b/include/linux/omirr.h new file mode 100644 index 000000000..379867423 --- /dev/null +++ b/include/linux/omirr.h @@ -0,0 +1,17 @@ +/* + * fs/proc/omirr.c - online mirror support + * + * (C) 1997 Thomas Schoebel-Theuer + */ + +#ifndef OMIRR_H +#define OMIRR_H +#include <linux/fs.h> +#include <linux/dalloc.h> + +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 --git a/include/linux/pci.h b/include/linux/pci.h index 10c0f76b7..b13929d6a 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -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 --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index acc7c8f24..b0e33a0c6 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -48,8 +48,10 @@ enum root_directory_inos { 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 @@ enum net_directory_inos { 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 }; @@ -354,6 +361,11 @@ extern struct inode_operations proc_fd_inode_operations; #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 --git a/include/linux/sched.h b/include/linux/sched.h index 215774036..189194a49 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -500,13 +500,8 @@ extern inline struct file *file_from_fd(const unsigned int fd) */ 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 --git a/drivers/char/selection.h b/include/linux/selection.h index 4ed656ff9..94d3d9a8e 100644 --- a/drivers/char/selection.h +++ b/include/linux/selection.h @@ -73,8 +73,6 @@ extern void putconsxy(int currcons, char *p); /* how to access screen memory */ -#include <linux/config.h> - #if defined(CONFIG_TGA_CONSOLE) extern int tga_blitc(unsigned int, unsigned long); @@ -113,7 +111,7 @@ static inline unsigned short scr_readw(unsigned short * addr) #elif defined (CONFIG_SGI) -#include "vt_kern.h" +#include <linux/vt_kern.h> #include <linux/kd.h> extern void newport_blitc(unsigned short, unsigned long); extern void memsetw(void * s, unsigned short c, unsigned int count); diff --git a/include/linux/socket.h b/include/linux/socket.h index 6d0ed9158..96ec54d1d 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -128,7 +128,7 @@ struct ucred #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 */ @@ -148,7 +148,7 @@ struct ucred #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 --git a/include/linux/swap.h b/include/linux/swap.h index b0bdc40b6..56fef7a21 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -66,8 +66,7 @@ extern void swap_in(struct task_struct *, struct vm_area_struct *, /* 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 @@ extern void swap_free(unsigned long); #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_total; 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 --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 1840a6fbe..2ec41aa05 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -68,6 +68,8 @@ enum 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 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 @@ enum NET_ROSE, NET_X25, NET_TR, + NET_DECNET }; @@ -110,6 +112,7 @@ enum NET_CORE_RMEM_MAX, NET_CORE_WMEM_DEFAULT, NET_CORE_RMEM_DEFAULT, + NET_CORE_DESTROY_DELAY, }; /* /proc/sys/net/ethernet */ @@ -118,12 +121,19 @@ enum /* /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 @@ enum 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 @@ enum { /* /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 @@ enum 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 @@ extern int proc_dointvec(ctl_table *, int, struct file *, 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 --git a/include/linux/sysrq.h b/include/linux/sysrq.h new file mode 100644 index 000000000..8cfd21b0e --- /dev/null +++ b/include/linux/sysrq.h @@ -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 <mj@atrey.karlin.mff.cuni.cz> + */ + +#include <linux/config.h> + +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 --git a/include/linux/sysv_fs.h b/include/linux/sysv_fs.h index 7b19dac3c..e68f5d5f1 100644 --- a/include/linux/sysv_fs.h +++ b/include/linux/sysv_fs.h @@ -373,7 +373,7 @@ extern int sysv_symlink(struct inode * inode, const char * name, int len, 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 --git a/include/linux/umsdos_fs.p b/include/linux/umsdos_fs.p index 333f9940f..f271694c5 100644 --- a/include/linux/umsdos_fs.p +++ b/include/linux/umsdos_fs.p @@ -122,8 +122,7 @@ int UMSDOS_rename (struct inode *old_dir, 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 --git a/drivers/char/vt_kern.h b/include/linux/vt_kern.h index 1692f991c..1692f991c 100644 --- a/drivers/char/vt_kern.h +++ b/include/linux/vt_kern.h diff --git a/include/linux/wrapper.h b/include/linux/wrapper.h index 13de8d4ae..750b97084 100644 --- a/include/linux/wrapper.h +++ b/include/linux/wrapper.h @@ -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 --git a/include/net/checksum.h b/include/net/checksum.h index 2fb596b13..19dea08ea 100644 --- a/include/net/checksum.h +++ b/include/net/checksum.h @@ -26,6 +26,7 @@ #ifndef _CHECKSUM_H #define _CHECKSUM_H +#include <asm/types.h> #include <asm/byteorder.h> #include <net/ip.h> #include <asm/checksum.h> diff --git a/include/net/sock.h b/include/net/sock.h index a25907b19..a6035bd57 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -70,6 +70,10 @@ #include <linux/atalk.h> #endif +#if defined(CONFIG_DECNET) || defined(CONFIG_DECNET_MODULE) +#include <net/dn.h> +#endif + #include <linux/igmp.h> #include <asm/atomic.h> @@ -447,6 +451,7 @@ struct sock 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 @@ struct sock rose_cb *rose; #endif #endif +#if defined(CONFIG_DECNET) || defined(CONFIG_DECNET_MODULE) + dn_cb *dn; +#endif } protinfo; /* @@ -523,6 +531,7 @@ struct sock int (*backlog_rcv) (struct sock *sk, struct sk_buff *skb); + void (*destruct)(struct sock *sk); }; /* diff --git a/init/main.c b/init/main.c index fb7653141..a0d15926e 100644 --- a/init/main.c +++ b/init/main.c @@ -32,6 +32,7 @@ #include <linux/slab.h> #include <linux/major.h> #include <linux/blk.h> +#include <linux/nametrans.h> #include <linux/init.h> #ifdef CONFIG_ROOT_NFS #include <linux/nfs_fs.h> @@ -75,6 +76,7 @@ extern unsigned long pci_init(unsigned long, unsigned long); 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); @@ -87,6 +89,9 @@ extern void msmouse_setup(char *str, int *ints); 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); @@ -335,6 +340,9 @@ struct { #ifdef CONFIG_INET { "ether=", eth_setup }, #endif +#ifdef CONFIG_DECNET + { "decnet=", decnet_setup }, +#endif #ifdef CONFIG_PRINTER { "lp=", lp_setup }, #endif @@ -562,6 +570,12 @@ __initfunc(static int checksetup(char *line)) 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)) { @@ -901,6 +915,7 @@ __initfunc(asmlinkage void start_kernel(void)) proc_root_init(); #endif uidcache_init(); + filescache_init(); vma_init(); buffer_init(); inode_init(); diff --git a/kernel/exit.c b/kernel/exit.c index 88e012ba3..f6e8fb9b1 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -19,6 +19,7 @@ #include <linux/smp.h> #include <linux/smp_lock.h> #include <linux/module.h> +#include <linux/slab.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -367,14 +368,18 @@ static inline void close_files(struct files_struct * files) 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; @@ -383,7 +388,7 @@ static inline void __exit_files(struct task_struct *tsk) tsk->files = NULL; if (!--files->count) { close_files(files); - kfree(files); + kmem_cache_free(files_cachep, files); } } } diff --git a/kernel/fork.c b/kernel/fork.c index 804e37bd5..c3bcf7cca 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -11,6 +11,7 @@ * management can be a bitch. See 'mm/mm.c': 'copy_page_tables()' */ +#include <linux/init.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -36,6 +37,9 @@ int last_pid=0; /* 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 @@ static struct uid_taskcount { 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 @@ int charge_uid(struct task_struct *p, int count) return 0; } -void uidcache_init(void) +__initfunc(void uidcache_init(void)) { int i; @@ -148,8 +155,10 @@ static inline int find_empty_process(void) 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 @@ static inline int dup_mmap(struct mm_struct * mm) 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 @@ static inline int copy_fs(unsigned long clone_flags, struct task_struct * tsk) 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 @@ static inline int copy_files(unsigned long clone_flags, struct task_struct * tsk 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; @@ -470,3 +499,21 @@ 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 --git a/kernel/ksyms.c b/kernel/ksyms.c index ec0be876f..8e5607e1e 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -142,9 +142,8 @@ EXPORT_SYMBOL(getname); 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(ll_rw_block); 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_string); 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(read_exec); 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(chrdev_inode_operations); 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 --git a/kernel/panic.c b/kernel/panic.c index c5482bffe..c08b67aab 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -16,6 +16,7 @@ #include <linux/smp.h> #include <linux/reboot.h> #include <linux/init.h> +#include <linux/sysrq.h> #include <asm/sgialib.h> @@ -73,6 +74,8 @@ NORET_TYPE void panic(const char * fmt, ...) printk("Press L1-A to return to the boot prom\n"); #endif sti(); - for(;;); + for(;;) { + CHECK_EMERGENCY_SYNC + } } diff --git a/kernel/sched.c b/kernel/sched.c index 9f32305ee..94662ddb3 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -140,6 +140,7 @@ static inline void move_last_runqueue(struct task_struct * p) prev->next_run = p; } +#ifdef __SMP__ /* * The tasklist_lock protects the linked list of processes. * @@ -154,6 +155,7 @@ static inline void move_last_runqueue(struct task_struct * p) 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 --git a/kernel/sys.c b/kernel/sys.c index 311527865..ca3d17807 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -4,6 +4,7 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ +#include <linux/config.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -20,6 +21,7 @@ #include <linux/fcntl.h> #include <linux/acct.h> #include <linux/tty.h> +#include <linux/nametrans.h> #include <linux/smp.h> #include <linux/smp_lock.h> #include <linux/notifier.h> @@ -397,6 +399,7 @@ int acct_process(long exitcode) 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 @@ asmlinkage int sys_sethostname(char *name, int len) 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 @@ asmlinkage int sys_setdomainname(char *name, int len) 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 --git a/kernel/sysctl.c b/kernel/sysctl.c index 3f2e86a6b..e4bdcfc1a 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -16,6 +16,7 @@ #include <linux/mm.h> #include <linux/sysctl.h> #include <linux/swapctl.h> +#include <linux/nametrans.h> #include <linux/proc_fs.h> #include <linux/malloc.h> #include <linux/stat.h> @@ -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 @@ struct inode_operations proc_sys_inode_operations = NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -114,6 +112,7 @@ struct inode_operations proc_sys_inode_operations = 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 @@ static ctl_table kern_table[] = { 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 @@ static ctl_table kern_table[] = { {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 kern_table[] = { 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 @@ int proc_dostring(ctl_table *table, int write, struct file *filp, 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 @@ int proc_dointvec(ctl_table *table, int write, struct file *filp, } 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 @@ int proc_dointvec(ctl_table *table, int write, struct file *filp, 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 @@ int proc_dointvec(ctl_table *table, int write, struct file *filp, 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 @@ int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp, 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 @@ int sysctl_string(ctl_table *table, int *name, int nlen, if (len == table->maxlen) len--; ((char *) table->data)[len] = 0; +#ifdef CONFIG_TRANS_NAMES + translations_dirty = 1; +#endif } return 0; } diff --git a/mm/filemap.c b/mm/filemap.c index 88c2fd49d..56aa1b486 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -921,6 +921,7 @@ static inline int do_write_page(struct inode * inode, struct file * file, 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; } @@ -1195,7 +1196,7 @@ int generic_file_mmap(struct inode * inode, struct file * file, struct vm_area_s inode->i_dirt = 1; } vma->vm_inode = inode; - inode->i_count++; + atomic_inc(&inode->i_count); vma->vm_ops = ops; return 0; } diff --git a/mm/memory.c b/mm/memory.c index 4bcf1a74e..81022e770 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -195,7 +195,7 @@ static inline void copy_one_pte(pte_t * old_pte, pte_t * new_pte, int cow) } 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 --git a/mm/mlock.c b/mm/mlock.c index 27bff13ff..5a69e4b55 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -39,7 +39,7 @@ static inline int mlock_fixup_start(struct vm_area_struct * vma, 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 @@ static inline int mlock_fixup_end(struct vm_area_struct * vma, 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 @@ static inline int mlock_fixup_middle(struct vm_area_struct * vma, 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); @@ -409,7 +409,7 @@ static void unmap_fixup(struct vm_area_struct *area, 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 @@ void merge_segments (struct mm_struct * mm, unsigned long start_addr, unsigned l } 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 --git a/mm/mprotect.c b/mm/mprotect.c index 7f5e26243..2e46ca142 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -111,7 +111,7 @@ static inline int mprotect_fixup_start(struct vm_area_struct * vma, 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 @@ static inline int mprotect_fixup_end(struct vm_area_struct * vma, 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 @@ static inline int mprotect_fixup_middle(struct vm_area_struct * vma, 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 --git a/mm/mremap.c b/mm/mremap.c index dfe826847..a52db58de 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -141,7 +141,7 @@ static inline unsigned long move_vma(struct vm_area_struct * vma, 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 --git a/mm/page_alloc.c b/mm/page_alloc.c index e32f1a92e..07264f81e 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -97,7 +97,9 @@ static inline void remove_mem_queue(struct page * entry) * * 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 @@ static inline void free_pages_ok(unsigned long map_nr, unsigned long order) 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 @@ void free_pages(unsigned long addr, unsigned long order) 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 @@ __initfunc(unsigned long free_area_init(unsigned long start_mem, unsigned long e 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 @@ void swap_in(struct task_struct * tsk, struct vm_area_struct * vma, } 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 --git a/mm/page_io.c b/mm/page_io.c index 6a16ccee8..30d0c882e 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -83,7 +83,9 @@ void rw_swap_page(int rw, unsigned long entry, char * buf, int wait) 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); @@ -769,6 +769,7 @@ kmem_cache_create(const char *name, size_t size, size_t offset, 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 @@ kmem_cache_create(const char *name, size_t size, size_t offset, 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 @@ opps2: 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 @@ __kmem_cache_free(kmem_cache_t *cachep, void *objp) 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 @@ passed_extra: 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 @@ extra_checks: } 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) { @@ -1713,24 +1710,49 @@ kmem_cache_reap(int pri, int dma, int wait) 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; @@ -1747,6 +1769,7 @@ kmem_cache_reap(int pri, int dma, int wait) 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, @@ -1756,9 +1779,14 @@ kmem_cache_reap(int pri, int dma, int wait) 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; @@ -1769,10 +1797,8 @@ kmem_cache_reap(int pri, int dma, int wait) * 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) { @@ -1797,8 +1823,21 @@ next: 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); @@ -1809,6 +1848,7 @@ next: kmem_slab_destroy(best_cachep, slabp); return 1; } +dma_fail: spin_unlock_irq(&best_cachep->c_spinlock); return 0; } diff --git a/mm/swap_state.c b/mm/swap_state.c index f3ffa46d5..e0cfe1fef 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -24,15 +24,6 @@ #include <asm/bitops.h> #include <asm/pgtable.h> -/* - * To save us from swapping out pages which have just been swapped in and - * have not been modified since then, we keep in swap_cache[page>>PAGE_SHIFT] - * the swap entry which was last used to fill the page, or zero if the - * page does not currently correspond to a page in swap. PAGE_DIRTY makes - * this info useless. - */ -unsigned long *swap_cache; - #ifdef SWAP_CACHE_INFO unsigned long swap_cache_add_total = 0; unsigned long swap_cache_add_success = 0; @@ -50,7 +41,7 @@ void show_swap_cache_info(void) } #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,10 +49,9 @@ int add_to_swap_cache(unsigned long index, unsigned long entry) 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 @@ -70,18 +60,6 @@ int add_to_swap_cache(unsigned long index, unsigned long entry) 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) { struct swap_info_struct * p; diff --git a/mm/swapfile.c b/mm/swapfile.c index 32a5ed8b0..819ae7aa8 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -176,14 +176,16 @@ static inline int unuse_pte(struct vm_area_struct * vma, unsigned long address, 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 @@ asmlinkage int sys_swapoff(const char * specialfile) 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 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags) } 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 --git a/mm/vmscan.c b/mm/vmscan.c index 875f668ee..21c178159 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -87,7 +87,7 @@ static inline int try_to_swap_out(struct task_struct * tsk, struct vm_area_struc /* 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 @@ static inline int try_to_swap_out(struct task_struct * tsk, struct vm_area_struc 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 --git a/net/Config.in b/net/Config.in index 97441ad6c..4cd3619c3 100644 --- a/net/Config.in +++ b/net/Config.in @@ -42,6 +42,10 @@ if [ "$CONFIG_AX25" != "n" ]; then 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 --git a/net/Makefile b/net/Makefile index 9c45939cb..09924ff89 100644 --- a/net/Makefile +++ b/net/Makefile @@ -105,6 +105,14 @@ else 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 --git a/net/README b/net/README index 09327483c..a88ccfc5a 100644 --- a/net/README +++ b/net/README @@ -8,6 +8,7 @@ Code Section Bug Report Contact 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 --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c index 9ad9b8e93..f8a510e62 100644 --- a/net/appletalk/aarp.c +++ b/net/appletalk/aarp.c @@ -49,6 +49,12 @@ #include <linux/atalk.h> #include <linux/init.h> + +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 @@ static void aarp_kick(struct aarp_entry **n) { /* 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 @@ static void aarp_expire_timeout(unsigned long unused) } 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 @@ int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, vo 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 @@ int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, vo * 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 @@ int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, vo */ 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 @@ int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, vo 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 @@ static void aarp_resolved(struct aarp_entry **list, struct aarp_entry *a, int ha 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 @@ static int aarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type 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 @@ __initfunc(void aarp_proto_init(void)) 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 --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 4dbcc0a9c..de05f7047 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -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 @@ static void atif_drop_device(struct device *dev) 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 @@ static struct atalk_iface *atif_add_device(struct device *dev, struct at_addr *s iface->next=atalk_iface_list; atalk_iface_list=iface; restore_flags(flags); - MOD_INC_USE_COUNT; return iface; } @@ -399,9 +402,21 @@ struct at_addr *atalk_find_dev_addr(struct device *dev) 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 @@ int atif_ioctl(int cmd, void *arg) ((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 @@ static int atalk_create(struct socket *sock, int protocol) 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 @@ static int atalk_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg) case SIOCGIFADDR: case SIOCSIFADDR: case SIOCGIFBRDADDR: + case SIOCATALKDIFADDR: return atif_ioctl(cmd,(void *)arg); /* * Physical layer ioctl calls @@ -2056,6 +2083,10 @@ __initfunc(void atalk_proto_init(struct net_proto *pro)) 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 @@ extern inline void free_interface_list(void) while (list != NULL) { tmp = list->next; + list->dev->atalk_ptr = NULL; kfree_s(list, sizeof(struct atalk_iface)); list = tmp; } @@ -2112,6 +2144,10 @@ void cleanup_module(void) aarp_cleanup_module(); +#ifdef CONFIG_SYSCTL + atalk_unregister_sysctl(); +#endif + #ifdef CONFIG_PROC_FS proc_net_unregister(PROC_NET_ATALK); proc_net_unregister(PROC_NET_AT_ROUTE); diff --git a/net/appletalk/sysctl_net_atalk.c b/net/appletalk/sysctl_net_atalk.c index 307278992..6d5159ddc 100644 --- a/net/appletalk/sysctl_net_atalk.c +++ b/net/appletalk/sysctl_net_atalk.c @@ -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 <linux/mm.h> #include <linux/sysctl.h> -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 --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index fe5d4dca6..37b679600 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -148,6 +148,11 @@ void ax25_free_cb(ax25_cb *ax25) 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 @@ void ax25_destroy_socket(ax25_cb *ax25) /* Not static as it's used by the timer add_timer(&ax25->timer); } else { sk_free(ax25->sk); - ax25_free_cb(ax25); } } else { ax25_free_cb(ax25); @@ -858,7 +862,8 @@ int ax25_create(struct socket *sock, int protocol) } 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 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev) } 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 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev) 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 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le #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 --git a/net/core/dev.c b/net/core/dev.c index 07a5c1706..2b593cbb1 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1485,7 +1485,6 @@ int dev_ioctl(unsigned int cmd, void *arg) case SIOCGIFMTU: case SIOCGIFMEM: case SIOCGIFHWADDR: - case SIOCSIFHWADDR: case SIOCGIFSLAVE: case SIOCGIFMAP: case SIOGIFINDEX: @@ -1499,6 +1498,7 @@ int dev_ioctl(unsigned int cmd, void *arg) case SIOCSIFMETRIC: case SIOCSIFMTU: case SIOCSIFMEM: + case SIOCSIFHWADDR: case SIOCSIFMAP: case SIOCSIFSLAVE: case SIOCADDMULTI: diff --git a/net/core/sock.c b/net/core/sock.c index f28ea828e..37f73485c 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -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_rmem_max = SK_RMEM_MAX; __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 @@ struct sock *sk_alloc(int priority) void sk_free(struct sock *sk) { + if (sk->destruct) + sk->destruct(sk); + kmem_cache_free(sk_cachep, sk); } @@ -787,7 +794,7 @@ void sklist_destroy_socket(struct sock **list,struct sock *sk) * 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_callback3(struct sock *sk) } } +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 @@ void sock_init_data(struct socket *sock, struct sock *sk) 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 --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index fd770becd..c912e8b2e 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -13,6 +13,8 @@ extern __u32 sysctl_rmem_max; 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 @@ ctl_table core_table[] = { {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 --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index a3a126529..eb47c3dfe 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -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 @@ static __inline__ void kill_sk_later(struct sock *sk) 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 @@ static int inet_create(struct socket *sock, int protocol) } sock_init_data(sock,sk); - + sk->destruct = NULL; + sk->zapped=0; #ifdef CONFIG_TCP_NAGLE_OFF sk->nonagle = 1; diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index da0685340..c12417c52 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -81,7 +81,7 @@ static unsigned long ip_get_mask(unsigned long addr) * 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 --git a/net/ipv4/fib.c b/net/ipv4/fib.c index 7daab2e61..6dc90b0ab 100644 --- a/net/ipv4/fib.c +++ b/net/ipv4/fib.c @@ -1896,8 +1896,8 @@ static void ip_rt_add_broadcasts(struct device *dev, u32 brd, u32 mask) 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 @@ void ip_rt_change_dstaddr(struct device *dev, u32 dstaddr) { 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 @@ void ip_rt_change_netmask(struct device *dev, u32 mask) 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 @@ int ip_rt_event(int event, struct device *dev) 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 @@ int ip_rt_event(int event, struct device *dev) } 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 --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 2aaef74de..fbc5403fc 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -88,6 +88,9 @@ #include <linux/igmp.h> #include <net/checksum.h> +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 @@ static struct ip_router_info *igmp_get_mrouter_info(struct device *dev) 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 @@ static void igmp_start_timer(struct ip_mc_list *im,unsigned char max_resp_time) 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 @@ static void igmp_heard_query(struct device *dev, unsigned char max_resp_time, 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 @@ static void igmp_heard_query(struct device *dev, unsigned char max_resp_time, } } 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 --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 290f871a1..e4fe370fd 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -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 <waltje@uWalt.NL.Mugnet.ORG> * Alan Cox <Alan.Cox@linux.org> @@ -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 @@ static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph) 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 @@ struct sk_buff *ip_defrag(struct sk_buff *skb) 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 --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 1a38c5275..20246148a 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1031,7 +1031,7 @@ int ipmr_mfc_info(char *buffer, char **start, off_t offset, int length, int dumm } if(pos>offset+length) { - sti(); + end_bh_atomic(); goto done; } mfc=mfc->next; diff --git a/net/ipv4/packet.c b/net/ipv4/packet.c index b98b58f35..f69449e76 100644 --- a/net/ipv4/packet.c +++ b/net/ipv4/packet.c @@ -160,7 +160,7 @@ static int packet_sendmsg(struct sock *sk, struct msghdr *msg, int len) 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 @@ static int packet_sendmsg(struct sock *sk, struct msghdr *msg, int len) * 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 --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 18a8d2bf8..6d7ba591f 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -34,10 +34,17 @@ extern int sysctl_arp_timeout; 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_sack; 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 @@ ctl_table ipv4_table[] = { &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 @@ ctl_table ipv4_table[] = { {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 --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 000813b94..b43a972cc 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -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, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -431,6 +431,8 @@ #include <asm/uaccess.h> +int sysctl_tcp_fin_timeout = TCP_FIN_TIMEOUT; + unsigned long seq_offset; struct tcp_mib tcp_statistics; @@ -1385,7 +1387,7 @@ static int tcp_close_state(struct sock *sk, int dead) 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 @@ void tcp_close(struct sock *sk, unsigned long timeout) 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 --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 3ab1dee42..604bd1c84 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -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, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -56,13 +56,15 @@ static void tcp_cong_avoid_vanj(struct sock *sk, u32 seq, u32 ack, 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 @@ queue_and_out: /* 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 @@ queue_and_out: } /* 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 @@ static __inline__ void tcp_ack_snd_check(struct sock *sk) 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 --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index ce6c60feb..b4810e784 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -22,7 +22,11 @@ #include <net/tcp.h> -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 @@ static int tcp_write_timeout(struct sock *sk) /* 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 @@ static int tcp_write_timeout(struct sock *sk) } /* 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 @@ static int tcp_write_timeout(struct sock *sk) } /* 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 @@ void tcp_probe_timer(unsigned long data) { * 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 @@ static __inline__ int tcp_keepopen_proc(struct sock *sk) 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 @@ static __inline__ int tcp_keepopen_proc(struct sock *sk) */ #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 @@ static void tcp_keepalive(unsigned long data) 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 @@ static void tcp_syn_recv_timer(unsigned long data) 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 --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 1de20e358..3d23b6e86 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -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 @@ static int inet6_create(struct socket *sock, int protocol) sock_init_data(sock, sk); + sk->destruct = NULL; sk->zapped = 0; sk->family = AF_INET6; sk->protocol = protocol; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 3c61f7b50..4bf0207d9 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $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 @@ static void tcp_v6_send_synack(struct sock *sk, struct open_request *req) 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 @@ static void tcp_v6_send_synack(struct sock *sk, struct open_request *req) 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 --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index cfb47bb42..de3588e41 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -751,7 +751,7 @@ static int ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb) } #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 @@ static int ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb) 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 @@ static int ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb) 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 @@ static int ipx_create(struct socket *sock, int protocol) 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 --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index a6af49f15..22e1afbee 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -86,8 +86,6 @@ static struct proto_ops nr_proto_ops; static void nr_free_sock(struct sock *sk) { - kfree(sk->protinfo.nr); - sk_free(sk); MOD_DEC_USE_COUNT; diff --git a/net/netsyms.c b/net/netsyms.c index 9f13cabca..525f08689 100644 --- a/net/netsyms.c +++ b/net/netsyms.c @@ -326,6 +326,17 @@ EXPORT_SYMBOL(tty_register_ldisc); EXPORT_SYMBOL(kill_fasync); EXPORT_SYMBOL(ip_rcv); EXPORT_SYMBOL(arp_rcv); + +#if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) +#include<linux/if_ltalk.h> +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 --git a/net/protocols.c b/net/protocols.c index 24e67cde1..a0bb0a6b8 100644 --- a/net/protocols.c +++ b/net/protocols.c @@ -47,6 +47,10 @@ extern void inet6_proto_init(struct net_proto *pro); #endif #endif +#if defined(CONFIG_DECNET) +#include <net/decnet_call.h> +#endif + #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) #define NEED_802 #include <net/atalkcall.h> @@ -107,9 +111,11 @@ struct net_proto protocols[] = { { "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 --git a/net/rose/af_rose.c b/net/rose/af_rose.c index bd0ecd843..9896de9cb 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -136,8 +136,6 @@ int rosecmpm(rose_address *addr1, rose_address *addr2, unsigned short mask) static void rose_free_sock(struct sock *sk) { - kfree(sk->protinfo.rose); - sk_free(sk); MOD_DEC_USE_COUNT; diff --git a/net/socket.c b/net/socket.c index 482255255..2587083bc 100644 --- a/net/socket.c +++ b/net/socket.c @@ -212,7 +212,7 @@ static int get_fd(struct inode *inode) 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 @@ asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_ad int len; lock_kernel(); +restart: if ((sock = sockfd_lookup(fd, &err))!=NULL) { if (!(newsock = sock_alloc())) @@ -834,7 +835,13 @@ asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_ad 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 --git a/net/sysctl_net.c b/net/sysctl_net.c index eb23ea698..1acd01749 100644 --- a/net/sysctl_net.c +++ b/net/sysctl_net.c @@ -24,10 +24,6 @@ extern ctl_table ipv4_table[]; 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 @@ -59,9 +55,6 @@ ctl_table net_table[] = { #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}, #endif diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 80d91481e..1dfdf1832 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -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 @@ extern __inline__ void unix_release_addr(struct unix_address *addr) } } +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 @@ static void unix_destroy_timer(unsigned long data) 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 @@ static void unix_destroy_timer(unsigned long data) * 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_destroy_timer(unsigned long data) 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 @@ static void unix_destroy_socket(unix_socket *sk) 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 @@ static int unix_create(struct socket *sock, int protocol) 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 @@ static int unix_accept(struct socket *sock, struct socket *newsock, int flags) } 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 --git a/net/unix/sysctl_net_unix.c b/net/unix/sysctl_net_unix.c index 5af2df443..18ce57684 100644 --- a/net/unix/sysctl_net_unix.c +++ b/net/unix/sysctl_net_unix.c @@ -14,6 +14,15 @@ #include <linux/mm.h> #include <linux/sysctl.h> +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 --git a/net/wanrouter/wanproc.c b/net/wanrouter/wanproc.c index de207d319..04a49d803 100644 --- a/net/wanrouter/wanproc.c +++ b/net/wanrouter/wanproc.c @@ -121,7 +121,6 @@ static struct inode_operations router_inode = NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -160,7 +159,6 @@ static struct inode_operations wandev_inode = NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ - NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index c7cb33613..a77380648 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -341,7 +341,6 @@ void x25_destroy_socket(struct sock *sk) /* Not static as it's used by the timer sk->timer.data = (unsigned long)sk; add_timer(&sk->timer); } else { - kfree(sk->protinfo.x25); sk_free(sk); MOD_DEC_USE_COUNT; } diff --git a/scripts/Configure b/scripts/Configure index c774e32be..79a2ce28a 100644 --- a/scripts/Configure +++ b/scripts/Configure @@ -363,6 +363,28 @@ function hex () { } # +# 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 --git a/scripts/header.tk b/scripts/header.tk index 763eca6db..54637138a 100644 --- a/scripts/header.tk +++ b/scripts/header.tk @@ -209,6 +209,10 @@ proc read_config { filename } { 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_hex { file1 file2 varname variable dep } { } } +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] \ @@ -312,6 +326,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 } { frame $w.x$line menubutton $w.x$line.x -textvariable $variable -menu \ diff --git a/scripts/mkdep.c b/scripts/mkdep.c index 4afbd7381..2ac2e514c 100644 --- a/scripts/mkdep.c +++ b/scripts/mkdep.c @@ -6,7 +6,6 @@ #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> -#include <errno.h> #include <sys/fcntl.h> #include <sys/mman.h> diff --git a/scripts/tkcond.c b/scripts/tkcond.c index 9cc10fa4f..41b370f43 100644 --- a/scripts/tkcond.c +++ b/scripts/tkcond.c @@ -195,6 +195,7 @@ struct condition * get_token_cond(struct condition ** cond, int depth) 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 @@ void fix_conditionals(struct kconfig * scfg) case tok_tristate: case tok_int: case tok_hex: + case tok_string: case tok_choice: case tok_make: /* @@ -402,6 +404,7 @@ void fix_conditionals(struct kconfig * scfg) 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 @@ void fix_conditionals(struct kconfig * scfg) 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 --git a/scripts/tkgen.c b/scripts/tkgen.c index a3aea9055..15f8f7bfd 100644 --- a/scripts/tkgen.c +++ b/scripts/tkgen.c @@ -289,6 +289,7 @@ void generate_if(struct kconfig * item, 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 @@ void generate_if_for_outfile(struct kconfig * item, 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 @@ static void find_menu_size(struct kconfig *cfg, case tok_dep_tristate: case tok_int: case tok_hex: + case tok_string: case tok_choose: tot++; break; @@ -702,6 +708,7 @@ void dump_tk_script(struct kconfig *scfg) 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 @@ void dump_tk_script(struct kconfig *scfg) 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 @@ void dump_tk_script(struct kconfig *scfg) 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 @@ void dump_tk_script(struct kconfig *scfg) { case tok_int: case tok_hex: + case tok_string: case tok_bool: case tok_tristate: case tok_dep_tristate: @@ -1050,6 +1072,12 @@ void dump_tk_script(struct kconfig *scfg) cfg->optionname, cfg->optionname); } + else if (cfg->tok == tok_string ) + { + printf("\twrite_string $cfg $autocfg %s $%s $notmod\n", + cfg->optionname, + cfg->optionname); + } else if (cfg->tok == tok_make ) { printf("\tdo_make {%s}\n",cfg->value); diff --git a/scripts/tkparse.c b/scripts/tkparse.c index 2a000217c..98d1393ca 100644 --- a/scripts/tkparse.c +++ b/scripts/tkparse.c @@ -370,6 +370,11 @@ void parse(char * pnt) { 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 @@ void parse(char * pnt) { 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 @@ int main(int argc, char * argv[]) case tok_hex: printf("hex "); break; + case tok_string: + printf("istring "); + break; case tok_comment: printf("comment "); break; @@ -732,6 +741,7 @@ int main(int argc, char * argv[]) 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 --git a/scripts/tkparse.h b/scripts/tkparse.h index 911abdfbe..af7beac93 100644 --- a/scripts/tkparse.h +++ b/scripts/tkparse.h @@ -12,6 +12,7 @@ enum token { tok_fi, tok_int, tok_hex, + tok_string, tok_make, tok_define, tok_choose, |