diff -u --recursive --new-file v2.1.1/linux/CREDITS linux/CREDITS --- v2.1.1/linux/CREDITS Thu Sep 26 07:54:52 1996 +++ linux/CREDITS Mon Oct 7 07:45:16 1996 @@ -1088,13 +1088,12 @@ D: The Linux Support Team Erlangen N: Daniel Quinlan -E: Daniel.Quinlan@linux.org -W: http://www.bucknell.edu/~quinlan +E: quinlan@pathname.com +W: http://www.pathname.com/~quinlan/ D: FSSTND coordinator; FHS editor D: random Linux documentation, patches, and hacks -S: Box C-5083 -S: Bucknell University -S: Lewisburg, Pennsylvania 17837 +S: 4390 Albany Dr. #41A +S: San Jose, California 95129 S: USA N: Eric S. Raymond diff -u --recursive --new-file v2.1.1/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.1/linux/Documentation/Configure.help Thu Sep 12 08:27:33 1996 +++ linux/Documentation/Configure.help Sat Oct 5 12:14:25 1996 @@ -3,13 +3,12 @@ # This version of the Linux kernel configuration help texts # corresponds to the kernel versions 2.0.x. # -# International versions available on the WWW: -# - http://www.eis.or.jp/muse/kikutani/Configure.help-1.2.x.euc -# is a Japanese translation of a previous version of this file, -# written by kikutani@eis.or.jp. +# International versions of this file available on the WWW: +# - http://jf.gee.kyoto-u.ac.jp/JF/JF-ftp/euc/Configure.help.euc +# is a Japanese translation, maintained by Tetsuyasu YAMADA +# (tetsu@cauchy.nslab.ntt.jp). # - http://nevod.perm.su/service/linux/doc/kernel/Configure.help -# is a Russian translation of this file, maintained by -# kaf@linux.nevod.perm.su. +# is a Russian translation, maintained by kaf@linux.nevod.perm.su. # # Information about what a kernel is, what it does, how to patch and # compile it and much more is contained in the Kernel-HOWTO, available @@ -115,18 +114,15 @@ Loop device support CONFIG_BLK_DEV_LOOP - Enabling this option will allow you to mount a file as a file system. - This is useful if you want to check an ISO9660 file system before - burning the CD, or want to use floppy images without first writing - them to floppy. - This option also allows one to mount a filesystem with encryption. - To use these features, you need a recent version of mount, such as - the one found at ftp.win.tue.nl:/pub/linux/util/mount-2.5X.tar.gz. - If you want to use encryption, you might also be interested in the - (old) DES package ftp.funet.fi:/pub/OS/Linux/BETA/loop/des.1.tar.gz. - Note that this loop device has nothing to do with the loopback - device used for network connections from the machine to itself. - Most users will answer N here. + Enabling this option will allow you to mount a file as a file + system. This is useful if you want to check an ISO9660 file system + before burning the CD, or want to use floppy images without first + writing them to floppy. This option also allows one to mount a + filesystem with encryption. To use these features, you need a + recent version of mount (check the file Documentation/Changes for + location and latest version). Note that this loop device has + nothing to do with the loopback device used for network connections + from the machine to itself. Most users will answer N here. Enhanced IDE/MFM/RLL disk/cdrom/tape support CONFIG_BLK_DEV_IDE @@ -566,10 +562,9 @@ If your PCI system uses an IDE harddrive (as opposed to SCSI, say) and includes the Intel 430FX PCI Triton chipset, you will want to enable this option to allow use of bus-mastering DMA data transfers. - Read the comments at the beginning of drivers/block/triton.c. The - hdparm utility can be obtained via ftp (user: anonymous) from - sunsite.unc.edu:/pub/Linux/kernel/patches/diskdrives/. It is safe - to say Y. + Read the comments at the beginning of drivers/block/triton.c. Check + the file Documentation/Changes for location and latest version of + the hdparm utility. It is safe to say Y to this question. System V IPC CONFIG_SYSVIPC @@ -593,56 +588,55 @@ executables used across different architectures and operating systems. This option will enable your kernel to run ELF binaries and enlarge it by about 2kB. ELF support under Linux is quickly - replacing the traditional Linux a.out format because it is portable - (this does *not* mean that you will be able to run executables from - different architectures or operating systems!) and makes building - run-time libraries very easy. Many new executables are distributed - solely in ELF format. You definitely want to say Y here. Information - about ELF is on the WWW at + replacing the traditional Linux a.out formats (QMAGIC and ZMAGIC) + because it is portable (this does *not* mean that you will be able + to run executables from different architectures or operating + systems!) and makes building run-time libraries very easy. Many new + executables are distributed solely in ELF format. You definitely + want to say Y here. Information about ELF is on the WWW at http://www.sjc.ox.ac.uk/users/barlow/elf-howto.html (To browse the WWW, you need to have access to a machine on the Internet that has one of the programs lynx, netscape or Mosaic). If you find that after upgrading to Linux kernel 1.3 and saying Y here, you still can't run any ELF binaries (they just crash), then you'll have to - install the newest ELF runtime libraries, including ld.so (available - via ftp (user: anonymous) from - tsx-11.mit.edu:/pub/linux/packages/GCC). Also note that ELF binary - support was broken in kernel versions 1.3.0 - 1.3.2. Either use a - newer 1.3 kernel or one of the stable 1.2 versions. If you want to - compile this as a module ( = code which can be inserted in and - removed from the running kernel whenever you want), say M here and - read Documentation/modules.txt. Saying M or N here is dangerous - because some crucial programs on your system might be in ELF - format. + install the newest ELF runtime libraries, including ld.so (check the + file Documentation/Changes for location and latest version). If you + want to compile this as a module ( = code which can be inserted in + and removed from the running kernel whenever you want), say M here + and read Documentation/modules.txt. Saying M or N here is dangerous + because some crucial programs on your system might be in ELF format. Compile kernel as ELF - if your GCC is ELF-GCC CONFIG_KERNEL_ELF The gcc version 2.7.0 and newer produces the new ELF binary format - as default. If you have such a compiler (try "gcc -v"), say Y - here, otherwise N. + as default. If you have such a compiler (try "gcc -v"), say Y here, + otherwise N. It is possible, albeit almost pointless, to compile the kernel in - a.out format even if your compiler produces ELF as default. For - that, you would have to say N here and change the variables LD and - CC in the toplevel Makefile. Similarly, if your compiler produces - a.out by default but is able to produce ELF, you can compile the - kernel in ELF by saying Y here and editing the variables CC - and LD in the toplevel Makefile. + a.out (i.e. QMAGIC) format even if your compiler produces ELF as + default. For that, you would have to say N here and change the + variables LD and CC in the toplevel Makefile. Similarly, if your + compiler produces a.out by default but is able to produce ELF, you + can compile the kernel in ELF by saying Y here and editing the + variables CC and LD in the toplevel Makefile. Kernel support for A.OUT binaries CONFIG_BINFMT_AOUT - A.OUT (Assembler.OUTput) format is a format for libraries and - executables used in the earliest versions of UNIX. Linux used this - format until it was replaced with the ELF format. - As more and more programs are converted to ELF, the use for A.OUT + A.out (Assembler.OUTput) is a set of formats for libraries and + executables used in the earliest versions of UNIX. Linux used the + a.out formats QMAGIC and ZMAGIC until they were replaced with the + ELF format. + As more and more programs are converted to ELF, the use for a.out will gradually diminish. If you disable this option it will reduce your kernel by one page. This is not much and by itself does not - warrant removing support. However its removal is a good idea when - you wish to ensure that absolutely none of your programs will use - this older executable format. If you don't know what to answer at - this point then answer Y. You may answer M for module support and - later load the module when you find a program which needs a.out - format. Saying M or N here is dangerous, because some crucial - programs on your system might be in A.OUT format. + warrant removing support. However its removal is a good idea if you + wish to ensure that absolutely none of your programs will use this + older executable format. If you don't know what to answer at this + point then answer Y. If someone told you "You need a kernel with + QMAGIC support" then you'll have to say Y here. You may answer M + to compile a.out support as a module and later load the module when + you want to use a program or library in a.out format. Saying M or N + here is dangerous though, because some crucial programs on your + system might still be in A.OUT format. Kernel support for JAVA binaries CONFIG_BINFMT_JAVA @@ -664,7 +658,7 @@ warrant removing support. However its removal is a good idea if you do not have the JDK installed. If you don't know what to answer at this point then answer Y. You may answer M for module support and - later load the module when you install the JDK or find a interesting + later load the module when you install the JDK or find an interesting Java program that you can't live without. Processor type @@ -699,7 +693,7 @@ opposed to mips-linux-gcc or mips-linuxelf-gcc), say Y here, otherwise N. Most MIPS machines use little-endian code, but it might be necessary to run older Mips systems, such as the Sony News and - MIPS RC3xxx in big endian mode. + MIPS RC3xxx, in big endian mode. Enable loadable module support CONFIG_MODULES @@ -717,14 +711,13 @@ kernel. Enabling this option makes it possible, and safe, to use the same modules even after compiling a new kernel; this requires the program modprobe. All the software needed for module support is in - the modules package in sunsite.unc.edu:/pub/Linux/kernel, available - via ftp (user: anonymous) to be extracted with "tar xzvf filename". - NOTE: if you say Y here but don't have the program genksyms (which - is also contained in the above mentioned modules package), then the - building of your kernel will fail. - If you are going to use modules that are generated from non-kernel - sources, you would benefit from this option. Otherwise it's not that - important. So, N ought to be a safe bet. + the modules package (check the file Documentation/Changes for + location and latest version). NOTE: if you say Y here but don't + have the program genksyms (which is also contained in the above + mentioned modules package), then the building of your kernel will + fail. If you are going to use modules that are generated from + non-kernel sources, you would benefit from this option. Otherwise + it's not that important. So, N ought to be a safe bet. Kernel daemon support CONFIG_KERNELD @@ -840,19 +833,20 @@ about 2kB. You may need to read the FIREWALL-HOWTO, available via ftp (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. Also, you will need the - ipfwadm tool (available via ftp (user: anonymous) from ftp.xos.nl) - to allow selective blocking of internet traffic based - on type, origin and destination. You need to enable IP firewalling - in order to be able to use IP masquerading (i.e. local computers can - chat with an outside host, but that outside host is made to think - that it is talking to the firewall box. Makes the local network - completely invisible and avoids the need to allocate valid IP host - addresses for the machines on the local net) or to use the IP packet - accounting to see what is using all your network bandwidth. - This option is also needed when you want to enable the transparent - proxying support (makes the computers on the local network think - they're talking to a remote computer, while in reality the traffic - is redirected by your Linux firewall to a local proxy server). + ipfwadm tool (check the file Documentation/Changes for location and + latest version) to allow selective blocking of internet traffic + based on type, origin and destination. You need to enable IP + firewalling in order to be able to use IP masquerading (i.e. local + computers can chat with an outside host, but that outside host is + made to think that it is talking to the firewall box. Makes the + local network completely invisible and avoids the need to allocate + valid IP host addresses for the machines on the local net) or to use + the IP packet accounting to see what is using all your network + bandwidth. This option is also needed when you want to enable the + transparent proxying support (makes the computers on the local + network think they're talking to a remote computer, while in reality + the traffic is redirected by your Linux firewall to a local proxy + server). IP: accounting CONFIG_IP_ACCT @@ -863,7 +857,8 @@ firewalling. The data is accessible with "cat /proc/net/ip_acct", so you want to say Y to the /proc filesystem below, if you say Y here. To specify what exactly should be recorded, you need the tool - ipfwadm (available from ftp.xos.nl if you don't have a copy already). + ipfwadm (check the file Documentation/Changes for location and + latest version). IP: tunneling CONFIG_NET_IPIP @@ -977,17 +972,25 @@ Reverse ARP CONFIG_INET_RARP - Since you asked: if there's a diskless machine on your local network - that know its hardware ethernet address but doesn't know its IP - address upon startup, it can send out a Reverse Address Resolution - Protocol request to find out its own IP address. If you want your - Linux box to be able to *answer* such requests, say Y here; you'd - have to run the program rarp ("man rarp") on your box. Superior - solutions to the same problem are given by the protocols BOOTP and - DHCP. If you want to compile RARP support as a module ( = code which - can be inserted in and removed from the running kernel whenever you - want), say M here and read Documentation/modules.txt. If you don't - understand a word, say N and rest in peace. + Since you asked: if there are (usually diskless or portable) + machines on your local network that know their hardware ethernet + addresses but don't know their IP addresses upon startup, they can + send out a Reverse Address Resolution Protocol (RARP) request to + find out their own IP addresses. Diskless Sun 3 machines use this + procedure at boot time. If you want your Linux box to be able to + *answer* such requests, say Y here; you'd have to run the program + rarp ("man rarp") on your box. If you actually want to use a + diskless Sun 3 machine as an Xterminal to Linux, say Y here and + fetch Linux-Xkernel from + ftp://sunsite.unc.edu/pub/Linux/system/Network/boot.net/. Superior + solutions to the problem of booting and configuring machines over a + net connection are given by the protocol BOOTP and its successor + DHCP. See the DHCP FAQ + http://web.syr.edu/~jmwobus/comfaqs/dhcp.faq.html for details. If + you want to compile RARP support as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. If you don't + understand a word of the above, say N and rest in peace. Assume subnets are local CONFIG_INET_SNARL @@ -1734,7 +1737,8 @@ module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. If you want to use more than one dummy - device at a time, you need to compile it as a module. + device at a time, you need to compile it as a module. Instead of + 'dummy', it will they will then be called 'dummy0', 'dummy1' etc. SLIP (serial line) support CONFIG_SLIP @@ -1974,7 +1978,7 @@ Sangoma S502A FRAD support CONFIG_SDLA - Say Y here if you need a driver for the Sangoma S502A, S502E and + Say Y here if you need a driver for the Sangoma S502A, S502E, and S508 Frame Relay Access Devices. These are multi-protocol cards, but only frame relay is supported by the driver at this time. Please read Documentation/framerelay.txt. This driver is also @@ -2978,25 +2982,25 @@ BOOTP support CONFIG_RNFS_BOOTP If you want your Linux box to mount its whole root filesystem from - some other computer over the net via NFS and you want the address - of your computer to be discovered automatically using the BOOTP - protocol (a special protocol designed for doing this job), say Y - here. In case the boot ROM of your network card was designed for - booting Linux and does BOOTP itself, providing all necessary - information on the kernel command line, you can say N here. - If unsure, say Y. Note that in case you want to use BOOTP, a BOOTP + some other computer over the net via NFS and you want the IP address + of your computer to be discovered automatically at boot time using + the BOOTP protocol (a special protocol designed for doing this job), + say Y here. In case the boot ROM of your network card was designed + for booting Linux and does BOOTP itself, providing all necessary + information on the kernel command line, you can say N here. If + unsure, say Y. Note that in case you want to use BOOTP, a BOOTP server must be operating on your network. Read Documentation/nfsroot.txt for details. RARP support CONFIG_RNFS_RARP If you want your Linux box to mount its whole root filesystem from - some other computer over the net via NFS and you want the address - of your computer to be discovered automatically using the RARP - protocol (an older protocol which is being obsoleted by BOOTP), say - Y here. Note that in case you want to use RARP, a RARP server must be - operating on your network. Read Documentation/nfsroot.txt for - details. + some other computer over the net via NFS and you want the IP address + of your computer to be discovered automatically at boot time using + the RARP protocol (an older protocol which is being obsoleted by + BOOTP), say Y here. Note that in case you want to use RARP, a RARP + server must be operating on your network. Read + Documentation/nfsroot.txt for details. ISO9660 cdrom filesystem support CONFIG_ISO9660_FS diff -u --recursive --new-file v2.1.1/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt --- v2.1.1/linux/Documentation/ioctl-number.txt Wed Aug 7 12:31:18 1996 +++ linux/Documentation/ioctl-number.txt Sat Oct 5 16:51:15 1996 @@ -1,5 +1,5 @@ Ioctl Numbers -6 Aug 1996 +5 Oct 1996 Michael Chastain @@ -51,7 +51,7 @@ code to call verify_area to validate parameters. This table lists ioctls visible from user land for Linux/i386. It is -current to Linux 2.0.11. +current to Linux 2.1.1 Code Seq# Include File Comments ======================================================== @@ -104,3 +104,5 @@ 0x89 00-0F asm-i386/sockios.h 0x89 10-FF linux/sockios.h 0x90 00 linux/sbpcd.h +0x99 00-0F 537-Addinboard driver (in development, e-mail contact: + b.kohl@ipn-b.comlink.apc.org) diff -u --recursive --new-file v2.1.1/linux/Makefile linux/Makefile --- v2.1.1/linux/Makefile Sat Oct 5 16:58:33 1996 +++ linux/Makefile Mon Oct 7 10:58:39 1996 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 1 +SUBLEVEL = 2 ARCH = i386 diff -u --recursive --new-file v2.1.1/linux/arch/alpha/kernel/apecs.c linux/arch/alpha/kernel/apecs.c --- v2.1.1/linux/arch/alpha/kernel/apecs.c Tue Jul 9 08:08:18 1996 +++ linux/arch/alpha/kernel/apecs.c Mon Oct 7 12:40:22 1996 @@ -526,8 +526,8 @@ #define MCHK_NO_DEVSEL 0x205L #define MCHK_NO_TABT 0x204L if (apecs_mcheck_expected && - (((unsigned int)mchk_procdata->paltemp[0] == MCHK_NO_DEVSEL) || - ((unsigned int)mchk_procdata->paltemp[0] == MCHK_NO_TABT)) + (((unsigned int)mchk_header->code == MCHK_NO_DEVSEL) || + ((unsigned int)mchk_header->code == MCHK_NO_TABT)) ) { #else @@ -550,19 +550,21 @@ printk("apecs_machine_check: HW correctable (0x%lx)\n", vector); } else { - printk("APECS machine check:\n"); - printk(" vector=0x%lx la_ptr=0x%lx\n", + printk(KERN_CRIT "APECS machine check:\n"); + printk(KERN_CRIT " vector=0x%lx la_ptr=0x%lx\n", vector, la_ptr); - printk(" pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", + printk(KERN_CRIT + " pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", regs->pc, mchk_header->size, mchk_header->proc_offset, mchk_header->sys_offset); - printk(" expected %d DCSR 0x%lx PEAR 0x%lx\n", + printk(KERN_CRIT " expected %d DCSR 0x%lx PEAR 0x%lx\n", apecs_mcheck_expected, mchk_sysdata->epic_dcsr, mchk_sysdata->epic_pear); ptr = (unsigned long *)la_ptr; for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { - printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]); + printk(KERN_CRIT " +%lx %lx %lx\n", + i*sizeof(long), ptr[i], ptr[i+1]); } #if 0 /* doesn't work with MILO */ diff -u --recursive --new-file v2.1.1/linux/arch/alpha/kernel/cia.c linux/arch/alpha/kernel/cia.c --- v2.1.1/linux/arch/alpha/kernel/cia.c Sat Jun 8 11:24:57 1996 +++ linux/arch/alpha/kernel/cia.c Mon Oct 7 12:40:22 1996 @@ -21,6 +21,19 @@ extern struct hwrpb_struct *hwrpb; extern asmlinkage void wrmces(unsigned long mces); extern int alpha_sys_type; + +/* + * Machine check reasons. Defined according to PALcode sources + * (osf.h and platform.h). + */ +#define MCHK_K_TPERR 0x0080 +#define MCHK_K_TCPERR 0x0082 +#define MCHK_K_HERR 0x0084 +#define MCHK_K_ECC_C 0x0086 +#define MCHK_K_ECC_NC 0x0088 +#define MCHK_K_OS_BUGCHECK 0x008A +#define MCHK_K_PAL_BUGCHECK 0x0090 + /* * BIOS32-style PCI interface: */ @@ -38,7 +51,7 @@ static volatile unsigned int CIA_mcheck_expected = 0; static volatile unsigned int CIA_mcheck_taken = 0; -static unsigned long CIA_jd, CIA_jd1, CIA_jd2; +static unsigned long CIA_jd; /* @@ -438,16 +451,19 @@ } void cia_machine_check(unsigned long vector, unsigned long la_ptr, - struct pt_regs * regs) + struct pt_regs * regs) { -#if 0 - printk("CIA machine check ignored\n") ; -#else struct el_common *mchk_header; + struct el_procdata *mchk_procdata; struct el_CIA_sysdata_mcheck *mchk_sysdata; + unsigned long * ptr; + const char * reason; + char buf[128]; + long i; mchk_header = (struct el_common *)la_ptr; - + mchk_procdata = + (struct el_procdata *)(la_ptr + mchk_header->proc_offset); mchk_sysdata = (struct el_CIA_sysdata_mcheck *)(la_ptr + mchk_header->sys_offset); @@ -458,13 +474,14 @@ CIA_mcheck_expected, mchk_sysdata->epic_dcsr, mchk_sysdata->epic_pear)); #ifdef DEBUG { - unsigned long *ptr; - int i; + unsigned long *ptr; + int i; - ptr = (unsigned long *)la_ptr; - for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { - printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]); - } + ptr = (unsigned long *)la_ptr; + for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { + printk(" +%lx %lx %lx\n", i*sizeof(long), + ptr[i], ptr[i+1]); + } } #endif /* DEBUG */ /* @@ -483,12 +500,56 @@ cia_pci_clr_err(); wrmces(0x7); mb(); + return; + } + + switch ((unsigned int) mchk_header->code) { + case MCHK_K_TPERR: reason = "tag parity error"; break; + case MCHK_K_TCPERR: reason = "tag control parity error"; break; + case MCHK_K_HERR: reason = "generic hard error"; break; + case MCHK_K_ECC_C: reason = "correctable ECC error"; break; + case MCHK_K_ECC_NC: reason = "uncorrectable ECC error"; break; + case MCHK_K_OS_BUGCHECK: reason = "OS-specific PAL bugcheck"; break; + case MCHK_K_PAL_BUGCHECK: reason = "callsys in kernel mode"; break; + case 0x96: reason = "i-cache read retryable error"; break; + case 0x98: reason = "processor detected hard error"; break; + + /* system specific (these are for Alcor, at least): */ + case 0x203: reason = "system detected uncorrectable ECC error"; break; + case 0x205: reason = "parity error detected by CIA"; break; + case 0x207: reason = "non-existent memory error"; break; + case 0x209: reason = "PCI SERR detected"; break; + case 0x20b: reason = "PCI data parity error detected"; break; + case 0x20d: reason = "PCI address parity error detected"; break; + case 0x20f: reason = "PCI master abort error"; break; + case 0x211: reason = "PCI target abort error"; break; + case 0x213: reason = "scatter/gather PTE invalid error"; break; + case 0x215: reason = "flash ROM write error"; break; + case 0x217: reason = "IOA timeout detected"; break; + case 0x219: reason = "IOCHK#, EISA add-in board parity or other catastrophic error"; break; + case 0x21b: reason = "EISA fail-safe timer timeout"; break; + case 0x21d: reason = "EISA bus time-out"; break; + case 0x21f: reason = "EISA software generated NMI"; break; + case 0x221: reason = "unexpected ev5 IRQ[3] interrupt"; break; + default: + sprintf(buf, "reason for machine-check unknown (0x%x)", + (unsigned int) mchk_header->code); + reason = buf; + break; + } + wrmces(rdmces()); /* reset machine check pending flag */ + mb(); + + printk(KERN_CRIT " CIA machine check: %s%s\n", + reason, mchk_header->retry ? " (retryable)" : ""); + + /* dump the the logout area to give all info: */ + + ptr = (unsigned long *)la_ptr; + for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { + printk(KERN_CRIT " +%8lx %016lx %016lx\n", + i*sizeof(long), ptr[i], ptr[i+1]); } -#if 1 - else - printk("CIA machine check NOT expected\n") ; -#endif -#endif } #endif /* CONFIG_ALPHA_CIA */ diff -u --recursive --new-file v2.1.1/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v2.1.1/linux/arch/alpha/kernel/entry.S Sat Jun 8 11:09:03 1996 +++ linux/arch/alpha/kernel/entry.S Tue Oct 8 08:50:19 1996 @@ -55,6 +55,7 @@ stq $2,16($30); \ stq $3,24($30); \ stq $4,32($30); \ + lda $2,hae; \ stq $5,40($30); \ stq $6,48($30); \ stq $7,56($30); \ @@ -62,6 +63,7 @@ stq $19,72($30); \ stq $20,80($30); \ stq $21,88($30); \ + ldq $2,HAE_CACHE($2); \ stq $22,96($30); \ stq $23,104($30); \ stq $24,112($30); \ @@ -69,34 +71,33 @@ stq $26,128($30); \ stq $27,136($30); \ stq $28,144($30); \ - lda $2,hae; \ - ldq $2,HAE_CACHE($2); \ stq $2,152($30) #define RESTORE_ALL \ - lda $8,hae; \ - ldq $7,HAE_CACHE($8); \ - ldq $6,152($30); \ - subq $7,$6,$5; \ - beq $5,99f; \ - ldq $7,HAE_REG($8); \ - addq $31,7,$16; \ - call_pal PAL_swpipl; \ - stq $6,HAE_CACHE($8); \ - stq $6,0($7); \ - mb; \ - bis $0,$0,$16; \ - call_pal PAL_swpipl; \ -99:; \ + lda $19,hae; \ ldq $0,0($30); \ ldq $1,8($30); \ ldq $2,16($30); \ ldq $3,24($30); \ + ldq $20,152($30); \ + ldq $21,HAE_CACHE($19); \ ldq $4,32($30); \ ldq $5,40($30); \ ldq $6,48($30); \ ldq $7,56($30); \ + subq $20,$21,$20; \ ldq $8,64($30); \ + beq $20,99f; \ + ldq $20,HAE_REG($19); \ + addq $31,7,$16; \ + call_pal PAL_swpipl; \ + stq $21,HAE_CACHE($19); \ + stq $21,0($20); \ + bis $0,$0,$16; \ + call_pal PAL_swpipl; \ + ldq $0,0($30); \ + ldq $1,8($30); \ +99:; \ ldq $19,72($30); \ ldq $20,80($30); \ ldq $21,88($30); \ @@ -111,7 +112,7 @@ .text .set noat -#ifdef __linux__ +#if defined(__linux__) && !defined(__ELF__) .set singlegp #endif @@ -473,24 +474,22 @@ .globl ret_from_sys_call .ent entSys entSys: - stq $16,24($30) - stq $17,32($30) - stq $18,40($30) SAVE_ALL - /* FIXME: optimize */ lda $1,current_set + lda $4,NR_SYSCALLS($31) + stq $16,SP_OFF+24($30) + lda $5,sys_call_table ldq $2,0($1) + lda $27,do_entSys + cmpult $0,$4,$4 ldq $3,TASK_FLAGS($2) + stq $17,SP_OFF+32($30) + s8addq $0,$5,$5 and $3,PF_PTRACED,$3 + stq $18,SP_OFF+40($30) bne $3,strace - /* end of strace */ - lda $1,NR_SYSCALLS($31) - lda $2,sys_call_table - lda $27,do_entSys - cmpult $0,$1,$1 - s8addq $0,$2,$2 - beq $1,1f - ldq $27,0($2) + beq $4,1f + ldq $27,0($5) 1: jsr $26,($27),do_entSys blt $0,syscall_error /* the call failed */ stq $0,0($30) diff -u --recursive --new-file v2.1.1/linux/arch/alpha/kernel/head.S linux/arch/alpha/kernel/head.S --- v2.1.1/linux/arch/alpha/kernel/head.S Mon Jul 1 20:06:05 1996 +++ linux/arch/alpha/kernel/head.S Tue Oct 8 09:09:59 1996 @@ -125,3 +125,52 @@ lda $30,0x10($30) ret ($26) .end wrfpcr + +#define ex_count 0($16) +#define ex_r9 8($16) +#define ex_r10 16($16) +#define ex_r11 24($16) +#define ex_r12 32($16) +#define ex_r13 40($16) +#define ex_r14 48($16) +#define ex_r15 56($16) +#define ex_r26 64($16) +#define ex_r30 72($16) + + .align 3 + .globl __exception + .ent __exception +__exception: + ldq $1,ex_count + bis $31,$31,$0 /* return 0 */ + addq $1,1,$2 + bne $1,1f /* don't save state if orig_count != 0 */ + stq $9,ex_r9 + stq $10,ex_r10 + stq $11,ex_r11 + stq $12,ex_r12 + stq $13,ex_r13 + stq $14,ex_r14 + stq $15,ex_r15 + stq $26,ex_r26 + stq $30,ex_r30 +1: stq $2,ex_count + ret ($26) + .end __exception + + .align 3 + .globl __handle_exception + .ent __handle_exception +__handle_exception: + ldq $9,ex_r9 + ldq $10,ex_r10 + ldq $11,ex_r11 + ldq $12,ex_r12 + ldq $13,ex_r13 + ldq $14,ex_r14 + ldq $15,ex_r15 + ldq $26,ex_r26 + ldq $30,ex_r30 + bis $31,1,$0 /* return 1 */ + ret ($26) + .end __handle_exception diff -u --recursive --new-file v2.1.1/linux/arch/alpha/kernel/lca.c linux/arch/alpha/kernel/lca.c --- v2.1.1/linux/arch/alpha/kernel/lca.c Mon Jul 15 09:47:41 1996 +++ linux/arch/alpha/kernel/lca.c Mon Oct 7 12:40:22 1996 @@ -386,11 +386,14 @@ void lca_machine_check (unsigned long vector, unsigned long la, struct pt_regs *regs) { + unsigned long * ptr; const char * reason; union el_lca el; char buf[128]; + long i; - printk("lca: machine check (la=0x%lx,pc=0x%lx)\n", la, regs->pc); + printk(KERN_CRIT "lca: machine check (la=0x%lx,pc=0x%lx)\n", + la, regs->pc); el.c = (struct el_common *) la; /* * The first quadword after the common header always seems to @@ -399,9 +402,9 @@ * logout frame, the upper 32 bits is the machine check * revision level, which we ignore for now. */ - switch (el.s->reason & 0xffffffff) { + switch (el.c->code & 0xffffffff) { case MCHK_K_TPERR: reason = "tag parity error"; break; - case MCHK_K_TCPERR: reason = "tag something parity error"; break; + case MCHK_K_TCPERR: reason = "tag control parity error"; break; case MCHK_K_HERR: reason = "access to non-existent memory"; break; case MCHK_K_ECC_C: reason = "correctable ECC error"; break; case MCHK_K_ECC_NC: reason = "non-correctable ECC error"; break; @@ -416,7 +419,7 @@ case MCHK_K_UNKNOWN: default: sprintf(buf, "reason for machine-check unknown (0x%lx)", - el.s->reason & 0xffffffff); + el.c->code & 0xffffffff); reason = buf; break; } @@ -425,7 +428,8 @@ switch (el.c->size) { case sizeof(struct el_lca_mcheck_short): - printk(" Reason: %s (short frame%s, dc_stat=%lx):\n", + printk(KERN_CRIT + " Reason: %s (short frame%s, dc_stat=%lx):\pn", reason, el.c->retry ? ", retryable" : "", el.s->dc_stat); if (el.s->esr & ESR_EAV) { mem_error(el.s->esr, el.s->ear); @@ -436,11 +440,12 @@ break; case sizeof(struct el_lca_mcheck_long): - printk(" Reason: %s (long frame%s):\n", + printk(KERN_CRIT " Reason: %s (long frame%s):\n", reason, el.c->retry ? ", retryable" : ""); - printk(" reason: %lx exc_addr: %lx dc_stat: %lx\n", + printk(KERN_CRIT + " reason: %lx exc_addr: %lx dc_stat: %lx\n", el.l->pt[0], el.l->exc_addr, el.l->dc_stat); - printk(" car: %lx\n", el.l->car); + printk(KERN_CRIT " car: %lx\n", el.l->car); if (el.l->esr & ESR_EAV) { mem_error(el.l->esr, el.l->ear); } @@ -450,7 +455,15 @@ break; default: - printk(" Unknown errorlog size %d\n", el.c->size); + printk(KERN_CRIT " Unknown errorlog size %d\n", el.c->size); + } + + /* dump the the logout area to give all info: */ + + ptr = (unsigned long *) la; + for (i = 0; i < el.c->size / sizeof(long); i += 2) { + printk(KERN_CRIT " +%8lx %016lx %016lx\n", + i*sizeof(long), ptr[i], ptr[i+1]); } } diff -u --recursive --new-file v2.1.1/linux/arch/alpha/lib/memcpy.c linux/arch/alpha/lib/memcpy.c --- v2.1.1/linux/arch/alpha/lib/memcpy.c Sun Aug 4 13:37:59 1996 +++ linux/arch/alpha/lib/memcpy.c Mon Oct 7 08:55:45 1996 @@ -81,7 +81,7 @@ } /* - * Hmm.. Strange. The __asm__ here is there to make gcc use a integer register + * Hmm.. Strange. The __asm__ here is there to make gcc use an integer register * for the load-store. I don't know why, but it would seem that using a floating * point register for the move seems to slow things down (very small difference, * though). diff -u --recursive --new-file v2.1.1/linux/arch/alpha/mm/fault.c linux/arch/alpha/mm/fault.c --- v2.1.1/linux/arch/alpha/mm/fault.c Mon Sep 9 21:04:56 1996 +++ linux/arch/alpha/mm/fault.c Tue Oct 8 09:45:14 1996 @@ -97,6 +97,11 @@ */ bad_area: up(&mm->mmap_sem); + /* Did we have an exception handler installed? */ + if (current->tss.ex.count == 1) { + current->tss.ex.count = 0; + __handle_exception(¤t->tss.ex); + } if (user_mode(®s)) { printk("%s: memory violation at pc=%08lx rp=%08lx (bad address = %08lx)\n", tsk->comm, regs.pc, regs.r26, address); diff -u --recursive --new-file v2.1.1/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c --- v2.1.1/linux/arch/alpha/mm/init.c Wed Sep 25 12:14:59 1996 +++ linux/arch/alpha/mm/init.c Mon Oct 7 08:55:46 1996 @@ -30,7 +30,7 @@ * BAD_PAGE is the page that is used for page faults when linux * is out-of-memory. Older versions of linux just did a * do_exit(), but using this instead means there is less risk - * for a process dying in kernel mode, possibly leaving a inode + * for a process dying in kernel mode, possibly leaving an inode * unused etc.. * * BAD_PAGETABLE is the accompanying page-table: it is initialized diff -u --recursive --new-file v2.1.1/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- v2.1.1/linux/arch/i386/kernel/entry.S Tue Sep 24 14:03:16 1996 +++ linux/arch/i386/kernel/entry.S Sat Oct 5 20:29:50 1996 @@ -30,14 +30,12 @@ * 18(%esp) - %eax * 1C(%esp) - %ds * 20(%esp) - %es - * 24(%esp) - %fs - * 28(%esp) - %gs - * 2C(%esp) - orig_eax - * 30(%esp) - %eip - * 34(%esp) - %cs - * 38(%esp) - %eflags - * 3C(%esp) - %oldesp - * 40(%esp) - %oldss + * 24(%esp) - orig_eax + * 28(%esp) - %eip + * 2C(%esp) - %cs + * 30(%esp) - %eflags + * 34(%esp) - %oldesp + * 38(%esp) - %oldss * * "current" is in register %ebx during any slow entries. */ @@ -57,14 +55,12 @@ EAX = 0x18 DS = 0x1C ES = 0x20 -FS = 0x24 -GS = 0x28 -ORIG_EAX = 0x2C -EIP = 0x30 -CS = 0x34 -EFLAGS = 0x38 -OLDESP = 0x3C -OLDSS = 0x40 +ORIG_EAX = 0x24 +EIP = 0x28 +CS = 0x2C +EFLAGS = 0x30 +OLDESP = 0x34 +OLDSS = 0x38 CF_MASK = 0x00000001 IF_MASK = 0x00000200 @@ -88,8 +84,6 @@ #define SAVE_ALL \ cld; \ - push %gs; \ - push %fs; \ push %es; \ push %ds; \ pushl %eax; \ @@ -204,8 +198,6 @@ popl %eax; \ pop %ds; \ pop %es; \ - pop %fs; \ - pop %gs; \ addl $4,%esp; \ iret @@ -228,8 +220,6 @@ popl %eax; \ pop %ds; \ pop %es; \ - pop %fs; \ - pop %gs; \ addl $4,%esp; \ iret #endif @@ -287,7 +277,6 @@ movl SYMBOL_NAME(sys_call_table)(,%eax,4),%eax testl %eax,%eax je ret_from_sys_call - andl $~CF_MASK,EFLAGS(%esp) # clear carry - assume no errors testb $0x20,flags(%ebx) # PF_TRACESYS jne tracesys call *%eax @@ -296,51 +285,39 @@ .globl ret_from_sys_call ret_from_sys_call: cmpl $0,SYMBOL_NAME(intr_count) - jne 2f + jne 1f 9: movl SYMBOL_NAME(bh_mask),%eax andl SYMBOL_NAME(bh_active),%eax jne handle_bottom_half - movl EFLAGS(%esp),%eax # check VM86 flag: CS/SS are - testl $(VM_MASK),%eax # different then - jne 1f - cmpw $(KERNEL_CS),CS(%esp) # was old code segment supervisor ? - je 2f -1: sti - orl $(IF_MASK),%eax # these just try to make sure - andl $~NT_MASK,%eax # the program doesn't do anything - movl %eax,EFLAGS(%esp) # stupid + movl EFLAGS(%esp),%eax # mix EFLAGS and CS + movb CS(%esp),%al + testl $(VM_MASK | 3),%eax # return to VM86 mode or non-supervisor? + je 1f cmpl $0,SYMBOL_NAME(need_resched) jne reschedule - cmpl SYMBOL_NAME(task),%ebx # task[0] cannot have signals - je 2f - movl blocked(%ebx),%ecx - movl %ecx,%eax # save blocked in %eax for signal handling - notl %ecx - andl signal(%ebx),%ecx + movl blocked(%ebx),%eax + movl %eax,%esi # save blocked in %esi for signal handling + notl %eax + andl signal(%ebx),%eax jne signal_return -2: RESTORE_ALL +1: RESTORE_ALL ALIGN signal_return: - movl %esp,%ecx - pushl %ecx - testl $(VM_MASK),EFLAGS(%ecx) + testl $(VM_MASK),EFLAGS(%esp) + pushl %esp jne v86_signal_return - pushl %eax + pushl %esi call SYMBOL_NAME(do_signal) - popl %eax - popl %eax + addl $8,%esp RESTORE_ALL ALIGN v86_signal_return: - pushl %eax call SYMBOL_NAME(save_v86_state) - popl %edx movl %eax,%esp pushl %eax - pushl %edx + pushl %esi call SYMBOL_NAME(do_signal) - popl %edx - popl %edx + addl $8,%esp RESTORE_ALL ALIGN tracesys: @@ -357,8 +334,6 @@ pushl $ SYMBOL_NAME(do_divide_error) ALIGN error_code: - push %fs - push %es push %ds pushl %eax xorl %eax,%eax @@ -369,12 +344,12 @@ decl %eax # eax = -1 pushl %ecx pushl %ebx - cld xorl %ecx,%ecx # zero ecx + cld + mov %es,%cx # get the lower order bits of es xchgl %eax, ORIG_EAX(%esp) # orig_eax (get the error code. ) - mov %gs,%bx # get the lower order bits of gs movl %esp,%edx - xchgl %ecx, GS(%esp) # get the address and save gs. + xchgl %ecx, ES(%esp) # get the address and save es. pushl %eax # push the error code pushl %edx movl $(KERNEL_DS),%edx diff -u --recursive --new-file v2.1.1/linux/arch/i386/kernel/ioport.c linux/arch/i386/kernel/ioport.c --- v2.1.1/linux/arch/i386/kernel/ioport.c Wed Jan 11 21:10:53 1995 +++ linux/arch/i386/kernel/ioport.c Sat Oct 5 20:29:50 1996 @@ -75,8 +75,8 @@ */ asmlinkage int sys_iopl(long ebx,long ecx,long edx, long esi, long edi, long ebp, long eax, long ds, - long es, long fs, long gs, long orig_eax, - long eip,long cs,long eflags,long esp,long ss) + long es, long orig_eax, long eip, long cs, + long eflags, long esp, long ss) { unsigned int level = ebx; diff -u --recursive --new-file v2.1.1/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- v2.1.1/linux/arch/i386/kernel/irq.c Mon Sep 9 09:32:19 1996 +++ linux/arch/i386/kernel/irq.c Mon Oct 7 08:55:46 1996 @@ -187,7 +187,7 @@ #else /* - * Note that on a 486, we don't want to do a SIGFPE on a irq13 + * Note that on a 486, we don't want to do a SIGFPE on an irq13 * as the irq is unreliable, and exception 16 works correctly * (ie as explained in the intel literature). On a 386, you * can't use exception 16 due to bad IBM design, so we have to diff -u --recursive --new-file v2.1.1/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v2.1.1/linux/arch/i386/kernel/process.c Wed Sep 25 12:53:02 1996 +++ linux/arch/i386/kernel/process.c Tue Oct 8 18:49:00 1996 @@ -225,17 +225,16 @@ void show_regs(struct pt_regs * regs) { printk("\n"); - printk("EIP: %04x:[<%08lx>]",0xffff & regs->cs,regs->eip); - if (regs->cs & 3) - printk(" ESP: %04x:%08lx",0xffff & regs->ss,regs->esp); + printk("EIP: %04x:[<%08lx>]",0xffff & regs->xcs,regs->eip); + if (regs->xcs & 3) + printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp); printk(" EFLAGS: %08lx\n",regs->eflags); printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", regs->eax,regs->ebx,regs->ecx,regs->edx); printk("ESI: %08lx EDI: %08lx EBP: %08lx", regs->esi, regs->edi, regs->ebp); - printk(" DS: %04x ES: %04x FS: %04x GS: %04x\n", - 0xffff & regs->ds,0xffff & regs->es, - 0xffff & regs->fs,0xffff & regs->gs); + printk(" DS: %04x ES: %04x\n", + 0xffff & regs->xds,0xffff & regs->xes); } /* @@ -387,7 +386,23 @@ if (dump->start_stack < TASK_SIZE) dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT; - dump->regs = *regs; + dump->regs.ebx = regs->ebx; + dump->regs.ecx = regs->ecx; + dump->regs.edx = regs->edx; + dump->regs.esi = regs->esi; + dump->regs.edi = regs->edi; + dump->regs.ebp = regs->ebp; + dump->regs.eax = regs->eax; + dump->regs.ds = regs->xds; + dump->regs.es = regs->xes; + __asm__("mov %%fs,%0":"=r" (dump->regs.fs)); + __asm__("mov %%gs,%0":"=r" (dump->regs.gs)); + dump->regs.orig_eax = regs->orig_eax; + dump->regs.eip = regs->eip; + dump->regs.cs = regs->xcs; + dump->regs.eflags = regs->eflags; + dump->regs.esp = regs->esp; + dump->regs.ss = regs->xss; dump->u_fpvalid = dump_fpu (regs, &dump->i387); } diff -u --recursive --new-file v2.1.1/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c --- v2.1.1/linux/arch/i386/kernel/ptrace.c Mon Sep 23 14:39:39 1996 +++ linux/arch/i386/kernel/ptrace.c Tue Oct 8 18:37:55 1996 @@ -28,10 +28,9 @@ #define TRAP_FLAG 0x100 /* - * this is the number to subtract from the top of the stack. To find - * the local frame. + * Offset of eflags on child stack.. */ -#define MAGICNUMBER 68 +#define EFL_OFFSET ((EFL-2)*4-sizeof(struct pt_regs)) /* change a pid into a task struct. */ static inline struct task_struct * get_task(int pid) @@ -295,6 +294,71 @@ return 0; } +static int putreg(struct task_struct *child, + unsigned long regno, unsigned long value) +{ + switch (regno >> 2) { + case ORIG_EAX: + return -EIO; + case FS: + if (value && (value & 3) != 3) + return -EIO; + child->tss.fs = value; + return 0; + case GS: + if (value && (value & 3) != 3) + return -EIO; + child->tss.gs = value; + return 0; + case DS: + case ES: + if (value && (value & 3) != 3) + return -EIO; + value &= 0xffff; + break; + case SS: + case CS: + if ((value & 3) != 3) + return -EIO; + value &= 0xffff; + break; + case EFL: + value &= FLAG_MASK; + value |= get_stack_long(child, EFL_OFFSET) & ~FLAG_MASK; + } + if (regno > GS*4) + regno -= 2*4; + put_stack_long(child, regno - sizeof(struct pt_regs), value); + return 0; +} + +static unsigned long getreg(struct task_struct *child, + unsigned long regno) +{ + unsigned long retval = ~0UL; + + switch (regno >> 2) { + case FS: + retval = child->tss.fs; + break; + case GS: + retval = child->tss.gs; + break; + case DS: + case ES: + case SS: + case CS: + retval = 0xffff; + /* fall through */ + default: + if (regno > GS*4) + regno -= 2*4; + regno = regno - sizeof(struct pt_regs); + retval &= get_stack_long(child, regno); + } + return retval; +} + asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; @@ -376,15 +440,8 @@ if (res) return res; tmp = 0; /* Default return condition */ - if(addr < 17*sizeof(long)) { - addr = addr >> 2; /* temporary hack. */ - - tmp = get_stack_long(child, sizeof(long)*addr - MAGICNUMBER); - if (addr == DS || addr == ES || - addr == FS || addr == GS || - addr == CS || addr == SS) - tmp &= 0xffff; - }; + if(addr < 17*sizeof(long)) + tmp = getreg(child, addr); if(addr >= (long) &dummy->u_debugreg[0] && addr <= (long) &dummy->u_debugreg[7]){ addr -= (long) &dummy->u_debugreg[0]; @@ -405,35 +462,14 @@ addr > sizeof(struct user) - 3) return -EIO; - addr = addr >> 2; /* temporary hack. */ - - if (addr == ORIG_EAX) - return -EIO; - if (addr == DS || addr == ES || - addr == FS || addr == GS || - addr == CS || addr == SS) { - data &= 0xffff; - if (data && (data & 3) != 3) - return -EIO; - } - if (addr == EFL) { /* flags. */ - data &= FLAG_MASK; - data |= get_stack_long(child, EFL*sizeof(long)-MAGICNUMBER) & ~FLAG_MASK; - } - /* Do not allow the user to set the debug register for kernel - address space */ - if(addr < 17){ - if (put_stack_long(child, sizeof(long)*addr-MAGICNUMBER, data)) - return -EIO; - return 0; - }; + if (addr < 17*sizeof(long)) + return putreg(child, addr, data); /* We need to be very careful here. We implicitly want to modify a portion of the task_struct, and we have to be selective about what portions we allow someone to modify. */ - addr = addr << 2; /* Convert back again */ if(addr >= (long) &dummy->u_debugreg[0] && addr <= (long) &dummy->u_debugreg[7]){ @@ -469,8 +505,8 @@ child->exit_code = data; wake_up_process(child); /* make sure the single step bit is not set. */ - tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG; - put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp); + tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; + put_stack_long(child, EFL_OFFSET,tmp); return 0; } @@ -487,8 +523,8 @@ wake_up_process(child); child->exit_code = SIGKILL; /* make sure the single step bit is not set. */ - tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG; - put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp); + tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; + put_stack_long(child, EFL_OFFSET, tmp); return 0; } @@ -498,8 +534,8 @@ if ((unsigned long) data > NSIG) return -EIO; child->flags &= ~PF_TRACESYS; - tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) | TRAP_FLAG; - put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp); + tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG; + put_stack_long(child, EFL_OFFSET, tmp); wake_up_process(child); child->exit_code = data; /* give it a chance to run. */ @@ -518,8 +554,8 @@ child->p_pptr = child->p_opptr; SET_LINKS(child); /* make sure the single step bit is not set. */ - tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG; - put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp); + tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; + put_stack_long(child, EFL_OFFSET, tmp); return 0; } diff -u --recursive --new-file v2.1.1/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c --- v2.1.1/linux/arch/i386/kernel/signal.c Sat Oct 5 16:58:34 1996 +++ linux/arch/i386/kernel/signal.c Sat Oct 5 20:29:50 1996 @@ -79,23 +79,31 @@ */ asmlinkage int sys_sigreturn(unsigned long __unused) { -#define COPY(x) regs->x = context.x -#define COPY_SEG(x) \ -if ((context.x & 0xfffc) && (context.x & 3) != 3) goto badframe; COPY(x); -#define COPY_SEG_STRICT(x) \ -if (!(context.x & 0xfffc) || (context.x & 3) != 3) goto badframe; COPY(x); - struct sigcontext context; +#define COPY(x) regs->x = context->x +#define COPY_SEG(seg) \ +{ unsigned int tmp = context->seg; \ +if ((tmp & 0xfffc) && (tmp & 3) != 3) goto badframe; \ +regs->x##seg = tmp; } +#define COPY_SEG_STRICT(seg) \ +{ unsigned int tmp = context->seg; \ +if ((tmp & 0xfffc) && (tmp & 3) != 3) goto badframe; \ +regs->x##seg = tmp; } +#define GET_SEG(seg) \ +{ unsigned int tmp = context->seg; \ +if ((tmp & 0xfffc) && (tmp & 3) != 3) goto badframe; \ +__asm__("mov %w0,%%" #seg: :"r" (tmp)); } + struct sigcontext * context; struct pt_regs * regs; regs = (struct pt_regs *) &__unused; - if (verify_area(VERIFY_READ, (void *) regs->esp, sizeof(context))) + context = (struct sigcontext *) regs->esp; + if (verify_area(VERIFY_READ, context, sizeof(*context))) goto badframe; - memcpy_fromfs(&context,(void *) regs->esp, sizeof(context)); - current->blocked = context.oldmask & _BLOCKABLE; + current->blocked = context->oldmask & _BLOCKABLE; COPY_SEG(ds); COPY_SEG(es); - COPY_SEG(fs); - COPY_SEG(gs); + GET_SEG(fs); + GET_SEG(gs); COPY_SEG_STRICT(ss); COPY_SEG_STRICT(cs); COPY(eip); @@ -104,15 +112,15 @@ COPY(esp); COPY(ebp); COPY(edi); COPY(esi); regs->eflags &= ~0x40DD5; - regs->eflags |= context.eflags & 0x40DD5; + regs->eflags |= context->eflags & 0x40DD5; regs->orig_eax = -1; /* disable syscall checks */ - if (context.fpstate) { - struct _fpstate * buf = context.fpstate; + if (context->fpstate) { + struct _fpstate * buf = context->fpstate; if (verify_area(VERIFY_READ, buf, sizeof(*buf))) goto badframe; restore_i387(buf); } - return context.eax; + return context->eax; badframe: do_exit(SIGSEGV); } @@ -164,7 +172,7 @@ unsigned long * frame; frame = (unsigned long *) regs->esp; - if (regs->ss != USER_DS && sa->sa_restorer) + if ((regs->xss & 0xffff) != USER_DS && sa->sa_restorer) frame = (unsigned long *) sa->sa_restorer; frame -= 64; if (verify_area(VERIFY_WRITE,frame,64*4)) @@ -178,10 +186,15 @@ put_user(current->exec_domain->signal_invmap[signr], frame+1); else put_user(signr, frame+1); - put_user(regs->gs, frame+2); - put_user(regs->fs, frame+3); - put_user(regs->es, frame+4); - put_user(regs->ds, frame+5); + { + unsigned int tmp = 0; +#define PUT_SEG(seg, mem) \ +__asm__("mov %%" #seg",%w0":"=r" (tmp):"0" (tmp)); *(mem) = tmp; + PUT_SEG(gs, frame+2); + PUT_SEG(fs, frame+3); + } + put_user(regs->xes, frame+4); + put_user(regs->xds, frame+5); put_user(regs->edi, frame+6); put_user(regs->esi, frame+7); put_user(regs->ebp, frame+8); @@ -193,10 +206,10 @@ put_user(current->tss.trap_no, frame+14); put_user(current->tss.error_code, frame+15); put_user(regs->eip, frame+16); - put_user(regs->cs, frame+17); + put_user(regs->xcs, frame+17); put_user(regs->eflags, frame+18); put_user(regs->esp, frame+19); - put_user(regs->ss, frame+20); + put_user(regs->xss, frame+20); put_user((unsigned long) save_i387((struct _fpstate *)(frame+32)),frame+21); /* non-iBCS2 extensions.. */ put_user(oldmask, frame+22); @@ -211,9 +224,15 @@ /* Set up registers for signal handler */ regs->esp = (unsigned long) frame; regs->eip = (unsigned long) sa->sa_handler; - regs->cs = USER_CS; regs->ss = USER_DS; - regs->ds = USER_DS; regs->es = USER_DS; - regs->gs = USER_DS; regs->fs = USER_DS; + { + unsigned long seg = USER_DS; + __asm__("mov %w0,%%fs ; mov %w0,%%gs":"=r" (seg) :"0" (seg)); + set_fs(seg); + regs->xds = seg; + regs->xes = seg; + regs->xss = seg; + regs->xcs = USER_CS; + } regs->eflags &= ~TF_MASK; } @@ -273,7 +292,7 @@ * including volatiles for the inline function to get * current combined with this gets it confused. */ - struct task_struct *t=current; + struct task_struct *t=current; __asm__("bsf %3,%1\n\t" "btrl %1,%0" :"=m" (t->signal),"=r" (signr) diff -u --recursive --new-file v2.1.1/linux/arch/i386/kernel/sys_i386.c linux/arch/i386/kernel/sys_i386.c --- v2.1.1/linux/arch/i386/kernel/sys_i386.c Fri Apr 12 09:49:30 1996 +++ linux/arch/i386/kernel/sys_i386.c Mon Oct 7 15:12:29 1996 @@ -16,6 +16,7 @@ #include #include +#include /* * sys_pipe() is the normal C calling standard for creating diff -u --recursive --new-file v2.1.1/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- v2.1.1/linux/arch/i386/kernel/traps.c Mon Sep 23 14:39:39 1996 +++ linux/arch/i386/kernel/traps.c Sat Oct 5 14:33:35 1996 @@ -102,22 +102,22 @@ esp = (unsigned long) ®s->esp; ss = KERNEL_DS; - if ((regs->eflags & VM_MASK) || (3 & regs->cs) == 3) + if ((regs->eflags & VM_MASK) || (3 & regs->xcs) == 3) return; - if (regs->cs & 3) { + if (regs->xcs & 3) { esp = regs->esp; - ss = regs->ss; + ss = regs->xss & 0xffff; } console_verbose(); printk("%s: %04lx\n", str, err & 0xffff); printk("CPU: %d\n", smp_processor_id()); - printk("EIP: %04x:[<%08lx>]\nEFLAGS: %08lx\n", 0xffff & regs->cs,regs->eip,regs->eflags); + printk("EIP: %04x:[<%08lx>]\nEFLAGS: %08lx\n", 0xffff & regs->xcs,regs->eip,regs->eflags); printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", regs->eax, regs->ebx, regs->ecx, regs->edx); printk("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n", regs->esi, regs->edi, regs->ebp, esp); - printk("ds: %04x es: %04x fs: %04x gs: %04x ss: %04x\n", - regs->ds, regs->es, regs->fs, regs->gs, ss); + printk("ds: %04x es: %04x ss: %04x\n", + regs->xds & 0xffff, regs->xes & 0xffff, ss); store_TR(i); if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page) printk("Corrupted stack page\n"); @@ -158,7 +158,7 @@ } printk("\nCode: "); for(i=0;i<20;i++) - printk("%02x ",0xff & get_seg_byte(regs->cs,(i+(char *)regs->eip))); + printk("%02x ",0xff & get_seg_byte(regs->xcs & 0xffff,(i+(char *)regs->eip))); printk("\n"); do_exit(SIGSEGV); } @@ -174,13 +174,9 @@ DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS, current) DO_ERROR(11, SIGBUS, "segment not present", segment_not_present, current) DO_ERROR(12, SIGBUS, "stack segment", stack_segment, current) +DO_ERROR(15, SIGSEGV, "reserved", reserved, current) DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current) -asmlinkage void do_reserved(struct pt_regs * regs, long error_code) -{ - printk("Uhhuh.. Reserved trap code, whazzup? (%ld)\n", error_code); -} - asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) { if (regs->eflags & VM_MASK) { @@ -215,7 +211,7 @@ force_sig(SIGTRAP, current); current->tss.trap_no = 1; current->tss.error_code = error_code; - if ((regs->cs & 3) == 0) { + if ((regs->xcs & 3) == 0) { /* If this is a kernel mode trap, then reset db7 and allow us to continue */ __asm__("movl %0,%%db7" : /* no output */ @@ -330,7 +326,7 @@ return; } smptrap++; - if (strncmp((char*)phys_to_virt(0x0FFFD9), "EISA", 4) == 0) + if (readl(0x0FFFD9) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24)) EISA_bus = 1; set_call_gate(&default_ldt,lcall7); set_trap_gate(0,÷_error); diff -u --recursive --new-file v2.1.1/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c --- v2.1.1/linux/arch/i386/mm/fault.c Mon Sep 23 10:28:23 1996 +++ linux/arch/i386/mm/fault.c Tue Oct 8 14:07:43 1996 @@ -110,6 +110,7 @@ */ bad_area: up(&mm->mmap_sem); + handle_exception(&tsk->tss.ex); if (error_code & 4) { tsk->tss.cr2 = address; tsk->tss.error_code = error_code; diff -u --recursive --new-file v2.1.1/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c --- v2.1.1/linux/arch/i386/mm/init.c Wed Sep 25 12:14:59 1996 +++ linux/arch/i386/mm/init.c Mon Oct 7 08:55:46 1996 @@ -40,7 +40,7 @@ * BAD_PAGE is the page that is used for page faults when linux * is out-of-memory. Older versions of linux just did a * do_exit(), but using this instead means there is less risk - * for a process dying in kernel mode, possibly leaving a inode + * for a process dying in kernel mode, possibly leaving an inode * unused etc.. * * BAD_PAGETABLE is the accompanying page-table: it is initialized diff -u --recursive --new-file v2.1.1/linux/arch/m68k/atari/ataints.c linux/arch/m68k/atari/ataints.c --- v2.1.1/linux/arch/m68k/atari/ataints.c Wed Sep 25 10:47:38 1996 +++ linux/arch/m68k/atari/ataints.c Mon Oct 7 08:55:46 1996 @@ -393,7 +393,7 @@ if (ATARIHW_PRESENT(PCM_8BIT) && ATARIHW_PRESENT(MICROWIRE)) { /* Initialize the LM1992 Sound Controller to enable the PSG sound. This is misplaced here, it should - be in a atasound_init(), that doesn't exist yet. */ + be in an atasound_init(), that doesn't exist yet. */ atari_microwire_cmd(MW_LM1992_PSG_HIGH); } diff -u --recursive --new-file v2.1.1/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c --- v2.1.1/linux/arch/m68k/mm/init.c Wed Sep 25 10:47:40 1996 +++ linux/arch/m68k/mm/init.c Mon Oct 7 08:55:46 1996 @@ -31,7 +31,7 @@ * BAD_PAGE is the page that is used for page faults when linux * is out-of-memory. Older versions of linux just did a * do_exit(), but using this instead means there is less risk - * for a process dying in kernel mode, possibly leaving a inode + * for a process dying in kernel mode, possibly leaving an inode * unused etc.. * * BAD_PAGETABLE is the accompanying page-table: it is initialized diff -u --recursive --new-file v2.1.1/linux/arch/mips/mm/init.c linux/arch/mips/mm/init.c --- v2.1.1/linux/arch/mips/mm/init.c Mon May 6 12:26:03 1996 +++ linux/arch/mips/mm/init.c Mon Oct 7 08:55:46 1996 @@ -34,7 +34,7 @@ * BAD_PAGE is the page that is used for page faults when linux * is out-of-memory. Older versions of linux just did a * do_exit(), but using this instead means there is less risk - * for a process dying in kernel mode, possibly leaving a inode + * for a process dying in kernel mode, possibly leaving an inode * unused etc.. * * BAD_PAGETABLE is the accompanying page-table: it is initialized diff -u --recursive --new-file v2.1.1/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c --- v2.1.1/linux/arch/ppc/mm/init.c Mon Jul 8 11:27:43 1996 +++ linux/arch/ppc/mm/init.c Mon Oct 7 08:55:46 1996 @@ -35,7 +35,7 @@ * BAD_PAGE is the page that is used for page faults when linux * is out-of-memory. Older versions of linux just did a * do_exit(), but using this instead means there is less risk - * for a process dying in kernel mode, possibly leaving a inode + * for a process dying in kernel mode, possibly leaving an inode * unused etc.. * * BAD_PAGETABLE is the accompanying page-table: it is initialized diff -u --recursive --new-file v2.1.1/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c --- v2.1.1/linux/arch/sparc/mm/init.c Thu Apr 25 13:22:05 1996 +++ linux/arch/sparc/mm/init.c Mon Oct 7 08:55:46 1996 @@ -32,7 +32,7 @@ * BAD_PAGE is the page that is used for page faults when linux * is out-of-memory. Older versions of linux just did a * do_exit(), but using this instead means there is less risk - * for a process dying in kernel mode, possibly leaving a inode + * for a process dying in kernel mode, possibly leaving an inode * unused etc.. * * BAD_PAGETABLE is the accompanying page-table: it is initialized diff -u --recursive --new-file v2.1.1/linux/drivers/char/console.c linux/drivers/char/console.c --- v2.1.1/linux/drivers/char/console.c Mon Sep 23 16:30:46 1996 +++ linux/drivers/char/console.c Tue Oct 8 11:17:30 1996 @@ -1391,7 +1391,12 @@ disable_bh(CONSOLE_BH); while (!tty->stopped && count) { enable_bh(CONSOLE_BH); + if (exception()) { + n = -EFAULT; + break; + } c = from_user ? get_user(buf) : *buf; + end_exception(); buf++; n++; count--; disable_bh(CONSOLE_BH); diff -u --recursive --new-file v2.1.1/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c --- v2.1.1/linux/drivers/char/cyclades.c Wed Sep 25 11:52:45 1996 +++ linux/drivers/char/cyclades.c Tue Oct 8 08:03:28 1996 @@ -1,5 +1,5 @@ static char rcsid[] = -"$Revision: 1.36.3.7A $$Date: 1996/07/27 10:25:50 $"; +"$Revision: 1.36.3.9 $$Date: 1996/10/07 19:47:13 $"; /* * linux/drivers/char/cyclades.c * @@ -24,6 +24,14 @@ * int cy_open(struct tty_struct *tty, struct file *filp); * * $Log: cyclades.c,v $ + * Revision 1.36.3.9 1996/10/07 19:47:13 bentson + * add MOD_DEC_USE_COUNT in one return from cy_close (as + * noted by Jon Lewis ) + * + * Revision 1.36.3.8 1996/06/07 16:29:00 bentson + * starting minor number at zero; added missing verify_area + * as noted by Heiko Eissfeldt + * * Revision 1.36.3.7 1996/04/19 21:06:18 bentson * remove unneeded boot message & fix CLOCAL hardware flow * control (Miquel van Smoorenburg ); @@ -2355,6 +2363,7 @@ /* If the TTY is being hung up, nothing to do */ if (tty_hung_up_p(filp)) { + MOD_DEC_USE_COUNT; restore_flags(flags); return; } diff -u --recursive --new-file v2.1.1/linux/drivers/char/ftape/fdc-io.c linux/drivers/char/ftape/fdc-io.c --- v2.1.1/linux/drivers/char/ftape/fdc-io.c Sun Sep 1 09:14:45 1996 +++ linux/drivers/char/ftape/fdc-io.c Mon Oct 7 08:55:46 1996 @@ -418,7 +418,7 @@ fdc_update_dsr(); } -/* Read back the Drive Specification regs on a i82078, so that we +/* Read back the Drive Specification regs on an i82078, so that we * are able to restore them later */ void fdc_save_drive_specs(void) @@ -1011,11 +1011,11 @@ result = fdc_issue_command(cmd, 1, stat, 1); TRACE(2, "FDC is already locked"); } - /* Test for a i82078 FDC */ + /* Test for an i82078 FDC */ cmd[0] = FDC_PARTID; result = fdc_issue_command(cmd, 1, stat, 1); if (result < 0 || stat[0] == 0x80) { - /* invalid command: not a i82078xx type FDC */ + /* invalid command: not an i82078xx type FDC */ result = no_fdc; for (i = 0; i < 4; ++i) { outb_p(i, fdc.tdr); @@ -1045,12 +1045,12 @@ result = fdc_issue_command(cmd, 1, stat, 16); if (result < 0) { TRACE(1, "FDC_SAVE failed. Dunno why"); - /* guess we better claim the fdc to be a i82078 */ + /* guess we better claim the fdc to be an i82078 */ result = i82078; TRACE(2, "Type i82078 FDC (i suppose) found"); } else { if ((stat[0] & FDC_SEL3V_BIT)) { - /* fdc running off 5Volts; Pray that it's a i82078-1 + /* fdc running off 5Volts; Pray that it's an i82078-1 */ TRACE(2, "Type i82078-1 or 5Volt i82078SL FDC found"); TRACE(2, "Treating it as an i82078-1 (2Mbps) FDC"); diff -u --recursive --new-file v2.1.1/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c --- v2.1.1/linux/drivers/char/keyboard.c Mon Sep 23 16:31:29 1996 +++ linux/drivers/char/keyboard.c Mon Oct 7 08:55:46 1996 @@ -1062,7 +1062,7 @@ /* * send_data sends a character to the keyboard and waits - * for a acknowledge, possibly retrying if asked to. Returns + * for an acknowledge, possibly retrying if asked to. Returns * the success status. */ static int send_data(unsigned char data) diff -u --recursive --new-file v2.1.1/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c --- v2.1.1/linux/drivers/char/n_tty.c Sun Sep 1 09:14:45 1996 +++ linux/drivers/char/n_tty.c Tue Oct 8 11:17:30 1996 @@ -809,6 +809,11 @@ } add_wait_queue(&tty->read_wait, &wait); + + if (exception()) + goto user_fault; + + disable_bh(TQUEUE_BH); while (1) { /* First test for status change. */ if (tty->packet && tty->link->ctrl_status) { @@ -844,7 +849,9 @@ retval = -ERESTARTSYS; break; } + enable_bh(TQUEUE_BH); schedule(); + disable_bh(TQUEUE_BH); continue; } current->state = TASK_RUNNING; @@ -859,9 +866,7 @@ while (1) { int eol; - disable_bh(TQUEUE_BH); if (!tty->read_cnt) { - enable_bh(TQUEUE_BH); break; } eol = clear_bit(tty->read_tail, @@ -870,7 +875,6 @@ tty->read_tail = ((tty->read_tail+1) & (N_TTY_BUF_SIZE-1)); tty->read_cnt--; - enable_bh(TQUEUE_BH); if (!eol) { put_user(c, b++); if (--nr) @@ -887,10 +891,8 @@ break; } } else { - disable_bh(TQUEUE_BH); copy_from_read_buf(tty, &b, &nr); copy_from_read_buf(tty, &b, &nr); - enable_bh(TQUEUE_BH); } /* If there is enough space in the read buffer now, let the @@ -905,6 +907,8 @@ if (time) current->timeout = time + jiffies; } + enable_bh(TQUEUE_BH); + end_exception(); remove_wait_queue(&tty->read_wait, &wait); if (!waitqueue_active(&tty->read_wait)) @@ -919,7 +923,13 @@ goto do_it_again; if (!size && !retval) clear_bit(TTY_PUSH, &tty->flags); - return (size ? size : retval); + return (size ? size : retval); + +user_fault: + enable_bh(TQUEUE_BH); + remove_wait_queue(&tty->read_wait, &wait); + current->timeout = 0; + return -EFAULT; } static int write_chan(struct tty_struct * tty, struct file * file, @@ -949,12 +959,17 @@ break; } if (O_OPOST(tty)) { + if (exception()) { + retval = -EFAULT; + break; + } while (nr > 0) { c = get_user(b); if (opost(c, tty) < 0) break; b++; nr--; } + end_exception(); if (tty->driver.flush_chars) tty->driver.flush_chars(tty); } else { diff -u --recursive --new-file v2.1.1/linux/drivers/char/pcxx.c linux/drivers/char/pcxx.c --- v2.1.1/linux/drivers/char/pcxx.c Thu Aug 1 15:40:32 1996 +++ linux/drivers/char/pcxx.c Sat Oct 5 09:46:32 1996 @@ -1120,10 +1120,12 @@ pcxe_termios = kmalloc(sizeof(struct termios *) * nbdevs, GFP_KERNEL); if (!pcxe_termios) panic("Unable to allocate pcxe_termios struct"); + memset(pcxe_termios,0,sizeof(struct termios *)*nbdevs); pcxe_termios_locked = kmalloc(sizeof(struct termios *) * nbdevs, GFP_KERNEL); if (!pcxe_termios_locked) panic("Unable to allocate pcxe_termios_locked struct"); + memset(pcxe_termios_locked,0,sizeof(struct termios *)*nbdevs); init_bh(DIGI_BH,do_pcxe_bh); enable_bh(DIGI_BH); diff -u --recursive --new-file v2.1.1/linux/drivers/char/pty.c linux/drivers/char/pty.c --- v2.1.1/linux/drivers/char/pty.c Sat Sep 28 22:58:22 1996 +++ linux/drivers/char/pty.c Tue Oct 8 11:17:30 1996 @@ -123,6 +123,10 @@ down(&tmp_buf_sem); temp_buffer = tmp_buf + ((tty->driver.subtype-1) * PTY_BUF_SIZE); + if (exception()) { + up(&tmp_buf_sem); + return -EFAULT; + } while (count > 0) { n = MIN(count, PTY_BUF_SIZE); memcpy_fromfs(temp_buffer, buf, n); @@ -134,6 +138,7 @@ buf += n; c+= n; count -= n; } + end_exception(); up(&tmp_buf_sem); } else { c = MIN(count, to->ldisc.receive_room(to)); diff -u --recursive --new-file v2.1.1/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.1.1/linux/drivers/char/tty_io.c Sat Sep 28 23:07:54 1996 +++ linux/drivers/char/tty_io.c Tue Oct 8 09:45:14 1996 @@ -11,7 +11,7 @@ * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0. * * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the - * tty_struct and tty_queue structures. Previously there was a array + * tty_struct and tty_queue structures. Previously there was an array * of 256 tty_struct's which was statically allocated, and the * tty_queue structures were allocated at boot time. Both are now * dynamically allocated only when the tty is open. @@ -1441,16 +1441,22 @@ sizeof (struct winsize)); if (retval) return retval; + if (exception()) + return -EFAULT; memcpy_tofs((struct winsize *) arg, &tty->winsize, sizeof (struct winsize)); + end_exception(); return 0; case TIOCSWINSZ: retval = verify_area(VERIFY_READ, (void *) arg, sizeof (struct winsize)); if (retval) - return retval; + return retval; + if (exception()) + return -EFAULT; memcpy_fromfs(&tmp_ws, (struct winsize *) arg, sizeof (struct winsize)); + end_exception(); if (memcmp(&tmp_ws, &tty->winsize, sizeof(struct winsize))) { if (tty->pgrp > 0) @@ -1477,7 +1483,10 @@ retval = verify_area(VERIFY_READ, (void *) arg, sizeof(int)); if (retval) return retval; + if (exception()) + return -EFAULT; arg = get_user((unsigned int *) arg); + end_exception(); if (arg) file->f_flags |= O_NONBLOCK; else @@ -1539,7 +1548,10 @@ sizeof (pid_t)); if (retval) return retval; + if (exception()) + return -EFAULT; put_user(real_tty->pgrp, (pid_t *) arg); + end_exception(); return 0; case TIOCSPGRP: retval = tty_check_change(real_tty); @@ -1563,7 +1575,10 @@ sizeof (int)); if (retval) return retval; + if (exception()) + return -EFAULT; put_user(tty->ldisc.num, (int *) arg); + end_exception(); return 0; case TIOCSETD: retval = tty_check_change(tty); @@ -1573,7 +1588,10 @@ sizeof (int)); if (retval) return retval; + if (exception()) + return -EFAULT; arg = get_user((int *) arg); + end_exception(); return tty_set_ldisc(tty, arg); case TIOCLINUX: if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE) @@ -1583,7 +1601,11 @@ retval = verify_area(VERIFY_READ, (void *) arg, 1); if (retval) return retval; - switch (retval = get_user((char *)arg)) + if (exception()) + return -EFAULT; + retval = get_user((char *)arg); + end_exception(); + switch (retval) { case 0: case 8: diff -u --recursive --new-file v2.1.1/linux/drivers/char/vga.c linux/drivers/char/vga.c --- v2.1.1/linux/drivers/char/vga.c Tue May 7 07:50:53 1996 +++ linux/drivers/char/vga.c Sat Oct 5 12:03:25 1996 @@ -409,10 +409,10 @@ arg += cmapsz; if (set) for (i=0; i jiffies ) if ( !( hp100_inw( LAN_CFG_VG ) & ( HP100_LINK_UP_ST | HP100_LINK_CABLE_ST | diff -u --recursive --new-file v2.1.1/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c --- v2.1.1/linux/drivers/net/ibmtr.c Wed Aug 21 09:12:49 1996 +++ linux/drivers/net/ibmtr.c Mon Oct 7 08:55:47 1996 @@ -1488,7 +1488,7 @@ /* tok_get_stats(): Basically a scaffold routine which will return the address of the tr_statistics structure associated with - this device -- the tr.... structure is a ethnet look-alike + this device -- the tr.... structure is an ethnet look-alike so at least for this iteration may suffice. */ static struct enet_statistics * tok_get_stats(struct device *dev) { diff -u --recursive --new-file v2.1.1/linux/drivers/net/lance32.c linux/drivers/net/lance32.c --- v2.1.1/linux/drivers/net/lance32.c Thu Jul 4 08:52:04 1996 +++ linux/drivers/net/lance32.c Mon Oct 7 08:55:47 1996 @@ -55,7 +55,7 @@ * only tested on Alpha Noname Board * v0.02: changed IRQ handling for new interrupt scheme (dev_id) * tested on a ASUS SP3G - * v0.10: fixed a odd problem with the 79C794 in a Compaq Deskpro XL + * v0.10: fixed an odd problem with the 79C794 in a Compaq Deskpro XL * looks like the 974 doesn't like stopping and restarting in a * short period of time; now we do a reinit of the lance; the * bug was triggered by doing ifconfig eth0 broadcast diff -u --recursive --new-file v2.1.1/linux/drivers/net/ne.c linux/drivers/net/ne.c --- v2.1.1/linux/drivers/net/ne.c Tue May 28 07:39:18 1996 +++ linux/drivers/net/ne.c Mon Oct 7 20:27:59 1996 @@ -299,14 +299,21 @@ wordlength = 1; } + /* At this point, wordlength *only* tells us if the SA_prom is doubled + up or not because some broken PCI cards don't respect the byte-wide + request in program_seq above, and hence don't have doubled up values. + These broken cards would otherwise be detected as an ne1000. */ + + if (wordlength == 2) + for (i = 0; i < 16; i++) + SA_prom[i] = SA_prom[i+i]; + + if (pci_irq_line) + wordlength = 2; /* Catch broken cards mentioned above. */ + if (wordlength == 2) { /* We must set the 8390 for word mode. */ outb_p(0x49, ioaddr + EN0_DCFG); - /* We used to reset the ethercard here, but it doesn't seem - to be necessary. */ - /* Un-double the SA_prom values. */ - for (i = 0; i < 16; i++) - SA_prom[i] = SA_prom[i+i]; start_page = NESM_START_PG; stop_page = NESM_STOP_PG; } else { diff -u --recursive --new-file v2.1.1/linux/drivers/net/ni65.h linux/drivers/net/ni65.h --- v2.1.1/linux/drivers/net/ni65.h Mon Feb 26 11:58:15 1996 +++ linux/drivers/net/ni65.h Mon Oct 7 08:55:47 1996 @@ -1,6 +1,6 @@ /* am7990 (lance) definitions * - * This is a extension to the Linux operating system, and is covered by + * This is an extension to the Linux operating system, and is covered by * same Gnu Public License that covers that work. * * Michael Hipp diff -u --recursive --new-file v2.1.1/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c --- v2.1.1/linux/drivers/net/seeq8005.c Mon May 6 12:26:08 1996 +++ linux/drivers/net/seeq8005.c Mon Oct 7 08:55:47 1996 @@ -101,7 +101,7 @@ (detachable devices only). */ #ifdef HAVE_DEVLIST -/* Support for a alternate probe manager, which will eliminate the +/* Support for an alternate probe manager, which will eliminate the boilerplate below. */ struct netdev_entry seeq8005_drv = {"seeq8005", seeq8005_probe1, SEEQ8005_IO_EXTENT, seeq8005_portlist}; diff -u --recursive --new-file v2.1.1/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c --- v2.1.1/linux/drivers/net/sk_g16.c Mon May 6 12:26:09 1996 +++ linux/drivers/net/sk_g16.c Mon Oct 7 08:55:47 1996 @@ -390,7 +390,7 @@ * * PROM: The PROM obtains the ETHERNET-MAC-Address. It is realised as a * 8-Bit PROM, this means only the 16 even addresses are used of the - * 32 Byte Address region. Access to a odd address results in invalid + * 32 Byte Address region. Access to an odd address results in invalid * data. * * LANCE I/O Reg: The I/O Reg is build of 4 single Registers, Low-Byte Write, diff -u --recursive --new-file v2.1.1/linux/drivers/net/skeleton.c linux/drivers/net/skeleton.c --- v2.1.1/linux/drivers/net/skeleton.c Fri Mar 1 07:50:45 1996 +++ linux/drivers/net/skeleton.c Mon Oct 7 08:55:47 1996 @@ -120,7 +120,7 @@ */ #ifdef HAVE_DEVLIST /* - * Support for a alternate probe manager, + * Support for an alternate probe manager, * which will eliminate the boilerplate below. */ struct netdev_entry netcard_drv = diff -u --recursive --new-file v2.1.1/linux/drivers/net/smc9194.c linux/drivers/net/smc9194.c --- v2.1.1/linux/drivers/net/smc9194.c Fri Apr 12 09:49:39 1996 +++ linux/drivers/net/smc9194.c Mon Oct 7 08:55:47 1996 @@ -1454,7 +1454,7 @@ PRINTK2(("RCV: STATUS %4x LENGTH %4x\n", status, packet_length )); /* . the packet length contains 3 extra words : - . status, length, and a extra word with an odd byte . + . status, length, and an extra word with an odd byte . */ packet_length -= 6; diff -u --recursive --new-file v2.1.1/linux/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c --- v2.1.1/linux/drivers/scsi/53c7,8xx.c Sat Oct 5 16:58:34 1996 +++ linux/drivers/scsi/53c7,8xx.c Mon Oct 7 08:55:47 1996 @@ -153,7 +153,7 @@ * in the host code. * * On the NCR53c710, interrupts are generated as on the NCR53c8x0, - * only the lack of a interrupt-on-the-fly facility complicates + * only the lack of an interrupt-on-the-fly facility complicates * things. Also, SCSI ID registers and commands are * bit fielded rather than binary encoded. * @@ -248,7 +248,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.1.1/linux/drivers/scsi/NCR5380.c linux/drivers/scsi/NCR5380.c --- v2.1.1/linux/drivers/scsi/NCR5380.c Mon Apr 29 17:14:19 1996 +++ linux/drivers/scsi/NCR5380.c Mon Oct 7 08:55:47 1996 @@ -196,7 +196,7 @@ /* * Using this file : * This file a skeleton Linux SCSI driver for the NCR 5380 series - * of chips. To use it, you write a architecture specific functions + * of chips. To use it, you write an architecture specific functions * and macros and include this file in your driver. * * These macros control options : diff -u --recursive --new-file v2.1.1/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c --- v2.1.1/linux/drivers/scsi/advansys.c Fri Sep 27 07:52:57 1996 +++ linux/drivers/scsi/advansys.c Sat Oct 5 13:39:00 1996 @@ -1,4 +1,4 @@ -/* $Id: advansys.c,v 1.20 1996/09/26 00:47:54 bobf Exp bobf $ */ +/* $Id: advansys.c,v 1.24 1996/10/05 00:58:14 bobf Exp bobf $ */ /* * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters * @@ -18,9 +18,10 @@ */ /* - * The driver has been run with the v1.2.13, v1.3.57, and v2.0.21 kernels. + * The driver has been used in the following kernels: + * v1.2.13, v1.3.57, v2.0.21, v2.1.0 */ -#define ASC_VERSION "1.7" /* AdvanSys Driver Version */ +#define ASC_VERSION "1.8" /* AdvanSys Driver Version */ /* @@ -441,9 +442,38 @@ 5. Remove the request timeout issue form the driver issues list. 6. Miscellaneous documentation additions and changes. + 1.8 (10/4/96): + 1. Make changes to handle the new v2.1.0 kernel memory mapping + in which a kernel virtual address may not be equivalent to its + bus or DMA memory address. + 2. Change abort and reset request handling to make it yet even + more robust. + 3. Try to mitigate request starvation by sending ordered requests + to heavily loaded, tag queuing enabled devices. + 4. Maintain statistics on request response time. + 5. Add request response time statistics and other information to + the adapter /proc file: /proc/scsi/advansys[0...]. + I. Known Problems or Issues - None + 1. If a large "Device Queue Size" is set in the adapter + BIOS and a device supports the queue depth and the device + is heavily loaded, requests may be sent to the device + faster than they can be executed causing the requests to + queue up in the low-level driver on a wait queue. This may + lead to time-out abort requests by the mid-level driver. + + The short term solution is to set a smaller "Device Queue + Size" in the adapter BIOS. Response times can be monitored + per device by reading the /proc/scsi/advansys/[0...] file. + + The long term solution is to modify the mid-level driver to + institute a flow control mechanism between the two levels. + The low-level driver would notify the mid-level driver when + a device is falling behind on executing requests. This would + prevent the mid-level driver from sending more requests until + the low-level driver has notified it that the device has caught + up on request execution. J. Credits @@ -2137,15 +2167,52 @@ #define DRIVER_BYTE(byte) ((byte) << 24) /* - * REQ and REQP are the generic name for a SCSI request block and pointer. - * REQPTID(reqp) returns reqp's target id. - * REQPNEXT(reqp) returns reqp's next pointer. - * REQPNEXTP(reqp) returns a pointer to reqp's next pointer. + * The following definitions and macros are OS independent interfaces to + * the queue functions: + * REQ - SCSI request structure + * REQP - pointer to SCSI request structure + * REQPTID(reqp) - reqp's target id + * REQPNEXT(reqp) - reqp's next pointer + * REQPNEXTP(reqp) - pointer to reqp's next pointer + * REQPTIME(reqp) - reqp's time stamp value + * REQTIMESTAMP() - system time stamp value */ typedef Scsi_Cmnd REQ, *REQP; #define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble)) #define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble)) #define REQPTID(reqp) ((reqp)->target) +#define REQPTIME(reqp) ((reqp)->SCp.this_residual) +#define REQTIMESTAMP() (jiffies) + +#define REQTIMESTAT(function, ascq, reqp, tid) \ +{ \ + /* + * If the request time stamp is less than the system time stamp, then \ + * maybe the system time stamp wrapped. Set the request time to zero.\ + */ \ + if (REQPTIME(reqp) <= REQTIMESTAMP()) { \ + REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \ + } else { \ + /* Indicate an error occurred with the assertion. */ \ + ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \ + REQPTIME(reqp) = 0; \ + } \ + /* Handle first minimum time case without external initialization. */ \ + if (((ascq)->q_tot_cnt[tid] == 1) || \ + (REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \ + (ascq)->q_min_tim[tid] = REQPTIME(reqp); \ + ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \ + (function), (tid), (ascq)->q_min_tim[tid]); \ + } \ + if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \ + (ascq)->q_max_tim[tid] = REQPTIME(reqp); \ + ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \ + (function), tid, (ascq)->q_max_tim[tid]); \ + } \ + (ascq)->q_tot_tim[tid] += REQPTIME(reqp); \ + /* Reset the time stamp field. */ \ + REQPTIME(reqp) = 0; \ +} /* asc_enqueue() flags */ #define ASC_FRONT 1 @@ -2287,8 +2354,7 @@ #define ASC_DBG3(lvl, s, a1, a2, a3) #define ASC_DBG4(lvl, s, a1, a2, a3, a4) #define ASC_DBG_PRT_SCSI_HOST(lvl, s) -#define ASC_DBG_PRT_DVC_VAR(lvl, v) -#define ASC_DBG_PRT_DVC_CFG(lvl, c) +#define ASC_DBG_PRT_SCSI_CMND(lvl, s) #define ASC_DBG_PRT_SCSI_Q(lvl, scsiqp) #define ASC_DBG_PRT_QDONE_INFO(lvl, qdone) #define ASC_DBG_PRT_HEX(lvl, name, start, length) @@ -2348,17 +2414,10 @@ } \ } -#define ASC_DBG_PRT_DVC_VAR(lvl, v) \ - { \ - if (asc_dbglvl >= (lvl)) { \ - asc_prt_dvc_var(v); \ - } \ - } - -#define ASC_DBG_PRT_DVC_CFG(lvl, c) \ +#define ASC_DBG_PRT_SCSI_CMND(lvl, s) \ { \ if (asc_dbglvl >= (lvl)) { \ - asc_prt_dvc_cfg(c); \ + asc_prt_scsi_cmnd(s); \ } \ } @@ -2447,6 +2506,10 @@ #ifdef ADVANSYS_STATS short q_cur_cnt[ASC_MAX_TID+1]; /* current queue count */ short q_max_cnt[ASC_MAX_TID+1]; /* maximum queue count */ + ulong q_tot_cnt[ASC_MAX_TID+1]; /* total enqueue count */ + ulong q_tot_tim[ASC_MAX_TID+1]; /* total time queued */ + ushort q_max_tim[ASC_MAX_TID+1]; /* maximum time queued */ + ushort q_min_tim[ASC_MAX_TID+1]; /* minimum time queued */ #endif /* ADVANSYS_STATS */ } asc_queue_t; @@ -2464,10 +2527,11 @@ ASC_DVC_CFG asc_dvc_cfg; /* Device configuration */ asc_queue_t active; /* Active command queue */ asc_queue_t waiting; /* Waiting command queue */ + asc_queue_t done; /* Done command queue */ ASC_SCSI_BIT_ID_TYPE init_tidmask; /* Target initialized mask */ ASCEEP_CONFIG eep_config; /* EEPROM configuration */ - asc_queue_t scsi_done_q; /* Completion command queue */ - ulong reset_jiffies; /* Saved time of last reset */ + ulong last_reset; /* Saved time of last reset */ + ushort rcnt[ASC_MAX_TID+1]; /* Starvation Request Count */ #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) /* /proc/scsi/advansys/[0...] */ char *prtbuf; /* Statistics Print Buffer */ @@ -2646,6 +2710,7 @@ #endif /* ADVANSYS_STATS */ #ifdef ADVANSYS_DEBUG STATIC void asc_prt_scsi_host(struct Scsi_Host *); +STATIC void asc_prt_scsi_cmnd(Scsi_Cmnd *); STATIC void asc_prt_dvc_cfg(ASC_DVC_CFG *); STATIC void asc_prt_dvc_var(ASC_DVC_VAR *); STATIC void asc_prt_scsi_q(ASC_SCSI_Q *); @@ -3512,7 +3577,9 @@ * Polled-I/O. Apparently host drivers shouldn't return until * command is finished. * - * XXX - Can host drivers block here instead of spinning on command status? + * Note: This is an old interface that is no longer used by the SCSI + * mid-level driver. The new interface, advansys_queuecommand(), + * currently handles all requests. */ int advansys_command(Scsi_Cmnd *scp) @@ -3521,6 +3588,10 @@ ASC_STATS(scp->host, command); scp->SCp.Status = 0; /* Set to a known state */ advansys_queuecommand(scp, advansys_command_done); + /* + * XXX - Can host drivers block here instead of spinning on + * command status? + */ while (scp->SCp.Status == 0) { continue; } @@ -3571,11 +3642,11 @@ } /* - * Add blocked requests to the board's 'scsi_done_q'. The queued + * Add blocked requests to the board's 'done' queue. The queued * requests will be completed at the end of the abort or reset * handling. */ - asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK); + asc_enqueue(&boardp->done, scp, ASC_BACK); restore_flags(flags); return 0; } @@ -3601,7 +3672,7 @@ * target waiting list. * * If an error occurred, the request will have been placed on the - * board's 'scsi_done_q' and must be completed before returning. + * board's 'done' queue and must be completed before returning. */ scp->scsi_done = done; switch (asc_execute_scsi_cmnd(scp)) { @@ -3612,7 +3683,7 @@ break; case ASC_ERROR: default: - done_scp = asc_dequeue_list(&boardp->scsi_done_q, NULL, ASC_TID_ALL); + done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL); /* Interrupts could be enabled here. */ asc_scsi_done_list(done_scp); break; @@ -3634,42 +3705,63 @@ asc_board_t *boardp; ASC_DVC_VAR *asc_dvc_varp; int flags; - int status = ASC_FALSE; - int abort_do_done = ASC_FALSE; - Scsi_Cmnd *done_scp; - int ret = ASC_ERROR; - - ASC_DBG1(1, "advansys_abort: scp %x\n", (unsigned) scp); + int do_scsi_done; + int scp_found; + Scsi_Cmnd *done_scp = NULL; + int ret; /* Save current flags and disable interrupts. */ save_flags(flags); cli(); + ASC_DBG1(1, "advansys_abort: scp %x\n", (unsigned) scp); + #ifdef ADVANSYS_STATS if (scp->host != NULL) { ASC_STATS(scp->host, abort); } #endif /* ADVANSYS_STATS */ +#ifdef ADVVANSYS_DEBUG + do_scsi_done = ASC_ERROR; + scp_found = ASC_ERROR; + ret = ASC_ERROR; +#endif /* ADVANSYS_DEBUG */ + #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) if (scp->serial_number != scp->serial_number_at_timeout) { + ASC_PRINT1( +"advansys_abort: timeout serial number changed for request %x\n", + (unsigned) scp); + do_scsi_done = ASC_FALSE; + scp_found = ASC_FALSE; ret = SCSI_ABORT_NOT_RUNNING; } else #endif /* version >= v1.3.89 */ if ((shp = scp->host) == NULL) { scp->result = HOST_BYTE(DID_ERROR); + do_scsi_done = ASC_TRUE; + scp_found = ASC_FALSE; ret = SCSI_ABORT_ERROR; } else if ((boardp = ASC_BOARDP(shp))->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) { ASC_PRINT2( "advansys_abort: board %d: Nested host reset or abort, flags 0x%x\n", boardp->id, boardp->flags); + do_scsi_done = ASC_TRUE; + if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) || + (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) { + scp_found = ASC_TRUE; + } else { + scp_found = ASC_FALSE; + } scp->result = HOST_BYTE(DID_ERROR); ret = SCSI_ABORT_ERROR; } else { /* Set abort flag to avoid nested reset or abort requests. */ boardp->flags |= ASC_HOST_IN_ABORT; + do_scsi_done = ASC_TRUE; if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) { /* * If asc_rmqueue() found the command on the waiting @@ -3678,6 +3770,7 @@ */ ASC_DBG1(1, "advansys_abort: scp %x found on waiting queue\n", (unsigned) scp); + scp_found = ASC_TRUE; scp->result = HOST_BYTE(DID_ABORT); ret = SCSI_ABORT_SUCCESS; } else if (asc_isqueued(&boardp->active, scp) == ASC_TRUE) { @@ -3693,7 +3786,7 @@ sti(); /* Enable interrupts for AscAbortSRB(). */ ASC_DBG1(1, "advansys_abort: before AscAbortSRB(), scp %x\n", (unsigned) scp); - switch (status = AscAbortSRB(asc_dvc_varp, (ulong) scp)) { + switch (AscAbortSRB(asc_dvc_varp, (ulong) scp)) { case ASC_TRUE: /* asc_isr_callback() will be called */ ASC_DBG(1, "advansys_abort: AscAbortSRB() TRUE\n"); @@ -3713,20 +3806,23 @@ cli(); /* - * If the abort failed, remove the request from the - * active list and complete it. + * The request will either still be on the active queue + * or have been added to the board's done queue. */ - if (status != ASC_TRUE) { - if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) { - scp->result = HOST_BYTE(DID_ABORT); - abort_do_done = ASC_TRUE; - } + if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) { + scp->result = HOST_BYTE(DID_ABORT); + scp_found = ASC_TRUE; + } else { + scp_found = asc_rmqueue(&boardp->done, scp); + ASC_ASSERT(scp_found == ASC_TRUE); } } else { /* * The command was not found on the active or waiting queues. */ + do_scsi_done = ASC_TRUE; + scp_found = ASC_FALSE; ret = SCSI_ABORT_NOT_RUNNING; } @@ -3736,11 +3832,11 @@ /* * Because the ASC_HOST_IN_ABORT flag causes both * 'advansys_interrupt' and 'asc_isr_callback' to - * queue requests to the board's 'scsi_done_q' and + * queue requests to the board's 'done' queue and * prevents waiting commands from being executed, * these queued requests must be handled here. */ - done_scp = asc_dequeue_list(&boardp->scsi_done_q, NULL, ASC_TID_ALL); + done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL); /* * Start any waiting commands for the board. @@ -3749,22 +3845,39 @@ ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n"); asc_execute_queue(&boardp->waiting); } + } - /* Interrupts could be enabled here. */ + /* Interrupts could be enabled here. */ - /* - * If needed, complete the aborted request. - */ - if (abort_do_done == ASC_TRUE) { + /* + * Complete the request to be aborted, unless it has been + * restarted as detected above, even if it was not found on + * the device active or waiting queues. + */ + ASC_ASSERT(do_scsi_done != ASC_ERROR); + ASC_ASSERT(scp_found != ASC_ERROR); + if (do_scsi_done == ASC_TRUE) { + if (scp->scsi_done == NULL) { + ASC_PRINT1( +"advansys_abort: aborted request scsi_done() is NULL, %x\n", + (unsigned) scp); + } else { + if (scp_found == ASC_FALSE) { + ASC_PRINT1( +"advansys_abort: abort request not active or waiting, completing anyway %x\n", + (unsigned) scp); + } ASC_STATS(scp->host, done); scp->scsi_done(scp); } + } - /* - * It is possible for the request done function to re-enable - * interrupts without confusing the driver. But here interrupts - * aren't enabled until all requests have been completed. - */ + /* + * It is possible for the request done function to re-enable + * interrupts without confusing the driver. But here interrupts + * aren't enabled until all requests have been completed. + */ + if (done_scp != NULL) { asc_scsi_done_list(done_scp); } @@ -3795,18 +3908,18 @@ int flags; Scsi_Cmnd *done_scp = NULL, *last_scp = NULL; Scsi_Cmnd *tscp, *new_last_scp; - int scp_found = ASC_FALSE; - int device_reset = ASC_FALSE; + int do_scsi_done; + int scp_found; int status; int target; - int ret = ASC_ERROR; - - ASC_DBG1(1, "advansys_reset: %x\n", (unsigned) scp); + int ret; /* Save current flags and disable interrupts. */ save_flags(flags); cli(); + ASC_DBG1(1, "advansys_reset: %x\n", (unsigned) scp); + #ifdef ADVANSYS_STATS if (scp->host != NULL) { ASC_STATS(scp->host, reset); @@ -3815,21 +3928,35 @@ #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) if (scp->serial_number != scp->serial_number_at_timeout) { + ASC_PRINT1( +"advansys_reset: timeout serial number changed for request %x\n", + (unsigned) scp); + do_scsi_done = ASC_FALSE; + scp_found = ASC_FALSE; ret = SCSI_RESET_NOT_RUNNING; } else #endif /* version >= v1.3.89 */ if ((shp = scp->host) == NULL) { scp->result = HOST_BYTE(DID_ERROR); + do_scsi_done = ASC_TRUE; + scp_found = ASC_FALSE; ret = SCSI_RESET_ERROR; } else if ((boardp = ASC_BOARDP(shp))->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) { ASC_PRINT2( "advansys_reset: board %d: Nested host reset or abort, flags 0x%x\n", boardp->id, boardp->flags); + do_scsi_done = ASC_TRUE; + if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) || + (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) { + scp_found = ASC_TRUE; + } else { + scp_found = ASC_FALSE; + } scp->result = HOST_BYTE(DID_ERROR); ret = SCSI_RESET_ERROR; - } else if (jiffies >= boardp->reset_jiffies && - jiffies < (boardp->reset_jiffies + (10 * HZ))) { + } else if (jiffies >= boardp->last_reset && + jiffies < (boardp->last_reset + (10 * HZ))) { /* * Don't allow a reset to be attempted within 10 seconds * of the last reset. @@ -3840,15 +3967,27 @@ */ ASC_DBG(1, "advansys_reset: reset within 10 sec of last reset ignored\n"); + do_scsi_done = ASC_TRUE; + if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) || + (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) { + scp_found = ASC_TRUE; + } else { + scp_found = ASC_FALSE; + } scp->result = HOST_BYTE(DID_ERROR); ret = SCSI_RESET_ERROR; } else { + int device_reset = ASC_FALSE; + + do_scsi_done = ASC_TRUE; + /* Set reset flag to avoid nested reset or abort requests. */ boardp->flags |= ASC_HOST_IN_RESET; /* - * If the request is on the target waiting or active queue, - * note that it was found and remove it from its queue. + * If the request is on the target waiting or active queue + * or the board done queue, then remove it and note that it + * was found. */ if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) { ASC_DBG(1, "advansys_reset: active scp_found = TRUE\n"); @@ -3856,6 +3995,10 @@ } else if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) { ASC_DBG(1, "advansys_reset: waiting scp_found = TRUE\n"); scp_found = ASC_TRUE; + } else if (asc_rmqueue(&boardp->done, scp) == ASC_TRUE) { + scp_found = ASC_TRUE; + } else { + scp_found = ASC_FALSE; } /* @@ -3939,11 +4082,11 @@ /* * Because the ASC_HOST_IN_RESET flag causes both * 'advansys_interrupt' and 'asc_isr_callback' to - * queue requests to the board's 'scsi_done_q' and + * queue requests to the board's 'done' queue and * prevents waiting commands from being executed, * these queued requests must be handled here. */ - done_scp = asc_dequeue_list(&boardp->scsi_done_q, &last_scp, + done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL); /* @@ -4006,7 +4149,7 @@ } /* Save the time of the most recently completed reset. */ - boardp->reset_jiffies = jiffies; + boardp->last_reset = jiffies; /* Clear reset flag. */ boardp->flags &= ~ASC_HOST_IN_RESET; @@ -4018,34 +4161,35 @@ ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n"); asc_execute_queue(&boardp->waiting); } + ret = SCSI_RESET_SUCCESS; + } - /* Interrupts could be enabled here. */ + /* Interrupts could be enabled here. */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) - /* - * If the command was found on the active or waiting request - * queues or if the the SCSI_RESET_SYNCHRONOUS flag is set, - * then done the command now. - */ - if (scp_found == ASC_TRUE || (reset_flags & SCSI_RESET_SYNCHRONOUS)) { - scp->result = HOST_BYTE(DID_RESET); - ASC_STATS(scp->host, done); - scp->scsi_done(scp); - } -#else /* version >= v1.3.89 */ - if (scp_found == ASC_TRUE) { - scp->result = HOST_BYTE(DID_RESET); + ASC_ASSERT(do_scsi_done != ASC_ERROR); + ASC_ASSERT(scp_found != ASC_ERROR); + if (do_scsi_done == ASC_TRUE) { + if (scp->scsi_done == NULL) { + ASC_PRINT1( +"advansys_reset: reset request scsi_done() is NULL, %x\n", + (unsigned) scp); + } else { + if (scp_found == ASC_FALSE) { + ASC_PRINT1( +"advansys_reset: reset request not active or waiting, completing anyway %x\n", + (unsigned) scp); + } ASC_STATS(scp->host, done); scp->scsi_done(scp); } -#endif /* version >= v1.3.89 */ - ret = SCSI_RESET_SUCCESS; + } - /* - * It is possible for the request done function to re-enable - * interrupts without confusing the driver. But here interrupts - * aren't enabled until requests have been completed. - */ + /* + * It is possible for the request done function to re-enable + * interrupts without confusing the driver. But here interrupts + * aren't enabled until requests have been completed. + */ + if (done_scp != NULL) { asc_scsi_done_list(done_scp); } @@ -4239,11 +4383,11 @@ * Add to the list of requests that must be completed. */ if (done_scp == NULL) { - done_scp = asc_dequeue_list(&boardp->scsi_done_q, &last_scp, + done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL); } else { ASC_ASSERT(last_scp != NULL); - REQPNEXT(last_scp) = asc_dequeue_list(&boardp->scsi_done_q, + REQPNEXT(last_scp) = asc_dequeue_list(&boardp->done, &new_last_scp, ASC_TID_ALL); if (new_last_scp != NULL) { ASC_ASSERT(REQPNEXT(last_scp) != NULL); @@ -4318,6 +4462,7 @@ tscp = REQPNEXT(scp); REQPNEXT(scp) = NULL; ASC_STATS(scp->host, done); + ASC_ASSERT(scp->scsi_done != NULL); scp->scsi_done(scp); scp = tscp; } @@ -4360,7 +4505,7 @@ * host_scribble - used for pointer to another Scsi_Cmnd * * If this function returns ASC_NOERROR or ASC_ERROR the request - * has been enqueued on the board's 'scsi_done_q' and must be + * has been enqueued on the board's 'done' queue and must be * completed by the caller. * * If ASC_BUSY is returned the request must be enqueued by the @@ -4387,7 +4532,7 @@ if ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(scp->target)) == 0) { if (asc_init_dev(asc_dvc_varp, scp) == ASC_FALSE) { scp->result = HOST_BYTE(DID_BAD_TARGET); - asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK); + asc_enqueue(&boardp->done, scp, ASC_BACK); return ASC_ERROR; } boardp->init_tidmask |= ASC_TIX_TO_TARGET_ID(scp->target); @@ -4412,9 +4557,29 @@ asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->target); asc_scsi_q.q1.target_lun = scp->lun; asc_scsi_q.q2.target_ix = ASC_TIDLUN_TO_IX(scp->target, scp->lun); +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) asc_scsi_q.q1.sense_addr = (ulong) &scp->sense_buffer[0]; +#else /* version >= v2.1.0 */ + asc_scsi_q.q1.sense_addr = virt_to_bus(&scp->sense_buffer[0]); +#endif /* version >= v2.1.0 */ asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer); - asc_scsi_q.q2.tag_code = M2_QTAG_MSG_SIMPLE; + + /* + * If there are more than five outstanding commands for the + * current target, then every tenth command send an ORDERED + * request. This heuristic tries to retain the benefit of + * request sorting while preventing request starvation. + * + * The request count is incremented below for every successfully + * started request. + * + */ + if ((asc_dvc_varp->cur_dvc_qng[scp->target] > 5) && + (boardp->rcnt[scp->target] % 10) == 0) { + asc_scsi_q.q2.tag_code = M2_QTAG_MSG_ORDERED; + } else { + asc_scsi_q.q2.tag_code = M2_QTAG_MSG_SIMPLE; + } /* * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather @@ -4425,8 +4590,11 @@ * CDB request of single contiguous buffer. */ ASC_STATS(scp->host, cont_cnt); - /* request_buffer is already a real address. */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) asc_scsi_q.q1.data_addr = (ulong) scp->request_buffer; +#else /* version >= v2.1.0 */ + asc_scsi_q.q1.data_addr = virt_to_bus(scp->request_buffer); +#endif /* version >= v2.1.0 */ asc_scsi_q.q1.data_cnt = scp->request_bufflen; ASC_STATS_ADD(scp->host, cont_xfer, ASC_CEILING(scp->request_bufflen, 512)); @@ -4444,7 +4612,7 @@ "asc_execute_scsi_cmnd: board %d: use_sg %d > sg_tablesize %d\n", boardp->id, scp->use_sg, scp->host->sg_tablesize); scp->result = HOST_BYTE(DID_ERROR); - asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK); + asc_enqueue(&boardp->done, scp, ASC_BACK); return ASC_ERROR; } @@ -4468,7 +4636,11 @@ */ slp = (struct scatterlist *) scp->request_buffer; for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) { +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) asc_sg_head.sg_list[sgcnt].addr = (ulong) slp->address; +#else /* version >= v2.1.0 */ + asc_sg_head.sg_list[sgcnt].addr = virt_to_bus(slp->address); +#endif /* version >= v2.1.0 */ asc_sg_head.sg_list[sgcnt].bytes = slp->length; ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512)); } @@ -4484,6 +4656,11 @@ switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) { case ASC_NOERROR: ASC_STATS(scp->host, asc_noerror); + /* + * Increment monotonically increasing per device successful + * request count. Wrapping of 'rcnt' doesn't matter. + */ + boardp->rcnt[scp->target]++; asc_enqueue(&boardp->active, scp, ASC_BACK); ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n"); break; @@ -4497,7 +4674,7 @@ boardp->id, asc_dvc_varp->err_code); ASC_STATS(scp->host, asc_error); scp->result = HOST_BYTE(DID_ERROR); - asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK); + asc_enqueue(&boardp->done, scp, ASC_BACK); break; default: ASC_PRINT2( @@ -4505,7 +4682,7 @@ boardp->id, asc_dvc_varp->err_code); ASC_STATS(scp->host, asc_unknown); scp->result = HOST_BYTE(DID_ERROR); - asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK); + asc_enqueue(&boardp->done, scp, ASC_BACK); break; } @@ -4645,7 +4822,7 @@ * The done function for the command will be called from * advansys_interrupt(). */ - asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK); + asc_enqueue(&boardp->done, scp, ASC_BACK); return; } @@ -5188,12 +5365,14 @@ ascq->q_tidmask |= ASC_TIX_TO_TARGET_ID(tid); #ifdef ADVANSYS_STATS /* Maintain request queue statistics. */ + ascq->q_tot_cnt[tid]++; ascq->q_cur_cnt[tid]++; if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) { ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid]; ASC_DBG2(1, "asc_enqueue: new q_max_cnt[%d] %d\n", tid, ascq->q_max_cnt[tid]); } + REQPTIME(reqp) = REQTIMESTAMP(); #endif /* ADVANSYS_STATS */ ASC_DBG1(1, "asc_enqueue: reqp %x\n", (unsigned) reqp); return; @@ -5227,6 +5406,7 @@ /* Maintain request queue statistics. */ ascq->q_cur_cnt[tid]--; ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0); + REQTIMESTAT("asc_dequeue", ascq, reqp, tid); #endif /* ADVANSYS_STATS */ } ASC_DBG1(1, "asc_dequeue: reqp %x\n", (unsigned) reqp); @@ -5249,6 +5429,9 @@ * (or the function return value) is not NULL, i.e. use a temporary * variable for 'lastpp' and check its value after the function return * before assigning it to the list last pointer. + * + * Unfortunately collecting queuing time statistics adds overhead to + * the function that isn't inherent to the function's algorithm. */ REQP asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid) @@ -5268,7 +5451,7 @@ if (tid != ASC_TID_ALL) { /* Return all requests for the specified 'tid'. */ if ((ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid)) == 0) { - /* List is empty set first and last return pointers to NULL. */ + /* List is empty; Set first and last return pointers to NULL. */ firstp = lastp = NULL; } else { firstp = ascq->q_first[tid]; @@ -5276,7 +5459,13 @@ ascq->q_first[tid] = ascq->q_last[tid] = NULL; ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid); #ifdef ADVANSYS_STATS - ascq->q_cur_cnt[tid] = 0; + { + REQP reqp; + ascq->q_cur_cnt[tid] = 0; + for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) { + REQTIMESTAT("asc_dequeue_list", ascq, reqp, tid); + } + } #endif /* ADVANSYS_STATS */ } } else { @@ -5299,6 +5488,14 @@ #endif /* ADVANSYS_STATS */ } } +#ifdef ADVANSYS_STATS + { + REQP reqp; + for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) { + REQTIMESTAT("asc_dequeue_list", ascq, reqp, reqp->target); + } + } +#endif /* ADVANSYS_STATS */ } if (lastpp) { *lastpp = lastp; @@ -5324,7 +5521,7 @@ int tid; int ret = ASC_FALSE; - ASC_DBG2(1, "asc_rmqueue: ascq %x, reqp %d\n", + ASC_DBG2(1, "asc_rmqueue: ascq %x, reqp %x\n", (unsigned) ascq, (unsigned) reqp); ASC_ASSERT(interrupts_enabled() == ASC_FALSE); ASC_ASSERT(reqp != NULL); @@ -5373,6 +5570,7 @@ /* Maintain request queue statistics. */ if (ret == ASC_TRUE) { ascq->q_cur_cnt[tid]--; + REQTIMESTAT("asc_rmqueue", ascq, reqp, tid); } ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0); #endif /* ADVANSYS_STATS */ @@ -5406,6 +5604,7 @@ break; } } + ASC_DBG1(1, "asc_isqueued: ret %x\n", ret); return ret; } @@ -5608,40 +5807,40 @@ ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) +" host_busy %u, last_reset %u, max_id %u, max_lun %u\n", + shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun); +#else /* version >= v1.3.89 */ " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n", shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun, shp->max_channel); -#else /* version >= v1.3.89 */ -" host_busy %u, last_reset %u, max_id %u, max_lun %u\n", - shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun); #endif /* version >= v1.3.89 */ ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,57) +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,57) +" can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n", + shp->can_queue, shp->this_id, shp->sg_tablesize, shp->cmd_per_lun); +#else /* version >= v1.3.57 */ " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n", shp->unique_id, shp->can_queue, shp->this_id, shp->sg_tablesize, shp->cmd_per_lun); -#else /* version >= v1.3.57 */ -" can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n", - shp->can_queue, shp->this_id, shp->sg_tablesize, shp->cmd_per_lun); #endif /* version >= v1.3.57 */ ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,57) -" unchecked_isa_dma %d, use_clustering %d, loaded_as_module %d\n", - shp->unchecked_isa_dma, shp->use_clustering, shp->loaded_as_module); -#else /* version >= v1.3.57 */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,57) " unchecked_isa_dma %d, loaded_as_module %d\n", shp->unchecked_isa_dma, shp->loaded_as_module); +#else /* version >= v1.3.57 */ +" unchecked_isa_dma %d, use_clustering %d, loaded_as_module %d\n", + shp->unchecked_isa_dma, shp->use_clustering, shp->loaded_as_module); #endif /* version >= v1.3.57 */ ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" flags %x, reset_jiffies %x, jiffies %x\n", - ASC_BOARDP(shp)->flags, ASC_BOARDP(shp)->reset_jiffies, jiffies); +" flags %x, last_reset %x, jiffies %x\n", + ASC_BOARDP(shp)->flags, ASC_BOARDP(shp)->last_reset, jiffies); ASC_PRT_NEXT(); return totlen; @@ -5897,18 +6096,19 @@ } /* - * Convert a virtual address to a virtual address. - * - * Apparently Linux is loaded V=R (virtual equals real). Just return - * the virtual address. + * Convert a virtual address to a bus address. */ ulong DvcGetPhyAddr(uchar *buf_addr, ulong buf_len) { - ulong phys_addr; + ulong bus_addr; - phys_addr = (ulong) buf_addr; - return phys_addr; +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) + bus_addr = (ulong) buf_addr; +#else /* version >= v2.1.0 */ + bus_addr = virt_to_bus(buf_addr); +#endif /* version >= v2.1.0 */ + return bus_addr; } ulong @@ -5919,7 +6119,11 @@ buf_size = buf_len; asc_sg_head_ptr->entry_cnt = 1; +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) asc_sg_head_ptr->sg_list[0].addr = (ulong) buf_addr; +#else /* version >= v2.1.0 */ + asc_sg_head_ptr->sg_list[0].addr = virt_to_bus(buf_addr); +#endif /* version >= v2.1.0 */ asc_sg_head_ptr->sg_list[0].bytes = buf_size; return buf_size; } @@ -6170,25 +6374,6 @@ ASC_PRT_NEXT(); /* - * Display request queuing statistics. - */ - len = asc_prt_line(cp, leftlen, -" Active and Pending Request Queues:\n"); - ASC_PRT_NEXT(); - - active = &ASC_BOARDP(shp)->active; - waiting = &ASC_BOARDP(shp)->waiting; - for (i = 0; i < ASC_MAX_TID + 1; i++) { - if (active->q_max_cnt[i] > 0 || waiting->q_max_cnt[i] > 0) { - len = asc_prt_line(cp, leftlen, -" target %d: active [cur %d, max %d], waiting [cur %d, max %d]\n", - i, active->q_cur_cnt[i], active->q_max_cnt[i], - waiting->q_cur_cnt[i], waiting->q_max_cnt[i]); - ASC_PRT_NEXT(); - } - } - - /* * Display data transfer statistics. */ if (s->cont_cnt > 0) { @@ -6235,6 +6420,44 @@ ASC_PRT_NEXT(); } + /* + * Display request queuing statistics. + */ + len = asc_prt_line(cp, leftlen, +" Active and Waiting Request Queues (time unit: %d HZ):\n", HZ); + ASC_PRT_NEXT(); + + active = &ASC_BOARDP(shp)->active; + waiting = &ASC_BOARDP(shp)->waiting; + for (i = 0; i < ASC_MAX_TID + 1; i++) { + if (active->q_tot_cnt[i] > 0 || waiting->q_tot_cnt[i] > 0) { + len = asc_prt_line(cp, leftlen, " target %d\n", i); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n", + active->q_cur_cnt[i], active->q_max_cnt[i], + active->q_tot_cnt[i], + active->q_min_tim[i], active->q_max_tim[i], + (active->q_tot_cnt[i] == 0) ? 0 : + (active->q_tot_tim[i]/active->q_tot_cnt[i]), + (active->q_tot_cnt[i] == 0) ? 0 : + ASC_TENTHS(active->q_tot_tim[i], active->q_tot_cnt[i])); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n", + waiting->q_cur_cnt[i], waiting->q_max_cnt[i], + waiting->q_tot_cnt[i], + waiting->q_min_tim[i], waiting->q_max_tim[i], + (waiting->q_tot_cnt[i] == 0) ? 0 : + (waiting->q_tot_tim[i]/waiting->q_tot_cnt[i]), + (waiting->q_tot_cnt[i] == 0) ? 0 : + ASC_TENTHS(waiting->q_tot_tim[i], waiting->q_tot_cnt[i])); + ASC_PRT_NEXT(); + } + } + return totlen; } #endif /* ADVANSYS_STATS */ @@ -6272,6 +6495,60 @@ asc_prt_dvc_var(&ASC_BOARDP(s)->asc_dvc_var); asc_prt_dvc_cfg(&ASC_BOARDP(s)->asc_dvc_cfg); +} + +/* + * asc_prt_scsi_cmnd() + */ +STATIC void +asc_prt_scsi_cmnd(Scsi_Cmnd *s) +{ + printk("Scsi_Cmnd at addr %x\n", (unsigned) s); + +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) + printk( +" host %x, device %x, target %u, lun %u\n", + (unsigned) s->host, (unsigned) s->device, s->target, s->lun); +#else /* version >= v1.3.0 */ + printk( +" host %x, device %x, target %u, lun %u, channel %u,\n", + (unsigned) s->host, (unsigned) s->device, s->target, s->lun, + s->channel); +#endif /* version >= v1.3.0 */ + + asc_prt_hex(" CDB", s->cmnd, s->cmd_len); + + printk( +" use_sg %u, sglist_len %u, abort_reason %x\n", + s->use_sg, s->sglist_len, s->abort_reason); + +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) + printk( +" retries %d, allowed %d\n", + s->retries, s->allowed); +#else /* version >= v1.3.89 */ + printk( +" serial_number %x, serial_number_at_timeout %x, retries %d, allowed %d\n", + (unsigned) s->serial_number, (unsigned) s->serial_number_at_timeout, + s->retries, s->allowed); +#endif /* version >= v1.3.89 */ + + printk( +" timeout_per_command %d, timeout_total %d, timeout %d\n", + s->timeout_per_command, s->timeout_total, s->timeout); + + printk( +" internal_timeout %u, flags %u, this_count %d\n", + s->internal_timeout, s->flags, s->this_count); + + printk( +" scsi_done %x, done %x, host_scribble %x, result %x\n", + (unsigned) s->scsi_done, (unsigned) s->done, + (unsigned) s->host_scribble, s->result); + + printk( +" tag %u, pid %u\n", + (unsigned) s->tag, (unsigned) s->pid); } /* diff -u --recursive --new-file v2.1.1/linux/drivers/scsi/atari_NCR5380.c linux/drivers/scsi/atari_NCR5380.c --- v2.1.1/linux/drivers/scsi/atari_NCR5380.c Sat May 18 11:15:09 1996 +++ linux/drivers/scsi/atari_NCR5380.c Mon Oct 7 08:55:47 1996 @@ -194,7 +194,7 @@ /* * Using this file : * This file a skeleton Linux SCSI driver for the NCR 5380 series - * of chips. To use it, you write a architecture specific functions + * of chips. To use it, you write an architecture specific functions * and macros and include this file in your driver. * * These macros control options : diff -u --recursive --new-file v2.1.1/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.1.1/linux/drivers/scsi/scsi.c Thu Sep 26 15:28:24 1996 +++ linux/drivers/scsi/scsi.c Sat Oct 5 12:17:34 1996 @@ -282,6 +282,7 @@ {"PIONEER","CD-ROM DRM-604X","*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"EMULEX","MD21/S2 ESDI","*", BLIST_SINGLELUN}, {"CANON","IPUBJD","*", BLIST_SPARSELUN}, +{"MATSHITA","PD","*", BLIST_FORCELUN | BLIST_SINGLELUN}, /* * Must be at end of list... */ diff -u --recursive --new-file v2.1.1/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c --- v2.1.1/linux/drivers/scsi/sg.c Sat Aug 31 20:52:43 1996 +++ linux/drivers/scsi/sg.c Mon Oct 7 12:40:22 1996 @@ -73,7 +73,7 @@ switch(cmd_in) { case SG_SET_TIMEOUT: - result = verify_area(VERIFY_READ, (const void *)arg, sizeof(long)); + result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int)); if (result) return result; scsi_generics[dev].timeout=get_user((int *) arg); @@ -196,7 +196,7 @@ * complete semaphores to tell us whether the buffer is available for us * and whether the command is actually done. */ -static int sg_read(struct inode *inode,struct file *filp,char *buf,int count) +static long sg_read(struct inode *inode,struct file *filp,char *buf,unsigned long count) { int dev=MINOR(inode->i_rdev); int i; @@ -318,7 +318,7 @@ wake_up(&scsi_generics[dev].read_wait); } -static int sg_write(struct inode *inode,struct file *filp,const char *buf,int count) +static long sg_write(struct inode *inode,struct file *filp,const char *buf,unsigned long count) { int bsize,size,amt,i; unsigned char cmnd[MAX_COMMAND_SIZE]; diff -u --recursive --new-file v2.1.1/linux/drivers/sound/audio.c linux/drivers/sound/audio.c --- v2.1.1/linux/drivers/sound/audio.c Sun Aug 18 10:46:48 1996 +++ linux/drivers/sound/audio.c Tue Oct 8 19:12:23 1996 @@ -403,7 +403,7 @@ case SNDCTL_DSP_GETOSPACE: if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return 0; + return -EPERM; if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX)) return -(EBUSY); @@ -418,7 +418,7 @@ return err; if (DMAbuf_get_curr_buffer (dev, &buf_no, &dma_buf, &buf_ptr, &buf_size) >= 0) - info.bytes += buf_size - buf_ptr; + info.bytes -= buf_ptr; memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info)); return 0; diff -u --recursive --new-file v2.1.1/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c --- v2.1.1/linux/drivers/sound/sb_common.c Tue Sep 10 10:08:12 1996 +++ linux/drivers/sound/sb_common.c Mon Oct 7 08:55:47 1996 @@ -65,7 +65,7 @@ /* * Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes * called while interrupts are disabled. This means that the timer is - * disabled also. However the timeout situation is a abnormal condition. + * disabled also. However the timeout situation is an abnormal condition. * Normally the DSP should be ready to accept commands after just couple of * loops. */ diff -u --recursive --new-file v2.1.1/linux/fs/dquot.c linux/fs/dquot.c --- v2.1.1/linux/fs/dquot.c Sat Sep 28 23:54:26 1996 +++ linux/fs/dquot.c Mon Oct 7 08:55:47 1996 @@ -675,7 +675,7 @@ } /* - * Initialize pointer in a inode to the right dquots. + * Initialize pointer in an inode to the right dquots. */ void dquot_initialize(struct inode *inode, short type) { @@ -734,7 +734,7 @@ /* * This is a simple algorithm that calculates the size of a file in blocks. - * This is only used on filesystems that do not have a i_blocks count. + * This is only used on filesystems that do not have an i_blocks count. */ static u_long isize_to_blocks(size_t isize, size_t blksize) { diff -u --recursive --new-file v2.1.1/linux/fs/ext/truncate.c linux/fs/ext/truncate.c --- v2.1.1/linux/fs/ext/truncate.c Mon Apr 18 11:38:17 1994 +++ linux/fs/ext/truncate.c Mon Oct 7 08:55:47 1996 @@ -242,7 +242,7 @@ } /* - * Called when a inode is released. Note that this is different + * Called when an inode is released. Note that this is different * from ext_open: open gets called at every open, but release * gets called only when /all/ the files are closed. */ diff -u --recursive --new-file v2.1.1/linux/fs/ext2/file.c linux/fs/ext2/file.c --- v2.1.1/linux/fs/ext2/file.c Mon Sep 30 08:49:14 1996 +++ linux/fs/ext2/file.c Tue Oct 8 08:50:19 1996 @@ -80,6 +80,21 @@ NULL /* smap */ }; +static inline void remove_suid(struct inode *inode) +{ + unsigned int mode; + + /* set S_IGID if S_IXGRP is set, and always set S_ISUID */ + mode = (inode->i_mode & S_IXGRP)*(S_ISGID/S_IXGRP) | S_ISUID; + + /* was any of the uid bits set? */ + mode &= inode->i_mode; + if (mode && suser()) { + inode->i_mode &= ~mode; + inode->i_dirt = 1; + } +} + static long ext2_file_write (struct inode * inode, struct file * filp, const char * buf, unsigned long count) { @@ -111,6 +126,7 @@ inode->i_mode); return -EINVAL; } + remove_suid(inode); if (filp->f_flags & O_APPEND) pos = inode->i_size; else @@ -153,7 +169,13 @@ break; } } + if (exception()) { + brelse(bh); + written = -EFAULT; + break; + } memcpy_fromfs (bh->b_data + offset, buf, c); + end_exception(); update_vm_cache(inode, pos, bh->b_data + offset, c); pos2 += c; pos += c; @@ -201,7 +223,7 @@ } /* - * Called when a inode is released. Note that this is different + * Called when an inode is released. Note that this is different * from ext2_open: open gets called at every open, but release * gets called only when /all/ the files are closed. */ diff -u --recursive --new-file v2.1.1/linux/fs/noquot.c linux/fs/noquot.c --- v2.1.1/linux/fs/noquot.c Tue Dec 26 06:03:00 1995 +++ linux/fs/noquot.c Mon Oct 7 08:55:47 1996 @@ -39,7 +39,7 @@ } /* - * Initialize pointer in a inode to the right dquots. + * Initialize pointer in an inode to the right dquots. */ void dquot_initialize(struct inode *inode, short type) { diff -u --recursive --new-file v2.1.1/linux/fs/open.c linux/fs/open.c --- v2.1.1/linux/fs/open.c Tue Aug 20 11:59:19 1996 +++ linux/fs/open.c Mon Oct 7 08:55:47 1996 @@ -550,7 +550,7 @@ } /* - * Find a empty file descriptor entry, and mark it busy + * Find an empty file descriptor entry, and mark it busy */ int get_unused_fd(void) { diff -u --recursive --new-file v2.1.1/linux/fs/pipe.c linux/fs/pipe.c --- v2.1.1/linux/fs/pipe.c Sat Sep 28 23:52:55 1996 +++ linux/fs/pipe.c Tue Oct 8 14:36:32 1996 @@ -51,6 +51,10 @@ interruptible_sleep_on(&PIPE_WAIT(*inode)); } PIPE_LOCK(*inode)++; + if (exception()) { + PIPE_LOCK(*inode)--; + return -EFAULT; + } while (count>0 && (size = PIPE_SIZE(*inode))) { chars = PIPE_MAX_RCHUNK(*inode); if (chars > count) @@ -66,6 +70,7 @@ memcpy_tofs(buf, pipebuf, chars ); buf += chars; } + end_exception(); PIPE_LOCK(*inode)--; wake_up_interruptible(&PIPE_WAIT(*inode)); if (read) { @@ -105,6 +110,10 @@ interruptible_sleep_on(&PIPE_WAIT(*inode)); } PIPE_LOCK(*inode)++; + if (exception()) { + PIPE_LOCK(*inode)--; + return -EFAULT; + } while (count>0 && (free = PIPE_FREE(*inode))) { chars = PIPE_MAX_WCHUNK(*inode); if (chars > count) @@ -118,6 +127,7 @@ memcpy_fromfs(pipebuf, buf, chars ); buf += chars; } + end_exception(); PIPE_LOCK(*inode)--; wake_up_interruptible(&PIPE_WAIT(*inode)); free = 1; diff -u --recursive --new-file v2.1.1/linux/fs/read_write.c linux/fs/read_write.c --- v2.1.1/linux/fs/read_write.c Sat Oct 5 16:58:35 1996 +++ linux/fs/read_write.c Sat Oct 5 22:24:33 1996 @@ -112,6 +112,7 @@ int error; struct file * file; struct inode * inode; + long (*read)(struct inode *, struct file *, char *, unsigned long); error = -EBADF; file = fget(fd); @@ -123,19 +124,16 @@ error = -EBADF; if (!(file->f_mode & 1)) goto out; - error = -EINVAL; - if (!file->f_op || !file->f_op->read) - goto out; - error = 0; - if (count <= 0) - goto out; error = locks_verify_area(FLOCK_VERIFY_READ,inode,file,file->f_pos,count); if (error) goto out; error = verify_area(VERIFY_WRITE,buf,count); if (error) goto out; - error = file->f_op->read(inode,file,buf,count); + error = -EINVAL; + if (!file->f_op || !(read = file->f_op->read)) + goto out; + error = read(inode,file,buf,count); out: fput(file, inode); bad_file: @@ -147,6 +145,7 @@ int error; struct file * file; struct inode * inode; + long (*write)(struct inode *, struct file *, const char *, unsigned long); error = -EBADF; file = fget(fd); @@ -157,39 +156,17 @@ goto out; if (!(file->f_mode & 2)) goto out; - error = -EINVAL; - if (!file->f_op || !file->f_op->write) - goto out; - error = 0; - if (!count) - goto out; error = locks_verify_area(FLOCK_VERIFY_WRITE,inode,file,file->f_pos,count); if (error) goto out; error = verify_area(VERIFY_READ,buf,count); if (error) goto out; - /* - * If data has been written to the file, remove the setuid and - * the setgid bits. We do it anyway otherwise there is an - * extremely exploitable race - does your OS get it right |-> - * - * Set ATTR_FORCE so it will always be changed. - */ - if (!suser() && (inode->i_mode & (S_ISUID | S_ISGID))) { - struct iattr newattrs; - /* - * Don't turn off setgid if no group execute. This special - * case marks candidates for mandatory locking. - */ - newattrs.ia_mode = inode->i_mode & - ~(S_ISUID | ((inode->i_mode & S_IXGRP) ? S_ISGID : 0)); - newattrs.ia_valid = ATTR_CTIME | ATTR_MODE | ATTR_FORCE; - notify_change(inode, &newattrs); - } - + error = -EINVAL; + if (!file->f_op || !(write = file->f_op->write)) + goto out; down(&inode->i_sem); - error = file->f_op->write(inode,file,buf,count); + error = write(inode,file,buf,count); up(&inode->i_sem); out: fput(file, inode); diff -u --recursive --new-file v2.1.1/linux/fs/select.c linux/fs/select.c --- v2.1.1/linux/fs/select.c Fri Jul 5 13:48:39 1996 +++ linux/fs/select.c Mon Oct 7 08:55:48 1996 @@ -35,7 +35,7 @@ * sleep/wakeup mechanism works. * * Two very simple procedures, select_wait() and free_wait() make all the work. - * select_wait() is a inline-function defined in , as all select + * select_wait() is an inline-function defined in , as all select * functions have to call it to add an entry to the select table. */ @@ -67,86 +67,143 @@ * and we aren't going to sleep on the select_table. -- jrs */ -static int check(int flag, select_table * wait, struct file * file) +static inline int __check( + int (*select) (struct inode *, struct file *, int, select_table *), + struct inode *inode, + struct file *file, + int flag, + select_table * wait) { - struct inode * inode; - struct file_operations *fops; - int (*select) (struct inode *, struct file *, int, select_table *); - - inode = file->f_inode; - if ((fops = file->f_op) && (select = fops->select)) - return select(inode, file, flag, wait) - || (wait && select(inode, file, flag, NULL)); - if (flag != SEL_EX) - return 1; - return 0; + return select(inode, file, flag, wait) || + (wait && select(inode, file, flag, NULL)); } -static int do_select(int n, fd_set *in, fd_set *out, fd_set *ex, - fd_set *res_in, fd_set *res_out, fd_set *res_ex) +#define check(flag,wait,file) \ +(((file)->f_op && (file)->f_op->select) ? \ + __check((file)->f_op->select,(file)->f_inode,file,flag,wait) \ + : \ + (flag != SEL_EX)) + +/* + * Due to kernel stack usage, we use a _limited_ fd_set type here, and once + * we really start supporting >256 file descriptors we'll probably have to + * allocate the kernel fd_set copies dynamically.. (The kernel select routines + * are careful to touch only the defined low bits of any fd_set pointer, this + * is important for performance too). + */ +typedef unsigned long limited_fd_set[NR_OPEN/(8*(sizeof(unsigned long)))]; + +typedef struct { + limited_fd_set in, out, ex; + limited_fd_set res_in, res_out, res_ex; +} fd_set_buffer; + +#define __IN(in) (in) +#define __OUT(in) (in + sizeof(limited_fd_set)/sizeof(unsigned long)) +#define __EX(in) (in + 2*sizeof(limited_fd_set)/sizeof(unsigned long)) +#define __RES_IN(in) (in + 3*sizeof(limited_fd_set)/sizeof(unsigned long)) +#define __RES_OUT(in) (in + 4*sizeof(limited_fd_set)/sizeof(unsigned long)) +#define __RES_EX(in) (in + 5*sizeof(limited_fd_set)/sizeof(unsigned long)) + +#define BITS(in) (*__IN(in)|*__OUT(in)|*__EX(in)) + +static int max_select_fd(unsigned long n, fd_set_buffer *fds) { - int count; - select_table wait_table, *wait; - struct select_table_entry *entry; + unsigned long *open_fds, *in; unsigned long set; - int i,j; - int max = -1; + int max; - j = 0; - for (;;) { - i = j * __NFDBITS; - if (i >= n) - break; - set = in->fds_bits[j] | out->fds_bits[j] | ex->fds_bits[j]; - j++; - for ( ; set ; i++,set >>= 1) { - if (i >= n) - goto end_check; - if (!(set & 1)) - continue; - if (!current->files->fd[i]) - return -EBADF; - if (!current->files->fd[i]->f_inode) - return -EBADF; - max = i; + /* handle last in-complete long-word first */ + set = ~(~0UL << (n & (__NFDBITS-1))); + n /= __NFDBITS; + open_fds = current->files->open_fds.fds_bits+n; + in = fds->in+n; + max = 0; + if (set) { + set &= BITS(in); + if (set) { + if (!(set & ~*open_fds)) + goto get_max; + return -EBADF; } } -end_check: - n = max + 1; + while (n) { + in--; + open_fds--; + n--; + set = BITS(in); + if (!set) + continue; + if (set & ~*open_fds) + return -EBADF; + if (max) + continue; +get_max: + do { + max++; + set >>= 1; + } while (set); + max += n * __NFDBITS; + } + + return max; +} + +#define BIT(i) (1UL << ((i)&(__NFDBITS-1))) +#define MEM(i,m) ((m)+(unsigned)(i)/__NFDBITS) +#define ISSET(i,m) (((i)&*(m)) != 0) +#define SET(i,m) (*(m) |= (i)) + +static int do_select(int n, fd_set_buffer *fds) +{ + int retval; + select_table wait_table, *wait; + struct select_table_entry *entry; + int i; + + retval = max_select_fd(n, fds); + if (retval < 0) + goto out; + n = retval; + retval = -ENOMEM; if(!(entry = (struct select_table_entry*) __get_free_page(GFP_KERNEL))) - return -ENOMEM; - count = 0; + goto out; + retval = 0; wait_table.nr = 0; wait_table.entry = entry; wait = &wait_table; -repeat: - current->state = TASK_INTERRUPTIBLE; - for (i = 0 ; i < n ; i++) { - if (FD_ISSET(i,in) && check(SEL_IN,wait,current->files->fd[i])) { - FD_SET(i, res_in); - count++; - wait = NULL; - } - if (FD_ISSET(i,out) && check(SEL_OUT,wait,current->files->fd[i])) { - FD_SET(i, res_out); - count++; - wait = NULL; - } - if (FD_ISSET(i,ex) && check(SEL_EX,wait,current->files->fd[i])) { - FD_SET(i, res_ex); - count++; - wait = NULL; + for (;;) { + struct file ** fd = current->files->fd; + current->state = TASK_INTERRUPTIBLE; + for (i = 0 ; i < n ; i++,fd++) { + unsigned long bit = BIT(i); + unsigned long *in = MEM(i,fds->in); + if (ISSET(bit,__IN(in)) && check(SEL_IN,wait,*fd)) { + SET(bit, __RES_IN(in)); + retval++; + wait = NULL; + } + if (ISSET(bit,__OUT(in)) && check(SEL_OUT,wait,*fd)) { + SET(bit, __RES_OUT(in)); + retval++; + wait = NULL; + } + if (ISSET(bit,__EX(in)) && check(SEL_EX,wait,*fd)) { + SET(bit, __RES_EX(in)); + retval++; + wait = NULL; + } } - } - wait = NULL; - if (!count && current->timeout && !(current->signal & ~current->blocked)) { + wait = NULL; + if (retval || !current->timeout || (current->signal & ~current->blocked)) + break; schedule(); - goto repeat; } free_wait(&wait_table); free_page((unsigned long) entry); current->state = TASK_RUNNING; - return count; +out: + return retval; } /* @@ -202,20 +259,11 @@ } /* - * Due to kernel stack usage, we use a _limited_ fd_set type here, and once - * we really start supporting >256 file descriptors we'll probably have to - * allocate the kernel fd_set copies dynamically.. (The kernel select routines - * are careful to touch only the defined low bits of any fd_set pointer, this - * is important for performance too). - * * Note a few subtleties: we use "long" for the dummy, not int, and we do a * 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.. */ -typedef struct { - unsigned long dummy[NR_OPEN/(8*(sizeof(unsigned long)))]; -} limited_fd_set; #define get_fd_set(nr,fsp,fdp) \ __get_fd_set(nr, (int *) (fsp), (int *) (fdp)) @@ -237,9 +285,7 @@ asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp) { int error; - limited_fd_set res_in, in; - limited_fd_set res_out, out; - limited_fd_set res_ex, ex; + fd_set_buffer fds; unsigned long timeout; error = -EINVAL; @@ -247,9 +293,9 @@ goto out; if (n > NR_OPEN) n = NR_OPEN; - if ((error = get_fd_set(n, inp, &in)) || - (error = get_fd_set(n, outp, &out)) || - (error = get_fd_set(n, exp, &ex))) goto out; + if ((error = get_fd_set(n, inp, &fds.in)) || + (error = get_fd_set(n, outp, &fds.out)) || + (error = get_fd_set(n, exp, &fds.ex))) goto out; timeout = ~0UL; if (tvp) { error = verify_area(VERIFY_WRITE, tvp, sizeof(*tvp)); @@ -260,17 +306,11 @@ if (timeout) timeout += jiffies + 1; } - zero_fd_set(n, &res_in); - zero_fd_set(n, &res_out); - zero_fd_set(n, &res_ex); + zero_fd_set(n, &fds.res_in); + zero_fd_set(n, &fds.res_out); + zero_fd_set(n, &fds.res_ex); current->timeout = timeout; - error = do_select(n, - (fd_set *) &in, - (fd_set *) &out, - (fd_set *) &ex, - (fd_set *) &res_in, - (fd_set *) &res_out, - (fd_set *) &res_ex); + error = do_select(n, &fds); timeout = current->timeout - jiffies - 1; current->timeout = 0; if ((long) timeout < 0) @@ -289,9 +329,9 @@ goto out; error = 0; } - set_fd_set(n, inp, &res_in); - set_fd_set(n, outp, &res_out); - set_fd_set(n, exp, &res_ex); + set_fd_set(n, inp, &fds.res_in); + set_fd_set(n, outp, &fds.res_out); + set_fd_set(n, exp, &fds.res_ex); out: return error; } diff -u --recursive --new-file v2.1.1/linux/include/asm-alpha/cia.h linux/include/asm-alpha/cia.h --- v2.1.1/linux/include/asm-alpha/cia.h Mon Jul 15 11:34:11 1996 +++ linux/include/asm-alpha/cia.h Mon Oct 7 12:40:22 1996 @@ -379,48 +379,73 @@ /* * Data structure for handling CIA machine checks: */ +/* ev5-specific info: */ +struct el_procdata { + unsigned long shadow[8]; /* PALmode shadow registers */ + unsigned long paltemp[24]; /* PAL temporary registers */ + /* EV5-specific fields */ + unsigned long exc_addr; /* Address of excepting instruction. */ + unsigned long exc_sum; /* Summary of arithmetic traps. */ + unsigned long exc_mask; /* Exception mask (from exc_sum). */ + unsigned long exc_base; /* PALbase at time of exception. */ + unsigned long isr; /* Interrupt summary register. */ + unsigned long icsr; /* Ibox control register. */ + unsigned long ic_perr_stat; + unsigned long dc_perr_stat; + unsigned long va; /* Effective VA of fault or miss. */ + unsigned long mm_stat; + unsigned long sc_addr; + unsigned long sc_stat; + unsigned long bc_tag_addr; + unsigned long ei_addr; + unsigned long fill_syn; + unsigned long ei_stat; + unsigned long ld_lock; +}; + +/* system-specific info: */ struct el_CIA_sysdata_mcheck { - u_long coma_gcr; - u_long coma_edsr; - u_long coma_ter; - u_long coma_elar; - u_long coma_ehar; - u_long coma_ldlr; - u_long coma_ldhr; - u_long coma_base0; - u_long coma_base1; - u_long coma_base2; - u_long coma_cnfg0; - u_long coma_cnfg1; - u_long coma_cnfg2; - u_long epic_dcsr; - u_long epic_pear; - u_long epic_sear; - u_long epic_tbr1; - u_long epic_tbr2; - u_long epic_pbr1; - u_long epic_pbr2; - u_long epic_pmr1; - u_long epic_pmr2; - u_long epic_harx1; - u_long epic_harx2; - u_long epic_pmlt; - u_long epic_tag0; - u_long epic_tag1; - u_long epic_tag2; - u_long epic_tag3; - u_long epic_tag4; - u_long epic_tag5; - u_long epic_tag6; - u_long epic_tag7; - u_long epic_data0; - u_long epic_data1; - u_long epic_data2; - u_long epic_data3; - u_long epic_data4; - u_long epic_data5; - u_long epic_data6; - u_long epic_data7; + unsigned long coma_gcr; + unsigned long coma_edsr; + unsigned long coma_ter; + unsigned long coma_elar; + unsigned long coma_ehar; + unsigned long coma_ldlr; + unsigned long coma_ldhr; + unsigned long coma_base0; + unsigned long coma_base1; + unsigned long coma_base2; + unsigned long coma_cnfg0; + unsigned long coma_cnfg1; + unsigned long coma_cnfg2; + unsigned long epic_dcsr; + unsigned long epic_pear; + unsigned long epic_sear; + unsigned long epic_tbr1; + unsigned long epic_tbr2; + unsigned long epic_pbr1; + unsigned long epic_pbr2; + unsigned long epic_pmr1; + unsigned long epic_pmr2; + unsigned long epic_harx1; + unsigned long epic_harx2; + unsigned long epic_pmlt; + unsigned long epic_tag0; + unsigned long epic_tag1; + unsigned long epic_tag2; + unsigned long epic_tag3; + unsigned long epic_tag4; + unsigned long epic_tag5; + unsigned long epic_tag6; + unsigned long epic_tag7; + unsigned long epic_data0; + unsigned long epic_data1; + unsigned long epic_data2; + unsigned long epic_data3; + unsigned long epic_data4; + unsigned long epic_data5; + unsigned long epic_data6; + unsigned long epic_data7; }; #define RTC_PORT(x) (0x70 + (x)) diff -u --recursive --new-file v2.1.1/linux/include/asm-alpha/io.h linux/include/asm-alpha/io.h --- v2.1.1/linux/include/asm-alpha/io.h Mon Sep 30 16:52:20 1996 +++ linux/include/asm-alpha/io.h Mon Oct 7 08:55:48 1996 @@ -150,7 +150,7 @@ #endif /* - * The "address" in IO memory space is not clearly either a integer or a + * The "address" in IO memory space is not clearly either an integer or a * pointer. We will accept both, thus the casts. * * On the alpha, we have the whole physical address space mapped at all diff -u --recursive --new-file v2.1.1/linux/include/asm-alpha/lca.h linux/include/asm-alpha/lca.h --- v2.1.1/linux/include/asm-alpha/lca.h Fri Apr 12 09:49:44 1996 +++ linux/include/asm-alpha/lca.h Mon Oct 7 12:40:22 1996 @@ -317,7 +317,6 @@ */ struct el_lca_mcheck_short { struct el_common h; /* common logout header */ - unsigned long reason; /* reason for machine check */ unsigned long esr; /* error-status register */ unsigned long ear; /* error-address register */ unsigned long dc_stat; /* dcache status register */ @@ -327,7 +326,7 @@ struct el_lca_mcheck_long { struct el_common h; /* common logout header */ - unsigned long pt[32]; /* PAL temps (pt[0] is reason) */ + unsigned long pt[31]; /* PAL temps */ unsigned long exc_addr; /* exception address */ unsigned long pad1[3]; unsigned long pal_base; /* PALcode base address */ diff -u --recursive --new-file v2.1.1/linux/include/asm-alpha/mman.h linux/include/asm-alpha/mman.h --- v2.1.1/linux/include/asm-alpha/mman.h Mon Dec 11 09:07:22 1995 +++ linux/include/asm-alpha/mman.h Mon Oct 7 12:40:22 1996 @@ -20,8 +20,9 @@ /* These are linux-specific */ #define MAP_GROWSDOWN 0x1000 /* stack-like segment */ #define MAP_DENYWRITE 0x2000 /* ETXTBSY */ -#define MAP_EXECUTABLE 0x4000 /* mark it as a executable */ +#define MAP_EXECUTABLE 0x4000 /* mark it as an executable */ #define MAP_LOCKED 0x8000 /* lock the mapping */ +#define MAP_NORESERVE 0x10000 /* don't check for reservations */ #define MS_ASYNC 1 /* sync memory asynchronously */ #define MS_SYNC 2 /* synchronous memory sync */ diff -u --recursive --new-file v2.1.1/linux/include/asm-alpha/mmu_context.h linux/include/asm-alpha/mmu_context.h --- v2.1.1/linux/include/asm-alpha/mmu_context.h Fri Apr 19 13:28:06 1996 +++ linux/include/asm-alpha/mmu_context.h Mon Oct 7 08:55:48 1996 @@ -16,7 +16,7 @@ * EV5 this is 127. * * On the EV4, the ASNs are more-or-less useless anyway, as they are - * only used as a icache tag, not for TB entries. On the EV5 ASN's + * only used as an icache tag, not for TB entries. On the EV5 ASN's * also validate the TB entries, and thus make a lot more sense. * * The EV4 ASN's don't even match the architecture manual, ugh. And diff -u --recursive --new-file v2.1.1/linux/include/asm-alpha/processor.h linux/include/asm-alpha/processor.h --- v2.1.1/linux/include/asm-alpha/processor.h Thu Sep 12 16:13:49 1996 +++ linux/include/asm-alpha/processor.h Tue Oct 8 09:00:50 1996 @@ -26,6 +26,32 @@ #define wp_works_ok 1 #define wp_works_ok__is_a_macro /* for versions in ksyms.c */ +/* + * The VM exception save area. We need to save + * return address (r26) + * PC (r30) + * function-call-saved regs (r9-r15) + * Count is used to do some basic sanity checking, and + * to handle the case where a kernel service itself sets + * up exceptions while another exception is active. + * + * NOTE: Exceptions are not "recursive": in the case above + * the oldest exception is the one that is left active, but + * the VM fault handler will notice a count != 1 and abort + * because exceptions within exceptions are an error. + */ +struct exception_struct { + unsigned long count; + unsigned long r9, r10, r11, r12, r13, r14, r15; + unsigned long r26, r30; +}; + +extern int __exception(struct exception_struct *); +extern void __handle_exception(struct exception_struct *) __attribute__((noreturn)); + +#define exception() __exception(¤t->tss.ex) +#define end_exception() (current->tss.ex.count--) + struct thread_struct { /* the fields below are used by PALcode and must match struct pcb: */ unsigned long ksp; @@ -47,6 +73,7 @@ * bit 1..5: IEEE_TRAP_ENABLE bits (see fpu.h) */ unsigned long flags; + struct exception_struct ex; }; #define INIT_MMAP { &init_mm, 0xfffffc0000000000, 0xfffffc0010000000, \ @@ -56,7 +83,8 @@ 0, 0, 0, \ 0, 0, 0, \ 0, 0, 0, \ - 0 \ + 0, \ + { 0, } \ } #define alloc_kernel_stack() __get_free_page(GFP_KERNEL) diff -u --recursive --new-file v2.1.1/linux/include/asm-alpha/shmparam.h linux/include/asm-alpha/shmparam.h --- v2.1.1/linux/include/asm-alpha/shmparam.h Fri Apr 12 09:49:44 1996 +++ linux/include/asm-alpha/shmparam.h Mon Oct 7 15:12:29 1996 @@ -2,14 +2,11 @@ #define _ASMAXP_SHMPARAM_H /* - * Address range for shared memory attaches if no address passed to - * shmat(). These ought to be changed to something >4GB so 32-bit - * errors are caught more easily. However, they don't seem to be used - * except for ELF stuff, so it's not really critical until we get ELF - * support for the Alpha. + * Address range for shared memory attaches if no address passed to shmat(). */ -#define SHM_RANGE_START 0x50000000 -#define SHM_RANGE_END 0x60000000 +#define SHM_RANGE_START 0x14000000000 +#define SHM_RANGE_END 0x15000000000 + /* * Format of a swap-entry for shared memory pages currently out in diff -u --recursive --new-file v2.1.1/linux/include/asm-i386/bugs.h linux/include/asm-i386/bugs.h --- v2.1.1/linux/include/asm-i386/bugs.h Mon Sep 30 11:19:00 1996 +++ linux/include/asm-i386/bugs.h Tue Oct 8 18:58:23 1996 @@ -115,7 +115,7 @@ #ifndef CONFIG_M386 /* * The 386 chips don't support TLB finegrained invalidation. - * They will fault when they hit a invlpg instruction. + * 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"); diff -u --recursive --new-file v2.1.1/linux/include/asm-i386/io.h linux/include/asm-i386/io.h --- v2.1.1/linux/include/asm-i386/io.h Mon Sep 30 16:52:08 1996 +++ linux/include/asm-i386/io.h Mon Oct 7 08:55:48 1996 @@ -153,7 +153,7 @@ /* * Note that due to the way __builtin_constant_p() works, you - * - can't use it inside a inline function (it will never be true) + * - can't use it inside an inline function (it will never be true) * - you don't have to worry about side effects within the __builtin.. */ #define outb(val,port) \ diff -u --recursive --new-file v2.1.1/linux/include/asm-i386/ipc.h linux/include/asm-i386/ipc.h --- v2.1.1/linux/include/asm-i386/ipc.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-i386/ipc.h Mon Oct 7 15:12:29 1996 @@ -0,0 +1,28 @@ +#ifndef __i386_IPC_H__ +#define __i386_IPC_H__ + +/* + * These are used to wrap system calls on x86. + * + * See arch/i386/kernel/sys_i386.c for ugly details.. + */ +struct ipc_kludge { + struct msgbuf *msgp; + long msgtyp; +}; + +#define SEMOP 1 +#define SEMGET 2 +#define SEMCTL 3 +#define MSGSND 11 +#define MSGRCV 12 +#define MSGGET 13 +#define MSGCTL 14 +#define SHMAT 21 +#define SHMDT 22 +#define SHMGET 23 +#define SHMCTL 24 + +#define IPCCALL(version,op) ((version)<<16 | (op)) + +#endif diff -u --recursive --new-file v2.1.1/linux/include/asm-i386/irq.h linux/include/asm-i386/irq.h --- v2.1.1/linux/include/asm-i386/irq.h Tue Sep 24 12:20:49 1996 +++ linux/include/asm-i386/irq.h Mon Oct 7 15:18:26 1996 @@ -27,8 +27,6 @@ #define SAVE_ALL \ "cld\n\t" \ - "push %gs\n\t" \ - "push %fs\n\t" \ "push %es\n\t" \ "push %ds\n\t" \ "pushl %eax\n\t" \ @@ -40,9 +38,7 @@ "pushl %ebx\n\t" \ "movl $" STR(KERNEL_DS) ",%edx\n\t" \ "mov %dx,%ds\n\t" \ - "mov %dx,%es\n\t" \ - "movl $0,%edx\n\t" \ - "movl %edx,%db7\n\t" + "mov %dx,%es\n\t" /* * SAVE_MOST/RESTORE_MOST is used for the faster version of IRQ handlers, diff -u --recursive --new-file v2.1.1/linux/include/asm-i386/mman.h linux/include/asm-i386/mman.h --- v2.1.1/linux/include/asm-i386/mman.h Mon Dec 11 09:06:30 1995 +++ linux/include/asm-i386/mman.h Mon Oct 7 08:55:48 1996 @@ -14,8 +14,9 @@ #define MAP_GROWSDOWN 0x0100 /* stack-like segment */ #define MAP_DENYWRITE 0x0800 /* ETXTBSY */ -#define MAP_EXECUTABLE 0x1000 /* mark it as a executable */ +#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ #define MAP_LOCKED 0x2000 /* pages are locked */ +#define MAP_NORESERVE 0x4000 /* don't check for reservations */ #define MS_ASYNC 1 /* sync memory asynchronously */ #define MS_INVALIDATE 2 /* invalidate the caches */ diff -u --recursive --new-file v2.1.1/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h --- v2.1.1/linux/include/asm-i386/pgtable.h Mon Sep 30 11:19:11 1996 +++ linux/include/asm-i386/pgtable.h Tue Oct 8 18:58:33 1996 @@ -5,7 +5,7 @@ /* * Define USE_PENTIUM_MM if you want the 4MB page table optimizations. - * This works only on a intel Pentium. + * This works only on an intel Pentium. */ #define USE_PENTIUM_MM 1 @@ -248,8 +248,8 @@ #define __S111 PAGE_SHARED /* - * Define this if things work differently on a i386 and a i486: - * it will (on a i486) warn about kernel memory accesses that are + * Define this if things work differently on an i386 and an i486: + * it will (on an i486) warn about kernel memory accesses that are * done without a 'verify_area(VERIFY_WRITE,..)' */ #undef TEST_VERIFY_AREA diff -u --recursive --new-file v2.1.1/linux/include/asm-i386/processor.h linux/include/asm-i386/processor.h --- v2.1.1/linux/include/asm-i386/processor.h Tue Sep 24 10:50:27 1996 +++ linux/include/asm-i386/processor.h Tue Oct 8 14:17:26 1996 @@ -42,6 +42,59 @@ #define TASK_SIZE (0xC0000000UL) /* + * VM exception register save area.. + * + * When no exceptions are active, count = -1. + */ +struct exception_struct { + unsigned long count; + unsigned long ebx; + unsigned long esi; + unsigned long edi; + unsigned long ebp; + unsigned long esp; + unsigned long eip; +}; + +extern inline int __exception(struct exception_struct *ex) +{ + int result; + __asm__("incl 0(%2)\n\t" + "jne 1f\n\t" + "movl %%ebx,4(%2)\n\t" + "movl %%esi,8(%2)\n\t" + "movl %%edi,12(%2)\n\t" + "movl %%ebp,16(%2)\n\t" + "movl %%esp,20(%2)\n\t" + "movl $1f,24(%2)\n" + "1:" + :"=a" (result) + :"0" (0), "d" (ex) + :"cx","memory"); + return result; +} + +extern inline void handle_exception(struct exception_struct *ex) +{ + if (!ex->count) { + ex->count--; + __asm__("movl 4(%0),%%ebx\n\t" + "movl 8(%0),%%esi\n\t" + "movl 12(%0),%%edi\n\t" + "movl 16(%0),%%ebp\n\t" + "movl 20(%0),%%esp\n\t" + "movl 24(%0),%%eax\n\t" + "jmp *%%eax" + : /* no outputs */ + :"d" (ex) + :"memory"); + } +} + +#define exception() __exception(¤t->tss.ex) +#define end_exception() (current->tss.ex.count--) + +/* * Size of io_bitmap in longwords: 32 is ports 0-0x3ff. */ #define IO_BITMAP_SIZE 32 @@ -111,6 +164,7 @@ struct vm86_struct * vm86_info; unsigned long screen_bitmap; unsigned long v86flags, v86mask, v86mode; + struct exception_struct ex; }; #define INIT_MMAP { &init_mm, 0xC0000000, 0xFFFFF000, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC } @@ -128,16 +182,21 @@ {~0, }, /* ioperm */ \ _TSS(0), 0, 0, 0, KERNEL_DS, \ { { 0, }, }, /* 387 state */ \ - NULL, 0, 0, 0, 0 /* vm86_info */ \ + NULL, 0, 0, 0, 0 /* vm86_info */, \ + { -1, } \ } #define alloc_kernel_stack() __get_free_page(GFP_KERNEL) #define free_kernel_stack(page) free_page((page)) #define start_thread(regs, new_eip, new_esp) do {\ - set_fs(USER_DS); \ - regs->cs = USER_CS; \ - regs->ds = regs->es = regs->ss = regs->fs = regs->gs = USER_DS; \ + unsigned long seg = USER_DS; \ + __asm__("mov %w0,%%fs ; mov %w0,%%gs":"=r" (seg) :"0" (seg)); \ + set_fs(seg); \ + regs->xds = seg; \ + regs->xes = seg; \ + regs->xss = seg; \ + regs->xcs = USER_CS; \ regs->eip = new_eip; \ regs->esp = new_esp; \ } while (0) diff -u --recursive --new-file v2.1.1/linux/include/asm-i386/ptrace.h linux/include/asm-i386/ptrace.h --- v2.1.1/linux/include/asm-i386/ptrace.h Wed Sep 13 10:08:39 1995 +++ linux/include/asm-i386/ptrace.h Sat Oct 5 14:34:11 1996 @@ -31,20 +31,18 @@ long edi; long ebp; long eax; - unsigned short ds, __dsu; - unsigned short es, __esu; - unsigned short fs, __fsu; - unsigned short gs, __gsu; + int xds; + int xes; long orig_eax; long eip; - unsigned short cs, __csu; + int xcs; long eflags; long esp; - unsigned short ss, __ssu; + int xss; }; #ifdef __KERNEL__ -#define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->cs)) +#define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs)) #define instruction_pointer(regs) ((regs)->eip) extern void show_regs(struct pt_regs *); #endif diff -u --recursive --new-file v2.1.1/linux/include/asm-i386/user.h linux/include/asm-i386/user.h --- v2.1.1/linux/include/asm-i386/user.h Mon Sep 23 09:25:57 1996 +++ linux/include/asm-i386/user.h Tue Oct 8 17:57:23 1996 @@ -41,13 +41,29 @@ long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */ }; +/* + * This is the old layout of "struct pt_regs", and + * is still the layout used by user more (the new + * pt_regs doesn't have all registers as the kernel + * doesn't use the extra segment registers) + */ +struct user_regs_struct { + long ebx, ecx, edx, esi, edi, ebp, eax; + unsigned short ds, __ds, es, __es; + unsigned short fs, __fs, gs, __gs; + long orig_eax, eip; + unsigned short cs, __cs; + long eflags, esp; + unsigned short ss, __ss; +}; + /* When the kernel dumps core, it starts by dumping the user struct - this will be used by gdb to figure out where the data and stack segments are within the file, and what virtual addresses to use. */ struct user{ /* We start with the registers, to mimic the way that "memory" is returned from the ptrace(3,...) function. */ - struct pt_regs regs; /* Where the registers are actually stored */ + struct user_regs_struct regs; /* Where the registers are actually stored */ /* ptrace does not yet supply these. Someday.... */ int u_fpvalid; /* True if math co-processor being used. */ /* for this mess. Not yet used. */ diff -u --recursive --new-file v2.1.1/linux/include/asm-m68k/mman.h linux/include/asm-m68k/mman.h --- v2.1.1/linux/include/asm-m68k/mman.h Sat Mar 23 22:23:19 1996 +++ linux/include/asm-m68k/mman.h Mon Oct 7 08:55:48 1996 @@ -14,7 +14,7 @@ #define MAP_GROWSDOWN 0x0100 /* stack-like segment */ #define MAP_DENYWRITE 0x0800 /* ETXTBSY */ -#define MAP_EXECUTABLE 0x1000 /* mark it as a executable */ +#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ #define MAP_LOCKED 0x2000 /* pages are locked */ #define MS_ASYNC 1 /* sync memory asynchronously */ diff -u --recursive --new-file v2.1.1/linux/include/asm-mips/io.h linux/include/asm-mips/io.h --- v2.1.1/linux/include/asm-mips/io.h Wed Dec 13 12:39:45 1995 +++ linux/include/asm-mips/io.h Mon Oct 7 08:55:48 1996 @@ -192,7 +192,7 @@ /* * Note that due to the way __builtin_constant_p() works, you - * - can't use it inside a inline function (it will never be true) + * - can't use it inside an inline function (it will never be true) * - you don't have to worry about side effects within the __builtin.. */ #define outb(val,port) \ diff -u --recursive --new-file v2.1.1/linux/include/asm-mips/mman.h linux/include/asm-mips/mman.h --- v2.1.1/linux/include/asm-mips/mman.h Wed Dec 13 12:39:46 1995 +++ linux/include/asm-mips/mman.h Mon Oct 7 08:55:48 1996 @@ -39,7 +39,7 @@ #define MAP_ANONYMOUS 0x0800 /* don't use a file */ #define MAP_GROWSDOWN 0x1000 /* stack-like segment */ #define MAP_DENYWRITE 0x2000 /* ETXTBSY */ -#define MAP_EXECUTABLE 0x4000 /* mark it as a executable */ +#define MAP_EXECUTABLE 0x4000 /* mark it as an executable */ #define MAP_LOCKED 0x8000 /* pages are locked */ /* diff -u --recursive --new-file v2.1.1/linux/include/asm-ppc/mman.h linux/include/asm-ppc/mman.h --- v2.1.1/linux/include/asm-ppc/mman.h Mon May 27 12:00:59 1996 +++ linux/include/asm-ppc/mman.h Mon Oct 7 08:55:48 1996 @@ -15,7 +15,7 @@ #define MAP_GROWSDOWN 0x0100 /* stack-like segment */ #define MAP_DENYWRITE 0x0800 /* ETXTBSY */ -#define MAP_EXECUTABLE 0x1000 /* mark it as a executable */ +#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ #define MS_ASYNC 1 /* sync memory asynchronously */ #define MS_INVALIDATE 2 /* invalidate the caches */ diff -u --recursive --new-file v2.1.1/linux/include/asm-ppc/pgtable.h linux/include/asm-ppc/pgtable.h --- v2.1.1/linux/include/asm-ppc/pgtable.h Mon May 27 12:00:59 1996 +++ linux/include/asm-ppc/pgtable.h Mon Oct 7 08:55:48 1996 @@ -168,8 +168,8 @@ #endif /* - * Define this if things work differently on a i386 and a i486: - * it will (on a i486) warn about kernel memory accesses that are + * Define this if things work differently on an i386 and an i486: + * it will (on an i486) warn about kernel memory accesses that are * done without a 'verify_area(VERIFY_WRITE,..)' */ #undef CONFIG_TEST_VERIFY_AREA diff -u --recursive --new-file v2.1.1/linux/include/asm-sparc/mman.h linux/include/asm-sparc/mman.h --- v2.1.1/linux/include/asm-sparc/mman.h Thu Apr 25 13:23:18 1996 +++ linux/include/asm-sparc/mman.h Mon Oct 7 08:55:48 1996 @@ -22,7 +22,7 @@ #define MAP_GROWSDOWN 0x0100 /* stack-like segment */ #define MAP_DENYWRITE 0x0800 /* ETXTBSY */ -#define MAP_EXECUTABLE 0x1000 /* mark it as a executable */ +#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ #define MS_ASYNC 1 /* sync memory asynchronously */ #define MS_INVALIDATE 2 /* invalidate the caches */ diff -u --recursive --new-file v2.1.1/linux/include/linux/config.h linux/include/linux/config.h --- v2.1.1/linux/include/linux/config.h Mon Sep 30 11:19:00 1996 +++ linux/include/linux/config.h Tue Oct 8 18:58:23 1996 @@ -27,7 +27,7 @@ * in linux/version.h, and should only be used by linux/version.c */ -/* Shouldn't these be defined somewhere in a i386 definition? */ +/* Shouldn't these be defined somewhere in an i386 definition? */ /* Don't touch these, unless you really know what you're doing. */ #define DEF_INITSEG 0x9000 diff -u --recursive --new-file v2.1.1/linux/include/linux/ipc.h linux/include/linux/ipc.h --- v2.1.1/linux/include/linux/ipc.h Sun Aug 4 14:38:04 1996 +++ linux/include/linux/ipc.h Mon Oct 7 15:12:29 1996 @@ -1,22 +1,21 @@ #ifndef _LINUX_IPC_H #define _LINUX_IPC_H + #include -typedef int key_t; /* should go in type for IPC key */ -#define IPC_PRIVATE ((key_t) 0) +#define IPC_PRIVATE ((__kernel_key_t) 0) struct ipc_perm { - key_t key; - ushort uid; /* owner euid and egid */ - ushort gid; - ushort cuid; /* creator euid and egid */ - ushort cgid; - ushort mode; /* access modes see mode flags below */ - ushort seq; /* sequence number */ + __kernel_key_t key; + __kernel_uid_t uid; + __kernel_gid_t gid; + __kernel_uid_t cuid; + __kernel_gid_t cgid; + __kernel_mode_t mode; + unsigned short seq; }; - /* resource get request flags */ #define IPC_CREAT 00001000 /* create if key is nonexistent */ #define IPC_EXCL 00002000 /* fail if key exists */ @@ -37,28 +36,6 @@ /* special shmsegs[id], msgque[id] or semary[id] values */ #define IPC_UNUSED ((void *) -1) #define IPC_NOID ((void *) -2) /* being allocated/destroyed */ - -/* - * These are used to wrap system calls. See ipc/util.c. - */ -struct ipc_kludge { - struct msgbuf *msgp; - long msgtyp; -}; - -#define SEMOP 1 -#define SEMGET 2 -#define SEMCTL 3 -#define MSGSND 11 -#define MSGRCV 12 -#define MSGGET 13 -#define MSGCTL 14 -#define SHMAT 21 -#define SHMDT 22 -#define SHMGET 23 -#define SHMCTL 24 - -#define IPCCALL(version,op) ((version)<<16 | (op)) #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.1.1/linux/include/linux/mm.h linux/include/linux/mm.h --- v2.1.1/linux/include/linux/mm.h Mon Sep 30 11:19:00 1996 +++ linux/include/linux/mm.h Tue Oct 8 18:58:23 1996 @@ -14,11 +14,26 @@ #include #include +#include #define VERIFY_READ 0 #define VERIFY_WRITE 1 -extern int verify_area(int, const void *, unsigned long); +extern int __verify_write(const void *, unsigned long); + +#define verify_write(type,addr,size) \ +(((type) && !wp_works_ok)?__verify_write((addr),(size)):0) + +extern inline int verify_area(int type, const void * addr, unsigned long size) +{ + int retval = 0; + if (get_fs() != KERNEL_DS) { + retval = -EFAULT; + if (size <= TASK_SIZE && TASK_SIZE-size >= (unsigned long) addr) + retval = verify_write(type,addr,size); + } + return retval; +} /* * Linux kernel virtual memory manager primitives. @@ -333,17 +348,18 @@ struct vm_area_struct * result = NULL; if (mm) { - struct vm_area_struct * tree = mm->mmap_avl; + struct vm_area_struct ** next = &mm->mmap_avl; for (;;) { + struct vm_area_struct *tree = *next; if (tree == avl_empty) break; - if (tree->vm_end > addr) { - result = tree; - if (tree->vm_start <= addr) - break; - tree = tree->vm_avl_left; - } else - tree = tree->vm_avl_right; + next = &tree->vm_avl_right; + if (tree->vm_end <= addr) + continue; + next = &tree->vm_avl_left; + result = tree; + if (tree->vm_start <= addr) + break; } } return result; diff -u --recursive --new-file v2.1.1/linux/include/linux/msg.h linux/include/linux/msg.h --- v2.1.1/linux/include/linux/msg.h Sun Aug 4 14:39:35 1996 +++ linux/include/linux/msg.h Mon Oct 7 15:12:29 1996 @@ -1,5 +1,6 @@ #ifndef _LINUX_MSG_H #define _LINUX_MSG_H + #include /* msgrcv options */ @@ -8,37 +9,37 @@ /* one msqid structure for each queue on the system */ struct msqid_ds { - struct ipc_perm msg_perm; - struct msg *msg_first; /* first message on queue */ - struct msg *msg_last; /* last message in queue */ - time_t msg_stime; /* last msgsnd time */ - time_t msg_rtime; /* last msgrcv time */ - time_t msg_ctime; /* last change time */ - struct wait_queue *wwait; - struct wait_queue *rwait; - ushort msg_cbytes; /* current number of bytes on queue */ - ushort msg_qnum; /* number of messages in queue */ - ushort msg_qbytes; /* max number of bytes on queue */ - ushort msg_lspid; /* pid of last msgsnd */ - ushort msg_lrpid; /* last receive pid */ + struct ipc_perm msg_perm; + struct msg *msg_first; /* first message on queue */ + struct msg *msg_last; /* last message in queue */ + __kernel_time_t msg_stime; /* last msgsnd time */ + __kernel_time_t msg_rtime; /* last msgrcv time */ + __kernel_time_t msg_ctime; /* last change time */ + struct wait_queue *wwait; + struct wait_queue *rwait; + unsigned short msg_cbytes; /* current number of bytes on queue */ + unsigned short msg_qnum; /* number of messages in queue */ + unsigned short msg_qbytes; /* max number of bytes on queue */ + __kernel_pid_t msg_lspid; /* pid of last msgsnd */ + __kernel_pid_t msg_lrpid; /* last receive pid */ }; /* message buffer for msgsnd and msgrcv calls */ struct msgbuf { - long mtype; /* type of message */ - char mtext[1]; /* message text */ + long mtype; /* type of message */ + char mtext[1]; /* message text */ }; /* buffer for msgctl calls IPC_INFO, MSG_INFO */ struct msginfo { - int msgpool; - int msgmap; - int msgmax; - int msgmnb; - int msgmni; - int msgssz; - int msgtql; - ushort msgseg; + int msgpool; + int msgmap; + int msgmax; + int msgmnb; + int msgmni; + int msgssz; + int msgtql; + unsigned short msgseg; }; #define MSGMNI 128 /* <= 1K */ /* max # of msg queue identifiers */ @@ -57,11 +58,11 @@ /* one msg structure for each message */ struct msg { - struct msg *msg_next; /* next message on queue */ - long msg_type; - char *msg_spot; /* message text address */ - time_t msg_stime; /* msgsnd time */ - short msg_ts; /* message text size */ + struct msg *msg_next; /* next message on queue */ + long msg_type; + char *msg_spot; /* message text address */ + time_t msg_stime; /* msgsnd time */ + short msg_ts; /* message text size */ }; /* ipcs ctl commands */ diff -u --recursive --new-file v2.1.1/linux/include/linux/posix_types.h linux/include/linux/posix_types.h --- v2.1.1/linux/include/linux/posix_types.h Sun Aug 4 14:37:29 1996 +++ linux/include/linux/posix_types.h Mon Oct 7 15:12:29 1996 @@ -45,6 +45,12 @@ unsigned long fds_bits [__FDSET_LONGS]; } __kernel_fd_set; +/* Type of a signal handler. */ +typedef void (*__kernel_sighandler_t)(int); + +/* Type of a SYSV IPC key. */ +typedef int __kernel_key_t; + #include #endif /* _LINUX_POSIX_TYPES_H */ diff -u --recursive --new-file v2.1.1/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h --- v2.1.1/linux/include/linux/proc_fs.h Mon Sep 30 11:19:11 1996 +++ linux/include/linux/proc_fs.h Tue Oct 8 18:58:33 1996 @@ -155,7 +155,7 @@ /* * This is not completely implemented yet. The idea is to - * create a in-memory tree (like the actual /proc filesystem + * create an in-memory tree (like the actual /proc filesystem * tree) of these proc_dir_entries, so that we can dynamically * add new files to /proc. * diff -u --recursive --new-file v2.1.1/linux/include/linux/sem.h linux/include/linux/sem.h --- v2.1.1/linux/include/linux/sem.h Sun Aug 4 14:38:04 1996 +++ linux/include/linux/sem.h Mon Oct 7 15:12:29 1996 @@ -1,5 +1,6 @@ #ifndef _LINUX_SEM_H #define _LINUX_SEM_H + #include /* semop flags */ @@ -16,43 +17,43 @@ /* One semid data structure for each set of semaphores in the system. */ struct semid_ds { - struct ipc_perm sem_perm; /* permissions .. see ipc.h */ - time_t sem_otime; /* last semop time */ - time_t sem_ctime; /* last change time */ - struct sem *sem_base; /* ptr to first semaphore in array */ - struct sem_queue *sem_pending; /* pending operations to be processed */ - struct sem_queue **sem_pending_last; /* last pending operation */ - struct sem_undo *undo; /* undo requests on this array */ - ushort sem_nsems; /* no. of semaphores in array */ + struct ipc_perm sem_perm; /* permissions .. see ipc.h */ + __kernel_time_t sem_otime; /* last semop time */ + __kernel_time_t sem_ctime; /* last change time */ + struct sem *sem_base; /* ptr to first semaphore in array */ + struct sem_queue *sem_pending; /* pending operations to be processed */ + struct sem_queue **sem_pending_last; /* last pending operation */ + struct sem_undo *undo; /* undo requests on this array */ + unsigned short sem_nsems; /* no. of semaphores in array */ }; /* semop system calls takes an array of these. */ struct sembuf { - ushort sem_num; /* semaphore index in array */ - short sem_op; /* semaphore operation */ - short sem_flg; /* operation flags */ + unsigned short sem_num; /* semaphore index in array */ + short sem_op; /* semaphore operation */ + short sem_flg; /* operation flags */ }; /* arg for semctl system calls. */ union semun { - int val; /* value for SETVAL */ - struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */ - ushort *array; /* array for GETALL & SETALL */ - struct seminfo *__buf; /* buffer for IPC_INFO */ - void *__pad; + int val; /* value for SETVAL */ + struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */ + unsigned short *array; /* array for GETALL & SETALL */ + struct seminfo *__buf; /* buffer for IPC_INFO */ + void *__pad; }; struct seminfo { - int semmap; - int semmni; - int semmns; - int semmnu; - int semmsl; - int semopm; - int semume; - int semusz; - int semvmx; - int semaem; + int semmap; + int semmni; + int semmns; + int semmnu; + int semmsl; + int semopm; + int semume; + int semusz; + int semvmx; + int semaem; }; #define SEMMNI 128 /* ? max # of semaphore identifiers */ @@ -72,8 +73,8 @@ /* One semaphore structure for each semaphore in the system. */ struct sem { - short semval; /* current value */ - short sempid; /* pid of last operation */ + int semval; /* current value */ + int sempid; /* pid of last operation */ }; /* ipcs ctl cmds */ @@ -82,25 +83,25 @@ /* One queue for each semaphore set in the system. */ struct sem_queue { - struct sem_queue * next; /* next entry in the queue */ - struct sem_queue ** prev; /* previous entry in the queue, *(q->prev) == q */ - struct wait_queue * sleeper; /* sleeping process */ - struct sem_undo * undo; /* undo structure */ - int pid; /* process id of requesting process */ - int status; /* completion status of operation */ - struct semid_ds * sma; /* semaphore array for operations */ - struct sembuf * sops; /* array of pending operations */ - int nsops; /* number of operations */ + struct sem_queue * next; /* next entry in the queue */ + struct sem_queue ** prev; /* previous entry in the queue, *(q->prev) == q */ + struct wait_queue * sleeper; /* sleeping process */ + struct sem_undo * undo; /* undo structure */ + int pid; /* process id of requesting process */ + int status; /* completion status of operation */ + struct semid_ds * sma; /* semaphore array for operations */ + struct sembuf * sops; /* array of pending operations */ + int nsops; /* number of operations */ }; /* Each task has a list of undo requests. They are executed automatically * when the process exits. */ struct sem_undo { - struct sem_undo * proc_next; /* next entry on this process */ - struct sem_undo * id_next; /* next entry on this semaphore set */ - int semid; /* semaphore set identifier */ - short * semadj; /* array of adjustments, one per semaphore */ + struct sem_undo * proc_next; /* next entry on this process */ + struct sem_undo * id_next; /* next entry on this semaphore set */ + int semid; /* semaphore set identifier */ + short * semadj; /* array of adjustments, one per semaphore */ }; asmlinkage int sys_semget (key_t key, int nsems, int semflg); diff -u --recursive --new-file v2.1.1/linux/include/linux/shm.h linux/include/linux/shm.h --- v2.1.1/linux/include/linux/shm.h Sun Aug 4 14:39:35 1996 +++ linux/include/linux/shm.h Mon Oct 7 15:12:29 1996 @@ -7,13 +7,13 @@ struct shmid_ds { struct ipc_perm shm_perm; /* operation perms */ - int shm_segsz; /* size of segment (bytes) */ - time_t shm_atime; /* last attach time */ - time_t shm_dtime; /* last detach time */ - time_t shm_ctime; /* last change time */ - unsigned short shm_cpid; /* pid of creator */ - unsigned short shm_lpid; /* pid of last operator */ - short shm_nattch; /* no. of current attaches */ + int shm_segsz; /* size of segment (bytes) */ + __kernel_time_t shm_atime; /* last attach time */ + __kernel_time_t shm_dtime; /* last detach time */ + __kernel_time_t shm_ctime; /* last change time */ + __kernel_pid_t shm_cpid; /* pid of creator */ + __kernel_pid_t shm_lpid; /* pid of last operator */ + unsigned short shm_nattch; /* no. of current attaches */ /* the following are private */ unsigned short shm_npages; /* size of segment (pages) */ unsigned long *shm_pages; /* array of ptrs to frames -> SHMMAX */ @@ -34,11 +34,11 @@ #define SHM_UNLOCK 12 struct shminfo { - int shmmax; - int shmmin; - int shmmni; - int shmseg; - int shmall; + int shmmax; + int shmmin; + int shmmni; + int shmseg; + int shmall; }; #ifdef __KERNEL__ @@ -50,21 +50,21 @@ /* ipcs ctl commands */ #define SHM_STAT 13 #define SHM_INFO 14 + struct shm_info { - int used_ids; - ulong shm_tot; /* total allocated shm */ - ulong shm_rss; /* total resident shm */ - ulong shm_swp; /* total swapped shm */ - ulong swap_attempts; - ulong swap_successes; + int used_ids; + unsigned long shm_tot; /* total allocated shm */ + unsigned long shm_rss; /* total resident shm */ + unsigned long shm_swp; /* total swapped shm */ + unsigned long swap_attempts; + unsigned long swap_successes; }; asmlinkage int sys_shmget (key_t key, int size, int flag); -asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *addr); +asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, unsigned long *addr); asmlinkage int sys_shmdt (char *shmaddr); asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf); #endif /* __KERNEL__ */ #endif /* _LINUX_SHM_H_ */ - diff -u --recursive --new-file v2.1.1/linux/include/linux/soundcard.h linux/include/linux/soundcard.h --- v2.1.1/linux/include/linux/soundcard.h Sat Aug 31 19:39:10 1996 +++ linux/include/linux/soundcard.h Mon Oct 7 08:55:48 1996 @@ -184,7 +184,7 @@ * * The low_note and high_note fields define the minimum and maximum note * frequencies for which this sample is valid. It is possible to define - * more than one samples for a instrument number at the same time. The + * more than one samples for an instrument number at the same time. The * low_note and high_note fields are used to select the most suitable one. * * The fields base_note, high_note and low_note should contain @@ -267,7 +267,7 @@ unsigned int key; /* Don't worry. Reserved for communication between the patch manager and the driver. */ #define PM_K_EVENT 1 /* Event from the /dev/sequencer driver */ -#define PM_K_COMMAND 2 /* Request from a application */ +#define PM_K_COMMAND 2 /* Request from an application */ #define PM_K_RESPONSE 3 /* From patmgr to application */ #define PM_ERROR 4 /* Error returned by the patmgr */ int device; diff -u --recursive --new-file v2.1.1/linux/include/linux/timex.h linux/include/linux/timex.h --- v2.1.1/linux/include/linux/timex.h Sat May 4 19:39:22 1996 +++ linux/include/linux/timex.h Mon Oct 7 08:55:48 1996 @@ -73,7 +73,7 @@ /* * The SHIFT_SCALE define establishes the decimal point of the time_phase - * variable which serves as a an extension to the low-order bits of the + * variable which serves as an extension to the low-order bits of the * system clock variable. The SHIFT_UPDATE define establishes the decimal * point of the time_offset variable which represents the current offset * with respect to standard time. The FINEUSEC define represents 1 usec in diff -u --recursive --new-file v2.1.1/linux/include/linux/types.h linux/include/linux/types.h --- v2.1.1/linux/include/linux/types.h Sun Aug 4 14:38:04 1996 +++ linux/include/linux/types.h Mon Oct 7 15:12:29 1996 @@ -16,6 +16,7 @@ typedef __kernel_uid_t uid_t; typedef __kernel_gid_t gid_t; typedef __kernel_daddr_t daddr_t; +typedef __kernel_key_t key_t; #if defined(__GNUC__) && !defined(__STRICT_ANSI__) typedef __kernel_loff_t loff_t; diff -u --recursive --new-file v2.1.1/linux/include/net/tcp.h linux/include/net/tcp.h --- v2.1.1/linux/include/net/tcp.h Mon Sep 30 11:24:39 1996 +++ linux/include/net/tcp.h Tue Oct 8 19:03:26 1996 @@ -159,7 +159,7 @@ extern void tcp_send_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th, struct proto *prot, struct options *opt, struct device *dev, int tos, int ttl); -extern void tcp_enqueue_partial(struct sk_buff *, struct sock *); +extern void tcp_enqueue_partial(struct sock *, struct sk_buff *); extern struct sk_buff * tcp_dequeue_partial(struct sock *); extern void tcp_shrink_skb(struct sock *,struct sk_buff *,u32); diff -u --recursive --new-file v2.1.1/linux/init/main.c linux/init/main.c --- v2.1.1/linux/init/main.c Mon Sep 23 13:31:03 1996 +++ linux/init/main.c Mon Oct 7 08:55:49 1996 @@ -849,7 +849,7 @@ * anything that can be useful, but shouldn't take time from the real * processes. * - * Right now task[0] just does a infinite idle loop. + * Right now task[0] just does an infinite idle loop. */ cpu_idle(NULL); } diff -u --recursive --new-file v2.1.1/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v2.1.1/linux/kernel/ksyms.c Thu Sep 26 09:17:27 1996 +++ linux/kernel/ksyms.c Tue Oct 8 08:50:20 1996 @@ -119,7 +119,7 @@ #endif /* process memory management */ - X(verify_area), + X(__verify_write), X(do_mmap), X(do_munmap), X(exit_mm), diff -u --recursive --new-file v2.1.1/linux/mm/filemap.c linux/mm/filemap.c --- v2.1.1/linux/mm/filemap.c Sat Sep 28 23:20:18 1996 +++ linux/mm/filemap.c Tue Oct 8 08:50:20 1996 @@ -657,14 +657,17 @@ */ { unsigned long offset, nr; + + if (exception()) + goto page_read_exception; offset = pos & ~PAGE_MASK; nr = PAGE_SIZE - offset; if (nr > count) nr = count; - if (nr > inode->i_size - pos) nr = inode->i_size - pos; memcpy_tofs(buf, (void *) (page_address(page) + offset), nr); + end_exception(); release_page(page); buf += nr; pos += nr; @@ -736,6 +739,11 @@ goto success; error = -EIO; /* Some unspecified error occurred.. */ } + release_page(page); + break; + +page_read_exception: + error = -EFAULT; release_page(page); break; } diff -u --recursive --new-file v2.1.1/linux/mm/memory.c linux/mm/memory.c --- v2.1.1/linux/mm/memory.c Wed Sep 25 12:27:40 1996 +++ linux/mm/memory.c Tue Oct 8 08:50:20 1996 @@ -678,16 +678,12 @@ /* * Ugly, ugly, but the goto's result in better assembly.. */ -int verify_area(int type, const void * addr, unsigned long size) +int __verify_write(const void * addr, unsigned long size) { struct vm_area_struct * vma; unsigned long start = (unsigned long) addr; - /* If the current user space is mapped to kernel space (for the - * case where we use a fake user buffer with get_fs/set_fs()) we - * don't expect to find the address in the user vm map. - */ - if (!size || get_fs() == KERNEL_DS) + if (!size) return 0; vma = find_vma(current->mm, start); @@ -697,37 +693,8 @@ goto check_stack; good_area: - if (type == VERIFY_WRITE) - goto check_write; - for (;;) { - struct vm_area_struct * next; - if (!(vma->vm_flags & VM_READ)) - goto bad_area; - if (vma->vm_end - start >= size) - return 0; - next = vma->vm_next; - if (!next || vma->vm_end != next->vm_start) - goto bad_area; - vma = next; - } - -check_write: if (!(vma->vm_flags & VM_WRITE)) goto bad_area; - if (!wp_works_ok) - goto check_wp_fault_by_hand; - for (;;) { - if (vma->vm_end - start >= size) - break; - if (!vma->vm_next || vma->vm_end != vma->vm_next->vm_start) - goto bad_area; - vma = vma->vm_next; - if (!(vma->vm_flags & VM_WRITE)) - goto bad_area; - } - return 0; - -check_wp_fault_by_hand: size--; size += start & ~PAGE_MASK; size >>= PAGE_SHIFT; @@ -914,7 +881,7 @@ * for other architectures too. * * Note that if write_access is true, we either now have - * a exclusive copy of the page, or this is a shared mapping, + * an exclusive copy of the page, or this is a shared mapping, * so we can make it writable and dirty to avoid having to * handle that later. */ diff -u --recursive --new-file v2.1.1/linux/mm/mmap.c linux/mm/mmap.c --- v2.1.1/linux/mm/mmap.c Mon Sep 23 14:38:29 1996 +++ linux/mm/mmap.c Sat Oct 5 12:07:55 1996 @@ -255,7 +255,8 @@ /* Private writable mapping? Check memory availability.. */ if ((vma->vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE) { - if (!vm_enough_memory(len >> PAGE_SHIFT)) { + if (!(flags & MAP_NORESERVE) && + !vm_enough_memory(len >> PAGE_SHIFT)) { kfree(vma); return -ENOMEM; } diff -u --recursive --new-file v2.1.1/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v2.1.1/linux/net/ipv4/tcp.c Sat Oct 5 16:58:37 1996 +++ linux/net/ipv4/tcp.c Tue Oct 8 17:25:46 1996 @@ -888,6 +888,54 @@ lock_sock(sk); } +/* + * Add more stuff to the end of skb->len + */ +static int fill_in_partial_skb(struct sock *sk, struct sk_buff *skb, + unsigned char * from, int seglen) +{ + void (*send)(struct sock *sk, struct sk_buff *skb); + int copy, tcp_size; + + tcp_size = skb->tail - (unsigned char *)(skb->h.th + 1); + + /* + * Now we may find the frame is as big, or too + * big for our MSS. Thats all fine. It means the + * MSS shrank (from an ICMP) after we allocated + * this frame. + */ + + copy = sk->mss - tcp_size; + if (copy <= 0) { + tcp_send_skb(sk, skb); + return 0; + } + + /* + * Otherwise continue to fill the buffer. + */ + send = tcp_send_skb; + if (copy > seglen) { + send = tcp_enqueue_partial; + copy = seglen; + } + if (exception()) { + tcp_enqueue_partial(sk, skb); + return -EFAULT; + } + memcpy_fromfs(skb->tail, from, copy); + end_exception(); + tcp_size += copy; + skb->tail += copy; + skb->len += copy; + skb->csum = csum_partial(skb->tail - tcp_size, tcp_size, 0); + if (!sk->packets_out) + send = tcp_send_skb; + send(sk, skb); + return copy; +} + /* * This routine copies from a user buffer into a socket, @@ -937,9 +985,10 @@ while(seglen > 0) { - int copy, delay; + int copy; int tmp; struct sk_buff *skb; + void (*send)(struct sock *, struct sk_buff *); /* * Stop on errors @@ -1004,56 +1053,21 @@ * If there is a partly filled frame we can fill * out. */ - if ((skb = tcp_dequeue_partial(sk)) != NULL) - { - int tcp_size; - - tcp_size = skb->tail - (unsigned char *)(skb->h.th + 1); - - /* Add more stuff to the end of skb->len */ - if (!(flags & MSG_OOB)) - { - copy = min(sk->mss - tcp_size, seglen); - - /* - * Now we may find the frame is as big, or too - * big for our MSS. Thats all fine. It means the - * MSS shrank (from an ICMP) after we allocated - * this frame. - */ - - if (copy <= 0) - { - /* - * Send the now forced complete frame out. - * - * Note for 2.1: The MSS reduce code ought to - * flush any frames in partial that are now - * full sized. Not serious, potential tiny - * performance hit. - */ - tcp_send_skb(sk,skb); - /* - * Get a new buffer and try again. - */ - continue; - } - /* - * Otherwise continue to fill the buffer. - */ - tcp_size += copy; - memcpy_fromfs(skb_put(skb,copy), from, copy); - skb->csum = csum_partial(skb->tail - tcp_size, tcp_size, 0); - from += copy; - copied += copy; - len -= copy; - sk->write_seq += copy; - seglen -= copy; + skb = tcp_dequeue_partial(sk); + if (skb) { + if (!(flags & MSG_OOB)) { + int retval; + retval = fill_in_partial_skb(sk, skb, from, seglen); + if (retval < 0) + return retval; + seglen -= retval; + from += retval; + copied += retval; + len -= retval; + sk->write_seq += retval; + continue; } - if (tcp_size >= sk->mss || (flags & MSG_OOB) || !sk->packets_out) - tcp_send_skb(sk, skb); - else - tcp_enqueue_partial(skb, sk); + tcp_send_skb(sk, skb); continue; } @@ -1084,12 +1098,12 @@ * We should really check the window here also. */ - delay = 0; + send = tcp_send_skb; tmp = copy + sk->prot->max_header + 15; if (copy < sk->mss && !(flags & MSG_OOB) && sk->packets_out) { tmp = tmp - copy + sk->mtu + 128; - delay = 1; + send = tcp_enqueue_partial; } skb = sock_wmalloc(sk, tmp, 0, GFP_KERNEL); @@ -1156,23 +1170,27 @@ skb->h.th->urg_ptr = ntohs(copy); } + if (exception()) + goto bad_access; skb->csum = csum_partial_copy_fromuser(from, - skb_put(skb,copy), copy, 0); - + skb->tail, copy, 0); + end_exception(); + skb->tail += copy; + skb->len += copy; from += copy; copied += copy; len -= copy; seglen -= copy; - skb->free = 0; sk->write_seq += copy; + skb->free = 0; - if (delay) - { - tcp_enqueue_partial(skb, sk); - continue; + send(sk, skb); + continue; + +bad_access: + sock_wfree(sk, skb); + return -EFAULT; } - tcp_send_skb(sk, skb); - } } sk->err = 0; @@ -1829,7 +1847,7 @@ /* - * Wait for a incoming connection, avoid race + * Wait for an incoming connection, avoid race * conditions. This must be called with the socket * locked. */ diff -u --recursive --new-file v2.1.1/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c --- v2.1.1/linux/net/ipv4/tcp_input.c Mon Sep 2 08:41:24 1996 +++ linux/net/ipv4/tcp_input.c Mon Oct 7 08:55:49 1996 @@ -184,7 +184,7 @@ } /* - * React to a out-of-window TCP sequence number in an incoming packet + * React to an out-of-window TCP sequence number in an incoming packet */ static void bad_tcp_sequence(struct sock *sk, struct tcphdr *th, u32 end_seq, diff -u --recursive --new-file v2.1.1/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c --- v2.1.1/linux/net/ipv4/tcp_output.c Mon Sep 2 08:41:24 1996 +++ linux/net/ipv4/tcp_output.c Tue Oct 8 14:57:41 1996 @@ -264,7 +264,7 @@ * Queue a partial frame */ -void tcp_enqueue_partial(struct sk_buff * skb, struct sock * sk) +void tcp_enqueue_partial(struct sock * sk, struct sk_buff * skb) { struct sk_buff * tmp; unsigned long flags; @@ -895,7 +895,7 @@ timeout = 0; timeout += jiffies; - /* Use new timeout only if there wasn't a older one earlier */ + /* Use new timeout only if there wasn't an older one earlier */ if (!del_timer(&sk->delack_timer) || timeout < sk->delack_timer.expires) sk->delack_timer.expires = timeout; diff -u --recursive --new-file v2.1.1/linux/net/unix/af_unix.c linux/net/unix/af_unix.c --- v2.1.1/linux/net/unix/af_unix.c Thu Sep 5 08:32:22 1996 +++ linux/net/unix/af_unix.c Sat Oct 5 16:49:05 1996 @@ -931,9 +931,9 @@ * have suggested. Big mallocs stress the vm too * much. */ - - if(size > 4000 && sock->type!=SOCK_DGRAM) - limit = 4000; /* Fall back to 4K if we can't grab a big buffer this instant */ +#define MAX_ALLOC (PAGE_SIZE*7/8) + if(size > MAX_ALLOC && sock->type!=SOCK_DGRAM) + limit = MAX_ALLOC; /* Fall back to 4K if we can't grab a big buffer this instant */ else limit = 0; /* Otherwise just grab and wait */