From d392db36693d1b630befdc89f77d397086157bf0 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:10:16 -0500 Subject: [PATCH] Import 1.3.32 --- CREDITS | 10 +- Makefile | 2 +- arch/alpha/kernel/apecs.c | 11 +- arch/alpha/kernel/bios32.c | 12 +- arch/alpha/kernel/entry.S | 2 +- arch/alpha/kernel/lca.c | 86 ++++++- arch/alpha/kernel/process.c | 4 + arch/i386/config.in | 8 +- arch/i386/kernel/process.c | 4 + arch/i386/math-emu/README | 8 +- arch/i386/math-emu/div_Xsig.S | 6 +- arch/i386/math-emu/div_small.S | 7 +- arch/i386/math-emu/fpu_asm.h | 6 +- arch/i386/math-emu/mul_Xsig.S | 6 +- arch/i386/math-emu/polynom_Xsig.S | 6 +- arch/i386/math-emu/reg_div.S | 6 +- arch/i386/math-emu/reg_norm.S | 6 +- arch/i386/math-emu/reg_round.S | 6 +- arch/i386/math-emu/reg_u_add.S | 6 +- arch/i386/math-emu/reg_u_div.S | 6 +- arch/i386/math-emu/reg_u_mul.S | 6 +- arch/i386/math-emu/reg_u_sub.S | 6 +- arch/i386/math-emu/round_Xsig.S | 6 +- arch/i386/math-emu/shr_Xsig.S | 6 +- arch/i386/math-emu/wm_shrx.S | 7 +- arch/i386/math-emu/wm_sqrt.S | 6 +- arch/mips/kernel/process.c | 7 + arch/sparc/kernel/process.c | 5 + drivers/net/3c507.c | 2 +- drivers/net/at1700.c | 2 +- drivers/net/eexpress.c | 2 +- drivers/net/ewrk3.c | 2 +- drivers/net/slhc.c | 8 + drivers/net/znet.c | 2 +- fs/nfs/Makefile | 2 +- fs/nfs/inode.c | 7 + fs/nfs/rpcsock.c | 391 ++++++++++++++++++++++++++++++ fs/nfs/sock.c | 218 ++++------------- include/asm-alpha/apecs.h | 11 +- include/asm-alpha/lca.h | 41 ++++ include/asm-alpha/system.h | 12 + include/asm-i386/byteorder.h | 8 +- include/asm-i386/ioctl.h | 1 + include/linux/if_eql.h | 2 + include/linux/mtio.h | 29 +++ include/linux/nfs_fs_sb.h | 2 + include/linux/resource.h | 2 + include/linux/rpcsock.h | 57 +++++ include/linux/sched.h | 1 + include/linux/serial.h | 3 + include/linux/tpqic02.h | 28 --- kernel/exit.c | 1 + net/ipv4/ip.c | 2 +- scripts/ksymoops.cc | 269 +++++++++++++++----- 54 files changed, 990 insertions(+), 372 deletions(-) create mode 100644 fs/nfs/rpcsock.c create mode 100644 include/linux/rpcsock.h diff --git a/CREDITS b/CREDITS index 9dfb3f47b621..216eea069a77 100644 --- a/CREDITS +++ b/CREDITS @@ -211,6 +211,15 @@ S: Northampton S: NN1 3QT S: United Kingdom +N: Ray Dassen +E: jdassen@wi.LeidenUniv.nl +U: http://www.wi.leidenuniv.nl/~jdassen/ +D: Debian GNU/Linux: www.debian.org maintainer, FAQ co-maintainer, +D: packages testing, nit-picking & fixing. Enjoying BugFree (TM) kernels. +S: Zuidsingel 10A +S: 2312 SB Leiden +S: The Netherlands + N: Wayne Davison E: davison@borland.com D: Second extended file system co-designer @@ -621,7 +630,6 @@ S: Fairfax, Virginia 22033 S: USA N: William (Bill) Metzenthen -E: billm@vaxc.cc.monash.edu.au E: billm@jacobi.maths.monash.edu.au D: Author of the FPU emulator. D: Minor kernel hacker for other lost causes (Hercules mono, etc). diff --git a/Makefile b/Makefile index 4c6b5f6ff15c..8fb1ab469360 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 3 -SUBLEVEL = 31 +SUBLEVEL = 32 ARCH = i386 diff --git a/arch/alpha/kernel/apecs.c b/arch/alpha/kernel/apecs.c index f6bbdcea98d4..3f684ab7671e 100644 --- a/arch/alpha/kernel/apecs.c +++ b/arch/alpha/kernel/apecs.c @@ -424,18 +424,17 @@ int apecs_pci_clr_err(void) void apecs_machine_check(unsigned long vector, unsigned long la_ptr, struct pt_regs * regs) { - struct el_common_logout_header *mchk_header; + struct el_common *mchk_header; struct el_apecs_sysdata_mcheck *mchk_sysdata; - mchk_header = (struct el_common_logout_header *)la_ptr; + mchk_header = (struct el_common *)la_ptr; mchk_sysdata = - (struct el_apecs_sysdata_mcheck *)(la_ptr + mchk_header->elfl_sysoffset); + (struct el_apecs_sysdata_mcheck *)(la_ptr + mchk_header->sys_offset); DBG(("apecs_machine_check: vector=0x%lx la_ptr=0x%lx\n", vector, la_ptr)); DBG((" pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", - regs->pc, mchk_header->elfl_size, mchk_header->elfl_procoffset, - mchk_header->elfl_sysoffset)); + regs->pc, mchk_header->size, mchk_header->proc_offset, mchk_header->sys_offset)); DBG(("apecs_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n", apecs_mcheck_expected, mchk_sysdata->epic_dcsr, mchk_sysdata->epic_pear)); #ifdef DEBUG @@ -443,7 +442,7 @@ void apecs_machine_check(unsigned long vector, unsigned long la_ptr, int i; ptr = (unsigned long *)la_ptr; - for (i = 0; i < mchk_header->elfl_size / sizeof(long); i += 2) { + for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { printk(" +%x %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]); } #endif /* DEBUG */ diff --git a/arch/alpha/kernel/bios32.c b/arch/alpha/kernel/bios32.c index 8d4e6423d3d8..9cc895f29d73 100644 --- a/arch/alpha/kernel/bios32.c +++ b/arch/alpha/kernel/bios32.c @@ -310,17 +310,17 @@ int pcibios_find_device (unsigned short vendor, unsigned short device_id, unsigned short index, unsigned char *bus, unsigned char *devfn) { - unsigned int current = 0; + unsigned int curr = 0; struct pci_dev *dev; for (dev = pci_devices; dev; dev = dev->next) { if (dev->vendor == vendor && dev->device == device_id) { - if (current == index) { + if (curr == index) { *devfn = dev->devfn; *bus = dev->bus->number; return PCIBIOS_SUCCESSFUL; } - ++current; + ++curr; } } return PCIBIOS_DEVICE_NOT_FOUND; @@ -334,17 +334,17 @@ int pcibios_find_device (unsigned short vendor, unsigned short device_id, int pcibios_find_class (unsigned int class_code, unsigned short index, unsigned char *bus, unsigned char *devfn) { - unsigned int current = 0; + unsigned int curr = 0; struct pci_dev *dev; for (dev = pci_devices; dev; dev = dev->next) { if (dev->class == class_code) { - if (current == index) { + if (curr == index) { *devfn = dev->devfn; *bus = dev->bus->number; return PCIBIOS_SUCCESSFUL; } - ++current; + ++curr; } } return PCIBIOS_DEVICE_NOT_FOUND; diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index ac0bb78214bb..1c8390c2cd3a 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -478,7 +478,7 @@ ret_from_sys_call: beq $0,restore_all ret_from_reschedule: lda $0,need_resched - lda $1,current + lda $1,current_set ldl $2,0($0) lda $4,init_task ldq $3,0($1) diff --git a/arch/alpha/kernel/lca.c b/arch/alpha/kernel/lca.c index 3ed4ad0a4d21..947139462b85 100644 --- a/arch/alpha/kernel/lca.c +++ b/arch/alpha/kernel/lca.c @@ -23,6 +23,29 @@ #define vulp volatile unsigned long * +/* + * 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_UNKNOWN 0x008A +#define MCHK_K_CACKSOFT 0x008C +#define MCHK_K_BUGCHECK 0x008E +#define MCHK_K_OS_BUGCHECK 0x0090 +#define MCHK_K_DCPERR 0x0092 +#define MCHK_K_ICPERR 0x0094 + +/* + * Platform-specific machine-check reasons: + */ +#define MCHK_K_SIO_SERR 0x204 /* all platforms so far */ +#define MCHK_K_SIO_IOCHK 0x206 /* all platforms so far */ +#define MCHK_K_DCSR 0x208 /* all but Noname */ + /* * Given a bus, device, and function number, compute resulting * configuration space address and setup the LCA_IOC_CONF register @@ -280,19 +303,60 @@ unsigned long lca_init(unsigned long mem_start, unsigned long mem_end) } + + void lca_machine_check (unsigned long vector, unsigned long la, struct pt_regs *regs) { - unsigned long mces; - - mces = rdmces(); - wrmces(mces); /* reset machine check asap */ - printk("Machine check (la=0x%lx,mces=0x%lx)\n", la, mces); - printk("esr=%lx, ear=%lx, ioc_stat0=%lx, ioc_stat1=%lx\n", - *(unsigned long*)LCA_MEM_ESR, *(unsigned long*)LCA_MEM_EAR, - *(unsigned long*)LCA_IOC_STAT0, *(unsigned long*)LCA_IOC_STAT1); -#ifdef CONFIG_ALPHA_NONAME - printk("NMMI status & control (0x61)=%02x\n", inb(0x61)); -#endif + const char * reason; + union el_lca el; + + printk("lca: machine check (la=0x%lx)\n", la); + el.c = (struct el_common *) la; + /* + * The first quadword after the common header always seems to + * be the machine check reason---don't know why this isn't + * part of the common header instead. + */ + switch (el.s->reason) { + case MCHK_K_TPERR: reason = "tag parity error"; break; + case MCHK_K_TCPERR: reason = "tag something 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; + case MCHK_K_CACKSOFT: reason = "MCHK_K_CACKSOFT"; break; /* what's this? */ + case MCHK_K_BUGCHECK: reason = "illegal exception in PAL mode"; break; + case MCHK_K_OS_BUGCHECK: reason = "callsys in kernel mode"; break; + case MCHK_K_DCPERR: reason = "d-cache parity error"; break; + case MCHK_K_ICPERR: reason = "i-cache parity error"; break; + case MCHK_K_SIO_SERR: reason = "SIO SERR occurred on on PCI bus"; break; + case MCHK_K_SIO_IOCHK: reason = "SIO IOCHK occurred on ISA bus"; break; + case MCHK_K_DCSR: reason = "MCHK_K_DCSR"; break; + case MCHK_K_UNKNOWN: + default: reason = "reason for machine-check unknown"; break; + } + + switch (el.c->size) { + case sizeof(struct el_lca_mcheck_short): + printk(" Reason: %s (short frame%s):\n", + reason, el.h->retry ? ", retryable" : ""); + printk("\tesr: %lx ear: %lx\n", el.s->esr, el.s->ear); + printk("\tdc_stat: %lx ioc_stat0: %lx ioc_stat1: %lx\n", + el.s->dc_stat, el.s->ioc_stat0, el.s->ioc_stat1); + break; + + case sizeof(struct el_lca_mcheck_long): + printk(" Reason: %s (long frame%s):\n", + reason, el.h->retry ? ", retryable" : ""); + printk("\treason: %lx exc_addr: %lx dc_stat: %lx\n", + el.l->pt[0], el.l->exc_addr, el.l->dc_stat); + printk("\tesr: %lx ear: %lx car: %lx\n", el.l->esr, el.l->ear, el.l->car); + printk("\tioc_stat0: %lx ioc_stat1: %lx\n", el.l->ioc_stat0, el.l->ioc_stat1); + break; + + default: + printk(" Unknown errorlog size %d\n", el.c->size); + } + wrmces(rdmces()); /* reset machine check asap */ } #endif /* CONFIG_ALPHA_LCA */ diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 2d372111eda2..8eeb37554a21 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -83,6 +83,10 @@ void flush_thread(void) { } +void release_thread(struct task_struct *dead_task) +{ +} + /* * "alpha_clone()".. By the time we get here, the * non-volatile registers have also been saved on the diff --git a/arch/i386/config.in b/arch/i386/config.in index 8a4dad907e90..597953e932d5 100644 --- a/arch/i386/config.in +++ b/arch/i386/config.in @@ -17,7 +17,7 @@ if [ "$CONFIG_ST506" = "y" ]; then bool ' Use new IDE driver for primary/secondary i/f' CONFIG_BLK_DEV_IDE y fi if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then - bool ' Include support for IDE/ATAPI CDROMs' CONFIG_BLK_DEV_IDECD n + bool ' Include support for IDE/ATAPI CDROMs' CONFIG_BLK_DEV_IDECD y fi fi @@ -80,7 +80,7 @@ fi comment 'SCSI support' -tristate 'SCSI support' CONFIG_SCSI y +tristate 'SCSI support' CONFIG_SCSI n if [ "$CONFIG_SCSI" = "n" ]; then @@ -101,8 +101,8 @@ bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN n comment 'SCSI low-level drivers' -dep_tristate 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X y $CONFIG_SCSI -dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 n $CONFIG_SCSI +dep_tristate 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X n $CONFIG_SCSI +dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 y $CONFIG_SCSI dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 n $CONFIG_SCSI dep_tristate 'Adaptec AHA274X/284X/294X support' CONFIG_SCSI_AIC7XXX n $CONFIG_SCSI dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC n $CONFIG_SCSI diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index ba2f2301216b..d6eec957deca 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -178,6 +178,10 @@ void flush_thread(void) current->debugreg[i] = 0; } +void release_thread(struct task_struct *dead_task) +{ +} + void copy_thread(int nr, unsigned long clone_flags, unsigned long esp, struct task_struct * p, struct pt_regs * regs) { diff --git a/arch/i386/math-emu/README b/arch/i386/math-emu/README index 2c0acb423f99..00b77898f46e 100644 --- a/arch/i386/math-emu/README +++ b/arch/i386/math-emu/README @@ -1,9 +1,9 @@ +---------------------------------------------------------------------------+ | wm-FPU-emu an FPU emulator for 80386 and 80486SX microprocessors. | | | - | Copyright (C) 1992,1993,1994 | + | Copyright (C) 1992,1993,1994,1995 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Australia. E-mail billm@jacobi.maths.monash.edu.au | | | | This program is free software; you can redistribute it and/or modify | | it under the terms of the GNU General Public License version 2 as | @@ -42,13 +42,11 @@ but is very close. See "Limitations" later in this file for a list of some differences. Please report bugs, etc to me at: - billm@vaxc.cc.monash.edu.au - or at: billm@jacobi.maths.monash.edu.au --Bill Metzenthen - August 1994 + October 1995 ----------------------- Internals of wm-FPU-emu ----------------------- diff --git a/arch/i386/math-emu/div_Xsig.S b/arch/i386/math-emu/div_Xsig.S index 5e2ee570a714..fd83732fc3c0 100644 --- a/arch/i386/math-emu/div_Xsig.S +++ b/arch/i386/math-emu/div_Xsig.S @@ -4,9 +4,9 @@ | | | Division subroutine for 96 bit quantities | | | - | Copyright (C) 1994 | + | Copyright (C) 1994,1995 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Australia. E-mail billm@jacobi.maths.monash.edu.au | | | | | +---------------------------------------------------------------------------*/ @@ -28,7 +28,7 @@ +---------------------------------------------------------------------------*/ #include "exception.h" -#include "fpu_asm.h" +#include "fpu_emu.h" #define XsigLL(x) (x) diff --git a/arch/i386/math-emu/div_small.S b/arch/i386/math-emu/div_small.S index b0b7ee25dd1c..13ab2b7ae5be 100644 --- a/arch/i386/math-emu/div_small.S +++ b/arch/i386/math-emu/div_small.S @@ -4,8 +4,9 @@ | | | Divide a 64 bit integer by a 32 bit integer & return remainder. | | | - | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Copyright (C) 1992,1995 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@jacobi.maths.monash.edu.au | | | | | +---------------------------------------------------------------------------*/ @@ -14,7 +15,7 @@ | unsigned long div_small(unsigned long long *x, unsigned long y) | +---------------------------------------------------------------------------*/ -#include "fpu_asm.h" +#include "fpu_emu.h" .text ENTRY(div_small) diff --git a/arch/i386/math-emu/fpu_asm.h b/arch/i386/math-emu/fpu_asm.h index 33c008d10647..de85ce66dfc4 100644 --- a/arch/i386/math-emu/fpu_asm.h +++ b/arch/i386/math-emu/fpu_asm.h @@ -1,8 +1,9 @@ /*---------------------------------------------------------------------------+ | fpu_asm.h | | | - | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Copyright (C) 1992,1995 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@jacobi.maths.monash.edu.au | | | +---------------------------------------------------------------------------*/ @@ -10,7 +11,6 @@ #define _FPU_ASM_H_ #include -#include "fpu_emu.h" #define EXCEPTION SYMBOL_NAME(exception) diff --git a/arch/i386/math-emu/mul_Xsig.S b/arch/i386/math-emu/mul_Xsig.S index 5e80762d2eda..717785a53eb4 100644 --- a/arch/i386/math-emu/mul_Xsig.S +++ b/arch/i386/math-emu/mul_Xsig.S @@ -3,9 +3,9 @@ | | | Multiply a 12 byte fixed point number by another fixed point number. | | | - | Copyright (C) 1992,1994 | + | Copyright (C) 1992,1994,1995 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Australia. E-mail billm@jacobi.maths.monash.edu.au | | | | Call from C as: | | void mul32_Xsig(Xsig *x, unsigned b) | @@ -21,7 +21,7 @@ .file "mul_Xsig.S" -#include "fpu_asm.h" +#include "fpu_emu.h" .text ENTRY(mul32_Xsig) diff --git a/arch/i386/math-emu/polynom_Xsig.S b/arch/i386/math-emu/polynom_Xsig.S index 19d1935b44ea..17315c89ff3d 100644 --- a/arch/i386/math-emu/polynom_Xsig.S +++ b/arch/i386/math-emu/polynom_Xsig.S @@ -3,9 +3,9 @@ | | | Fixed point arithmetic polynomial evaluation. | | | - | Copyright (C) 1992,1993,1994 | + | Copyright (C) 1992,1993,1994,1995 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Australia. E-mail billm@jacobi.maths.monash.edu.au | | | | Call from C as: | | void polynomial_Xsig(Xsig *accum, unsigned long long x, | @@ -23,7 +23,7 @@ +---------------------------------------------------------------------------*/ .file "polynomial_Xsig.S" -#include "fpu_asm.h" +#include "fpu_emu.h" #define TERM_SIZE $8 diff --git a/arch/i386/math-emu/reg_div.S b/arch/i386/math-emu/reg_div.S index 78b108675095..24d44ac6c1de 100644 --- a/arch/i386/math-emu/reg_div.S +++ b/arch/i386/math-emu/reg_div.S @@ -4,9 +4,9 @@ | | | Divide one FPU_REG by another and put the result in a destination FPU_REG.| | | - | Copyright (C) 1992,1993,1994 | + | Copyright (C) 1992,1993,1994,1995 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Australia. E-mail billm@jacobi.maths.monash.edu.au | | | | Call from C as: | | void reg_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest, | @@ -15,7 +15,7 @@ +---------------------------------------------------------------------------*/ #include "exception.h" -#include "fpu_asm.h" +#include "fpu_emu.h" .text diff --git a/arch/i386/math-emu/reg_norm.S b/arch/i386/math-emu/reg_norm.S index 6e30d46d0256..d2bd59cffd91 100644 --- a/arch/i386/math-emu/reg_norm.S +++ b/arch/i386/math-emu/reg_norm.S @@ -1,9 +1,9 @@ /*---------------------------------------------------------------------------+ | reg_norm.S | | | - | Copyright (C) 1992,1993,1994 | + | Copyright (C) 1992,1993,1994,1995 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Australia. E-mail billm@jacobi.maths.monash.edu.au | | | | Normalize the value in a FPU_REG. | | | @@ -14,7 +14,7 @@ | | +---------------------------------------------------------------------------*/ -#include "fpu_asm.h" +#include "fpu_emu.h" .text diff --git a/arch/i386/math-emu/reg_round.S b/arch/i386/math-emu/reg_round.S index 515636f37c09..2cbb26780fb1 100644 --- a/arch/i386/math-emu/reg_round.S +++ b/arch/i386/math-emu/reg_round.S @@ -4,9 +4,9 @@ | | | Rounding/truncation/etc for FPU basic arithmetic functions. | | | - | Copyright (C) 1993 | + | Copyright (C) 1993,1995 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Australia. E-mail billm@jacobi.maths.monash.edu.au | | | | This code has four possible entry points. | | The following must be entered by a jmp instruction: | @@ -69,7 +69,7 @@ +---------------------------------------------------------------------------*/ -#include "fpu_asm.h" +#include "fpu_emu.h" #include "exception.h" #include "control_w.h" diff --git a/arch/i386/math-emu/reg_u_add.S b/arch/i386/math-emu/reg_u_add.S index 36c6f86516a0..1dc0d41df659 100644 --- a/arch/i386/math-emu/reg_u_add.S +++ b/arch/i386/math-emu/reg_u_add.S @@ -5,9 +5,9 @@ | Add two valid (TW_Valid) FPU_REG numbers, of the same sign, and put the | | result in a destination FPU_REG. | | | - | Copyright (C) 1992,1993 | + | Copyright (C) 1992,1993,1995 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Australia. E-mail billm@jacobi.maths.monash.edu.au | | | | Call from C as: | | void reg_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, | @@ -25,7 +25,7 @@ */ #include "exception.h" -#include "fpu_asm.h" +#include "fpu_emu.h" #include "control_w.h" .text diff --git a/arch/i386/math-emu/reg_u_div.S b/arch/i386/math-emu/reg_u_div.S index a2d3738b64c9..5bba98dd807b 100644 --- a/arch/i386/math-emu/reg_u_div.S +++ b/arch/i386/math-emu/reg_u_div.S @@ -4,9 +4,9 @@ | | | Core division routines | | | - | Copyright (C) 1992,1993 | + | Copyright (C) 1992,1993,1995 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Australia. E-mail billm@jacobi.maths.monash.edu.au | | | | | +---------------------------------------------------------------------------*/ @@ -21,7 +21,7 @@ +---------------------------------------------------------------------------*/ #include "exception.h" -#include "fpu_asm.h" +#include "fpu_emu.h" #include "control_w.h" diff --git a/arch/i386/math-emu/reg_u_mul.S b/arch/i386/math-emu/reg_u_mul.S index d2d69ce5ef03..682fbec15748 100644 --- a/arch/i386/math-emu/reg_u_mul.S +++ b/arch/i386/math-emu/reg_u_mul.S @@ -4,9 +4,9 @@ | | | Core multiplication routine | | | - | Copyright (C) 1992,1993 | + | Copyright (C) 1992,1993,1995 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Australia. E-mail billm@jacobi.maths.monash.edu.au | | | | | +---------------------------------------------------------------------------*/ @@ -22,7 +22,7 @@ +---------------------------------------------------------------------------*/ #include "exception.h" -#include "fpu_asm.h" +#include "fpu_emu.h" #include "control_w.h" diff --git a/arch/i386/math-emu/reg_u_sub.S b/arch/i386/math-emu/reg_u_sub.S index 53a7768659e1..89167026002b 100644 --- a/arch/i386/math-emu/reg_u_sub.S +++ b/arch/i386/math-emu/reg_u_sub.S @@ -4,9 +4,9 @@ | | | Core floating point subtraction routine. | | | - | Copyright (C) 1992,1993 | + | Copyright (C) 1992,1993,1995 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Australia. E-mail billm@jacobi.maths.monash.edu.au | | | | Call from C as: | | void reg_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, | @@ -26,7 +26,7 @@ */ #include "exception.h" -#include "fpu_asm.h" +#include "fpu_emu.h" #include "control_w.h" .text diff --git a/arch/i386/math-emu/round_Xsig.S b/arch/i386/math-emu/round_Xsig.S index f2707719c452..bbe0e87718e4 100644 --- a/arch/i386/math-emu/round_Xsig.S +++ b/arch/i386/math-emu/round_Xsig.S @@ -1,9 +1,9 @@ /*---------------------------------------------------------------------------+ | round_Xsig.S | | | - | Copyright (C) 1992,1993,1994 | + | Copyright (C) 1992,1993,1994,1995 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Australia. E-mail billm@jacobi.maths.monash.edu.au | | | | Normalize and round a 12 byte quantity. | | Call from C as: | @@ -18,7 +18,7 @@ +---------------------------------------------------------------------------*/ .file "round_Xsig.S" -#include "fpu_asm.h" +#include "fpu_emu.h" .text diff --git a/arch/i386/math-emu/shr_Xsig.S b/arch/i386/math-emu/shr_Xsig.S index 1cd151cae77d..31cdd118e918 100644 --- a/arch/i386/math-emu/shr_Xsig.S +++ b/arch/i386/math-emu/shr_Xsig.S @@ -4,9 +4,9 @@ | | | 12 byte right shift function | | | - | Copyright (C) 1992,1994 | + | Copyright (C) 1992,1994,1995 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Australia. E-mail billm@jacobi.maths.monash.edu.au | | | | Call from C as: | | void shr_Xsig(Xsig *arg, unsigned nr) | @@ -18,7 +18,7 @@ | | +---------------------------------------------------------------------------*/ -#include "fpu_asm.h" +#include "fpu_emu.h" .text ENTRY(shr_Xsig) diff --git a/arch/i386/math-emu/wm_shrx.S b/arch/i386/math-emu/wm_shrx.S index 810ad9b77661..1ea7ff7da196 100644 --- a/arch/i386/math-emu/wm_shrx.S +++ b/arch/i386/math-emu/wm_shrx.S @@ -4,8 +4,9 @@ | | | 64 bit right shift functions | | | - | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Copyright (C) 1992,1995 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@jacobi.maths.monash.edu.au | | | | Call from C as: | | unsigned shrx(void *arg1, unsigned arg2) | @@ -14,7 +15,7 @@ | | +---------------------------------------------------------------------------*/ -#include "fpu_asm.h" +#include "fpu_emu.h" .text /*---------------------------------------------------------------------------+ diff --git a/arch/i386/math-emu/wm_sqrt.S b/arch/i386/math-emu/wm_sqrt.S index 898fafe1666a..848796188c15 100644 --- a/arch/i386/math-emu/wm_sqrt.S +++ b/arch/i386/math-emu/wm_sqrt.S @@ -4,9 +4,9 @@ | | | Fixed point arithmetic square root evaluation. | | | - | Copyright (C) 1992,1993 | + | Copyright (C) 1992,1993,1995 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Australia. E-mail billm@jacobi.maths.monash.edu.au | | | | Call from C as: | | void wm_sqrt(FPU_REG *n, unsigned int control_word) | @@ -26,7 +26,7 @@ +---------------------------------------------------------------------------*/ #include "exception.h" -#include "fpu_asm.h" +#include "fpu_emu.h" #ifndef NON_REENTRANT_FPU diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 7ffde05390ad..064942420e61 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -85,6 +85,13 @@ void flush_thread(void) */ } +void release_thread(struct task_struct *dead_task) +{ + /* + * Nothing to do + */ +} + #define IS_CLONE (regs->orig_reg2 == __NR_clone) void copy_thread(int nr, unsigned long clone_flags, struct task_struct * p, struct pt_regs * regs) diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c index 9dfa2f2158bd..4b69ecbe7247 100644 --- a/arch/sparc/kernel/process.c +++ b/arch/sparc/kernel/process.c @@ -72,6 +72,11 @@ void flush_thread(void) halt(); } +void release_thread(struct task_struct *dead_task) +{ + halt(); +} + extern void ret_sys_call(void); /* diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index 487a5406d797..63ef9c68f7b4 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -830,7 +830,7 @@ el16_rx(struct device *dev) ushort pkt_len = data_frame[0]; if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22 - || pkt_len & 0xC000 != 0xC000) { + || (pkt_len & 0xC000) != 0xC000) { printk("%s: Rx frame at %#x corrupted, status %04x cmd %04x" "next %04x data-buf @%04x %04x.\n", dev->name, rx_head, frame_status, rfd_cmd, next_rx_frame, data_buffer_addr, diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index 52c5e210c0b2..0ab4f3b71265 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -187,7 +187,7 @@ int at1700_probe1(struct device *dev, short ioaddr) #endif if (at1700_probe_list[inb(ioaddr + IOCONFIG) & 0x07] != ioaddr || read_eeprom(ioaddr, 4) != 0x0000 - || read_eeprom(ioaddr, 5) & 0xff00 != 0xF400) + || (read_eeprom(ioaddr, 5) & 0xff00) != 0xF400) return -ENODEV; /* Reset the internal state machines. */ diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index b5462ce4be54..177eb5c80081 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -923,7 +923,7 @@ eexp_rx(struct device *dev) pkt_len = inw(ioaddr); if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22 - || pkt_len & 0xC000 != 0xC000) { + || (pkt_len & 0xC000) != 0xC000) { printk("%s: Rx frame at %#x corrupted, status %04x cmd %04x" "next %04x data-buf @%04x %04x.\n", dev->name, rx_head, frame_status, rfd_cmd, next_rx_frame, data_buffer_addr, diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 86e3bfa1066f..ff2d6f05666d 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -417,7 +417,7 @@ ewrk3_hw_init(struct device *dev, short iobase) */ DISABLE_IRQs; - if (nicsr == TXD|RXD) { + if (nicsr == (TXD|RXD)) { /* ** Check that the EEPROM is alive and well and not living on Pluto... diff --git a/drivers/net/slhc.c b/drivers/net/slhc.c index 783b30ecfebf..d2241e122874 100644 --- a/drivers/net/slhc.c +++ b/drivers/net/slhc.c @@ -83,6 +83,10 @@ #include #include "slhc.h" +#ifdef __alpha__ +# include +#endif + int last_retran; static unsigned char *encode(unsigned char *cp, unsigned short n); @@ -621,7 +625,11 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) cp += (ip->ihl - 5) * 4; } +#ifdef __alpha__ + stw_u(ip_fast_csum(icp, ip->ihl), &((struct iphdr *)icp)->check); +#else ((struct iphdr *)icp)->check = ip_fast_csum(icp, ((struct iphdr*)icp)->ihl); +#endif memcpy(cp, thp, 20); cp += 20; diff --git a/drivers/net/znet.c b/drivers/net/znet.c index 492842c5c022..936b79f9bb88 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -448,7 +448,7 @@ static void znet_interrupt(int irq, struct pt_regs * regs) if (!(tx_status & 0x0040)) lp->stats.tx_heartbeat_errors++; if (tx_status & 0x0020) lp->stats.tx_aborted_errors++; /* ...and the catch-all. */ - if (tx_status | 0x0760 != 0x0760) + if ((tx_status | 0x0760) != 0x0760) lp->stats.tx_errors++; } dev->tbusy = 0; diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index 6927b84cc1fb..61466a09dfb7 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile @@ -8,7 +8,7 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := nfs.o -O_OBJS := proc.o sock.o inode.o file.o dir.o symlink.o mmap.o +O_OBJS := proc.o sock.o rpcsock.o inode.o file.o dir.o symlink.o mmap.o M_OBJS := $(O_TARGET) include $(TOPDIR)/Rules.make diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index b043455bbe85..92859293b29e 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -59,6 +59,7 @@ static void nfs_put_inode(struct inode * inode) void nfs_put_super(struct super_block *sb) { close_fp(sb->u.nfs_sb.s_server.file); + rpc_closesock(sb->u.nfs_sb.s_server.rsock); lock_super(sb); sb->s_dev = 0; unlock_super(sb); @@ -163,6 +164,12 @@ struct super_block *nfs_read_super(struct super_block *sb, void *raw_data, } /* End of JSP NFS patch */ + if ((server->rsock = rpc_makesock(filp)) == NULL) { + printk("NFS: cannot create RPC socket.\n"); + MOD_DEC_USE_COUNT; + return NULL; + } + sb->u.nfs_sb.s_root = data->root; unlock_super(sb); if (!(sb->s_mounted = nfs_fhget(sb, &data->root, NULL))) { diff --git a/fs/nfs/rpcsock.c b/fs/nfs/rpcsock.c new file mode 100644 index 000000000000..e5de461fcac0 --- /dev/null +++ b/fs/nfs/rpcsock.c @@ -0,0 +1,391 @@ +/* + * linux/fs/nfs/rpcsock.c + * + * This is a generic RPC call interface for datagram sockets that is able + * to place several concurrent RPC requests at the same time. It works like + * this: + * + * - When a process places a call, it allocates a request slot if + * one is available. Otherwise, it sleeps on the backlog queue. + * - The first process on the receive queue waits for the next RPC reply, + * and peeks at the XID. If it finds a matching request, it receives + * the datagram on behalf of that process and wakes it up. Otherwise, + * the datagram is discarded. + * - If the process having received the datagram was the first one on + * the receive queue, it wakes up the next one to listen for replies. + * - It then removes itself from the request queue. If there are more + * callers waiting on the backlog queue, they are woken up, too. + * + * Copyright (C) 1995, Olaf Kirch + */ + +#ifdef MODULE +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define msleep(sec) { current->timeout = sec * HZ / 1000; \ + current->state = TAKS_INTERRUPTIBLE; \ + schedule(); \ + } +#define dprintk if (0) printk + +static inline void +rpc_insque(struct rpc_sock *rsock, struct rpc_wait *slot) +{ + struct rpc_wait *tmp; + + if ((tmp = rsock->tail) != NULL) { + tmp->next = slot; + } else { + rsock->head = slot; + } + rsock->tail = slot; + slot->prev = tmp; + slot->next = NULL; + dprintk("RPC: inserted %08lx into queue.\n", (long)slot); + dprintk("RPC: head = %08lx, tail = %08lx.\n", + (long) rsock->head, (long) rsock->tail); +} + +static inline void +rpc_remque(struct rpc_sock *rsock, struct rpc_wait *slot) +{ + struct rpc_wait *prev = slot->prev, + *next = slot->next; + + if (prev != NULL) + prev->next = next; + else + rsock->head = next; + if (next != NULL) + next->prev = prev; + else + rsock->tail = prev; + dprintk("RPC: removed %08lx from queue.\n", (long)slot); + dprintk("RPC: head = %08lx, tail = %08lx.\n", + (long) rsock->head, (long) rsock->tail); +} + +static inline int +rpc_sendto(struct rpc_sock *rsock, const int *buf, int len, + struct sockaddr *sap, int salen) +{ + struct socket *sock = rsock->sock; + unsigned long oldfs; + int result; + + dprintk("RPC: sending %d bytes (buf %08lx)\n", len, (long) buf); + oldfs = get_fs(); + set_fs(get_ds()); + result = sock->ops->sendto(sock, buf, len, 0, 0, sap, salen); + set_fs(oldfs); + dprintk("RPC: result = %d\n", result); + + return result; +} + +/* + * This code is slightly complicated. Since the networking code does not + * honor the current->timeout value, we have to select on the socket. + */ +static inline int +rpc_select(struct rpc_sock *rsock) +{ + struct select_table_entry entry; + struct file *file = rsock->file; + select_table wait_table; + + dprintk("RPC: selecting on socket...\n"); + wait_table.nr = 0; + wait_table.entry = &entry; + current->state = TASK_INTERRUPTIBLE; + if (!file->f_op->select(file->f_inode, file, SEL_IN, &wait_table) + && !file->f_op->select(file->f_inode, file, SEL_IN, NULL)) { + schedule(); + remove_wait_queue(entry.wait_address, &entry.wait); + current->state = TASK_RUNNING; + if (current->signal & ~current->blocked) + return -ERESTARTSYS; + if (current->timeout == 0) + return -ETIMEDOUT; + } else if (wait_table.nr) + remove_wait_queue(entry.wait_address, &entry.wait); + current->state = TASK_RUNNING; + dprintk("RPC: ...Okay, there appears to be some data.\n"); + return 0; +} + +static inline int +rpc_recvfrom(struct rpc_sock *rsock, int *buf, int len, + struct sockaddr *sap, int salen, int flags) +{ + struct socket *sock = rsock->sock; + struct sockaddr sa; + int alen = sizeof(sa); + unsigned long oldfs; + int result; + + dprintk("RPC: receiving %d bytes max (buf %08lx)\n", len, (long) buf); + oldfs = get_fs(); + set_fs(get_ds()); + result = sock->ops->recvfrom(sock, buf, len, 1, flags, &sa, &alen); + set_fs(oldfs); + dprintk("RPC: result = %d\n", result); + +#if 0 + if (alen != salen || memcmp(&sa, sap, alen)) { + dprintk("RPC: reply address mismatch... rejected.\n"); + result = -EAGAIN; + } +#endif + + return result; +} + +/* + * Place the actual RPC call. + */ +static int +rpc_call_one(struct rpc_sock *rsock, struct rpc_wait *slot, + struct sockaddr *sap, int salen, + const int *sndbuf, int slen, int *rcvbuf, int rlen) +{ + struct rpc_wait *rovr = NULL; + int result; + u32 xid; + int safe; + + dprintk("RPC: placing one call, rsock = %08lx, slot = %08lx, " + "sap = %08lx, salen = %d, " + "sndbuf = %08lx, slen = %d, rcvbuf = %08lx, rlen = %d\n", + (long) rsock, (long) slot, (long) sap, + salen, (long) sndbuf, slen, (long) rcvbuf, rlen); + + result = rpc_sendto(rsock, sndbuf, slen, sap, salen); + if (result < 0) + return result; + + do { + /* We are not the receiver. Wait on the side lines. */ + if (rsock->head != slot) { + slot->wait = NULL; + interruptible_sleep_on(&slot->wait); + if (slot->gotit) + break; + if (current->timeout != 0) + continue; + if (rsock->shutdown) { + printk("RPC: aborting call due to shutdown.\n"); + return -EIO; + } + return -ETIMEDOUT; + } + + /* wait for data to arrive */ + result = rpc_select(rsock); + if (result < 0) { + dprintk("RPC: select error = %d\n", result); + break; + } + + result = rpc_recvfrom(rsock, (int *)&xid, sizeof(xid), + sap, salen, MSG_PEEK); + if (result < 0) { + switch (-result) { + case EAGAIN: case ECONNREFUSED: + continue; + default: + dprintk("rpc_call: recv error = %d\n", result); + case ERESTARTSYS: + return result; + } + } + + /* Look for the caller */ + safe = 0; + for (rovr = rsock->head; rovr; rovr = rovr->next) { + if (safe++ > NRREQS) { + printk("RPC: loop in request Q!!\n"); + rovr = NULL; + break; + } + if (rovr->xid == xid) + break; + } + + if (!rovr || rovr->gotit) { + /* bad XID or duplicate reply, discard dgram */ + dprintk("RPC: bad XID or duplicate reply.\n"); + rpc_recvfrom(rsock, (int *)&xid, sizeof(xid), + sap, salen, 0); + continue; + } + rovr->gotit = 1; + + /* Now receive the reply */ + result = rpc_recvfrom(rsock, rovr->buf, rovr->len, + sap, salen, 0); + + /* If this is not for ourselves, wake up the caller */ + if (rovr != slot) + wake_up(&rovr->wait); + } while (rovr != slot); + + /* This is somewhat tricky. We rely on the fact that we are able to + * remove ourselves from the queues before the next reader is scheduled, + * otherwise it would find that we're still at the head of the queue + * and go to sleep again. + */ + if (rsock->head == slot && slot->next != NULL) + wake_up(&slot->next->wait); + + return result; +} + +/* + * Generic RPC call routine. This handles retries and timeouts etc pp + */ +int +rpc_call(struct rpc_sock *rsock, struct sockaddr *sap, int addrlen, + const int *sndbuf, int slen, int *rcvbuf, int rlen, + struct rpc_timeout *strategy, int flag) +{ + struct rpc_wait *slot; + int result, retries; + unsigned long timeout; + + timeout = strategy->init_timeout; + retries = 0; + slot = NULL; + + do { + dprintk("RPC call TP1\n"); + current->timeout = jiffies + timeout; + if (slot == NULL) { + while ((slot = rsock->free) == NULL) { + if (!flag) { + current->timeout = 0; + return -ENOBUFS; + } + interruptible_sleep_on(&rsock->backlog); + if (current->timeout == 0) { + result = -ETIMEDOUT; + goto timedout; + } + if (rsock->shutdown) { + printk("RPC: aborting call due to shutdown.\n"); + current->timeout = 0; + return -EIO; + } + } + dprintk("RPC call TP2\n"); + slot->gotit = 0; + slot->xid = *(u32 *)sndbuf; + slot->buf = rcvbuf; + slot->len = rlen; + rsock->free = slot->next; + rpc_insque(rsock, slot); + } + + dprintk("RPC call TP3\n"); + result = rpc_call_one(rsock, slot, sap, addrlen, + sndbuf, slen, rcvbuf, rlen); + if (result != -ETIMEDOUT) + break; + +timedout: + dprintk("RPC call TP4\n"); + dprintk("RPC: rpc_call_one returned timeout.\n"); + if (strategy->exponential) + timeout <<= 1; + else + timeout += strategy->increment; + if (strategy->max_timeout && timeout >= strategy->max_timeout) + timeout = strategy->max_timeout; + if (strategy->retries && ++retries >= strategy->retries) + break; + } while (1); + + dprintk("RPC call TP5\n"); + current->timeout = 0; + if (slot != NULL) { + dprintk("RPC call TP6\n"); + rpc_remque(rsock, slot); + slot->next = rsock->free; + rsock->free = slot; + + /* wake up tasks that haven't sent anything yet. (Waking + * up the first one the wait queue would be enough) */ + if (rsock->backlog) + wake_up(&rsock->backlog); + } + + if (rsock->shutdown) + wake_up(&rsock->shutwait); + + return result; +} + +struct rpc_sock * +rpc_makesock(struct file *file) +{ + struct rpc_sock *rsock; + struct rpc_wait *slot; + int i; + + dprintk("RPC: make RPC socket...\n"); + if ((rsock = kmalloc(sizeof(struct rpc_sock), GFP_KERNEL)) == NULL) + return NULL; + + rsock->sock = &file->f_inode->u.socket_i; + rsock->file = file; + + rsock->free = rsock->waiting; + for (i = 0, slot = rsock->waiting; i < NRREQS-1; i++, slot++) + slot->next = slot + 1; + slot->next = NULL; + + rsock->backlog = NULL; + rsock->head = rsock->tail = NULL; + + rsock->shutwait = NULL; + rsock->shutdown = 0; + + dprintk("RPC: made socket %08lx", (long) rsock); + return rsock; +} + +int +rpc_closesock(struct rpc_sock *rsock) +{ + unsigned long t0 = jiffies; + + rsock->shutdown = 1; + while (rsock->head) { + interruptible_sleep_on(&rsock->shutwait); + if (current->signal & ~current->blocked) + return -EINTR; +#if 1 + if (t0 && t0 - jiffies > 60 * HZ) { + printk("RPC: hanging in rpc_closesock.\n"); + t0 = 0; + } +#endif + } + + kfree(rsock); + return 0; +} diff --git a/fs/nfs/sock.c b/fs/nfs/sock.c index 6b9f13c92858..dcb82d9dfef7 100644 --- a/fs/nfs/sock.c +++ b/fs/nfs/sock.c @@ -31,6 +31,7 @@ #include #include #include +#include /* JEJB/JSP 2/7/94 * this must match the value of NFS_SLACK_SPACE in linux/fs/nfs/proc.c @@ -49,197 +50,64 @@ * to the server socket. */ -static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end, int size) +int +nfs_rpc_call(struct nfs_server *server, int *start, int *end, int size) { - struct file *file; - struct inode *inode; - struct socket *sock; - unsigned short fs; - int result; - int xid; - int len; - select_table wait_table; - struct select_table_entry entry; - int (*select) (struct inode *, struct file *, int, select_table *); - int init_timeout, max_timeout; - int timeout; - int retrans; - int major_timeout_seen; - char *server_name; - int n; - int addrlen; - unsigned long old_mask; - /* JEJB/JSP 2/7/94 - * This is for a 4 byte recv of the xid only */ - int recv_xid; + struct rpc_timeout timeout; + unsigned long maxtimeo; + unsigned long oldmask; + int major_timeout_seen, result; - xid = start[0]; - len = ((char *) end) - ((char *) start); - file = server->file; - inode = file->f_inode; - select = file->f_op->select; - sock = &inode->u.socket_i; - if (!sock) { - printk("nfs_rpc_call: socki_lookup failed\n"); - return -EBADF; - } - init_timeout = server->timeo; - max_timeout = NFS_MAX_RPC_TIMEOUT*HZ/10; - retrans = server->retrans; - major_timeout_seen = 0; - server_name = server->hostname; - old_mask = current->blocked; + timeout.init_timeout = server->timeo; + timeout.max_timeout = maxtimeo = NFS_MAX_RPC_TIMEOUT*HZ/10; + timeout.retries = server->retrans; + timeout.exponential = 1; + + oldmask = current->blocked; current->blocked |= ~(_S(SIGKILL) -#if 0 - | _S(SIGSTOP) -#endif | ((server->flags & NFS_MOUNT_INTR) ? ((current->sig->action[SIGINT - 1].sa_handler == SIG_DFL ? _S(SIGINT) : 0) | (current->sig->action[SIGQUIT - 1].sa_handler == SIG_DFL ? _S(SIGQUIT) : 0)) : 0)); - fs = get_fs(); - set_fs(get_ds()); - for (n = 0, timeout = init_timeout; ; n++, timeout <<= 1) { - /* JSP 1995-07-01 Use sendto() not send() to cope with multi-homed hosts - as we have set the socket to have INADDR_ANY as it's desination */ - result = sock->ops->sendto(sock, (void *) start, len, 0, 0, - &(server->toaddr), sizeof((server->toaddr))) ; - if (result < 0) { - printk("nfs_rpc_call: send error = %d\n", result); - break; - } - re_select: - wait_table.nr = 0; - wait_table.entry = &entry; - current->state = TASK_INTERRUPTIBLE; - if (!select(inode, file, SEL_IN, &wait_table) - && !select(inode, file, SEL_IN, NULL)) { - if (timeout > max_timeout) { - /* JEJB/JSP 2/7/94 - * This is useful to see if the system is - * hanging */ - printk("NFS max timeout reached on %s\n", - server_name); - timeout = max_timeout; - } - current->timeout = jiffies + timeout; - schedule(); - remove_wait_queue(entry.wait_address, &entry.wait); - current->state = TASK_RUNNING; - if (current->signal & ~current->blocked) { - current->timeout = 0; - result = -ERESTARTSYS; + major_timeout_seen = 0; + + do { + result = rpc_call(server->rsock, + &server->toaddr, sizeof(server->toaddr), + start, ((char *) end) - ((char *) start), + start, size + 1024, + &timeout, 1); + if (current->signal & ~current->blocked) + result = -ERESTARTSYS; + if (result == -ETIMEDOUT) { + if (server->flags & NFS_MOUNT_SOFT) { + printk("NFS server %s not responding, " + "still trying.\n", server->hostname); + result = -EIO; break; } - if (!current->timeout) { - if (n < retrans) - continue; - if (server->flags & NFS_MOUNT_SOFT) { - printk("NFS server %s not responding, " - "timed out\n", server_name); - result = -EIO; - break; - } - n = 0; - timeout = init_timeout; - init_timeout <<= 1; - if (!major_timeout_seen) { - printk("NFS server %s not responding, " - "still trying\n", server_name); - } + if (!major_timeout_seen) { + printk("NFS server %s not responding, " + "timed out.\n", server->hostname); major_timeout_seen = 1; - continue; - } - else - current->timeout = 0; - } - else if (wait_table.nr) - remove_wait_queue(entry.wait_address, &entry.wait); - current->state = TASK_RUNNING; - addrlen = 0; - /* JEJB/JSP 2/7/94 - * Get the xid from the next packet using a peek, so keep it - * on the recv queue. If it is wrong, it will be some reply - * we don't now need, so discard it */ - result = sock->ops->recvfrom(sock, (void *)&recv_xid, - sizeof(recv_xid), 1, MSG_PEEK, - NULL, &addrlen); - if (result < 0) { - if (result == -EAGAIN) { -#if 0 - printk("nfs_rpc_call: bad select ready\n"); -#endif - goto re_select; - } - if (result == -ECONNREFUSED) { -#if 0 - printk("nfs_rpc_call: server playing coy\n"); -#endif - goto re_select; } - if (result != -ERESTARTSYS) { - printk("nfs_rpc_call: recv error = %d\n", - -result); - } - break; - } - if (recv_xid == xid) { - if (major_timeout_seen) - printk("NFS server %s OK\n", server_name); - break; + if ((timeout.init_timeout <<= 1) >= maxtimeo) + timeout.init_timeout = maxtimeo; + } else if (result < 0) { + printk("NFS: notice message: result = %d.\n", result); } - /* JEJB/JSP 2/7/94 - * we have xid mismatch, so discard the packet and start - * again. What a hack! but I can't call recvfrom with - * a null buffer yet. */ - (void)sock->ops->recvfrom(sock, (void *)&recv_xid, - sizeof(recv_xid), 1, 0, NULL, - &addrlen); -#if 0 - printk("nfs_rpc_call: XID mismatch\n"); -#endif - goto re_select; - } - /* JEJB/JSP 2/7/94 - * - * we have the correct xid, so read into the correct place and - * return it - * - */ - result=sock->ops->recvfrom(sock, (void *)start, - size + 1024, 1, 0, NULL, - /* Here is NFS_SLACK_SPACE..., hack */ - &addrlen); - if (result < 0) { - printk("NFS: notice message: result=%d\n", result); - } else if (result < addrlen) { - printk("NFS: just caught a too small read memory size..., email to NET channel\n"); - printk("NFS: result=%d,addrlen=%d\n", result, addrlen); + } while (result == -ETIMEDOUT && !(server->flags & NFS_MOUNT_SOFT)); + + if (result >= 0 && major_timeout_seen) + printk("NFS server %s OK.\n", server->hostname); + /* 20 is the minimum RPC reply header size */ + if (result >= 0 && result < 20) { + printk("NFS: too small read memory size (%d bytes)\n", result); result = -EIO; } - current->blocked = old_mask; - set_fs(fs); - return result; -} -/* - * For now we lock out other simultaneous nfs calls for the same filesystem - * because we are single-threaded and don't want to get mismatched - * RPC replies. - */ - -int nfs_rpc_call(struct nfs_server *server, int *start, int *end, int size) -{ - int result; - - while (server->lock) - sleep_on(&server->wait); - server->lock = 1; - result = do_nfs_rpc_call(server, start, end, size); - server->lock = 0; - wake_up(&server->wait); + current->blocked = oldmask; return result; } - diff --git a/include/asm-alpha/apecs.h b/include/asm-alpha/apecs.h index 451c8b6aa35a..1eddab64d22f 100644 --- a/include/asm-alpha/apecs.h +++ b/include/asm-alpha/apecs.h @@ -351,17 +351,8 @@ extern unsigned long apecs_init (unsigned long mem_start, #endif /* __KERNEL__ */ /* - * data structures for handling APECS machine checks + * Data structure for handling APECS machine checks: */ - -struct el_common_logout_header { - u_int elfl_size; /* size in bytes of logout area. */ - int elfl_sbz1:31; /* Should be zero. */ - char elfl_retry:1; /* Retry flag. */ - u_int elfl_procoffset; /* Processor-specific offset. */ - u_int elfl_sysoffset; /* Offset of system-specific. */ -}; - struct el_apecs_sysdata_mcheck { u_long coma_gcr; u_long coma_edsr; diff --git a/include/asm-alpha/lca.h b/include/asm-alpha/lca.h index db313b470da6..eeb3059cd180 100644 --- a/include/asm-alpha/lca.h +++ b/include/asm-alpha/lca.h @@ -52,6 +52,8 @@ * ugh). */ +#include + #define LCA_DMA_WIN_BASE (1024*1024*1024) #define LCA_DMA_WIN_SIZE (1024*1024*1024) @@ -324,6 +326,45 @@ extern unsigned long lca_init (unsigned long mem_start, unsigned long mem_end); #endif /* __KERNEL__ */ +/* + * Data structure for handling LCA machine checks. Correctable errors + * result in a short logout frame, uncorrectably ones in a long one. + */ +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 */ + unsigned long ioc_stat0; /* I/O controller status register 0 */ + unsigned long ioc_stat1; /* I/O controller status register 1 */ +}; + +struct el_lca_mcheck_long { + struct el_common h; /* common logout header */ + unsigned long pt[32]; /* PAL temps (pt[0] is reason) */ + unsigned long exc_addr; /* exception address */ + unsigned long pal_base; /* PALcode base address */ + unsigned long hier; /* hw interrupt enable */ + unsigned long hirr; /* hw interrupt request */ + unsigned long mm_csr; /* MMU control & status */ + unsigned long dc_stat; /* data cache status */ + unsigned long dc_addr; /* data cache addr register */ + unsigned long abox_ctl; /* address box control register */ + unsigned long esr; /* error status register */ + unsigned long ear; /* error address register */ + unsigned long car; /* cache control register */ + unsigned long ioc_stat0; /* I/O controller status register 0 */ + unsigned long ioc_stat1; /* I/O controller status register 1 */ + unsigned long va; /* virtual address register */ +}; + +union el_lca { + struct el_common * c; + struct el_lca_mcheck_long * l; + struct el_lca_mcheck_short * s; +}; + #define RTC_PORT(x) (0x70 + (x)) #define RTC_ADDR(x) (0x80 | (x)) #define RTC_ALWAYS_BCD 0 diff --git a/include/asm-alpha/system.h b/include/asm-alpha/system.h index 2d2c90397e6b..c053add9d2d3 100644 --- a/include/asm-alpha/system.h +++ b/include/asm-alpha/system.h @@ -31,6 +31,18 @@ #ifndef __ASSEMBLY__ +/* + * This is the logout header that should be common to all platforms + * (assuming they are running OSF/1 PALcode, I guess). + */ +struct el_common { + unsigned int size; /* size in bytes of logout area */ + int sbz1 : 31; /* should be zero */ + char retry : 1; /* retry flag */ + unsigned int proc_offset; /* processor-specific offset */ + unsigned int sys_offset; /* system-specific offset */ +}; + extern void wrent(void *, unsigned long); extern void wrkgp(unsigned long); extern void wrusp(unsigned long); diff --git a/include/asm-i386/byteorder.h b/include/asm-i386/byteorder.h index a6ff714f4620..4364339c99ad 100644 --- a/include/asm-i386/byteorder.h +++ b/include/asm-i386/byteorder.h @@ -19,10 +19,10 @@ extern unsigned short int ntohs(unsigned short int); extern unsigned long int htonl(unsigned long int); extern unsigned short int htons(unsigned short int); -extern unsigned long int __ntohl(unsigned long int); -extern unsigned short int __ntohs(unsigned short int); -extern unsigned long int __constant_ntohl(unsigned long int); -extern unsigned short int __constant_ntohs(unsigned short int); +extern __inline__ unsigned long int __ntohl(unsigned long int); +extern __inline__ unsigned short int __ntohs(unsigned short int); +extern __inline__ unsigned long int __constant_ntohl(unsigned long int); +extern __inline__ unsigned short int __constant_ntohs(unsigned short int); extern __inline__ unsigned long int __ntohl(unsigned long int x) diff --git a/include/asm-i386/ioctl.h b/include/asm-i386/ioctl.h index 8068397542d3..caeb531ca4a9 100644 --- a/include/asm-i386/ioctl.h +++ b/include/asm-i386/ioctl.h @@ -82,6 +82,7 @@ /* used to decode ioctl numbers.. */ #define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) +#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK) #define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK) #define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK) diff --git a/include/linux/if_eql.h b/include/linux/if_eql.h index 5a03f21c86bd..3883c75951c5 100644 --- a/include/linux/if_eql.h +++ b/include/linux/if_eql.h @@ -19,6 +19,8 @@ #ifndef _LINUX_IF_EQL_H #define _LINUX_IF_EQL_H +#include + #define EQL_DEFAULT_SLAVE_PRIORITY 28800 #define EQL_DEFAULT_MAX_SLAVES 4 #define EQL_DEFAULT_MTU 576 diff --git a/include/linux/mtio.h b/include/linux/mtio.h index bdfefd904074..0934945b3043 100644 --- a/include/linux/mtio.h +++ b/include/linux/mtio.h @@ -140,6 +140,35 @@ struct mtpos { }; +/* structure for MTIOCGETCONFIG/MTIOCSETCONFIG primarily intended + * as an interim solution for QIC-02 until DDI is fully implemented. + */ +struct mtconfiginfo { + long mt_type; /* drive type */ + long ifc_type; /* interface card type */ + unsigned short irqnr; /* IRQ number to use */ + unsigned short dmanr; /* DMA channel to use */ + unsigned short port; /* IO port base address */ + + unsigned long debug; /* debugging flags */ + + unsigned have_dens:1; + unsigned have_bsf:1; + unsigned have_fsr:1; + unsigned have_bsr:1; + unsigned have_eod:1; + unsigned have_seek:1; + unsigned have_tell:1; + unsigned have_ras1:1; + unsigned have_ras2:1; + unsigned have_ras3:1; + unsigned have_qfa:1; + + unsigned pad1:5; + char reserved[10]; +}; + + /* mag tape io control commands */ #define MTIOCTOP _IOW('m', 1, struct mtop) /* do a mag tape op */ #define MTIOCGET _IOR('m', 2, struct mtget) /* get tape status */ diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index c7f74bbd105b..bfdba35b45d6 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -1,10 +1,12 @@ #ifndef _NFS_FS_SB #define _NFS_FS_SB +#include #include struct nfs_server { struct file *file; + struct rpc_sock *rsock; struct sockaddr toaddr ; /* Added for change to NFS code to use sendto() 1995-06-02 JSP */ int lock; struct wait_queue *wait; diff --git a/include/linux/resource.h b/include/linux/resource.h index ebbbcfa4e757..e6f62ea8d566 100644 --- a/include/linux/resource.h +++ b/include/linux/resource.h @@ -1,6 +1,8 @@ #ifndef _LINUX_RESOURCE_H #define _LINUX_RESOURCE_H +#include + /* * Resource control/accounting header file for linux */ diff --git a/include/linux/rpcsock.h b/include/linux/rpcsock.h new file mode 100644 index 000000000000..d5a697681f4e --- /dev/null +++ b/include/linux/rpcsock.h @@ -0,0 +1,57 @@ +/* + * rpcsock.h Declarations for the RPC call interface. + * + * Coypright (C) 1995 Olaf Kirch + * + */ + + +#ifndef _LINUX_RPCSOCK_H +#define _LINUX_RPCSOCK_H + +/* Maximum number of outstanding RPCs per socket. + * With 32 slots, IP fragment reassembly would frequently + * fail due to low memory. + */ +#define NRREQS 16 + +/* This describes a timeout strategy */ +struct rpc_timeout { + unsigned long init_timeout, + max_timeout, + increment; + int retries; + char exponential; +}; + +/* Wait information */ +struct rpc_wait { + struct rpc_wait *prev, *next; + struct wait_queue *wait; + int *buf; + int len; + char gotit; + u32 xid; +}; + +struct rpc_sock { + struct file *file; + struct socket *sock; + struct rpc_wait waiting[NRREQS]; + struct rpc_wait *head, *tail, *free; + struct wait_queue *backlog; + struct wait_queue *shutwait; + int shutdown; +}; + +#ifdef __KERNEL__ + +int rpc_call(struct rpc_sock *, struct sockaddr *, int, + const int *, int, int *, int, + struct rpc_timeout *, int); +struct rpc_sock * rpc_makesock(struct file *); +int rpc_closesock(struct rpc_sock *); + +#endif /* __KERNEL__*/ + +#endif /* _LINUX_RPCSOCK_H */ diff --git a/include/linux/sched.h b/include/linux/sched.h index df82748fe3fb..66a9daf7afac 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -325,6 +325,7 @@ extern void exit_thread(void); extern void exit_fs(struct task_struct *); extern void exit_files(struct task_struct *); extern void exit_sighand(struct task_struct *); +extern void release_thread(struct task_struct *); extern int do_execve(char *, char **, char **, struct pt_regs *); extern int do_fork(unsigned long, unsigned long, struct pt_regs *); diff --git a/include/linux/serial.h b/include/linux/serial.h index 8a9dd9bf08c1..68fcfe6d64ae 100644 --- a/include/linux/serial.h +++ b/include/linux/serial.h @@ -107,6 +107,9 @@ struct serial_multiport_struct { * For definitions of the flags field, see tty.h */ +#include +#include + struct async_struct { int magic; int baud_base; diff --git a/include/linux/tpqic02.h b/include/linux/tpqic02.h index 8a824f7d0454..795b6d7bc326 100644 --- a/include/linux/tpqic02.h +++ b/include/linux/tpqic02.h @@ -628,34 +628,6 @@ typedef char flag; #define BLOCKS_BEYOND_EW 2 /* nr of blocks after Early Warning hole */ #define BOGUS_IRQ 32009 -/* structure for MTIOCGETCONFIG/MTIOCSETCONFIG primarily intended - * as an interim solution for QIC-02 until DDI is fully implemented. - */ -struct mtconfiginfo { - long mt_type; /* drive type */ - long ifc_type; /* interface card type */ - unsigned short irqnr; /* IRQ number to use */ - unsigned short dmanr; /* DMA channel to use */ - unsigned short port; /* IO port base address */ - - unsigned long debug; /* debugging flags */ - - unsigned have_dens:1; - unsigned have_bsf:1; - unsigned have_fsr:1; - unsigned have_bsr:1; - unsigned have_eod:1; - unsigned have_seek:1; - unsigned have_tell:1; - unsigned have_ras1:1; - unsigned have_ras2:1; - unsigned have_ras3:1; - unsigned have_qfa:1; - - unsigned pad1:5; - char reserved[10]; -}; - /* This is internal data, filled in based on the ifc_type field given * by the user. Everex is mapped to Wangtek with a different diff --git a/kernel/exit.c b/kernel/exit.c index 60721b34a45f..471179108c3a 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -94,6 +94,7 @@ void release(struct task_struct * p) nr_tasks--; task[i] = NULL; REMOVE_LINKS(p); + release_thread(p); if (STACK_MAGIC != *(unsigned long *)p->kernel_stack_page) printk(KERN_ALERT "release: %s kernel stack corruption. Aiee\n", p->comm); free_page(p->kernel_stack_page); diff --git a/net/ipv4/ip.c b/net/ipv4/ip.c index e0d196358de7..6015e6e672cc 100644 --- a/net/ipv4/ip.c +++ b/net/ipv4/ip.c @@ -1527,12 +1527,12 @@ int ip_forward(struct sk_buff *skb, struct device *dev, int is_frag, unsigned char *ptr; /* Data pointer */ unsigned long raddr; /* Router IP address */ struct options * opt = (struct options*)skb->proto_priv; + int encap = 0; /* Encap length */ #ifdef CONFIG_IP_FIREWALL int fw_res = 0; /* Forwarding result */ #ifdef CONFIG_IP_MASQUERADE struct sk_buff *skb_in = skb; /* So we can remember if the masquerader did some swaps */ #endif - int encap = 0; /* Encap length */ /* * See if we are allowed to forward this. diff --git a/scripts/ksymoops.cc b/scripts/ksymoops.cc index 53bac39d589f..9b2fe39c6f6e 100644 --- a/scripts/ksymoops.cc +++ b/scripts/ksymoops.cc @@ -1,31 +1,47 @@ -/* ksymoops.c -- simple Linux Oops-log symbol resolver - Copyright (C) 1995 Greg McGary - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* This is a simple filter to resolve EIP and call-trace symbols from - a Linux kernel "Oops" log. Supply the symbol-map file name as a - command-line argument, and redirect the oops-log into stdin. - Out will come the EIP and call-trace in symbolic form. */ +// ksymoops.cc v1.7 -- A simple filter to resolve symbols in Linux Oops-logs +// Copyright (C) 1995 Greg McGary +// compile like so: g++ -o ksymoops ksymoops.cc -liostream + +////////////////////////////////////////////////////////////////////////////// + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; see the file COPYING. If not, write to the +// Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +// This is a simple filter to resolve EIP and call-trace symbols from +// a Linux kernel "Oops" log. Supply the symbol-map file name as a +// command-line argument, and redirect the oops-log into stdin. Out +// will come the EIP and call-trace in symbolic form. + +////////////////////////////////////////////////////////////////////////////// + +// BUGS: +// * Doesn't deal with line-prefixes prepended by syslog--strip +// these off first, before submitting to ksymoops. +// * Only resolves operands of jump and call instructions. #include +#include +#include #include #include +#include +#include inline int strequ(char const* x, char const* y) { return (::strcmp(x, y) == 0); } +inline int strnequ(char const* x, char const* y, size_t n) { return (::strncmp(x, y, n) == 0); } + +const int code_size = 20; ////////////////////////////////////////////////////////////////////////////// @@ -35,37 +51,41 @@ class KSym private: long address_; - char type_; char* name_; long offset_; long extent_; - public: + private: + istream& scan(istream&); + ostream& print(ostream&) const; void set_extent(KSym const& next_ksym) { extent_ = next_ksym.address_ - address_; } - friend istream& operator >> (istream&, KSym&); - friend ostream& operator << (ostream&, const KSym&); + + public: + friend istream& operator >> (istream& is, KSym& k) { return k.scan(is); } + friend ostream& operator << (ostream& os, const KSym& k) { return k.print(os); } }; istream& -operator >> (istream& is, KSym& n) +KSym::scan(istream& is) { - is >> hex >> n.address_; - is >> n.type_; + is >> ::hex >> address_; + char type; + is >> type; char name[128]; is >> name; - n.name_ = new char [strlen(name)+1]; - strcpy(n.name_, name); - n.offset_ = 0; + name_ = new char [strlen(name)+1]; + strcpy(name_, name); + offset_ = 0; return is; } ostream& -operator << (ostream& os, const KSym& n) +KSym::print(ostream& os) const { - os << hex << n.address_ + n.offset_ << ' ' << n.type_ << ' ' << n.name_; - if (n.offset_) - os << '+' << hex << n.offset_ << '/' << hex << n.extent_; - return os; + os << ::hex << address_ + offset_ << ' ' << '<' << name_; + if (offset_) + os << '+' << ::hex << offset_ << '/' << ::hex << extent_; + return os << '>'; } ////////////////////////////////////////////////////////////////////////////// @@ -81,20 +101,30 @@ class NameList public: NameList() : cardinality_(0) { } + private: + istream& scan(istream&); + public: + int valid() { return (cardinality_ > 0); } + KSym* find(long address); + void decode(unsigned char* code, long eip_addr); public: - friend istream& operator >> (istream&, NameList&); + friend istream& operator >> (istream& is, NameList& n) { return n.scan(is); } }; KSym* NameList::find(long address) { + if (!valid()) + return 0; KSym* start = ksyms_0_; - KSym* end = &ksyms_0_[cardinality_]; - KSym* mid; + KSym* end = &ksyms_0_[cardinality_ - 1]; + if (address < start->address_ || address >= end->address_) + return 0; + KSym* mid; while (start <= end) { mid = &start[(end - start) / 2]; if (mid->address_ < address) @@ -112,18 +142,101 @@ NameList::find(long address) return mid; } +void +NameList::decode(unsigned char* code, long eip_addr) +{ + /* This is a hack to avoid using gcc. We create an object file by + concatenating objfile_head, the twenty bytes of code, and + objfile_tail. */ + unsigned char objfile_head[] = { + 0x07, 0x01, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + unsigned char objfile_tail[] = { + 0x00, 0x90, 0x90, 0x90, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x25, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, + 'g', 'c', 'c', '2', '_', 'c', 'o', 'm', + 'p', 'i', 'l', 'e', 'd', '.', '\0', '_', + 'E', 'I', 'P', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0' + }; + char const* objdump_command = "objdump -d oops_decode.o"; + char const* objfile_name = &objdump_command[11]; + ofstream objfile_stream(objfile_name); + + objfile_stream.write(objfile_head, sizeof(objfile_head)); + objfile_stream.write(code, code_size); + objfile_stream.write(objfile_tail, sizeof(objfile_tail)); + objfile_stream.close(); + + FILE* objdump_FILE = popen(objdump_command, "r"); + if (objdump_FILE == 0) { + clog << "Sorry, without " << objdump_command << ", I can't disassemble the `Code' section." << endl; + return; + } + + char buf[1024]; + int lines = 0; + while (fgets(buf, sizeof(buf), objdump_FILE)) { + if (!strnequ(&buf[9], "<_EIP", 5)) + continue; + if (strstr(buf, " is out of bounds")) + break; + lines++; + cout << "Code: "; + if (!valid()) { + cout << buf; + continue; + } + long offset = strtol(buf, 0, 16); + char* bp_0 = strchr(buf, '>') + 2; + KSym* ksym = find(eip_addr + offset); + if (ksym) + cout << *ksym << ' '; + char* bp = bp_0; + while (!isspace(*bp)) + bp++; + while (isspace(*bp)) + bp++; + if (*bp != '0') { + cout << bp_0; + } else if (*bp_0 == 'j' || strnequ(bp_0, "call", 4)) { // a jump or call insn + long rel_addr = strtol(bp, 0, 16); + ksym = find(eip_addr + rel_addr); + if (ksym) { + *bp++ = '\0'; + cout << bp_0 << *ksym << endl; + } else + cout << bp_0; + } else { + cout << bp_0; + } + } + if (!lines) + clog << "Sorry, your " << objdump_command << " can't disassemble--you must upgrade your binutils." << endl; + pclose(objdump_FILE); + unlink(objfile_name); +} + istream& -operator >> (istream& is, NameList& n) +NameList::scan(istream& is) { - KSym* ksyms = n.ksyms_0_; + KSym* ksyms = ksyms_0_; int cardinality = 0; while (!is.eof()) { is >> *ksyms; - ksyms[-1].set_extent(*ksyms); + if (cardinality++ > 0) + ksyms[-1].set_extent(*ksyms); ksyms++; - cardinality++; } - n.cardinality_ = --cardinality; + cardinality_ = --cardinality; return is; } @@ -134,7 +247,7 @@ char const* program_name; void usage() { - clog << "Usage: " << program_name << " system-map-file < oops-log" << endl; + clog << "Usage: " << program_name << " [ System.map ] < oops-log" << endl; exit(1); } @@ -142,38 +255,64 @@ int main(int argc, char** argv) { program_name = (argc--, *argv++); - if (argc != 1) - usage(); - char const* map_file_name = (argc--, *argv++); - ifstream map(map_file_name); - if (map.bad()) { - clog << program_name << ": Can't open `" << map_file_name << "'" << endl; - return 1; - } - NameList names; - map >> names; + if (argc > 1) + usage(); + else if (argc == 1) { + char const* map_file_name = (argc--, *argv++); + ifstream map(map_file_name); + if (map.bad()) + clog << program_name << ": Can't open `" << map_file_name << "'" << endl; + else { + map >> names; + cout << "Using `" << map_file_name << "' to map addresses to symbols." << endl; + } + } + if (!names.valid()) + cout << "No symbol map. I'll only show you disassembled code." << endl; + cout << endl; char buffer[1024]; while (!cin.eof()) { - long address; + long eip_addr; cin >> buffer; - if (strequ(buffer, "EIP:")) { - cin >> hex >> address; + if (strequ(buffer, "EIP:") && names.valid()) { + cin >> ::hex >> eip_addr; cin >> buffer[0]; - cin >> hex >> address; - KSym* ksym = names.find(address); + cin >> ::hex >> eip_addr; + cin >> buffer; + if (!strequ(buffer, "EFLAGS:")) { + clog << "Please strip the line-prefixes and rerun " << program_name << endl; + exit(1); + } + KSym* ksym = names.find(eip_addr); if (ksym) - cout << "EIP: " << *ksym << endl; - } else if (strequ(buffer, "Trace:")) { - while ((cin >> address) && address > 0xc) { + cout << ">>EIP: " << *ksym << endl; + } else if (strequ(buffer, "Trace:") && names.valid()) { + long address; + while ((cin >> ::hex >> address) && address > 0xc) { + cout << "Trace: "; KSym* ksym = names.find(address); if (ksym) - cout << "Trace: " << *ksym << endl; + cout << *ksym; + else + cout << ::hex << address; + cout << endl; } cout << endl; + } else if (strequ(buffer, "ode:") || strequ(buffer, "Code:")) { + // The 'C' might have been consumed as a hex number + unsigned char code[code_size]; + unsigned char* cp = code; + unsigned char* end = &code[code_size]; + while (cp < end) { + int c; + cin >> ::hex >> c; + *cp++ = c; + } + names.decode(code, eip_addr); } } cout << flush; -- 2.39.5